文章 "开发多币种 EA 交易(第 2 部分):过渡到交易策略的虚拟仓位" - 页 5

[删除]  
mytarmailS #:
在市场上,复杂的模型会比一篮子简单的 TS 更有效,这不是事实。
那么,就不必把每个 TS 都喝到谷底,只需在优化器运行几次后添加新的 TS 即可。
 
Maxim Dmitrievsky bagging)优化,而是进行 "助推"(boosting)优化。即先优化一个策略,然后将其信号作为参数替换为 第二个策略,再优化第二个策略,以此类推。

在我看来,突出显示的 实施是一项非同小可的任务。通常情况下,策略参数是在开始时设置的,而开仓/平仓信号是在策略运行时通过某种算法确定的。如果我们以某种统一的形式保存开仓历史,那么所有这些都必须输入到第二个策略的输入端....。是这样吗?如果我们以算法(函数)及其固定参数的形式提供这些信息,那么我们不就变成了同样的套袋,只不过走了后门?

 

非常感谢,我饶有兴趣地阅读了它。我也想做类似的事情,只是自动化程度更高,为此我打算毫不留情地将您的库投入使用,用于处理测试仪的 *.opt 和 *.tst 文件。

[删除]  
Yuriy Bykov #:

在我看来,突出显示的 实现是一项非常不简单的任务。通常情况下,策略参数会在启动时设置,而开仓/平仓信号会在策略运行时通过某种算法确定。如果我们以某种统一的形式保存开仓历史,那么所有这些都必须输入到第二个策略的输入端....。是这样吗?如果我们以算法(函数)及其固定参数的形式提供这些信息,那么我们岂不是又回到了同样的套袋,只不过是走了后门?

我还没想过如何通过优化器来实现。不,应该是每一个下一个策略都会改进上一个策略,即在其基础上更进一步。至于如何实现可视化,还需要时间。你可以在互联网上查找 "助推树 "的工作原理,并以此为基础进行设计。可能会有很多细微差别,没错。但我不会亲自动手,因为所有这些都已经包含在 MO 算法中了。它不是万能的,但就其特性而言,它可能比 TC 组合更好。

 
Maxim Dmitrievsky #:

还没想过如何通过优化器来实现。

通过将适当的 mqh 连接到 mq5,可以完全自动完成这一例程。


算法如下。

  1. 文件夹以文件形式包含之前的优化结果(如果没有优化结果,则为空)。
  2. 开始新的优化:TS 本身的交易 + 添加第 1 点的交易。在这种情况下,MM 在 p.1 和 TS 之间平均分配。
  3. 优化的最佳通过(任何类型的 OnTester)记录在项目 1 中。
  4. 在 p.2 中,TS 想要多少次就有多少次。

因此,您可以任意组合。很明显,即使是完整搜索,最终结果也取决于 TS 的启动顺序。

同样显而易见的是,即使在 SB 上,每通过一次,指标都会有所改善,但这只是一种拟合。

 
Yuriy Bykov #:

非常感谢,我已经看了代码。我稍后会研究如何传递输入参数。如果不完全采用这种方法,有些要点可能会非常有用。

我将目前的输入工作成果(在附录中)再次应用到本文的代码中。

下面是SimpleVolumesExpertSingle.mq5 的示例。

#define  INPUT_STRUCT_ADDON
#include "Advisor.mqh"
#include "SimpleVolumesStrategy.mqh"
#include "VolumeReceiver.mqh"

input string      symbol_              = "EURGBP";    // 交易工具(符号)
input group "===顾问参数"。
input ulong       magic_              = 27181; // 魔术

CAdvisor     *expert;         // 专家对象指针

//+------------------------------------------------------------------+
//| 专家初始化函数|
//+------------------------------------------------------------------+
int OnInit() {
   expert = new CAdvisor(new CVolumeReceiver(magic_));

   // 添加一个策略实例
   expert.Add(new CSimpleVolumesStrategy( symbol_, inStrategyInput + inSimpleVolumesStrategyInput));

   return(INIT_SUCCEEDED);
}


我设法在代码中实现了输入的一次性处方(SimpleVolumesStrategyInput.mqh)。

//https://www.mql5.com/zh/code/47932
// 使用此字符串查找所有输入 mqh。
// #include <fxsaber\Input_Struct\Input_Struct.mqh> // Original

#define  TYPENAME_INPUT SimpleVolumesStrategyInput

#define  MACROS_MULTI                    \
  MACROS(signalPeriod, int, 13)         \ // 平均交易量的蜡烛数量
  MACROS(signalDeviation, double, 0.3)  \ // 开第一单时与平均值的相对偏差
  MACROS(signaAddlDeviation, double, 1) \ // 开仓第二单和后续单时与平均值的相对偏差
  MACROS(openDistance, int, 0)          \ // 从价格到挂单的距离
  MACROS(stopLevel, double, 10500)      \ // 止损点(单位:点)
  MACROS(takeLevel, double, 465)        \ // 止盈(点数)
  MACROS(ordersExpiration, int, 1000)   \ // 挂单到期时间(分钟)
  MACROS(maxCountOfOrders, int, 3)        // 同时打开的最大订单数

附加的文件:
 
fxsaber #:

我将目前的输入结果(在附录中)再次应用到本文的代码中。

SimpleVolumesExpertSingle.mq5 的示例。


我设法在代码中实现了输入的一次性处方(SimpleVolumesStrategyInput.mqh)。

在我看来,这比之前的变体要容易得多。不过,也许只是当你再看一遍别人的代码时,它每次都会变得更清晰、更简单。非常感谢!在学习的过程中,我遇到了一个问题,"//从这里复制粘贴更新:"后面的代码不能放在一个包含文件中并附加上去,而不是粘贴上去吗?现在做实验不方便,所以想问一下。

在第三篇文章 中,我还没有提到输入参数:(......)。但肯定会有的。

 
Yuriy Bykov #:

在学习的过程中,我产生了一个问题:是否可以将"//从此处复制粘贴更新:"后面的代码放到一个包含文件中,然后插入而不是粘贴?现在做实验不方便,所以我决定问一问。

不幸的是,你不能这样做,因为同一文件的 #include 只发生一次--第一次遇到。之后就会被忽略。

这就是为什么你必须在这里 用不同的名字创建一个完全相同的文件的原因之一。


但总的来说,"复制-粘贴 "选项只需点击几下。不需要理解代码。

PriceChannel
PriceChannel
  • www.mql5.com
Ценовой канал произвольной длительности (таймфрейм) бара.
 
Yuriy Bykov #:

在第三篇文章 中,输入参数还没有达到 :( 。但肯定会有的。

你们的架构与我的有些不同,所以我没有为 INPUT_STRUCT 提供很多在这个项目中有用的东西。

你没有发表它是件好事,因为我又重新做了一次--做成了最简洁方便的版本(似乎是最终版本)。

我添加了分组、字符串输入和其他一些小功能,以方便将来使用。

#define  TYPENAME_INPUT StrategyInput

#define  MACROS_MULTI                           \
  INPUT(symbol, string, "EURGBP")              \ // 交易工具(符号)
  INPUT(timeframe, ENUM_TIMEFRAMES, PERIOD_H1) \ // 图表周期(时间框架)
  GROUP("===资本管理选项") \
  INPUT(fixedLot, double, 0.01)                  // 未结头寸的大小(固定)
#define  TYPENAME_INPUT SimpleVolumesStrategyInput

#define  MACROS_MULTI                           \
  GROUP("===开启信号的参数")   \
  INPUT(signalPeriod, int, 13)                 \ // 平均交易量的蜡烛数量
  INPUT(signalDeviation, double, 0.3)          \ // 开第一单时与平均值的相对偏差
  INPUT(signaAddlDeviation, double, 1)         \ // 开仓第二单和后续单时与平均值的相对偏差
  GROUP("===待处理订单参数"。)   \
  INPUT(openDistance, int, 0)                  \ // 从价格到挂单的距离
  INPUT(stopLevel, double, 10500)              \ // 止损点(单位:点)
  INPUT(takeLevel, double, 465)                \ // 止盈(点数)
  INPUT(ordersExpiration, int, 1000)           \ // 挂单到期时间(分钟)
  GROUP("===资本管理选项") \
  INPUT(maxCountOfOrders, int, 3)                // 同时打开的最大订单数


应用代码片段演示了如何使用。

#define  INPUT_STRUCT_ADDON
#include "Advisor.mqh"
#include "SimpleVolumesStrategy.mqh"
#include "VolumeReceiver.mqh"

input group "===顾问参数"。
input ulong       magic_              = 27181; // 魔术

CAdvisor     *expert;         // 专家对象指针

//+------------------------------------------------------------------+
//| 专家初始化函数|
//+------------------------------------------------------------------+
int OnInit() {
   expert = new CAdvisor(new CVolumeReceiver(magic_));

   // 添加一个策略实例
   expert.Add(new CSimpleVolumesStrategy(inStrategyInput + inSimpleVolumesStrategyInput));

   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 构造函数|
//+------------------------------------------------------------------+
CSimpleVolumesStrategy::CSimpleVolumesStrategy( const string sInputs ) : CStrategy(sInputs)
{
   this.Input = sInputs;

   ArrayResize(m_orders, this.Input.maxCountOfOrders);

   // 加载指标以获取刻度线量
   iVolumesHandle = iVolumes(this.InputStrategy.symbol, this.InputStrategy.timeframe, VOLUME_TICK);

// 设置刻度卷数组接收器的大小和所需的寻址方式
   ArrayResize(volumes, this.Input.signalPeriod);
   ArraySetAsSeries(volumes, true);
}
//+------------------------------------------------------------------+
//|| 构造函数|
//+------------------------------------------------------------------+
CStrategy::CStrategy( const string sInputs ) : m_isChanged(false)
{
  this.InputStrategy = sInputs;
}
//+------------------------------------------------------------------+
//| 专家初始化函数|
//+------------------------------------------------------------------+
int OnInit() {
// 检查参数是否正确
   if(startIndex_ < 0 || startIndex_ + totalStrategies_ > 9) {
      return INIT_PARAMETERS_INCORRECT;
   }

// 创建并填充策略实例数组
   CStrategy *strategies[9];

   StrategyInput InputBase;
   SimpleVolumesStrategyInput Input;

   InputBase.timeframe = PERIOD_H1;

   // 第一种设置方式是初始化。
   const StrategyInput InputBase0 = {"EURGBP", PERIOD_H1, NormalizeDouble(0.01 / 0.16 * depoPart_, 2)};
   const SimpleVolumesStrategyInput Input0 = {13, 0.3, 1.0, 0, 10500, 465, 1000, 3};
   strategies[0] = new CSimpleVolumesStrategy(InputBase0 + Input0);

   // 第二种指定方式是通过字符串和数组。
   InputBase.fixedLot = NormalizeDouble(0.01 / 0.09 * depoPart_, 2);
   const double Array1[] = {17, 1.7, 0.5, 0, 16500, 220, 1000, 3};
   strategies[1] = new CSimpleVolumesStrategy(InputBase["symbol = EURGBP"] + "," + Input[Array1]);

   // 第三种指定方式是字段赋值。
   InputBase.fixedLot = NormalizeDouble(0.01 / 0.16 * depoPart_, 2);
   InputBase.symbol = "EURGBP";
   const double Array2[] = {51, 0.5, 1.1, 0, 19500, 370, 22000, 3};
   strategies[2] = new CSimpleVolumesStrategy(InputBase + Input[Array2]);
附加的文件:
 
fxsaber #:

好在他们没有发布,因为我又重新做了一次--最简洁、最方便用户的版本(似乎是最终版本)。

是的,非常熟悉的情况。一切似乎都已就绪,然后你又重新做了一遍,结果就更好了。我认为这也不是最终版本,因为你在代码中使用参数的情况已经发布了。当涉及到将参数构建到集合中,甚至自动构建到集合中时,你可能会发现你还可以改进/简化。

谢谢