halo 的技术博客

返回

每年 3、6、9、12 月的第三个周五,股指期货、股指期权、个股期权在同一天结算。美国市场管这天叫 triple witching(如果算上单只股票期货就是 quadruple)。

关于这天的通俗说法是「成交量暴增、波动加大、小心为妙」。

这个说法有个问题:它不可检验,也不可交易。「波动加大」既没告诉你方向,也没告诉你幅度,更没告诉你该做什么。

更准确的框架是把三巫日尾盘异常写成一个乘法结构:

尾盘价格冲击 = 失衡规模(%ADV) × 价格弹性(bp per %ADV)
plaintext

前者是「有多少钱必须在收盘成交」,后者是「每单位这样的钱能推动多少价格」。这两个量在三巫日同时抬升,而绝大多数讨论只看第一个。

12 年 × 200 只成分股 × 57600 个观测的面板模拟给出的分解:失衡规模放大 7.46 倍,价格弹性放大 2.42 倍,合计 18.0 倍

而同期尾盘收益的波动率只放大了 1.23 倍

失衡-冲击弹性与两个乘数

左图三条回归线的斜率就是三类日子的价格弹性:三巫日 6.86、普通月度到期 3.49、普通交易日 2.84 bp/%ADV。右图把两个乘数拆开画。

一、为什么波动率是个误导性指标#

先解决上面那个矛盾:效应放大 18 倍,波动率只放大 1.23 倍。这两个数字都是对的,差异来自它们测量的不是同一件事。

尾盘收益的方差可以拆成两块:

Var(尾盘收益) = Var(失衡驱动的冲击) + Var(特质噪音)
plaintext

在普通交易日,第一项几乎为零(平均 |失衡| 只有 0.34% ADV),方差基本全是第二项——那 26bp 的特质噪音加上共同市场因子。在三巫日,第一项大幅上升,但第二项一点没变

结果就是:一个放大 18 倍的信号,混进一个纹丝不动的噪音池里,总波动只涨了 23%。

实测数字:三巫日尾盘收益波动 34.95bp,普通日 28.49bp。

如果你用「波动率是否异常」来判断三巫日效应存不存在,你会得出「有一点,但不多」的结论,然后错过一个 t 值 73.5 的现象。

这不是三巫日独有的问题。任何「信号叠加在固定噪音上」的场景都有这个性质:波动率对信号的敏感度是二次的、被稀释的,而条件均值(回归系数)对信号是线性的、干净的。要检验一个机制,就去回归那个机制的驱动变量,不要看无条件波动率。

弹性本身为什么会涨 2.42 倍,机制上也说得通:做市商在三巫日的库存已经被交割流占满,风险限额吃紧,同样的买单要推动更高的价格才能找到愿意接的对手方。这是供给曲线整体变陡,不是需求变多。

二、面板回归:两个必须做对的技术细节#

核心回归很简单:

尾盘超额收益(bp) = α + β × 签名失衡(%ADV) + ε
plaintext

但这里有两个坑,任何一个踩了结论就废了。

坑一:不做日内去均值#

同一个三巫日的 200 只股票,共享同一个市场因子。如果不控制它,这个共同冲击会进入残差,同时它和「当天的整体失衡方向」相关——因为指数再平衡流本来就是方向性的。

处理方式是按日去均值(等价于加日固定效应):

def demean_by_day(sub, cols):
    """按 (month, kind) 分组去均值 = 吸收日固定效应。
    不做这一步,共同市场因子会进残差且与失衡相关。"""
    out = sub.copy()
    for c in cols:
        out[c] = out[c] - out.groupby(["month", "kind"])[c].transform("mean")
    return out
python

不做这一步的结果:系数 7.07(t=79.5,R²=0.397),做了之后是 6.86(t=73.5,R²=0.360)。

系数虚高了约 3%。这个偏差不算大,但方向是系统性向上的,而且 t 值和 R² 都被抬高——它让你的结果看起来比实际更强。在真实数据上,指数再平衡的方向性更强,这个偏差会明显更大。

值得注意的是:这个 bug 不会让你的结论反向,它只是让你高估。这类 bug 最难被发现,因为所有的 sanity check 都会通过。

坑二:用 |失衡| 而不是签名失衡#

这个坑更致命,而且我见过不止一次。

直觉上「失衡越大、冲击越大」听起来对,于是有人直接把 |imb| 对尾盘收益回归。

结果:系数 -0.35(t=-1.83),R² = 0.0003

对比正确做法的 R² = 0.360

R² 差了三个数量级,而且系数符号是负的。

原因很简单:|失衡| 丢掉了方向。买方过剩推高价格,卖方过剩压低价格,两者的 |失衡| 可能一样大,但收益一正一负。把它们混在一起回归,正负相消,剩下的只有噪音。

方向信息就是这个回归的全部内容。 一旦丢掉,剩下的 R² 从 36% 掉到 0.03%。

这条推广开来:任何研究「订单流不平衡 → 价格」的场景,签名(signed)都是不可省略的。这也是为什么 Kyle lambda、VPIN、订单流失衡这些指标全都强调 signed volume 而不是 total volume。

三、次日反转:区分流动性成本与信息#

次日反转与对照组

冲击存在不等于可交易。关键问题是:尾盘那 6.86 bp/%ADV 的价格移动,是因为市场学到了新信息,还是因为有人被迫在错误的时间成交?

这两个假说有截然不同的可检验预测:

  • 信息假说:价格移动是永久的,不反转
  • 流动性成本假说:价格移动包含一个暂时成分,次日反转

实测:次日回归系数 -4.57(t=-16.9),反转比例 66.6%

这个 66.6% 正好等于模型设定的暂时性占比 TRANS_SHARE=0.66。也就是说,测量方法准确还原了真实参数——这是引擎自检的一部分,如果测出来是 30% 或者 95%,说明估计过程有偏。

分日型看反转比例:三巫日 66.6%、普通月度到期 65.7%、普通交易日 30.9%。

前两者接近设定值,普通交易日偏低——因为那天的失衡太小(0.34% ADV),信号淹没在噪音里,回归系数被衰减偏误(attenuation bias)拉向零。这本身也是个有用的提醒:在低信噪比的子样本里,你测出的系数会系统性偏小,不能直接和高信噪比子样本比较

三组对照#

对照组冲击系数t 值排除了什么
三巫日6.8673.5
普通月度到期3.4918.0
普通交易日2.847.0
打乱配对0.181.54排除「算法在任何数据上都出信号」
纯净市场(无冲击)0.070.73确认引擎不造假信号

前三行严格按机制强度排序:三巫日 > 普通到期 > 普通日。这个排序不是拟合出来的,它是三个独立子样本各自回归的结果。

打乱配对的对照特别值得说:它保留了失衡的边际分布和收益的边际分布,只破坏两者的配对关系。系数掉到 0.18(t=1.54),说明观测到的关系确实来自配对结构,不是两个变量各自的分布特征造成的伪相关。

纯净市场跑的是完全没有注入失衡冲击的收益序列,但用同一批失衡观测值、同一套回归代码,系数 0.07(t=0.73)。引擎清白。

四、供给曲线凸性:大失衡的单位成本更高#

凸性与成本曲线

模型里设了一个凸性参数 CONVEX=0.30,意思是价格冲击对失衡不是线性的,而是 冲击 ∝ |失衡|^1.30。这对应一个现实机制:流动性供给曲线是凸的,吃掉订单簿浅层容易,深层越来越贵。

按 |失衡| 五分位分组,各组内单独回归得到的单位冲击(bp per %ADV):

4.68 / 6.61 / 5.63 / 5.98 / 7.35

Q5/Q1 = 1.57 倍。方向对,但中间有起伏(Q2 高于 Q3、Q4)。

理论值应该是多少?如果 冲击 ∝ |imb|^1.30,那么单位冲击 ∝ |imb|^0.30,Q5/Q1 应该等于 (4.93/0.36)^0.30 = 2.19

实测 1.57,只有理论值的 71.7%。

这个衰减不是 bug,原因是可以定位的:日内去均值剥掉了失衡的共同成分,但凸性作用在总失衡上,不是在去均值后的残差失衡上。一只股票可能残差失衡很小但总失衡很大(因为当天整个指数都被大幅买入),分位数分组用残差排序就会把它分错组。

这暴露了一个更一般的张力:去均值是为了识别的干净,但它同时破坏了非线性结构的测量。这两个目标在这里是冲突的,我选择了保证识别干净,代价是凸性被低估。

诚实的表述是:凸性存在(Q5 显著高于 Q1),但 1.57 这个数字是下界,真实凸性更强。如果要准确估计凸性,需要换一套设计——比如用总失衡分组、日间比较,接受识别上的妥协。

五、可交易性:能赚钱的只有一小部分#

策略分层与容量

策略很直接:三巫日尾盘逆着失衡方向提供流动性(买方过剩时我卖),次日开盘平仓,赚那 66.6% 的反转。

先加一个现实约束。做市商看不到全市场的真实失衡,只能从自己的成交流里估计。模型里设观测比例 75% 加上噪音,最终观测失衡与真实失衡的相关系数 0.931

结果分层:

口径毛收益t 值扣 5bp 双边成本净 Sharpe
单股票观测(9600 个)7.18bp8.17
组合口径(48 次)7.18bp4.31-2.82bp-0.49
只做前 40% 大失衡14.37bp5.22+4.37bp0.46

三点值得说:

第一,全样本策略是亏的。 毛收益 7.18bp 在统计上非常显著(t=4.31),但盈亏平衡成本只有 3bp/单边,而三巫日尾盘的实际价差就在 5bp 上下——你想提供流动性的时刻,恰恰是流动性最贵的时刻。这不是巧合,是同一个原因造成的两个结果。

第二,只有筛选大失衡才转正。 前 40% 大失衡的毛收益 14.37bp,是全样本的两倍。凸性在这里从「学术观察」变成「策略设计原则」:既然大失衡的单位补偿更高,就只在补偿够高的时候进场。净收益 4.37bp,Sharpe 0.46——能做,但谈不上好。

第三,分散化只兑现了一半。 组合口径的 t 值(4.31)远低于单股票口径(8.17),尽管两者均值完全一样。原因是 200 只股票的收益不独立——失衡的共同成分让它们同涨同跌。

实测分散化效率:52.7%。也就是说,理论上 200 只股票应该把标准差降到 1/√200,实际只降到理论值的一半左右。

这条对任何「多标的同时下注」的策略都成立:你的有效样本量永远小于标的数量,而差距取决于共同因子的占比。用 √N 估计自己的 Sharpe,几乎总是高估。

逆向选择:34% 是你永远赚不回的#

提供流动性的回报有个上限,由暂时成分与永久成分的比例决定:

  • 暂时成分(可赚回):10.46bp/次
  • 永久成分(逆向选择损失):5.39bp/次

永久成分占 34%。这部分对应的是真实的再配置需求——有人在三巫日调整仓位,不是因为被迫,而是因为他确实想改变敞口。你作为对手方接下这些单,价格不会回来。

这是做市生意的本质约束:你赚的是暂时性冲击的回补,赔的是知情流的方向。三巫日的特殊之处在于暂时成分占比特别高(66%),因为大量交割流是机械的、无信息的。这才是这天值得做市的真正原因——不是波动大,是噪音交易者占比高。

容量#

按平方根冲击模型,即使在最小的 2 亿元规模,全样本策略的净收益也是 -3.66bp——容量墙在起点之前就已经存在。

这个结论要正确理解:它说的是全样本策略本来就不赚钱,加冲击成本只是让它更亏。对于筛选后的大失衡策略(净 4.37bp),能容纳的规模也就在几亿元量级。

三巫日一年只有 4 次。一个年化交易 4 次、单次赚 4bp、容量几亿元的策略,年化贡献不到 20bp。对专业做市商它是既有业务的边际优化,对独立策略它不成立。

六、三盆冷水#

第一,失衡是可观测的,这个假设很强。 模型里给了 0.931 的观测相关系数。真实世界里,收盘集合竞价的失衡信息在不同市场的披露程度差别巨大——美股有 MOC imbalance 的实时披露,A 股的收盘集合竞价只有 3 分钟且不披露失衡。在 A 股,这个策略的核心输入变量基本观测不到,你只能从盘中成交流反推,观测相关系数会低得多,而回归系数会被衰减偏误进一步压低。

第二,暂时/永久二分法过于干净。 模型里 TRANS_SHARE 是一个常数 0.66。现实中它随市场状态变化:恐慌时永久成分占比上升(因为真实的风险再定价增多),平静时下降。而你没法事前知道今天是哪种。更糟的是,这个占比很可能在你最需要它稳定的时候(大失衡日)最不稳定。

第三,5bp 的成本假设对个股是乐观的,对指数产品是悲观的。 三巫日尾盘个股价差走阔,流动性差的成分股可能到 10bp 以上;而如果你用股指期货或 ETF 表达同一个观点,成本可能只有 2-3bp,但你就失去了横截面选择的能力——只能赌整个指数的失衡方向,那是一个完全不同、且信噪比低得多的赌注。成本和信号质量在这里是此消彼长的,不存在两全的实施路径。

最后#

三巫日效应是真的:t=73.5 的弹性、66.6% 的反转、严格排序的三组对照。机制也清楚:可预测的非弹性需求撞上被占满的做市商库存。

但把它变成钱需要同时满足三个条件——能观测失衡、能筛出大失衡、成本低于 3bp。三个条件同时成立的,基本只有本来就在做收盘集合竞价的机构。

这和上一个结论殊途同归:市场规律的存在性和可交易性是两个独立的问题,而后者取决于你在市场结构里的位置

研究能告诉你规律在哪。它没法告诉你,你是不是那个能拿到它的人。

三巫日到期:股指期货、期权与个股期权同日结算的流动性异常
https://blog.halo26812.eu.org/blog/futures-expiry-triple-witching
Author halo
Published at 2026年7月31日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨