测试程序的预处理指令
在 程序的通用特性一节中,我们首先熟悉了MQL 程序中的 #property 指令。然后,我们认识了用于 脚本、 服务和 指标的指令。还有一组用于测试程序的指令。我们已经提到了其中一些。例如, tester_everytick_calculate 会影响指标的计算。
下表列出了所有测试程序指令及其解释。
指令 |
说明 |
---|---|
tester_indicator "string" |
自定义指标名称,格式为 "indicator_name.ex5 " |
tester_file "string" |
文件名,格式为 "file_name.extension",包含程序测试所需的初始数据 |
tester_library "string" |
库 名,扩展名为“library.ex5”或“library.dll” |
tester_set "string" |
文件名,格式为 "file_name.set",带有程序输入参数优化值及其范围的设置 |
tester_no_cache |
禁止读取先前优化的现有缓存(opt 文件) |
tester_everytick_calculate |
禁用测试程序中计算指标的资源节约模式 |
最后两个指令没有自变量。所有其他类型都需要一个带双引号的字符串,其中包含某种类型的文件名。由此还可以得出结论,这些指令可以在不同的文件中重复,也就是说,可以包括几个设置文件或几个指标。
tester_indicator 指令用于以常量字符串(文字)的形式将测试程序的源代码中没有提到的那些指标连接到测试过程。通常,如果在相应的参数中明确指定了指标名称,则编译器可以从 iCustom 调用中自动确定所需的指标,例如,iCustom(symbol, period, "indicator_name",...)。但是,情况并非总是如此。
假设我们正在编写一个通用的 EA 交易,其可以使用不同的移动平均线指标,而不仅仅是标准的内置指标。然后,我们可以创建一个输入变量,由用户指定指标名称。然后,iCustom 调用会变为 iCustom(symbol, period, CustomIndicatorName,...),其中 CustomIndicatorName 为 EA 交易的输入变量,其内容在编译时是未知的。此外,在这种情况下,开发人员可能会应用 IndicatorCreate 而不是 iCustom,因为还必须配置指标参数的数量和类型。在这种情况下,为了调试程序或者用特定的指标演示程序,我们应使用 tester_indicator 指令向测试程序提供名称。
在源代码中报告指标名称的需要极大地限制了测试这种可以在线连接各种指标的通用程序的能力。
如果没有 tester_indicator 指令,终端将无法向源代码中未明确声明的代理发送指标,其结果是相关程序将失去部分或全部函数。
tester_file 指令允许你指定一个文件,该文件将在测试之前被传输到代理并放置在沙箱中。文件的内容和类型没有规定。例如,可以是预先训练的神经网络权重、预先收集的市场深度数据(因为此类数据不能被测试程序再现)等等。
注意,tester_file 指令中的文件只有在编译时存在时才会被读取。如果源代码是在没有对应文件的情况下编译的,那么其在未来的出现将不再有帮助:编译后的程序将在没有辅助文件的情况下发送给代理。因此,例如,如果 tester_file 中指定的文件是在 OnTesterInit 中生成的,应确保具有给定名称的文件在编译时已经存在,即使它是空的。我们将在下面进行演示。
请注意,如果 tester_file 指令中指定的文件不存在,编译器不会生成警告。
连接的文件必须在终端的沙箱MQL5/Files/ 中。
tester_library 指令用于通知测试程序需要将库转移到代理,库是一个辅助程序,只能在另一个MQL 程序的上下文中工作。我们将在单独的 章节中详细介绍库。
测试所需的库由源代码中的 #import 指令自动确定。但是,如果外部指标使用任何库,则必须启用该特性。该库既可以带有 dll 扩展名,也可以带有 ex5 扩展名。
tester_set 指令用于操作带有 MQL 程序设置的 set 文件。该指令中指定的文件将从测试程序的上下文菜单中提供,并允许用户快速应用设置。
如果指定名称时没有包含路径,则 set 文件必须与 EA 交易位于同一目录中。这有点出乎意料,因为 set 文件的默认目录是 Presets,这是终端接口命令保存它们的位置。要从给定目录连接 set 文件,必须在指令中显式指定,并在其前面加一个斜杠,该斜杠指示 MQL5 文件夹内的绝对路径。
#property tester_set "/Presets/xyz.set" |
当没有前斜杠时,该路径相对于放置源文本的位置。
在添加文件并重新编译程序后,需要立即在测试程序中重新选择 EA 交易;否则文件不会被选取!
如果你将 EA 交易名称和版本号指定为类型为 set 文件的 <expert_name> _<number> .set,那么它会自动添加到版本号 <number> 下的参数版本下载菜单中。例如,名称 "MACD Sample_4.set" 表示它是 EA 交易 "MACD Sample.mq5" 的 set 文件,版本号为 4。
如果感兴趣,可以研究 set 文件的格式:为此,可在策略测试程序中手动保存测试/优化设置,然后在文本编辑器中打开以这种方式创建的文件。
现在我们来看 tester_no_cache 指令。执行优化时,策略测试程序会将所有执行过的测试轮次结果保存到优化缓存(扩展名为 opt 的文件)中,其中存储了每组输入参数的测试结果。这使得在对相同参数进行重新优化时,无需重新计算和浪费时间即可获得现成的结果。
但是,对于某些任务,如数学计算,无论优化缓存中是否存在现成的结果,都可能需要执行计算。在这种情况下,源代码必须包括特性 tester_no_cache。同时,测试结果本身仍将存储在缓存中,这样就可以在策略测试程序中看到所有已完成传递的数据。
tester_everytick_calculate 指令用于在测试程序的每条分时报价上启用指标计算模式。
默认情况下,仅在访问指标以获取数据时,即当请求指标缓冲区的值时,才会在测试程序中计算指标。如果你不需要在每个分时报价上获取指标值,则会大大加快测试和优化的速度。
但是,一些程序可能需要在每条分时报价上重新计算指标。在这种情况下,特性 tester_everytick_calculate 非常有用。
在以下情况下,策略测试程序中的指标也必须在每条分时报价上进行计算:
- 在可视化模式下测试时
- 如果指标中有 EventChartCustom、OnChartEvent 或 OnTimer 函数
此特性仅适用于策略测试程序中的操作。在终端中,指标总是在每个传入的分时报价上计算。
该指令实际上已经在 FrameTransfer.mq5 EA 交易
#property tester_set "FrameTransfer.set" |
中使用过,只是我们没有关注。"FrameTransfer.set" 文件位于源代码旁边。在同一个 EA 交易中,我们还需要上表中的另一个指令:
#property tester_no_cache |
此外,我们考虑 tester_file 指令的一个示例。在前面关于优化时 自动调优 EA 交易参数 一节中,我们介绍了BandOsMApro.mq5,其中需要引入几个影子参数来将优化范围传递给在代理上运行的源代码。
tester_file 指令可允许我们省略这些多余的参数。我们将新版本命名为 BandOsMAprofile.mq5。
既然我们现在已经熟悉了 tester_set 指令,那么我们将前面提到的文件 /Presets/MQL5Book/BandOsMA.set 添加到新版本中。
#property tester_set "/Presets/MQL5Book/BandOsMA.set" |
关于 FastOsMA 和 SlowOsMA 的变更周期的范围和步长信息将被保存到文件BandOsMAprofile.csv 中,而非保存到三个附加的输入参数 FastShadow4Optimization、SlowShadow4Optimization 和 StepsShadow4Optimization 中。
#define SETTINGS_FILE "BandOsMAprofile.csv"
|
对于允许的周期组合的完整枚举,仍然需要影子设置 FastSlowCombo4Optimization。
input group "A U X I L I A R Y"
|
注意,我们在 Iterate 函数中找到了其优化范围。我们第一次使用快慢周期组合的完整枚举在 OnTesterInit 中调用该参数。
基本上,我们可以将所有有效的组合存储在 PairOfPeriods 结构体数组中,并将其写入二进制文件,以便传输给代理。然后,在代理上,我们的 EA 交易可以从该文件中读取就需的数组,并通过 FastSlowCombo4Optimization 索引从数组中提取相应的 FastOsMA 和 SlowOsMA 对。
相反,我们将关注程序工作逻辑中的最小变化:继续恢复由于 OnInit 处理程序中的第二次调用 Iterate 而导致的几个周期。这一次,我们不是通过影子参数,而是通过 CSV 文件,获取周期值的枚举范围和步长。
以下是对 OnTesterInit 的更改。
int OnTesterInit()
|
注意,我们使用返回类型 int 创建了 OnTesterInit 处理程序,如果该文件不存在,就可以取消优化。但是,在任何情况下,实际数据都会被写入文件,所以如果它不存在,现在就应创建,并且随后的优化启动就肯定会成功。
如果想跳过这一步,可以事先创建一个空文件 MQL5/Files/BandOsMAprofile.csv。
OnInit 处理程序更改如下。
int OnInit()
|
在优化后运行单次测试时,我们将在日志中看到基于优化值 FastSlowCombo4Optimization 解码的 FastOsMA 和 SlowOsMA 周期值将来,我们可以在周期参数中替换这些值,并删除 csv 文件。我们还规定,如果 FastSlowCombo4Optimization 设置为 -1,则不会考虑该文件。