处理时间(第一部分):基础(基础篇)
📘

处理时间(第一部分):基础(基础篇)

第 1/2 篇

MT5 策略测试器的入口与负载事实

在 MT5 里做系统化验证,第一道关是「策略测试器」(Strategy Tester)。它和图表端手动盯盘不是一套逻辑:前者把历史 tick 或分钟数据按你的 EA 逻辑重放,产出可复算的结果。 这套环境自 2021-12-24 起在社区被一名叫 Carl Schreiber 的用户实测记录,原帖获得 4987 次浏览、11 条跟帖——说明即便基础模块,交易者仍频繁踩坑。 外汇与贵金属品种在这里回测时,点差、库存费、tick 精度都会显著改变权益曲线,属于典型高风险验证场景,结果只代表历史概率、不预示实盘。

「时间轴才是你的交易开关」

手工盯盘的人大多不愁时序:打开网页或终端,伦敦、纽约、东京的交易所开闭市一目了然,策略该在哪个钟点触发自己清楚。但一旦你的打法绑定了特定窗口,时间就从背景变量变成了入场条件。 夜间剥头皮客只在纽约股交所收盘后到欧盟盘前那几小时动手;做“伦敦突破”的必须卡在英国盘刚开的流动性裂缝;做股指或期货的更得服从当地交易所的实际钟点,而不是经纪商服务器时间。 这里有个容易踩的坑:MT5 默认显示的是经纪商时间(通常是 UTC+2 或 UTC+3),和交易所当地法定时间能差一两个小时。若你按 K 线形态信号无脑进场,时间无关;但若策略写明“NYSE 收盘后 30 分钟内”,用错时区就会把单子丢进错误流动性段,外汇与贵金属杠杆高,错时段滑点可能直接吞掉止损。

◍ 经纪商时移把回测时间搞成了拼图

屏幕上盯盘的人随时能看本地钟,MQL 里调 TimeGMT()、TimeGMTOffset() 也方便。可一旦要拿历史数据写和测时间相关的 EA,麻烦就来了:UTC 加个地理偏移看似够用,但冬夏令时(DST)每个地区自己定,欧盟和美国多年不变,俄罗斯 2014 年直接废了夏令时,欧盟 2018 年还闹过废除年年调钟的提案最后无疾而终。 经纪商再插一脚更乱。2015 年有家德国券商给我发通知:3 月 8 日前服务器用伦敦时间(=GMT),3 月 8 到 29 日切 CET(GMT+1),29 日起又回伦敦时间(实际 GMT+1)。本质就是伦敦时间叠了美国 DST,导致法兰克福那边的外汇开盘有时 21:00、通常 22:00、秋初某周 23:00,完全看美国调钟脸色。 策略测试器里跑指标或 EA 时,MT5 不会替你实时问券商现在偏移多少,所有时间只能靠 MQL 既有函数硬算,而这恰恰做不到。下一篇我们写函数自动判券商时移,本篇先铺几个宏替换,把偏移计算和表述控住,方便后面直接套。

用宏把时区与星期算清楚

在 MT5 里处理跨时区时间,最忌讳把偏移量硬编码进逻辑。把东京、纽约、伦敦、法兰克福、莫斯科的冬令时偏移全部提成宏,公式统一为「本地可变时间 + 时移 = GMT」,符号约定后括号就成了关键:纽约 16h 减 (纽约时移 +5h 加夏令 -1h) 得 GMT 20h,法兰克福 16h 减 (法兰克福时移 -1h 加夏令 -1h) 得 GMT 14h,漏看括号是标记错误的永恒来源。 MQL5 自带 TimeGMTOffset() 与 TimeDaylightSavings() 也遵循同一逻辑:TimeLocal() + TimeGMTOffset() = TimeGMT(),TimeLocal() + TimeDaylightSavings() 回退到 PC 标准冬令本地时。直接用这些系统函数比对自写宏,能快速发现经纪商服务器时区配置是否异常。 FxOPEN 与 FxCLOSE 都定义为 61200 秒(即纽约 17:00 = 17×3600),WeekInSec 给成 604800 而非散落数字,赋值可读性明显更好。TOSTR(A) 宏把变量名和值拼成「hGMT:22」式输出,调试时间换算时省去大量 Print 样板。 周内计算避开 MqlDateTime 标量读取的迂回:DoWi(t) 返回星期日 0 到星期六 6 的整数,DoWs(t) 借 _WkDy[] 数组回缩写;SoD(t) 取当天 00:00 以来秒数,SoD(TimeCurrent()) 直接是一根蜡烛已存活的秒数,除以 864(=0.01×24×3600)即得当天流逝百分比。HoW(t) 算自周日 00:00 的小时数,ToD(t) 把秒数转回 datetime 防编译警告,这些在外汇与贵金属短线策略里高频使用,但需注意跨期切换瞬间可能跳变,属高风险时点。

MQL5 / C++
class=class="str">"cmt">//--- defines
class="macro">#define TokyoShift   -class="num">32400                 class=class="str">"cmt">// always 9h
class="macro">#define NYShift       class="num">18000                 class=class="str">"cmt">// winter 17h=22h GMT: NYTime + NYshift = GMT
class="macro">#define LondonShift  class="num">0                     class=class="str">"cmt">// winter London offset
class="macro">#define SidneyShift  -class="num">39600                class=class="str">"cmt">// winter Sidney offset
class="macro">#define FfmShift     -class="num">3600                 class=class="str">"cmt">// winter Frankfurt offset
class="macro">#define MoskwaShift  -class="num">10800                class=class="str">"cmt">// winter Moscow offset
class="macro">#define FxOPEN       class="num">61200                 class=class="str">"cmt">// = NY class="num">17:class="num">00 = class="num">17*class="num">3600
class="macro">#define FxCLOSE      class="num">61200                 class=class="str">"cmt">// = NY class="num">17:class="num">00 = class="num">17*class="num">3600
class="macro">#define WeekInSec    class="num">604800                class=class="str">"cmt">// 60sec*60min*24h*7d = class="num">604800 => class="num">1 Week
class="macro">#define  TOSTR(A) class="macro">#A+":"+(class="type">class="kw">string)(A)+"  "     class=class="str">"cmt">// Print(TOSTR(hGMT)); => hGMT:class="num">22 (s.b.)
class="type">class="kw">string _WkDy[] =                                      class=class="str">"cmt">// week days
  {
   "Su.",
   "Mo.",
   "Tu.",
   "We.",
   "Th.",
   "Fr.",
   "Sa.",
   "Su."
  };

常见问题

多半是经纪商服务器时区与本地时区存在偏移,回测时间轴被切成了拼图。先在品种规格里确认经纪商 GMT 偏移,再手动对齐你的入场时间窗。
用 TimeDayOfWeek 宏直接取星期值,配合结构体内的年/月/日字段做判断,避免手写查表。周末贵金属与外汇流动性骤降,高风险下建议直接跳过。
可以。小布盯盘的 AIGC 会读取当前品种经纪商时区并标注偏移量,打开对应品种页即可看到时间轴校准提示,不用你自己算。
不一定。测试器启动时要加载整段历史并逐 tick 重算,入口负载本身就高。先减短回测区间验证逻辑,再放开到全量。
经纪商时移导致 K 线起点不同,突破触发自然错位。统一用服务器时间画分割线,并在代码里用 TimeGMT 系函数替代本地时间。