事件合约量化研究纪实:四条被否掉的路,和一个 56% 的边际

一套短周期事件合约策略的完整研究纪实:十条研究军规、四个被迫换方向的阶段、八个真实被否掉的方向、以及诚实的结论——真实前向约 56%–57.5%,薄、正,但统计上还不显著。

一、先看规则:难度写在合约条款里

这里要交易的是数字货币交易所的事件合约:一种超短周期的二元期权。

以 ETH 10 分钟档为例,规则简单到可以用一行说清:

t 时刻按当前价入场 → t+10 分钟按结算价结算
结算价 > 入场价:赢,得 +0.8 × 本金
结算价 < 入场价:输,亏 −1.0 × 本金

先算一个数。设胜率为 p,期望为 0.8p − 1.0(1−p) = 1.8p − 1。要期望为正:

p > 1 / 1.8 = 55.56%

55.56%,就是全部故事的分母。

这意味着:一个”胜率 54%“的策略在这里是稳定亏损的;一个”看起来有 56% 胜率”的策略, 扣掉一点执行成本就可能归零。市面上大多数”我找到了 60% 胜率的指标”的说法,都死在这个数字上。

规则里还埋着三颗钉子

做这件事的过程里,我最深的体会是:先把合约条款读透,比急着写策略重要得多。 这三颗钉子是后来所有坑的根源。

第一颗:结算价不是现货价。

合约按交易所的指数价(多家交易所合成的价格)结算,而绝大多数人的数据和直觉都建立在现货 K 线上。 同一批信号,用现货回测和用指数回测,胜率差大约 2 个百分点——正好是 55.56% 之上那点薄边的量级。

也就是说:一个用现货数据回测出来 56% 的策略,按真实结算口径可能只有 54%,是亏的。

第二颗:账户有并发上限。

这类平台的合约是”一单到期后再开下一单”的槽位制,可同时持有的仓位通常在个位数(我用的口径是 5)。 所有”一天几百单”的回测,如果不复刻并发约束,都在骗自己。我为这个坑专门付过一次学费,后面会讲。

第三颗:入场时刻是能观测到什么的边界。

入场发生在某根 1 分钟 K 线的开盘时刻。那么在按下按钮的那一秒,你已经能看到这根 bar 的开盘价, 但看不到它的最高、最低、收盘和成交量——那些要等 60 秒之后才存在。

这三颗钉子决定了后面所有方法的形状。我把它压缩成一句话写在研究守则第一页:

先保证这个数是真的会赢,再去想它能不能赢更多。

二、方法论:我最后留下的十条军规

研究时间越长,越会发现:真正值钱的不是某个因子,而是那套能持续否掉自己的流程。 下面这十条是踩坑踩出来的,每一条背后都有一次具体的翻车。

1. 因果性:把”事后才知道”翻译成”当下能知道”

这是最容易被忽略、杀伤力最大的一类错误。它不表现为”用了未来的收盘价”这种低级形态, 而是藏在计数序列里:

说法能不能在入场那一刻确认?
“连续第 3 根触发”✅ 能,第 3 次触发的那一刻就知道
“恰好有 2 个条件满足”❌ 不能,得等所有条件都走完才知道
“这一段波动结束了”❌ 不能,需要等后面不再发生
“取最后一个触发点进场”❌ 不能,得知道后面没有新的触发

我用过一个 10 分钟就能做完的判别测试,非常有效:

这条测试后来帮我避免了一次几乎要上线的灾难(见第五节)。

2. 只允许用决策时刻已存在的数据

具体到 1 分钟事件合约:特征只能用 t−1 及更早的已收盘 bar,或者入场时确实能观测到的开盘价。 所有滚动窗口、分位数、标准化参数都必须只依赖历史。

这条听起来是常识,但它的边界比想象的细: 滚动 z-score 的分母、分位数的阈值、regime 的分类边界,每一项都可能是泄漏源。

3. 滚动标准化,不用固定绝对阈值

加密市场的波动率、流动性和微观结构在几年里变化极大。 2021 年的”极端跌幅”和 2026 年的”极端跌幅”完全不是一个数值。

所以新因子一律默认先做因果滚动标准化(滚动 z-score、滚动分位)再设阈值, 用”相对近期市场有多极端”替代”是否越过某个历史绝对数值”。

4. Walk-forward:训练、选阈值、评估,三段严格分离

我的标准做法:

用 ≤ 某年 的数据训练模型
用紧邻的下一段数据选阈值
再往后逐年滚动,评估完全没参与过选择的数据

任何”全样本选参数、再全样本评估”的结果,我直接当无效处理。

5. 密封 holdout 只看一次

留出一段完全隔离的数据,在开发阶段一次都不碰。整个系统组装完成、所有层都冻结之后, 端到端跑一次,无论结果好坏都记录在案。

这条规则的价值在于:它把”我可以再调一次”这个诱惑物理地移除掉了。

6. 参数平台 > 参数尖峰

如果一个因子的最优窗口是”恰好 15 分钟”,把窗口改成 12 或 18 就失效,那这个结果大概率是过拟合。 我要求参数邻域内连续一片都能过线,孤立尖峰一律丢弃。

同理,阈值敏感度也要查:阈值在 0.60–0.70 全为正,和”只有 0.645 为正”,是两种完全不同性质的结果。

7. 方向分离:做多和做空是两个问题

这一点反直觉但非常重要。我一度把 UP 和 DOWN 混在一个组合里挖, 结果一个亏损的方向被另一个方向的成交量掩盖了

后来改成硬性规定:

UP 单独挖、单独评估、单独过门槛
DOWN 单独挖、单独评估、单独过门槛
只允许在最后的组合层合并
同一分钟两个方向冲突 → 默认跳过

而且接受”某一侧就是没有可用的策略”。不要为了对称而强行凑出一条空头线。

8. 回测必须复刻实盘约束

并发上限、同分钟同向去重、冲突跳过、真实结算价——这些不是”实盘细节”, 它们会直接改变结论的量级。

我曾经算出一版非常漂亮的收益曲线,后来发现忽略了并发槽位;补上真实约束之后,结论完全改变。 回测跑的是策略,不是理想世界。

9. 多重比较要认账

如果你试了 100 个因子,其中最好的那个表现优异,这个”优异”里有多少是运气?

我的做法是:

  • 报告同一族参数的整体表现,而不是只报最好的那个点
  • 随机零假设对照(把标签打乱重跑同样的流程),看真实结果比随机好多少
  • 明确写出”这个结果我看了几次”。同一个边际被反复观察 11 次,不等于 11 个独立证据

10. 每次研究都必须留下可复现的报告

每条研究线落地时,必须写清:

精确规则 / 决策时点 / 结算时点 / 数据范围 /
选择期 / 未触碰的评估期 / 赔付假设 / 样本数 / 胜率 / EV / 最大回撤

没有这份记录的研究,等于没做——因为三个月后你不会记得当时到底测了什么。

三、研究历程:四次换方向

回头看,整个过程不是”一条路走到底”,而是四次被迫换方向。每次换向都来自一次证伪。

阶段一:写规则,然后发现自己用了未来(早期)

最早的做法很朴素:写一批技术指标规则,回测,挑胜率高的。

很快撞上第一颗钉子——我发现自己一直在用未来信息。修正因果性之后, 一批原本”胜率 60%+“的规则全部回落到 50% 出头。

这一阶段的产出不是策略,是那套因果性检查清单(军规 1)。

阶段二:规模化因子挖掘(V13–V18 一线)

接受”手工写规则没用”之后,转向规模化:把几百个候选特征系统性扫一遍,用逐年样本外验证筛选。

这一阶段最重要的产出是一个否定的结论(见 4.1):直接模型预测 10 分钟涨跌, 准确率上限约 54%。而且这个 54% 不是噪声——所有实验的置信度十分位都单调上升, 说明特征里确实含方向信息,只是信息量不够跨过 55.56% 的门槛

阶段三:换框架——先分类市场,再找机会

既然”单一模型预测方向”有天花板,就换思路:先把市场状态分类, 在不同类别里用不同的规则。

这个阶段发现了边际的形态(见 4.2):反转类持续为正,动量类系统性亏损。 也第一次撞到了那个反复出现的”62% 天花板”(见 4.5)。

阶段四:换思路——从”找更强信号”到”只在高把握时下注”

最后一个转变是最关键的:不再试图提高模型的预测准确率, 而是让它回答一个更窄的问题——“这一注该不该下”

这就是”元标注”(meta-labeling)的思路,也是唯一一条通过了全套检验的线(见 4.3)。

延伸:把方法搬到别的地方

这套流程(因果检查 / walk-forward / 密封 holdout / 随机对照)与具体市场无关。

我试过把它搬到其他标的上,结论是:方法可以搬,边际不能搬。 每个市场需要重新找它自己的边际。

四、结果:诚实的版本

4.1 宽口径的硬天花板

在把几百个候选特征系统性扫过、并用逐年样本外验证之后,我得到的最稳定的结论是:

用直接模型预测 10 分钟涨跌,准确率上限约 54%。

而且这个 54% 不是噪声——所有实验的置信度十分位都单调上升, 说明特征里确实含方向信息,只是信息量不够跨过 55.56% 的门槛。

4.2 边际的形态:均值回归,且住在极尾里

两类主信号的对比极其干净:

类型表现
反转 / 极值衰竭 / 跨品种价差回归持续为正,逐年一致
动量 / 趋势跟随 / 领先滞后系统性亏损

结论是:这个尺度上的边际,本质是短周期均值回归。 顺势追单在这里是负期望。

更关键的一个发现是它的分布形态

真正的边际不是均匀铺在所有时点上,而是高度浓缩在极端尾部

把模型输出的”赢的概率”分十分位看,实际胜率从 50.5% 单调升到 55.3%; 只有最高的 5% 才勉强过平衡线,而实际部署用的阈值落在 top 0.1–0.3% 的位置。

这解释了一个长期困惑:为什么”精简”比”放量”更赚钱。 放松阈值不是”多赚一点、少赚一点”,而是在沿着一条单调曲线往下走,一直走到平衡线以下。

4.3 通过全套检验的那条线

最经得起检验的一条是”短周期反转 + 元标注过滤”:

检验项结果
样本外逐年三年均高于平衡线(56.0% / 58.4% / 62.2%)
独立前向窗口三个不同窗口期的主信号全部为正,未出现崩塌
随机零假设对照57.87% vs 随机 52.17% ± 0.94% → +5.71 个百分点
阈值稳健性阈值 0.60→0.70 全区间为正且单调
月度一致性18/29 个月过线,中位 58.0%
参数族整体性11 个反转窗口里 10 个为正,不是单一参数走运

配合校准检验(模型输出的概率与实际胜率的单调性相关系数 0.92–0.96,校准误差约 1 个百分点), 可以说:

这条线是项目里第一个通过了整套严格检验的边际。

4.4 但真实前瞻给出的数字要冷静得多

上面的结果都来自历史数据。真正干净的前向样本(固定规则跑在从未参与过选择的数据上)给出的数字是:

真实并发约束下    约 56%–57.5% 胜率
日均单量          18–28 单

薄,正,但统计上还不显著。 这就是诚实的现状。

这里需要区分两个口径:

口径胜率
选择过的样本外(参与过筛选流程的数据)约 58%–61%
完全干净的前向(固定规则跑在从未参与选择的数据上)约 56%–57.5%

把两者放在一起看,得到的判断是:

这套东西的真实边际落在 56%–60% 这个区间,方向上确实高于 55.56% 的平衡线, 但边际很薄,且对执行成本和数据口径高度敏感

4.5 一个反复出现的”天花板”

在多个独立分支上,我都撞到了同一个量级的上限:约 62%

它的表现方式很一致:无论走因子挖掘、走组合、走分类框架还是走元标注, 最好的那些切片的胜率最终都收敛到 60% 出头,再往上推不动。

我试过大量被寄予厚望的正交数据源:跨品种广度、订单流失衡、爆仓数据、跨市场散度、 第二个账户体系、宽网搜索……

结果高度一致:它们能增加成交量,但抬不动胜率。

这说明边际的来源非常集中——就是分钟级的价格 / 成交流 / 基差结构里的均值回归。 在这个尺度上,它已经被挖得比较透了。

五、失败档案

如果这篇纪实只有一句话值得看,应该是这句:

我用大部分时间做的事,是证明某些想法是错的。

下面这些都是真实发生过、并且被明确否掉的。它们比成功的部分更有信息量。

5.1 用了未来函数,胜率从 80% 掉到 54%

假设:价格创新高/新低,但主动成交流没有跟上(背离),说明这段走势”衰竭”了,之后会反转。

结果:初版回测胜率 79.9%,期望值 +0.438,多段数据一致,看起来是项目里最强的发现。

问题:策略在”一波触发结束之后的第一根”进场。而”这一波什么时候结束”需要知道 后面 15 分钟内不会再有新触发——这在入场那一刻是不可能知道的。

改成因果版本(每个触发点都取,不挑”最后一个”)之后:

版本单量胜率期望值
前视版(不可交易)25,88179.9%+0.438
因果版(可执行)72,92853.7%−0.034

因果版里包含了近 4.9 万笔”以为跌完了、结果继续跌”的提前进场,胜率只有 42%。

5.2 一个单位换算错误,让错误结论活了很久

我在回测里模拟并发槽位:持有期是 10 分钟,最多同时持 5 单。

实际代码里,时间戳的单位是微秒(1 分钟 = 60,000,000), 而持仓时长用了纳秒(10 分钟 = 600,000,000,000)。把纳秒当成微秒加上去之后——

600,000,000,000 / 60,000,000 = 10,000 分钟 ≈ 6.94 天

每一次开仓都把槽位锁了将近 7 天。 于是所有受并发约束回测的吞吐量都被压成了约 0.7 单/天。

这个 bug 造成的后果不是数字难看,而是一个错误的战略结论被反复确认: “并发槽位是吞吐的墙,高频根本不可能。”

发现它的线索很朴素:不管原始信号有多少(300 单/天还是 2 单/天), 加上约束后吞吐都变成同一个数字。这在数学上不可能——5 个槽位、10 分钟持有期,理论容量是每天 720 单。

修正并交叉验证(修正后的回测与真实模拟盘记录吻合)之后的真相:

线路修正后真实吞吐真实胜率
高频因子线 A18.0 单/天57.7%
高频因子线 B19.0 单/天59.1%
组合策略27.8 单/天56.9%
元标注反转线28 单/天56.2%

吞吐量从来不是问题。 真正的问题从一开始就是另一个,只是被这个 bug 掩盖了很久:

在每天 20 单的量上,胜率能不能干净、稳定地站在 55.56% 之上?

5.3 用现货结算,高估了 2 个百分点

在薄边世界里,2 个百分点就是生与死的差别。

我用逐笔数据重建了真实的指数价序列,把同一批信号在两种结算口径下对比:

现货价结算    58.41%
真实指数价    56.51%

差距全部来自现货与指数之间的基差。 结论:此后所有用现货回测的结果,默认都要打约 2 个百分点的折扣。

顺带还发现了一个免费的小改进:入场不要卡在整点那一秒。 整点时刻的指数价经常处于跳动或滞后的状态;等 5–10 秒再入场,各年份表现都更好, 且这是一个平台(不是孤立尖峰)。在最难的那一年,它把 54.12% 提升到 55.94%——正好从线下推到线上。

5.4 一个”看起来很强”的区域被证明是挑选出来的

在分类框架下重挖之后,我找到了一个全新的做空候选: 高位 + 主动买入效率过高(多头过热)→ 做空。

它的数字非常漂亮:胜率 63.3%,样本内外一致,冷却后不衰减,与现有策略重叠不到 8%。

问题在敏感性检验里暴露了:

  • 把极值分位从最极端的 5% 放松到 40%,期望值从 0.139 崩到 0.033,并且当年转负
  • 边际严重依赖单一年份(一年 0.045,另一年 0.406)

更关键的是,在唯一一段没有参与过任何选择的干净前瞻数据上, 它是所有模块里回归最狠的一个(选择期最强,前向 46.7%)。

5.5 复现别人的策略:三种不同的结局

我花了不少时间复现外部提供的策略包。结果分成三类,每一类都有价值:

第一类:真实的。 一套基于基差偏离 + 超买超卖 + 趋势状态门的组合, 在多段数据上复现出 61% 左右的胜率、日均约 14 单,逐年为正,置换检验 18.6 个标准差。 外部的说法可以被独立复现。

第二类:抬不动。 一套”宽池 + 打分模型、一天上百单”的方案。复现后确认: 原始宽池确实”宽而弱”(52.6%),打分确实能把胜率抬升约 2.5 个百分点—— 但抬不到 55.56%。 三个分位档全部不达标,网格细化后依然如此。 打分有真实但极弱的信号,只是不够赚钱。

第三类:复现不出来。 一套宣称全期 65.35% 胜率、累计正收益、零亏损月的策略。 按文档规则忠实复现后得到的是 55.37%、期望值约等于零、亏损月 23 个。 差异量级约 56 个标准差。

我进一步做了成交假设的敏感性测试,找到了差异的来源:

成交假设胜率
诚实口径(按文档描述的下一分钟开盘价成交)55.4%
用”信号收盘价与下一开盘价里更好的那个”57.7%
用”下一根 K 线的最有利极值”63.0%

只有引入前视性质的成交假设,那个宣称的数字才会出现。

5.6 把思路搬到更细的时间尺度:不行

我认真测过”把同样的配方搬到秒级”这件事,而且分两条路分别测:

作为信号:同样的反转配方,预测未来 600 秒。

1 分钟 bar 上    55.15%
10 秒 bar 上     44.66%

作为执行:同一套信号,用更细的 bar 去挑更好的入场点。结果同样是 null—— 更细的粒度只带来噪声。

结论:这个边际锁死在”分钟级 bar + 10 分钟预测窗”这个尺度上,平移会消失。 秒级框架不是没用,但它需要找的是另一个、独立的边际,不是这一条的加速版。

5.7 被否掉的其他假设(简表)

假设结论
动量 / 趋势跟随在这个尺度有效否,系统性亏损
资金费率 / 溢价 / 持仓量 / 爆仓数据是新边际否,作为触发和叠加层都不稳健
越多的正交数据源能提高胜率否,只提高成交量
对称地做”超买做空”否,结构性不对称:底部是事件,顶部是过程
直接用模型预测方向 + 置信度过滤否,置信度是假自信
用凯利公式复利放大否,在薄边上会让回撤达到本金的 3–6 倍
更细粒度的订单流能提升方向判断否,相关性全部 ≤ 0.04
某个指标(RSI、MACD、%B)在秒级有效否,数据量增加后效应归零

5.8 从样本外到实盘,还有一道折扣

这是最容易被忽略、也最贵的一课:“样本外表现”和”上线后的真实表现”之间,还有一段距离。

我跟踪过一条线的完整衰减过程:

离线样本外      58.7%
真实前向(同期) 54.6%
面板实际记录    48.0%   ← 但这一段样本量很小,含噪声

把差距拆解开之后,大致是三块:

  • 约 4 个百分点是真实的前向衰减(市场结构本身在变化)
  • 约 2 个百分点是口径差异(用现货价检验、实际按指数价结算)
  • 剩下的主要是小样本噪声(面板那一段的样本量还不足以区分 48% 和 53%)

关键结论不是”这个数字是多少”,而是:回测里的样本外数字,本身还需要再打一次折。

所以我的收益评估流程里有一条固定动作:新策略先跑纸面/模拟观察, 用真实成交口径累积够样本之后,才用它决定是否放大仓位。 而且监控要看三件事——胜率是否低于样本外预期、成交量是否异常、 单条线是否出现了超出历史范围的连亏——而不是只看总盈亏。

六、几个反直觉的发现

6.1 边际住在尾巴里

不是”这个策略有 58% 的胜率”,而是”这个策略在最极端的 0.1%–0.3% 时点上才有 58% 的胜率”。

这个形态决定了所有事:它意味着边际天然是低频的, 意味着”放量”和”提高胜率”在这个边际上是同一个旋钮的两端, 也意味着任何”我又多下了一倍的注”的想法,实际是在稀释自己。

6.2 模型需要先验,不然它的自信是噪声

直接让模型预测涨跌,它给出高置信度的那些点,实际胜率反而最差(51%)。 而让模型在”已经由规则定好方向”的前提下判断”这一注该不该下”,它的高置信度就变成真信息。

一个没有先验聚焦的模型,它的”自信”只是把概率撒在噪声上。

6.3 吞吐量不是问题,边际厚度才是

我花了很长时间(还因为一个 bug 走了弯路)纠结”能不能做到一天 20 单”。 最后发现:一天 20 单很容易,难的是在这个量上仍然是正的期望值。

6.4 选择偏差会精确地惩罚你

在选择期表现最好的模块,前向表现最差。这不是巧合,是选择偏差的定义。 这意味着”在我反复看过的数据上最好的那个”恰恰是最不该相信的那个。

6.5 分类框架本身是防过拟合手段

第一反应可能是”层数越多越容易过拟合”。实际上:层数增加的是结构,不是拟合参数。

一个主要由规则构成的多层流水线,其可调参数可能远少于一个全模型的两层方案, 而”把方向判断和风险取舍拆开”本身就是一种防过拟合的设计。

真正决定过拟合的是三件事:总拟合参数数量、同一段样本外数据被看了几次、最窄那一层的样本量。

七、这件事教会我的

第一,规则比策略重要。 合约条款里的三个数字(55.56%、2 个百分点、5 个槽位) 决定了整个研究的形状。不先把它们算清楚,后面所有工作都建立在错误的假设上。

第二,能被证伪的方法才是最贵的资产。 我最满意的一批成果其实不是某条策略, 而是那套能持续打掉自己乐观结论的流程:因果性检查、随机零假设、密封 holdout、 参数平台、选择偏差审计。它们在这一路上至少拦下了三次会真金白银亏钱的部署。

第三,薄边世界里,2 个百分点就是全部。 结算价用现货还是指数、入场卡整点还是等 5 秒、 并发约束复刻得对不对——这些在别的领域里是”工程细节”,在这里是策略生死。

第四,要接受”没有结论”。 到目前为止,我真实的、干净的前向记录只支持一个结论: 这套方法找到了一个薄弱但真实的正期望边际,约为 56%–60%,且它还不稳定到可以作为定论。 这个结论不性感,但它是真的。

附:这套方法的可迁移部分

如果你在做类似的事,下面这些是可以直接拿走的,与具体市场无关:

  1. 先算平衡点,再谈策略。 赔率决定了你需要多高的胜率,这个数字应该在写下第一行回测代码之前就贴在墙上。
  2. 给”未来函数”建一份检查清单,并且把”恰好 k 个 / 最后一个 / 序列结束 / 峰值之后”这些词当作红色警报。
  3. 参数邻域必须成片。 孤立的最优点等于过拟合。
  4. 方向分离。 别让一个方向的成交量掩盖另一个方向的亏损。
  5. 回测复刻真实约束。 并发、去重、结算价、入场延迟,一项都不能省。
  6. 留一段数据一次都不碰,最后端到端跑一次。
  7. 用随机对照检验你的模型,而不是只看它自己的准确率。
  8. 记录每一次失败。 失败档案是你未来最省时间的文档。

相关阅读


本文仅供技术交流,不构成投资建议。历史回测结果不代表未来表现。