期货

从合约规则到模拟盘:MGC 微型黄金期货的完整清单

把 MGC 加进自选只要几秒,让它按规则跑起来却要过一串定义。这份清单按真实研究顺序梳理合约规格、换月判据、交易时段、回测成本、参数搜索与模拟盘启动闸门。

本文目录

把 MGC 加进自选列表只要几秒钟。让它在一个策略实例里按规则跑起来,通常要几周,而且大部分时间并不花在策略上,而是花在把一堆模糊的词变成可核对的定义:这个合约一跳值多少钱、连续合约怎么接、那根日线覆盖的是哪 23 个小时、回测里的一跳滑点够不够、以及"已经在跑了"究竟指哪一个状态。

这份清单按一个真实的研究顺序展开:先合约,再数据,再成本,再参数,最后才是模拟盘。每一节都尽量给出可以核对的口径,而不是让人自我感觉良好的建议。

一分钟版本

  • MGC 是 10 金衡盎司的 COMEX 微型黄金期货,最小变动 0.10 美元/盎司,也就是每手每跳 1 美元。
  • 连续合约是构造出来的。不做复权,就会在换月日制造一个不存在的跳空。
  • 黄金交易日从 ET 18:00 到次日 17:00。naive 时间戳必须绑定一个时区,否则同一份数据能跑出两套结果。
  • 成本从来不是"一跳",而是一串跳加上手续费;结论要在 0、1、2 跳滑点下都站得住。
  • "跑起来了"至少包含五个彼此分离的状态,少一个都不算。

先把三种环境分开

回测、券商模拟盘(Paper)和产品演示(Demo)回答的是三个不同的问题,混在一起就会得出错误结论:

  • 回测回答"这套规则在这段历史数据上会怎样",结果完全取决于数据质量与成交假设。
  • Paper回答"这套规则在这条连接、这个账户、这套执行链路上会怎样",它检验的是工作流。
  • Demo回答"这个软件长什么样",它的报价和成交是样例,不是市场证据。

在 Paper 里看到的一段顺畅成交,只能说明链路通了,不能说明策略有优势;在 Demo 里看到的一笔盈利,连链路都没说明。这三者之间不能互相当证据。记录时把环境标签写在第一行,具体字段可以参照模拟交易复盘清单。

MGC 的合约事实:三个数字决定你的风险单位

项目数值
合约单位10 金衡盎司
报价单位美元 / 盎司
最小变动价位0.10 美元/盎司(每手每跳 1.00 美元)
交易所COMEX(CME Group)

合约乘数是 10,所以标的每变动 1 美元/盎司,一手合约的名义价值变动 10 美元。GC(标准黄金期货)是 100 盎司、每跳 10 美元,MGC 在单位和金额上都是它的十分之一——这就是"微型"的全部含义,不是另一种标的。

三个数字合起来决定了一件事:你能承受的最小风险颗粒度。假设金价 4,000 美元/盎司,一手 MGC 的名义价值约 40,000 美元。如果你的止损距离是 8 美元/盎司,那么每手止损金额是 80 美元。资金 8,000 美元、单笔风险预算 1% 时,刚好够一手;资金 4,000 美元时,连一手都放不下。期货没有小数手,这个颗粒度不会因为你把风险预算调小就变细。

这些数字不要手抄。真正下单时,乘数和最小变动应当从券商返回的合约详情里读,价格也必须落在 tick 网格上:限价和止损价格按最小变动归一化,否则订单会被拒绝,或者成交在一个你没预期的价格上。

换月:连续合约是构造出来的

期货合约有到期日,而研究需要一条长序列。把若干张到期合约接成一条"连续历史",这个动作本身就是一个建模选择,而不是数据搬运。

最常见的三种接法各有代价:

  • 不做复权:直接拼接。换月日会出现一个由两个不同合约报价造成的跳空,它不属于任何真实行情。策略如果在换月附近开仓或触发止损,回测结果里就混进了数据构造的收益。
  • 差值复权:按价差平移历史价格。价格水平连续了,但早期价格被改写成从未在市场上出现过的值。
  • 比例复权:按比例缩放。收益率的相对结构保留得更好,同样会改变绝对价格。

没有一种接法是"正确"的,只有"写清楚了没有"。研究记录里至少要注明:用了哪种接法、换月发生在哪些日期、以及换月点是否落进了样本内。

比接法更容易出错的是主力合约的判据。"取最近的月份"看起来最省事,但近月往往正是流动性最差的那个。在我们的实现里,切换月份要看证据:后一月份需要在连续两个完整交易时段的成交量上超过前一月份,才认为主力已经转移;如果证据不足、日期区间有中断、无法确认成交量,状态就保持不切换,而不是用最近的月份顶上。这个规则保守到有点笨,但它不会在你没注意的时候悄悄改变回测的标的。

运行中的实例还有一条独立的约束:执行合约是冻结的。换月不会自动改写一个正在持仓的实例所用的合约;旧合约上仍有持仓或活动委托时,重新绑定会被直接拒绝。也就是说,"合约到期了所以系统会自己换"是一个错误期待——换月是操作,不是自动行为。

时区与交易时段:样本边界是被定义的

COMEX 黄金的交易时段是 ET 18:00 开盘、次日 17:00 收盘,每天 17:00 到 18:00 之间是维护时段。这意味着一个"交易日"横跨两个日历日期,一根标注为 11 月 2 日的日线,实际覆盖的是 11 月 1 日 18:00 到 11 月 2 日 17:00 这一段。

由此产生两个具体的坑:

第一,naive 时间戳没有唯一解释。 同一份没有时区标记的 CSV,按交易所时区(ET)解释和按 UTC+8 解释,切出来的 bar 边界会差 12 到 13 个小时,同一个策略在同一份文件上会得到完全不同的样本。我们采用的约定是:naive 时间戳一律按合约交易所时区解释;真实 IB 数据路径使用 epoch 秒,绕开字符串时区推断。这样"这台机器在哪个时区"就不再是一个隐藏变量。

第二,ET 的 UTC 偏移一年变两次。 夏令时切换那一周,18:00 对应的 UTC 时刻会跳一小时。用固定偏移去换算会话边界,会在一年里错两次,而且往往错在最有意思的那两周。

校验办法很朴素:挑一个已知的假日或提前收盘日,数一数你那天的 bar 数量对不对;再把首尾两根 bar 的边界打印出来,和交易所日历对一遍。这两步能挡掉绝大多数"数据看起来没问题"的问题。

成本从来不是"一跳"

新手常把"一跳"当成交易成本,实际成本是一串以跳为单位的量叠加:

  • 买卖价差:成交价相对中间价的那半个价差,每一腿都要付。
  • 开仓滑点:信号出现到订单成交之间的价格偏移。
  • 平仓滑点:止损被触发时通常比限价更差,波动大的时段尤甚。
  • 手续费:按你券商的实际账单填,不要填零,也不要抄别人的数字。

举个只用于说明结构的算例:价差 1 跳、单边滑点 1 跳、往返手续费约 2.5 美元,那么一手往返的成本量级约 5.5 美元(0.5 跳价差 × 2 边 = 1 美元,1 跳滑点 × 2 边 = 2 美元,加手续费)。止损滑点要单独再加。这个数字不是任何券商的报价,它只是提醒你:一跳 1 美元,但成本不是 1 美元。

更有用的做法是做敏感性,而不是纠结于某个精确值:把滑点分别设成 0 跳、1 跳、2 跳各跑一遍。如果结论在 1 跳就翻转,那它本来就不是结论;如果三档都活得下来,成本假设的争议就不重要了。

参数优化给的是候选,不是结论

在同一段历史数据上试的参数组合越多,挑中"恰好贴合噪声"的那一组的概率就越高。这不是心态问题,是算术问题:试 200 组,最好的那组的样本内表现必然好看,而它的好看里有相当一部分来自选择本身。

几条能显著降低自欺的操作规则:

  • 记录搜索规模。写下试了多少组、每组是什么,而不是只留下最好的那组。
  • 一次只动一个变量。同时改止损和周期,你无法知道改进来自哪个。
  • 留出样本外。可以是时间上的后段,也可以是滚动前推;无论哪种,样本外数据在参数定稿前不许看。
  • 改写结论的措辞。把"这个参数最好"改成"在这段数据、这组成本假设下,这组参数是候选"。关于回测过拟合的系统讨论,Bailey 等人的《The Probability of Backtest Overfitting》值得读一遍(原文)。

研究范围本身怎么写清楚,另有一篇规划可复现的策略研究专门讲这个顺序。

进模拟盘之前,先定义什么叫"跑起来了"

这是整个流程里最容易被跳过、也最容易出事的一段。因为"启动"在界面上通常是一个按钮,但在系统内部它是若干个条件同时成立的结果。把状态揉成一个按钮,人就会以为"我点了开始,所以它在跑"。

至少要区分五个状态:

  1. 配置已保存——参数和版本被写入,不产生任何交易动作。
  2. 已激活——某个版本成为当前生效版本,仍然不交易。
  3. 实例已启用——该实例被允许运行,仍然不交易。
  4. 已启动(RUNNING)——只有显式的启动动作能把实例带到这里。
  5. 实盘权限——独立于以上四者的授权,且必须逐实例授予。

前四个状态里任何一个失败,实例都停在原处,而不会"差不多算跑着"。区分它们的意义在于排错:启动被拒绝时,你能立刻判断是版本没激活、实例没启用,还是根本没启动过。

实际启动前通常还要同时满足一组闸门,缺一项就停在未启动:

  • 券商模拟连接已确认(不是"上次连过");
  • 账户安全快照已就绪;
  • 自动交易权限已解锁;
  • 持仓与活动委托的对账已完成,没有结果未决的订单;
  • 存在已激活的策略版本;
  • 已选定并校验过执行合约;
  • 该品种的独立实时行情已就绪,且与冻结合约、周期一致;
  • 已有至少一根已完成的 K 线;
  • 仓位归属清晰——账户里没有未归属或被外部持有的同品种持仓。

最后一条比很多人想象的更常拦住启动。账户里有一笔 MGC 持仓,不等于这笔持仓属于策略。 未归属持仓不得被自动逻辑接管,必须先人工确认归属,或者先在券商端平掉。这条规则看上去繁琐,它防的其实是自动逻辑去管理一笔自己不了解来由的仓位——包括它的入场价、初始止损和持有意图。

开仓之后还有一条常被忽略的确认:保护止损必须挂在券商一侧并得到确认。订单成交只说明有人接了单,不说明风险已经受控。如果保护止损未获确认,实例应当停在"等待确认"的状态,而不是视为开仓完成。

停止不是平仓

stop 和 disable 的语义是"停止新的动作",不是"清掉仓位"。它们不会触发平仓,只会记录一条审计警告,把仓位留在原处由你处置。这条设计是有意为之:自动平仓在流动性差的时刻可能比不动更糟。但它要求操作者把"停机"和"空仓"当成两件独立的事分别确认。

另一件需要提前知道的事:进程重启后,那些临时的运行状态不会被恢复成"还在跑"。重新加载时它们会被归一化为已停止,要恢复运行必须再次显式启动。所以"重启后它应该会自己接着跑"也是一个错误期待,而这个期待恰恰是很多意外敞口开始的地方。

最后是一条不该被当成配置项的边界:最大亏损、硬止损、灾难止损、账户与持仓的风险限额、启动前检查、订单校验收闸——这些参数不随策略版本、参数优化或任何自动选择而改变。模型可以建议进场时机,但不能放宽自己的损失上限。

一份可直接使用的复盘清单

下面这张表可以直接复制到你的记录里。它的目的不是评估策略好坏,而是让下一次回看时能重建当时的上下文。

记录项为什么要记一个合格的样子
环境三种环境不能互相作证Paper,IBKR 模拟账户,软件版本 1.0.7
数据来源与权限行情权限不同,样本就不同IBKR 历史数据,含夜盘,订阅级别已注明
时区与交易时段边界定义决定了 bar 的组成交易所时区(ET),18:00 到次日 17:00
合约与换月口径换月点可能落进样本MGC 2026-12,比例复权,换月日已列出
策略版本与参数没有版本号就没有复现版本 v3,周期 30 分钟,参数全量记录
风控参数结果依赖风险上限单笔上限、日亏损上限、止损倍数
订单与成交信号价和成交价不是一回事市价开仓,成交价与信号价差 1 跳
偏差与异常异常往往比结果更有信息一次部分成交,一次拒单,原因已记录
下一步问题让复盘产生可执行动作在 2 跳滑点下重跑;补 2025 年缺失数据

局限与下一步

这篇文章不含任何绩效数据,也不评价 MGC 是否适合你。合约规格、保证金和交易时段会随交易所与券商调整,所有数字请以你当前看到的交易所规格页和券商账单为准。

诚实的局限还有几条:微型合约的风险颗粒度是整手,资金较小时仓位管理会很粗;黄金对宏观事件敏感,隔夜跳空可以轻松越过止损价,止损保护的是"通常情况",不是"最坏情况";回测里的流动性假设在真实薄时段可能完全不成立。

下一步很简单,也不需要新工具:把上面那张表变成你自己的工作流,先在一份你熟悉的数据上,把合约、时区、换月、成本这四个定义写清楚,再去谈策略。定义不清楚的时候,任何回测曲线都只是好看。

如果你希望这条链路有现成的工作流载体,Algoryn 的公开 Beta 把 MGC 的历史回测、参数优化和 Paper 实例管理放在同一个桌面工作区里,只支持模拟交易。但工具不改变顺序:先把定义写对,再让程序跑起来。