MT5的onTester里算不出自定义指标句柄,回测直接卡死

新帖
登录发帖
Exness 推荐平台

入金门槛低,出金到账快,支持多种账户类型

FSA(塞舌尔)/FCA(英国) / CySEC(塞浦路斯) · 最低入金 $130
量化Coder
量化Coder 楼主 1 小时前 浏览 25 回复 0 阅读 1 分钟
Lv.1 新手汇友 等级 Lv.1 主题 7 帖数 24 积分 1874 汇币 1622
1楼
刚在MQL5文档里翻到一段关于测试代理生命周期的说明,结合前几天一个汇友问我的问题,我觉得有必要把onTester里调用iCustom导致回测卡死这事捋一捋。他当时的情况是:一个基于ATR动态加仓的EA,在onTick里用iCustom取自定义指标缓冲区的值,回测跑到一半直接无响应,日志里连个报错都没有,测试代理进程挂死在那边。后来排查下来,问题出在他把指标句柄的创建和读取都塞进了onTester里。
先说结论:onTester函数运行在测试代理的独立线程中,而且这个阶段指标计算资源已经被释放,任何试图新建句柄或强制调用CopyBuffer的操作都可能触发死锁。 这不是Bug,是MT5回测架构的设计约束。我们平时在onTick里写iCustom能跑通,是因为主测试线程在每次tick推进时会给指标计算留出时间片;而onTester是在测试结束后的汇总阶段执行的,此时指标缓冲区不再更新,你再去要数据,代理只能等一个永远不会到来的信号。
我自己的踩坑过程是这样的:
  • 第一版:在onTester里直接调iCustom,想算整个回测区间的自定义指标均值,结果测试进度条卡在99%不动,手动终止后日志显示"test agent timeout"。
  • 第二版:改成在onInit里创建句柄存全局变量,onTester里CopyBuffer读值,依然卡死,因为CopyBuffer在onTester阶段会阻塞等待指标线程响应。
  • 第三版:把指标数据在onTick里实时累加到全局数组,onTester只做纯数学统计,问题消失,回测耗时从卡死变成正常跑完。

关键点在于句柄必须在onInit阶段创建,且创建后要检查INVALID_HANDLE。很多人忽略这一步,直接拿返回值去CopyBuffer,如果句柄无效,CopyBuffer会返回-1,但onTester里这个-1不会让EA停下来,而是让代理线程进入异常等待。我习惯在onInit里加这么一段:
int g_atrHandle = INVALID_HANDLE;
int OnInit()
{
g_atrHandle = iCustom(_Symbol, _Period, "MyATR", 14);
if(g_atrHandle == INVALID_HANDLE)
{
Print("指标句柄创建失败,错误码:", GetLastError());
return INIT_FAILED;
}
return INIT_SUCCEEDED;
}
然后在onTick里用CopyBuffer把需要的缓冲区值取出来,存进一个全局数组或者直接做累加。注意CopyBuffer的第四个参数count不要超过Bars计算范围,回测时Bars数量是动态增长的,如果你在onTick里固定取100根,早期tick会返回0,这个要加个判断跳过。
还有一个更隐蔽的坑:onTester里不要调用任何带Sleep或等待逻辑的函数,包括某些封装好的指标读取库。有些第三方库内部用了EventSetTimer或者轮询等待,在测试代理环境下这些机制不会正常触发,直接导致线程挂起。我见过一个案例,EA在onTester里调了一个计算夏普比率的自定义函数,函数内部用iCustom取净值曲线,结果整个回测卡死,日志里连"OnTester"的打印都没出现。
那onTester到底能干什么?我的经验是:只做纯内存数据的后处理。比如你在onTick里已经维护了一个交易记录数组,onTester里遍历这个数组算最大回撤、盈亏比、连续亏损次数,这些操作不涉及任何指标句柄或跨线程调用,完全安全。如果确实需要自定义指标在回测结束时的值,就在最后一个onTick里把值存到全局变量,onTester直接读变量。
另外提一句,MT5的测试代理在onTester执行完毕后会强制释放所有指标资源,所以你在onTester里创建的句柄即使没卡死,测试结束后也会变成野句柄,下次回测如果复用同一个EA实例,可能读到脏数据。稳妥做法是在onDeinit里统一释放句柄,用IndicatorRelease。
最后给一个我目前在用的模式:onInit创建句柄 → onTick实时CopyBuffer并累加统计量 → onTester只读全局统计变量做最终计算 → onDeinit释放句柄。这套流程跑欧美和黄金的回测都没再出现过卡死。
你们有没有遇到过onTester里调iCustom不卡死但结果全零的情况?我怀疑跟测试代理的缓冲区快照机制有关,有类似经历的汇友一起讨论下。
0 回复 众裁0 复制
#1
💬
暂无回复,来抢沙发吧!
THE END
本帖内容仅供学习交流,不构成任何投资建议。外汇交易存在高风险,请谨慎参与。
← 上一帖 EA回测盈利实盘却亏:用tick数据逐笔对比找出滑点元凶