市场模拟跨期订单:用历史数据打通期货合约连续图表(基础篇)
📈

市场模拟跨期订单:用历史数据打通期货合约连续图表(基础篇)

(1/2)·每月重置的期货序列让20周期均线刚画完就作废,长期策略如何不断线

含代码示例实战向 第 1/2 篇
做期货回测时,很多人直接拿主连数据跑指标,却没意识到月度合约到期会让移动平均线反复归零。图表上看着连贯的行情,背后其实是多个独立序列拼凑,EA 若按单合约处理跨期下单,路由和绘图都会错位。

◍ 用跨期订单给行情做压力测试

MT5 的策略测试器不止能跑 EA,还能用脚本手动挂跨期订单来模拟真实盘口的滑点与流动性断层。很多人在回测里看不出问题,一上实盘就被点差吃掉利润,根源就在于没在测试环境里复现跨合约切换的延迟。 具体做法是在测试器里同时下不同到期月的同品种订单,观察它们在同一根蜡烛上的成交价偏差。2025 年 11 月 3 日有交易者实测,在黄金跨期订单模拟中,近月与远月合约在波动率突增时价差一度拉到 0.8 美元/盎司,这种断层在普通单合约回测里完全看不见。 外汇和贵金属杠杆高、跳空频繁,跨期模拟能提前暴露风控漏洞。开 MT5 测试器选「手动」模式,自己挂两笔不同月份的单子,比看十篇理论文都管用。

「期货合约连续性问题卡在哪」

Chart Trade 把用户点买/卖/平的指令发到图表,EA 负责拦截解码执行,这套机制本身稳。但做期货资产时会撞上一个绕不开的不便:合约有到期日,且常同时存在完整合约与迷你合约。 以 B3 美元期货为例,它每月到期,每月约 20 个交易日(4 周×每周 5 日)。当你挂一条 20 周期均线,刚算满画好,合约就到期重置成新序列,指标从头再来;更长周期指标受影响更夸张。跨系列做长线的人,移动平均和各类指标每次都要重算,这是实打实的大问题。 程序员要管的不是交易者看不看得见,而是两件事:用历史数据接续绘图,以及把图表里的交易请求正确路由到服务器。迷你合约策略(如对冲)需要小交易量,但图表若显示完整合约,就得在后台把指令映射到迷你合约执行。 回放系统里这摊事更麻烦,但能拆开打:先死磕期货指标连续化。美元期货是最极端的样本,拿它打通了,同结构的其他合约照方抓药即可。打开 MT5 搜 B3 USD 连续合约,切 20 周期 MA 看每月重置断点,就能复现这个坑。

把历史图表路由到活合约

在 B3 这类交易所,期货合约有六种命名变体,但实质只归为三种主类型、各带完整与迷你两个子变体。图表上跑的历史数据不能直接下单,必须有一层把历史合约名映射到交易者当前想做的活合约。原方案只能同类型映射,比如完整合约历史只能发到完整活合约,迷你历史只能发到迷你活合约。 核心技巧在第 44 行枚举:迷你合约赋偶数值(WDO=2),完整合约赋奇数值(DOL=3)。最低有效位决定奇偶,用按位与就能隔离该位判断。修改后函数多一个参数,让交易者选要完整还是迷你;第 56 行用 EnumToString 把枚举转字符串后,通过两层三元运算符把 eTS 加减 1,实现 WDO↔DOL 的互映射。 举例:图表是 WDO 迷你美元历史,交易者要完整合约,eTS 从 2 变 3,EnumToString 出 DOL,订单就发到完整美元。反过来图表是 DOL 历史要迷你,eTS 从 3 变 2 得 WDO。若某合约无迷你版,枚举里不造奇偶副本(编译器会拒),sz0 保持原值即可,代码里多一道判断就行。 外汇与贵金属期货杠杆高、滑点大,这种映射错误可能直接发错合约类型,实盘前务必在 MT5 策略测试器用历史符号跑一遍确认。

MQL5 / C++
class="num">38. class=class="str">"cmt">//+------------------------------------------------------------------+
class="num">39.    class="type">void CurrentSymbol(class="type">void)
class="num">40.      {
class="num">41.       class="type">MqlDateTime mdt1;
class="num">42.       class="type">class="kw">string sz0, sz1;
class="num">43.       class="type">class="kw">datetime dt = macroGetDate(TimeCurrent(mdt1));
class="num">44.       enum eTypeSymbol {WIN, IND, WDO, DOL, OTHER} eTS = OTHER;
class="num">45. 
class="num">46.       sz0 = StringSubstr(m_Infos.szSymbol = _Symbol, class="num">0, class="num">3);
class="num">47.       for (eTypeSymbol c0 = class="num">0; (c0 < OTHER) && (eTS == OTHER); c0++) eTS = (EnumToString(c0) == sz0 ? c0 : eTS);
class="num">48.       class="kw">switch (eTS)
class="num">49.        {
class="num">50.         case DOL  :
class="num">51.         case WDO  : sz1 = "FGHJKMNQUVXZ"; class="kw">break;
class="num">52.         case IND  :

◍ 用到期月份代码反推连续合约标的

这段逻辑解决一个实操痛点:拿到当前图表品种后,如何自动拼出下一交割月的真实合约名。DOL/WDO 用月份代码串 "FGHJKMNQUVXZ",IND/WIN 用 "GJMQVZ",年份取自系统时间减 2000,例如 2024 年对应 i1=24。 循环里 i0 在代码串长度内递增,越界归零的同时 i1 加 1,相当于跨年翻月。每一轮用 StringFormat("%s%s%d", sz0, StringSubstr(sz1,i0,1), i1) 拼出候选符号,再取 SYMBOL_EXPIRATION_TIME 与当前时间比大小,第一次到期日大于当前时间就 break——这就是尚未到期的最近合约。 外汇与贵金属品种走 default 分支直接 return,不会误判。把这段塞进 EA 的合约切换模块,MT5 里切到 WIN 图表跑一下,大概率能看到它自动锁定下一张 GJMQVZ 组合出的合约。

MQL5 / C++
class="type">void CurrentSymbol(class="type">bool bUsingFull)
{
   class="type">MqlDateTime mdt1;
   class="type">class="kw">string sz0, sz1;
   class="type">class="kw">datetime dt = macroGetDate(TimeCurrent(mdt1));
   enum eTypeSymbol {WIN, IND, WDO, DOL, OTHER} eTS = OTHER;

   sz0 = StringSubstr(m_Infos.szSymbol = _Symbol, class="num">0, class="num">3);
   for (eTypeSymbol c0 = class="num">0; (c0 < OTHER) && (eTS == OTHER); c0++) eTS = (EnumToString(c0) == sz0 ? c0 : eTS);
   class="kw">switch (eTS)
   {
      case DOL  :
      case WDO  : sz1 = "FGHJKMNQUVXZ"; class="kw">break;
      case IND  :
      case WIN  : sz1 = "GJMQVZ";       class="kw">break;
      class="kw">default   : class="kw">return;
   }
   sz0 = EnumToString((eTypeSymbol)(((eTS & class="num">1) == class="num">1) ? (bUsingFull ? eTS : eTS - class="num">1) : (bUsingFull ? eTS + class="num">1: eTS)));
   for (class="type">int i0 = class="num">0, i1 = mdt1.year - class="num">2000, imax = StringLen(sz1);; i0 = ((++i0) < imax ? i0 : class="num">0), i1 += (i0 == class="num">0 ? class="num">1 : class="num">0))
让小布替你拼序列
这些跨期合约的连续化诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到序列断层提示,你只需专注策略逻辑而非数据拼接。

常见问题

每月新系列重新开始计算,20个交易日左右的短窗口内指标刚成型就随合约重置,更长周期指标受影响更明显,策略信号会频繁断裂。
迷你合约交易量更小,适合小仓位或对冲类策略,但图表常显示完整合约,EA 需把用户指令正确路由到迷你合约的交易服务器。
回放要复现历史序列切换且同步绘图与订单路由,普通EA只需对接实时服务器,模拟器得额外分解序列衔接问题。
可以,品种页的AIGC模块会标注当前图表涉及的到期切换点,帮助你快速判断指标连续性风险,不用自己写脚本排查。
不能,历史数据虽提供前序序列,但程序员仍要解决绘图连续性与订单正确发送,服务器并不关心图表怎么画。