回测中可能忽略的问题
假设交易逻辑以RSI超买超卖开仓,若以当前未走完的K线(i=0
,实时浮动指标值)作为判断依据,就会出现信号错误。因为实时K线的指标值是动态变化的,未固定,而回测环境使用的是历史固定K线(i=1
及之后,开高低收已确定)。若代码中未统一处理,实盘与回测的交易记录和绩效会相差甚远。
为什么要统一回测与实盘的价位模式?
以MT5为例,实盘与回测的报价处理机制不同:
- 实盘环境:
- 平台服务器(MT5 Server)接收实时报价,传递到本地MT5客户端(MT5 Client),再传递给EA,最后到
on tick
方法。 - 若前一个报价(Tick1)在
on tick
中未执行完毕,后续报价(Tick2、Tick3)会被丢弃,EA无法处理——代码运行效率影响报价接收。
- 平台服务器(MT5 Server)接收实时报价,传递到本地MT5客户端(MT5 Client),再传递给EA,最后到
- 回测环境:
- 本地测试环境直接生成历史报价,传递给EA和
on tick
方法。 - 会等待前一个报价执行完毕,再处理后续报价,不会丢弃任何Tick——保证所有历史价格被处理。
- 如果被丢弃的tick中刚好产生了交易信号, 则会导致回测结果与实盘结果不一致。
- 本地测试环境直接生成历史报价,传递给EA和
结论:实盘可能错过实时报价,回测则“不离不弃”,两者天然存在偏差。若再使用实时K线(i=0
)作为判断依据,不统一喂价模式,实盘与回测绩效会严重脱节。
统一喂价模式的解决方案
1. 使用 isNewBar
函数控制执行时机
在 OnTick
方法前添加 isNewBar
函数,确保仅在新K线生成时处理价格,避免实时报价干扰:
cpp
bool isNewBar(string symbol, ENUM_TIMEFRAMES tf, int &totalBar)
{
int totalBars = iBars(_Symbol, tf);
if (totalBars == totalBar)
return false;
totalBar = totalBars;
return true;
}
通过对比当前K线总数与全局变量,仅在新K线产生时执行策略,确保实盘与回测均基于K线第一个价格处理,统一喂价逻辑。
2. 优化回测时间周期设置
- 避免高频喂价:回测时若选择“每次报价”或“每个点(基于实时点)”,虽看似精确,但会显著降低回测速度(尤其针对小时级以上策略)。
- 推荐配置:
- 时间周期选择 M1(1分钟),喂价模式选择 “仅使用开盘价”,即每隔1分钟获取一次K线开盘价。
- 若策略周期为日线或更高,可放宽至5分钟或更长周期,在保证精度的同时大幅提升回测效率。