自动调优:ParameterGetRange 和 ParameterSetRange
上一节,我们学习了如何将一个优化标准传递给测试程序。但是,我们忽略了重要的一点。如果你查看我们的优化日志,会看到许多错误消息,如下所示。
...
|
换言之,每经过几次测试传递,输入参数就会有问题,这样的传递就无法执行。OnInit 处理程序包含以下检查:
if(FastOsMA >= SlowOsMA) return INIT_PARAMETERS_INCORRECT; |
对我们而言,施加这样的限制是很合理的,即慢速 MA 的周期应大于快速 MA 的周期。但是,测试程序并不知道我们算法的此类要求,因此会尝试对各种周期组合进行排序,包括不正确的组合。对于优化而言,这可能是一种常见的情况,但是却有负面后果。
由于我们应用了遗传优化,每一代中有几个被拒绝的样本不会参与进一步的突变。MetaTrader 5 优化器不会弥补这些损失,也就是说,不会为这些被拒绝的样本生成替代品。然后,样本数量较小会对质量产生负面影响。因此,有必要考虑一种方法来确保输入设置仅在正确的组合中被枚举。此处有两个 MQL5 API 函数可提供帮助:ParameterGetRange 和 ParameterSetRange。
这两个函数都有两个参数类型不同的重载原型:long 和 double。这是对 ParameterGetRange 函数的两种变体说明。
bool ParameterGetRange(const string name, bool &enable, long &value, long &start, long &step, long &stop)
bool ParameterGetRange(const string name, bool &enable, double &value, double &start, double &step, double &stop)
对于按名称指定的输入变量,函数在优化过程中接收有关其当前值 (value)、值范围 (start, stop) 和变化步长 (step) 的信息。此外,还会向 enable 变量写入一个特性,说明是否是名为 'name' 的输入变量启用了优化。
该函数返回成功 (true) 或错误 (false) 的指示。
该函数只能通过三个与优化相关的特殊处理程序中调用:OnTesterInit、OnTesterPass 和 OnTesterDeinit。我们将在 下一节中介绍。正如你从名称中可以猜到的,在优化开始之前调用OnTesterInit,在优化完成之后调用 OnTesterDeinit,在优化过程中的每一次传递之后调用 OnTesterPass。目前,我们只对 OnTesterInit 感兴趣。就像其他两个函数一样,该函数没有参数,可以用 void 类型进行说明,也就是说,不会返回任何值。
ParameterSetRange 函数的两个版本具有相似的原型,并执行相反的操作:它们可设置 EA 交易的输入参数的优化特性。
bool ParameterSetRange(const string name, bool enable, long value, long start, long step, long stop)
bool ParameterSetRange(const string name, bool enable, double value, double start, double step, double stop)
该函数在优化当前值、变化步长和值范围时为名为 name 的 input 变量设置修改规则。
在策略测试程序中启动优化时,只能通过 OnTesterInit 处理程序调用此函数。
因此,使用 ParameterGetRange 和 ParameterSetRange 函数,你可以分析并设置新的范围和步长值以及从优化中完全排除或包括某些参数,而不管策略测试程序中的设置如何。这允许你创建自己的脚本来管理优化期间的输入参数空间。
该函数甚至允许你在优化中使用那些用 sinput 修饰符声明的变量(用户没有将这些变量包含在优化中)。
注意!在调用 ParameterSetRange 并更改特定输入变量的设置之后,对 ParameterGetRange 的后续调用将不会“看到”这些更改,仍然会返回到原始设置。因此在复杂软件产品中不能一起使用这些函数,在复杂软件产品中,设置可以由独立开发人员的不同类和 库 来处理。
我们使用新函数来改进 BandOsMA EA 交易。更新后的版本命名为 BandOsMApro.mq5("pro" 可以有条件解码为“参数范围优化”)。
因此,我们有 OnTesterInit 处理程序,在其中我们可以读取 FastOsMA 和 SlowOsMA 参数的设置,并检查它们是否包含在优化中。如果包含,则需要关掉它们,并提供一些参数作为回报。
void OnTesterInit()
|
不幸的是,由于添加了 OnTesterInit,编译器也会要求添加 OnTesterDeinit,虽然我们并不需要这个函数。但是我们被迫同意并添加一个空白处理程序。
void OnTesterDeinit()
|
代码中存在 OnTesterInit/OnTesterDeinit 函数将导致这样一个事实,即当优化开始时,将在终端中打开一个额外的图表,在这个图表上运行我们的 EA 交易副本。该副本会以一种特殊的模式工作,允许你从代理的测试副本接收额外的数据(所谓的 frames),但我们将在后面探讨这种可能性。现在,我们需要注意的是,所有文件、日志、图表和对象的操作都像往常一样直接在终端(而不是代理)的 EA 交易的辅助副本中进行。特别是,所有错误消息和 Print 调用都将显示在终端的 Experts 选项卡上的日志中。
我们有关于这些参数变化范围和步骤的信息,我们可以准确地重新计算所有正确的组合。这个任务被分配给一个单独的 Iterate 函数,因为类似的操作必须由 OnInit 处理程序中代理的 EA 交易副本来重现。
在 Iterate 函数中,我们在快速和慢速 MA 周期上有两个嵌套循环,在这两个循环中,我们可统计有效组合的数量,比如,当 i 周期小于 j 时。当从 OnInit 调用Iterate 时,我们需要可选的 find 参数,以通过组合i 和 j 的序列号返回该组合对。由于需要返回 2 个数字,因此我们为其说明了 PairOfPeriods 结构体。
struct PairOfPeriods
|
从 OnTesterInit调用 Iterate 时,我们不使用 find 参数,而是一直计数到最后,并在结构体的第一个字段中返回得到的数量。这将是一些新的影子参数的值范围,我们必须为此启用优化。姑且称之为 FastSlowCombo4Optimization,然后加入新的一组辅助输入参数。此处,更多参数将很快添加进去。
input group "A U X I L I A R Y"
|
我们回到 OnTesterInit,使用 ParameterSetRange 在所需的范围内通过 FastSlowCombo4Optimization 参数组织一次 MQL5 优化。
void OnTesterInit()
|
请注意,新参数的迭代次数应显示在终端日志中。
在代理上进行测试时,使用 FastSlowCombo4Optimization 中的数字,通过再次调用 Iterate 可获得几个周期,这次可使用填充的 find 参数。但问题是,对于该操作,需要知道初始范围以及 FastOsMA 和 SlowOsMA 参数的变化步长。该信息仅存在于终端中。所以,我们需要以某种方式转移给代理。
现在我们将应用迄今为止我们知道的唯一解决方案:增加 3 个影子优化参数,并为其设置一些值。将来,我们将熟悉将文件传输给代理的技术(参见 测试程序的预处理指令)。然后便可以把 Iterate 函数计算的整个索引数组写入文件,并将其发送给代理。这样可避免使用三个额外的影子优化参数。
因此,我们添加三个输入参数:
sinput ulong FastShadow4Optimization = 0; // (reserved for optimization)
|
我们使用 ulong 类型更为合理:将 2 个 int 数打包到每个值中。这是它们在 OnTesterInit 中的填写方式。
void OnTesterInit()
|
所有 3 个参数都是不可优化的(第二个自变量为 false)。
对 OnTesterInit 函数的操作到此结束。我们来看接收方:OnInit 处理程序。
int OnInit()
|
使用 MQLInfoInteger 函数,我们可以确定所有的 EA 交易模式,包括那些与测试和优化相关的模式。将 ENUM_MQL_INFO_INTEGER 枚举的一个元素指定为参数后,我们将得到一个逻辑符号作为结果 (true/false):
- MQL_TESTER - 该程序在测试程序中运行
- MQL_VISUAL_MODE - 测试程序在可视化模式下运行
- MQL_OPTIMIZATION - 测试过程在优化过程中进行(不是单独运行)
- MQL_FORWARD - 在优化后的递进期间执行试过程(如果由优化设置指定)
- MQL_FRAME_MODE - EA 交易在终端图表上(而不是在代理上)以特殊服务模式运行,以控制优化( 下一节将详细介绍)
MQL 程序的测试模式
一切准备就绪,开始优化。一旦启动,使用所述的设置 Presets/MQL5Book/BandOsMA.set,我们将在终端的 Experts 日志中看到一条消息:
Parameter FastSlowCombo4Optimization is enabled with maximum: 698 |
这一次,优化日志中应没有错误,正常生成所有内容,不会崩溃。
...
|
这甚至可以通过增加的整体优化时间来确定:早先,一些传递在早期阶段被拒绝,现在它们都得到了完全处理。
但是我们的解决方案也有一个缺点。现在,EA 交易的工作设置不仅包括 FastOsMA 和 SlowOsMA 参数中的几个周期,还包括它们在所有可能组合中的序号 (FastSlowCombo4Optimization)。我们唯一能做的就是输出 OnInit 函数中解码的周期,这在上面已经演示过了。
因此,在优化的帮助下找到好的设置后,用户将像往常一样执行一次运行来完善交易系统的行为。在测试日志的开头,应出现以下形式的内容:
MA periods are restored from shadow: FastOsMA=27 SlowOsMA=175 |
然后,你可以在同名参数中输入指定的周期,并重置所有影子参数。