事件合约量化研究纪实:四条被否掉的路,和一个 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,881 | 79.9% | +0.438 |
| 因果版(可执行) | 72,928 | 53.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 单。
修正并交叉验证(修正后的回测与真实模拟盘记录吻合)之后的真相:
| 线路 | 修正后真实吞吐 | 真实胜率 |
|---|---|---|
| 高频因子线 A | 18.0 单/天 | 57.7% |
| 高频因子线 B | 19.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%,且它还不稳定到可以作为定论。 这个结论不性感,但它是真的。
附:这套方法的可迁移部分
如果你在做类似的事,下面这些是可以直接拿走的,与具体市场无关:
- 先算平衡点,再谈策略。 赔率决定了你需要多高的胜率,这个数字应该在写下第一行回测代码之前就贴在墙上。
- 给”未来函数”建一份检查清单,并且把”恰好 k 个 / 最后一个 / 序列结束 / 峰值之后”这些词当作红色警报。
- 参数邻域必须成片。 孤立的最优点等于过拟合。
- 方向分离。 别让一个方向的成交量掩盖另一个方向的亏损。
- 回测复刻真实约束。 并发、去重、结算价、入场延迟,一项都不能省。
- 留一段数据一次都不碰,最后端到端跑一次。
- 用随机对照检验你的模型,而不是只看它自己的准确率。
- 记录每一次失败。 失败档案是你未来最省时间的文档。
相关阅读
- 币安事件合约 API:能自动下单,但 55.56% 那道线还在 —— 本文讲”该不该下单”,那篇讲”怎么下单”
- HIBT 事件合约:日赚 1,000–2,000 U,10 天后失效被封 —— 一条真实跑过的线,以及本文没覆盖的另一种风险:对手方风险。 那篇里的”单机币”结构说明,当平台是你的对手盘时,持续盈利本身就是被终止的理由
本文仅供技术交流,不构成投资建议。历史回测结果不代表未来表现。