教科书里的协整很美:两只价格一价之差是平稳的,于是「价差一偏离均值就做反向、赚均值回复的钱」。但落地最常被打脸的一句话是——协整会断。今天还平稳的价差,可能因为一只标的换了主营业务、行业政策转向、或者流动性结构变化,对冲比悄悄漂移,价差里混入随机游走项,从此不再均值回复。本篇要解决的,就是怎么在关系断掉的当天就发现它,并且把组合从「用错的旧对冲比」切换到「自适应新对冲比」。
结论先放这:用固定对冲比 β=1.0 的静态协整,在断裂后价差标准差被放大 6.8 倍、半衰期从 1.5 个交易日直接退化到非平稳(∞);而用长度 120 的滚动窗口重估对冲比 β̂(t),能把断裂时的跳变(β 从 1.0 跳到 1.5)抓出来(估计均值 1.00→1.33),再叠加 DCC-GARCH 动态条件相关(ρ 从 0.82 阶跃降到 0.62,降幅 24.6%)作为二阶协同信号,自适应价差在断裂后标准差仍只有 0.024、半衰期 1.63 个交易日,继续均值回复。 抓住会断的关系,靠的不是「相信协整」,而是「持续重新检验协整」。

一、协整为什么会断:从生成过程说起#
为了干净地演示「断」,我们构造一对价格:x 是随机游走 I(1),y = βₜ·x + ε,其中 ε 是平稳的 AR(1) 价差项。关键设定是 βₜ 在 t=550 处从 1.0 结构性跳到 1.5,且突变后特质波动放大(σ_ε 从 0.005 升到 0.018):
import numpy as np
rng = np.random.default_rng(20260715)
T, break_t = 1000, 550
x = np.cumsum(rng.normal(0.0, 0.010, T)) # x: 随机游走 I(1)
beta_true = np.where(np.arange(T) < break_t, 1.0, 1.5) # βₜ 在断裂点跳变
sig_e = np.where(np.arange(T) < break_t, 0.005, 0.018) # 突变后特质波动放大
e = rng.normal(0.0, sig_e)
eps = np.zeros(T)
for t in range(1, T): # 平稳 AR(1) 价差项
eps[t] = 0.6 * eps[t - 1] + e[t]
y = beta_true * x + epspython注意断裂后的真实价差应该是 y − 1.5·x = ε(平稳)。但如果你不知道 β 变了,仍用旧的 β=1.0,写出来的价差是:
多出来的 0.5·xₜ 就是随机游走项——它让 sₜ 不再平稳。这才是「协整断了」的本质:不是价差波动变大,而是价差里混进了一个非平稳成分。
二、检测手段一:滚动窗口 Engle-Granger 重估对冲比#
标准 EG 检验是「全样本 OLS 估 β」。但全样本会把断裂前后的 β 混在一起,得到一个 1.25 的折中值,两边都不准。正确做法是在长度 L=120 的滚动窗口上重估 β̂(t),让估计随时间滑动:
L = 120
beta_hat = np.full(T, np.nan)
for t in range(L, T):
sl = slice(t - L, t)
Xw = np.vstack([np.ones(L), x[sl]]).T
co = np.linalg.lstsq(Xw, y[sl], rcond=None)[0]
beta_hat[t] = co[1] # 滚动对冲比 β̂(t)python跑出来:断裂前 β̂ 均值 1.003,断裂后均值 1.328——虽然因窗口平滑略低于真实 1.5,但跳变本身清晰可见。这就是第一道警报:当 β̂(t) 的持续水平相对于历史中枢偏移超过阈值(比如 ±2 个滚动标准差),就判定「对冲比漂移」。
三、检测手段二:DCC-GARCH 动态条件相关#
对冲比是「一阶」关系;但协整断裂往往也伴随二阶协同性下降——两只标的价格一起动的强度变弱。我们用 DCC(1,1) 在收益上估动态条件相关 ρ_t。先对两资产收益做滚动标准化(去条件波动),再用指数加权更新拟相关矩阵 Q:
rx, ry = np.diff(x), np.diff(y)
# 60 日滚动标准差标准化
def roll_std(s, w):
out = np.full(len(s), np.nan)
for i in range(w, len(s)):
out[i] = np.std(s[i-w:i], ddof=1)
return out
sx, sy = roll_std(rx, 60), roll_std(ry, 60)
ux = rx / sx; uy = ry / sy # 标准化收益
a, b = 0.04, 0.94
Q = np.cov(np.stack([ux, uy])[:, ~np.isnan(ux)]) # Qbar 作为长期基准
rho = np.full(len(rx), np.nan)
for t in range(len(rx)): # DCC(1,1) 递推
if np.isnan(ux[t]): continue
u = np.array([ux[t], uy[t]])
Q = (1-a-b)*Qbar + a*np.outer(u, u) + b*Q
rho[t] = Q[0,1] / np.sqrt(Q[0,0]*Q[1,1])python结果:断裂前 ρ≈0.82,断裂后跌到 0.62,降幅 24.6%。ρ 的阶跃下降和 β̂ 的跳变几乎同步发生——两个信号互相印证,误报率比单用其中一个低得多。

四、价差质量诊断:断裂前后,稳态差多少#
光有警报还不够,要量化「关系断了之后价差到底变成什么样」。用 OU 回归 Δs = φ·s_{t-1} + η 估半衰期:φ<0 均值回复(半衰期 = −ln2/φ),φ≥0 非平稳(→∞)。比较静态价差与自适应价差在断裂干净段(过渡期之后)的表现:
| 价差口径 | 断裂前 std | 断裂后 std | 半衰期(断裂后) |
|---|---|---|---|
| 静态(β=1.0) | 0.0057 | 0.0385(6.8×) | ∞(非平稳) |
| 自适应(β̂(t)) | ≈平稳 | 0.0236 | 1.63(仍均值回复) |
静态价差在断裂后标准差被放大近 7 倍且彻底失去均值回复性——任何基于它 z-score 的套利都会持续亏在「随机游走那一侧」;自适应价差标准差稳定、半衰期短,协整关系被「接住」了。

五、把检测变成执行:自适应配对#
实战里不是「发现断了就清仓」,而是用 β̂(t) 实时重建价差:
sp_adp = np.where(np.arange(T) < L, np.nan, y - beta_hat * x) # 滚动自适应价差
# 交易时只用截至 t-1 的窗口算 z-score,避免前视:
def signal(sp, t, warm):
win = sp[t-warm:t]
m, s = np.mean(win), np.std(win, ddof=1)
return np.clip(-(sp[t-1]-m)/s, -1, 1) # 价低→做多价差python当 β̂ 跳变触发「关系重置」,窗口会自然地把新对冲比吸收进来,价差回到平稳带。关键是检测与执行共用同一条 β̂(t) 序列,而不是检测一套、交易另一套——很多回测看似能抓住断裂,是因为它偷用了「断裂后已知 β=1.5」,那才是真前视。
六、六类真实陷阱(高阶必读)#
1. 滚动窗口的滞后偏差。 窗口 L=120 意味着 β̂(t) 对断裂的反应延迟约 L/2 期。真实突变是瞬时的,估计是平滑的——断裂刚发生的几十期里,β̂ 仍半新半旧,价差会短暂失真。应配合更短的「突变专检」(如 CUSUM、Sup-F 结构突变检验)缩短告警延迟。
2. DCC 对波动状态的敏感。 ρ 的下降可能只是「各自波动变大」而非「协同性真降」。本例同时放大了特质波动,ρ 下跌部分来自波动状态切换。务必区分「相关结构变化」与「波动水平变化」,可改用绝对相关或相关系数去条件化后再判。
3. 过渡期假信号。 断裂后β̂ 从旧值爬向新值的过程中,价差会经历一段「半旧半新」的非平稳过渡。这段窗口既不算旧关系也不算新关系,应显式标记为「重组期」、暂停加仓,而不是照常 z-score 交易。
4. 幸存者与point-in-time。 真实里「哪对该做协整」本身是选股问题。用事后挑出的高相关对回测,会严重幸存者偏差——必须在配对形成日 point-in-time 检验协整,再持有,而不是全样本挑完再回测。
5. 交易成本与容量。 自适应重估 + 重组期调仓会增加换手。若手续费/冲击超过均值回复收益,再「正确」的检测也不赚钱。本例完全未计成本,落地必须扣费后看净夏普。
6. 伪断裂(regime 内的正常漂移)。 β 的小幅时变是常态,不等于断裂。阈值设太敏会频繁重置、白白亏手续费;设太钝又接不住真断裂。阈值应基于 β̂ 的历史滚动标准差、而非固定绝对偏移。
七、代码清单与落地路径#
完整可运行脚本:generate_rolling_cointegration_break_images.py,含数据生成、滚动 EG、DCC(1,1) 与半衰期诊断(配图同源)。落地到真实研究时:
- 用 point-in-time 数据库取候选对的日度收盘,先全样本 EG 粗筛协整对;
- 对每对跑滚动 β̂(t)(窗口 60~120),监控 β̂ 相对其滚动中枢的偏移(>2σ 告警);
- 并行跑 DCC 得到 ρ_t,与 β̂ 跳变做「双信号与」确认,降低误报;
- 告警触发后进入过渡期(如 20 日),用新窗口 β̂ 重建价差、重置 z-score 基准,过渡期只减仓不加仓;
- 扣手续费/冲击后评估净夏普与最大回撤,只有净收益覆盖重置成本才上实盘。
协整的价值不在于「找到一对永不分离的资产」,而在于承认任何长期关系都会在某天松动,并建立一套持续重新检验、自动修复的机制。能抓住会断的关系,比相信关系永不断,更接近于真实的钱。
本文为量化专栏第 N 篇。所有数值来自自洽合成(含结构性断裂设定),仅用于演示检测与自适应机制;真实断裂强度、检测延迟与净收益请以 point-in-time 无幸存者偏差数据库为准。