有汇友在后台问我,说他把一套在MT4上跑了三年的欧美EA原封不动挪到MT5,结果回测夏普比率从1.8直接掉到0.9,问是不是MT5本身有问题。我去年也踩过这个坑,当时差点以为策略失效了,后来逐行对tick才找到原因,今天就把整个排查过程捋一遍。
先说结论:MT4和MT5的tick数据模型、订单执行逻辑、指标计算精度都不一样,同一套代码直接迁移,夏普腰斩是常态,不是个案。我当时那套EA核心是
我一开始怀疑是点差建模问题。MT4默认用当前点差回测,MT5可以导入真实tick。后来用TDS(tick data suite)分别给两个平台灌了同样的Dukascopy tick数据,差距缩小了一点,夏普从0.91回到1.12,但离1.76还差得远。说明tick精度只是部分原因,不是主因。
真正的坑在订单执行逻辑。MT4的EA里我用了大量OrderSend+OrderModify的写法,MT5里对应的MqlTradeRequest结构完全变了。我直接把MT4的订单模块用宏定义硬套过去,结果止盈止损挂单经常被拒,因为MT5对止损距离有最小限制(STOPS_LEVEL),而MT4某些经纪商是0。这就导致回测里很多本该止盈的单子被卡住,最后反向打止损。我后来在初始化里加了SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL)做动态校验,夏普回到1.35左右。
还有一个隐蔽的坑是指标句柄。MT4的iMA、iATR是每tick重新计算,MT5里必须用iMAHandle创建句柄,然后CopyBuffer取值。我偷懒直接在OnTick里反复创建句柄,结果内存泄漏不说,指标值还滞后一根K线。改完句柄复用后,夏普又回来0.2左右,到1.55。
最后剩下的差距在点差和滑点建模。MT4回测用的是经纪商固定的点差表,MT5我用了真实tick但没开滑点模拟。后来在MT5的策略测试器里勾选“随机延迟”和“滑点”,夏普落到1.48,但这个数字反而更接近我实盘的表现——MT4那个1.76本来就是虚高的。
所以现在我的做法是:
你们迁MT5的时候有没有遇到过止盈挂不上的情况?还是说直接重写成MQL5原生代码更省心?
补充一句:后来我把iATR的周期参数按MT5的tick精度重新调了一遍,夏普才慢慢爬回来——所以别急着换策略,先把指标计算的差异对齐再说。
先说结论:MT4和MT5的tick数据模型、订单执行逻辑、指标计算精度都不一样,同一套代码直接迁移,夏普腰斩是常态,不是个案。我当时那套EA核心是
- 基于MA交叉入场,周期M15
- 止损固定35点,止盈70点
- 用iATR做动态仓位
我一开始怀疑是点差建模问题。MT4默认用当前点差回测,MT5可以导入真实tick。后来用TDS(tick data suite)分别给两个平台灌了同样的Dukascopy tick数据,差距缩小了一点,夏普从0.91回到1.12,但离1.76还差得远。说明tick精度只是部分原因,不是主因。
真正的坑在订单执行逻辑。MT4的EA里我用了大量OrderSend+OrderModify的写法,MT5里对应的MqlTradeRequest结构完全变了。我直接把MT4的订单模块用宏定义硬套过去,结果止盈止损挂单经常被拒,因为MT5对止损距离有最小限制(STOPS_LEVEL),而MT4某些经纪商是0。这就导致回测里很多本该止盈的单子被卡住,最后反向打止损。我后来在初始化里加了SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL)做动态校验,夏普回到1.35左右。
还有一个隐蔽的坑是指标句柄。MT4的iMA、iATR是每tick重新计算,MT5里必须用iMAHandle创建句柄,然后CopyBuffer取值。我偷懒直接在OnTick里反复创建句柄,结果内存泄漏不说,指标值还滞后一根K线。改完句柄复用后,夏普又回来0.2左右,到1.55。
最后剩下的差距在点差和滑点建模。MT4回测用的是经纪商固定的点差表,MT5我用了真实tick但没开滑点模拟。后来在MT5的策略测试器里勾选“随机延迟”和“滑点”,夏普落到1.48,但这个数字反而更接近我实盘的表现——MT4那个1.76本来就是虚高的。
所以现在我的做法是:
- MT4的老EA不直接迁,先写一个适配层,把订单和指标接口抽象出来
- 迁移后必须用真实tick+滑点回测,别信默认点差
- 夏普下降先查STOPS_LEVEL和句柄,再查数据精度
你们迁MT5的时候有没有遇到过止盈挂不上的情况?还是说直接重写成MQL5原生代码更省心?
补充一句:后来我把iATR的周期参数按MT5的tick精度重新调了一遍,夏普才慢慢爬回来——所以别急着换策略,先把指标计算的差异对齐再说。
