拿镑美M5的均线信号做了个统计,我发现同样的策略,用MT5自带测试器跑出来的胜率是58%,换到Python里用pandas复现,胜率掉到49%。差了9个百分点,不是策略逻辑的问题,是时间戳错位了。MT5服务器返回的K线时间,默认是经纪商服务器时区,多数是GMT+2或GMT+3,夏令时还会跳。而Python这边如果直接用UTC或者本地时间做索引,信号触发的那根bar就会整体偏移一到两根,回测结果自然对不上。
我踩过的第一个坑是直接拿MT5的copy_rates_from_pos拉数据,以为时间列就是UTC。实际上它返回的是服务器时间,而且不带时区标记,pandas读进来默认当naive时间处理。后来我固定用copy_rates_range,并且显式把返回的time字段转成datetime,再用pytz的timezone('Etc/GMT-2')或者GMT-3去localize。注意这里GMT-2对应的是UTC+2,pytz的Etc/GMT符号是反的,这个坑我调了两个晚上才反应过来。
具体对齐的步骤我整理了一下,供参考:
另外提醒一点,夏令时切换那几周最容易出问题。比如欧美3月底和10月底,服务器时间会从GMT+2跳到GMT+3,如果你代码里写死offset,那两周的回测信号会整体偏一小时。我的做法是维护一个offset的查找表,按日期区间去取,或者直接用MetaTrader5的copy_rates返回的time做差分,检测跳变。VPS上跑实盘EA也一样,如果VPS系统时区设成UTC,而MT5服务器是GMT+3,日志时间会对不上,排查起来很痛苦。
最后说个验证方法:拿一段已知有非农或者利率决议的日期,比如某个月第一个周五的20:30(GMT+2服务器时间),看你Python回测里信号触发的时间戳是不是也落在那个窗口。如果偏了,就说明时区没对齐。你们平时是怎么处理MT5服务器时区和Python回测时间对齐的?有没有更省事的库或者封装?
我踩过的第一个坑是直接拿MT5的copy_rates_from_pos拉数据,以为时间列就是UTC。实际上它返回的是服务器时间,而且不带时区标记,pandas读进来默认当naive时间处理。后来我固定用copy_rates_range,并且显式把返回的time字段转成datetime,再用pytz的timezone('Etc/GMT-2')或者GMT-3去localize。注意这里GMT-2对应的是UTC+2,pytz的Etc/GMT符号是反的,这个坑我调了两个晚上才反应过来。
具体对齐的步骤我整理了一下,供参考:
- 第一步,先用mt5.symbol_info获取该品种的trade_tick_value和服务器时间偏移,或者直接看MT5终端右下角的时间,和UTC比对,算出固定offset。
- 第二步,拉取历史K线时,把返回的time列统一用pd.to_datetime转成datetime64,然后减去offset小时数,转成UTC,再tz_localize('UTC'),最后tz_convert到你策略需要的时区。
- 第三步,如果你用tick数据做回测,注意tick的time和bar的time可能不是同一套时区,MT5的copy_ticks_from返回的是毫秒时间戳,这个反而是UTC,别搞混了。
- 第四步,EA里如果用到iTime或者TimeCurrent,记得在Python端复现时也要把服务器时间转成对应时区,否则跨日、跨周的开盘信号会错位。
另外提醒一点,夏令时切换那几周最容易出问题。比如欧美3月底和10月底,服务器时间会从GMT+2跳到GMT+3,如果你代码里写死offset,那两周的回测信号会整体偏一小时。我的做法是维护一个offset的查找表,按日期区间去取,或者直接用MetaTrader5的copy_rates返回的time做差分,检测跳变。VPS上跑实盘EA也一样,如果VPS系统时区设成UTC,而MT5服务器是GMT+3,日志时间会对不上,排查起来很痛苦。
最后说个验证方法:拿一段已知有非农或者利率决议的日期,比如某个月第一个周五的20:30(GMT+2服务器时间),看你Python回测里信号触发的时间戳是不是也落在那个窗口。如果偏了,就说明时区没对齐。你们平时是怎么处理MT5服务器时区和Python回测时间对齐的?有没有更省事的库或者封装?
