
2010 年 5 月 6 日,道指在五分钟内跌掉近千点又弹回来。事后所有人都在找”那个按下按钮的人”,但 Easley、López de Prado、O’Hara 三人给出了另一个叙事:闪崩不是一瞬间的意外,而是做市商被有毒订单流持续放血几小时后的集体撤退。他们声称自己的指标——VPIN(Volume-Synchronized Probability of INformed trading)——在崩盘前一小时就已经飙到历史极值。
“毒性”(toxicity)这个词选得精准。对做市商来说,订单流有毒,是指对手方比你知道得多:你按当前报价接下的每一笔单,都在为别人的信息买单。毒性不高时做市商靠价差赚钱;毒性持续超过价差收入,做市商唯一理性的选择是撤单走人——而做市商集体撤退的市场,就是闪崩的干柴。VPIN 想做的事,是实时测量这个毒性水平,在干柴堆到足够高时报警。
这篇文章在一条 50 万分钟的合成 tick 流上完整复现 VPIN 的构造:成交量桶、滚动毒性、CDF 变换、闪崩预警,最后算一笔”按 VPIN 减仓”的账,并把这个指标十几年来争议最大的几个软肋摆出来。
从 PIN 到 VPIN:换掉时钟#
VPIN 是 PIN 的高频直系后代,但它扔掉了 PIN 最重的两个包袱:不再做 MLE(不用估计五个参数的混合泊松模型),不再用日历时间。
第一个改动是工程妥协——高频下 PIN 的似然估计既慢又不稳定。第二个改动是理念升级:信息到达的自然节拍不是分钟,而是成交量。重磅消息落地时,一分钟的成交量能顶平时一小时;用日历时间切样本,事件期的信息被压缩、平静期的噪声被拉伸。成交量时钟(volume clock)让每个样本承载等量的市场活动。
构造分三步:
第一步,切桶。 把连续的成交流按累计成交量切成等体积的桶,每桶 股。我们取 为日均成交量的 1/50,即平静期约 50 桶/天,剧烈期一天可能切出上百个桶——时钟自动加速。
第二步,桶内买卖分类。 原论文用 bulk volume classification(按价格变化的标准正态 CDF 把每根 bar 的量按比例劈成买卖),我们的合成流直接生成了带方向的量,跳过这层(后面会讨论这层近似的代价)。
第三步,滚动毒性。 对最近 个桶(取 50 桶 ≈ 1 天):
这就是 PIN 公式 的无参数化影子:分子用已实现的订单流不平衡替代知情流强度的期望,分母是总量。没有似然、没有优化器,一行 pandas 就能算:
import numpy as np
def compute_vpin(volume, buy_vol, sell_vol, n_buckets_per_day=50, window=50):
V = volume.sum() / (len(volume) / 240 * n_buckets_per_day) # 每桶体积
bucket_id = (np.cumsum(volume) // V).astype(int)
n = bucket_id.max() + 1
bb = np.bincount(bucket_id, weights=buy_vol, minlength=n) # 桶内买量
sb = np.bincount(bucket_id, weights=sell_vol, minlength=n) # 桶内卖量
oi = np.abs(bb - sb)
vpin = (np.convolve(oi, np.ones(window), "full")[:n] /
np.convolve(bb + sb, np.ones(window), "full")[:n])
vpin[:window] = np.nan
return vpinpython绝对值的 VPIN 水平因标的而异,没法跨股票比较,所以实用中都做 CDF 变换:取当前值在过去 N 个桶里的滚动分位数。VPIN CDF = 0.95 的含义是”当前毒性高于过去 95% 的时间”——这才是可以设阈值的量。
合成实验:毒性先于崩盘#
合成市场 500 个交易日、每天 240 分钟。订单流不平衡是均值回复过程,但植入三段”毒性事件”:知情流单向持续累积(两段做空方向、一段做多方向),量能同步放大,其中最后一段以一次 30 分钟跌 10% 的闪崩收尾。价格由不平衡的冲击驱动。这个设定刻意复刻了 ELO 论文对 2010 年闪崩的解读:毒性积累在前,价格崩溃在后。
文首全样本图里,三段阴影是植入的毒性区间,橙色 VPIN 在每一段都显著抬升。关键看闪崩前后的放大图:

VPIN CDF 在闪崩发生前 5.7 天就越过了 0.9 的预警线——因为这段毒性事件的知情卖压是渐进累积的,成交量时钟捕捉到了价格还没完全反映的单向流。这正是 VPIN 支持者叙事的理想形态:毒性是慢变量,崩盘是快变量,慢变量给你逃生窗口。
条件事件研究把预警能力做成统计:

按 VPIN CDF 分箱看未来 1 日的最大回撤:0 到 0.95 的五个箱子几乎没有差别(-1.09% 到 -1.13%),只有 >0.95 的极端箱跳到 -1.79%,是常态的 1.6 倍;未来已实现波动同样只在极端箱抬升(14.6%→16.0%)。这个形态本身就是重要结论:VPIN 不是线性预测因子,它是尾部指标——中低分位的读数毫无信息量,只有极端值才值得行动。拿 VPIN 去跑线性回归然后宣布”预测力弱”,和只盯 95% 分位以上的表现,会得出完全相反的评价,文献里的争论一半源于此。
减仓策略的账#
最直接的用法:前一日 VPIN CDF 峰值超过 0.9 就空仓一天。

这个含两段做空毒性事件的样本里,买入持有年化 -13.3%、最大回撤 -33.4%;VPIN 过滤后年化 -7.6%、最大回撤压缩到 -22.5%,代价是 15.2% 的时间空仓。改善几乎全部来自躲开了闪崩前后的那几天——again,尾部指标,平时不贡献收益,关键时刻少挨一刀。
必须诚实标注这笔账的水分:样本里的毒性事件是植入的、方向偏空的,等于给了 VPIN 主场作战;三段事件里有一段是做多方向的毒性(拉升行情),期间 VPIN 同样报警,若按”报警就减仓”执行,那段是踏空成本。VPIN 分子取了绝对值,它天生分不清毒性的方向——只知道有人在单边偷跑,不知道往哪边跑。
争议与软肋#
一,学术界最著名的对撞:Andersen-Bondarenko (2014)。 两人用同样的 E-mini 期货数据重做了 ELO 的闪崩分析,结论尖锐:VPIN 的预警能力主要来自它与成交量和已实现波动的机械相关——控制住这两个变量后,VPIN 的增量预测力所剩无几;且闪崩当天 VPIN 创”历史新高”的说法依赖于特定的参数选择。ELO 随后回击,论战持续多轮没有共识。对实践者的教益很具体:评估 VPIN 时必须与”滚动波动率分位数”这个免费基准对比,赢不了它就不值得多算一层。
二,bulk volume classification 是又一层近似。 真实数据没有买卖标签,BVC 按 bar 收益的正态 CDF 劈量,在趋势行情里系统性高估单边量——趋势本身就会被读成毒性。我们的合成流跳过了这层,等于又给 VPIN 让了一步。A 股有内外盘标记可以绕开 BVC,这是少数 A 股做微观结构比美股干净的地方。
三,参数敏感。 桶大小、窗口长度、CDF 回看期,三个参数没有一个有理论最优值。桶切小了噪声主导,切大了预警滞后;Andersen-Bondarenko 演示过换一组参数就能让闪崩预警消失。上线前的参数敏感性扫描不可省略。
四,误报率决定它只能当风控不能当策略。 极端 VPIN 后面跟着的多数不是闪崩,而是普通的高波动时段——我们样本里三段高毒性区间只有一段以崩盘收尾。把它用作”崩盘择时”胜率会很难看;把它用作动态减仓/降杠杆的风控层(报警时把仓位从 100% 降到 50%,而不是清仓赌崩盘),误报的成本才是可承受的。
结语#
VPIN 的正确定位是一台流动性提供方的疲劳监测仪,不是水晶球。它测的是”做市商还愿不愿意接你的单”,这个量在 99% 的时间里无关紧要,在剩下 1% 的时间里就是全部。工程上记住四件事:用成交量时钟不用日历时钟;用 CDF 分位不用绝对值;只对 >0.95 的极端读数行动;永远和波动率分位基准打一架再决定要不要它。至于它能不能提前一小时预告下一次闪崩——2010 年以来这个问题吵了十几年,诚实的答案是:在你自己的市场、自己的参数、自己的成本假设下跑过之前,别信任何一方。
本文使用合成数据演示方法论,所有收益数字不构成任何投资建议。