向量误差修正模型 VECM:把协整关系写成向长期均衡的拉力
两条价格各自都是随机游走,差分建模却会把它们之间最值钱的信息——长期均衡关系——直接扔掉。VECM 的答案:在差分方程里加回误差修正项 α(y1−βy2),让偏离均衡的距离本身成为回归的拉力。纯 numpy 走完全流程:Engle-Granger 两步法估出协整系数 1.232(真值 1.25),残差 ADF=−7.24 确认协整;伪回归对照组 R²=0.62 但 ADF 只有 −1.60——高 R² 不等于协整。误差修正系数 α₁=−0.061 (t=−3.8)、α₂=+0.062 (t=+3.8),两腿对向修正,价差半衰期 4.8 天;Johansen 迹检验 54.9 >> 15.5 临界值交叉验证。配对交易样本外 500 天:z>2 开仓、|z|<0.5 平仓、z>4 止损,净 Sharpe 2.08、回撤 3.5%、19 次动作。诚实说明:合成数据协整关系永不破裂,真实市场协整会死(招行/平安、可乐/百事都散过伙);EG 法把 β 的估计误差全部灌进价差;z>4 止损保护不了缓慢漂移型破裂。拆穿相关性=协整、半衰期恒定等经典误区(中阶)。
先说结论:两条价格序列各自都是随机游走(单位根过程),教科书说”非平稳序列要先差分再建模”。但如果这两条序列是协整的——存在某个线性组合是平稳的——差分建模会把它们之间最值钱的信息直接扔掉:长期均衡关系。VECM(Vector Error Correction Model)的做法是在差分方程里加回一个误差修正项 ,让”偏离均衡多远”本身成为把价格拉回来的力。 合成协整对实测:Engle-Granger 两步法估出协整系数 1.232(真值 1.25),残差 ADF 统计量 −7.24 远超临界值;误差修正系数 α₁=−0.061、α₂=+0.062,方向相反、双双显著(|t|=3.8),价差半衰期 4.8 天。配对交易样本外 500 天:净费后 Sharpe 2.08,最大回撤 3.5%,全程只动手 19 次。但必须先泼冷水:合成数据里协整关系永不破裂,真实市场里它会死——而且死的时候不会提前打招呼。

一、协整是什么:两个醉汉和一条狗绳#
经典比喻:两个醉汉各自随机游走,但他们之间拴着一条狗绳。任何一个人的位置都不可预测(单位根),但两人的距离是有界的、会回归的(平稳)。
数学上,若 都是 I(1)(一阶单整,差分后平稳),且存在 使得 是 I(0)(平稳),则称两者协整。本文的合成数据把这个结构写得很明白:
import numpy as np
rng = np.random.default_rng(7)
T = 1250 # 约5年日频
w = np.cumsum(rng.standard_normal(T) * 0.012) + 4.0 # 共同随机趋势(狗绳的主人)
u1 = np.zeros(T); u2 = np.zeros(T)
for t in range(1, T):
u1[t] = 0.92 * u1[t-1] + rng.standard_normal() * 0.010 # 各自的平稳偏离
u2[t] = 0.85 * u2[t-1] + rng.standard_normal() * 0.012
lp1 = w + u1 # log价格1: 载荷 1.0
lp2 = 0.8 * w + u2 + 1.0 # log价格2: 载荷 0.8python两条 log 价格共享同一个随机趋势 ,载荷分别是 1 和 0.8。于是 把 完全消掉,剩下的 是平稳的——协整向量是 。这就是”统计套利”的物理基础:你交易的不是价格,是那条被拉长的狗绳。
二、Engle-Granger 两步法:先回归,再验尸#
第一步,用前 750 天(训练段)做水平回归:
split = 750
X = np.column_stack([np.ones(split), lp2[:split]])
alpha_hat, beta_hat = np.linalg.lstsq(X, lp1[:split], rcond=None)[0]
spread_in = lp1[:split] - (alpha_hat + beta_hat * lp2[:split])
# 结果: lp1 = -1.175 + 1.232 * lp2 (真值斜率 1.25)python第二步,检验残差是否平稳。这一步是生死线——任何两条趋势序列做回归都能得到高 R²,但只有残差平稳才是协整,否则就是伪回归。手写 ADF 检验:
def adf_stat(x, lags=1):
dx = np.diff(x)
xl = x[lags:-1]
Xm = np.column_stack([np.ones(len(xl)), xl, dx[:-lags]])
y = dx[lags:]
b = np.linalg.lstsq(Xm, y, rcond=None)[0]
resid = y - Xm @ b
s2 = resid @ resid / (len(y) - Xm.shape[1])
se = np.sqrt(s2 * np.linalg.inv(Xm.T @ Xm)[1, 1])
return b[1] / se # 单位根 t 统计量python协整残差的 ADF = −7.24,远超 Engle-Granger 5% 临界值 −3.34(注意:EG 残差检验的临界值比普通 ADF 更严,因为 β 是估出来的),干脆利落地拒绝”无协整”。
对照组是本文最想让你记住的图:两条独立的带漂移随机游走互相回归,R² 高达 0.62——看起来”高度相关”——但残差 ADF 只有 −1.60,根本不平稳。

左图绿线(真协整残差)在零轴附近反复穿越,红线(伪回归残差)一去不回头。用相关系数或 R² 找配对,是配对交易散户亏钱的第一大原因:相关性度量的是短期共动,协整度量的是长期绑定,两者可以完全脱钩。
三、VECM:把偏离写成拉力#
确认协整后,第二步把动态写成误差修正形式:
方程同理。α 是调整速度:ECT 为正(资产1 相对贵了)时,α₁<0 会把 往下拽,α₂>0 会把 往上抬——两腿对向收敛。估计结果:
| 系数 | 估计值 | t 统计量 | 解读 |
|---|---|---|---|
| α₁ | −0.0605 | −3.8 | 资产1 每天修正偏离的 6% |
| α₂ | +0.0622 | +3.8 | 资产2 反向修正 6.2% |
两个 α 都显著且方向正确。这里有一个真实市场中非常有用的诊断:如果 α₁ 显著而 α₂ 不显著,说明收敛全靠资产1 完成,资产2 是”领导者”——配对交易时应该意识到你的均值回归敞口集中在跟随者那条腿上。价差 AR(1) 系数 0.866,对应半衰期 4.8 天:偏离一半的距离平均 5 天修复,这个数字直接决定策略的资金周转率和止损耐心。
用 statsmodels 的 Johansen 迹检验交叉验证:迹统计量 54.87 >> 5% 临界值 15.49(拒绝”0 个协整关系”),第二个统计量 2.11 < 3.84(接受”至多 1 个”)——恰好 1 条协整关系,标准化协整向量 (1, −1.24),与 EG 结果和真值一致。两变量用 EG 够了;三个以上变量必须上 Johansen,因为协整关系可能不止一条,EG 只能找到其中某一条的投影。
四、配对交易回测:z-score 开平仓状态机#
信号规则:价差 z-score(用训练段均值方差标准化)超过 ±2 开仓做收敛,回到 ±0.5 内平仓,突破 ±4 视为协整破裂止损。t 日确认信号,t+1 日成交:
mu_in, sd_in = spread_in.mean(), spread_in.std() # 只用训练段统计量
z = (ect - mu_in) / sd_in
state = 0
for t in range(split, T - 1):
if state == 0:
if z[t] > 2.0: state = -1 # 价差过高: 空1多2
elif z[t] < -2.0: state = 1 # 价差过低: 多1空2
else:
if abs(z[t]) < 0.5: state = 0 # 收敛平仓
elif abs(z[t]) > 4.0: state = 0 # 协整破裂止损
pos[t + 1] = state # t 确认, t+1 生效
spread_ret = pos[1:] * (r1 - beta_hat * r2) / (1 + beta_hat) # 两腿名义额归一python样本外 500 天结果(单边 5bp 交易成本):
| 口径 | 总收益 | Sharpe | 最大回撤 | 动作次数 |
|---|---|---|---|---|
| 毛收益 | +31.9% | 2.22 | 3.2% | 19 |
| 净收益 | +29.4% | 2.08 | 3.5% | 19 |

几个值得注意的读法。第一,成本侵蚀很小(Sharpe 2.22→2.08),因为半衰期 4.8 天的价差对应低频交易——500 天只动手 19 次。协整策略天然是低换手策略,这是它和高频统计套利的本质区别。第二,净值曲线是典型的”楼梯形”:持仓期赚取收敛收益,空仓期走平。橙色持仓区间显示大部分时间其实在场外等待——配对交易的收益密度集中在偏离发生后的几天里,其余时间的耐心是策略的一部分。第三,回撤只有 3.5%,因为多空对冲消掉了共同趋势 的方向性风险,剩下的敞口只有价差本身。
五、诚实的翻车与边界#
1. 合成数据里协整永不破裂,真实市场里它会死。 这是本文和现实之间最大的鸿沟。真实协整对的死法有很多种:招商银行/平安银行这类同行业对会因为基本面分化渐行渐远;可口可乐/百事的经典协整在 2000 年代逐渐失效;LTCM 的故事本质上就是”协整关系在你加满杠杆之后破裂”。z>4 止损能挡住急性破裂,挡不住缓慢漂移型破裂——价差从新的均衡水平看永远回不到旧均值,但 z-score 一直在 2~3 之间徘徊,让你反复开仓反复小亏。工程上的缓解是滚动重估 β 和滚动 ADF 监控:一旦残差平稳性检验开始失败,无条件退出。
2. EG 两步法把 β 的估计误差全部灌进价差。 第一步 OLS 估出的 β̂=1.232 不是真值 1.25,这 1.4% 的误差意味着你构造的”价差”里还残留着一小截没消干净的随机趋势 。样本内看不出来,样本外时间够长就会显形为价差的缓慢漂移。样本越短、两腿波动比越极端,这个问题越严重。Johansen 的极大似然估计在统计性质上更好,但也只是缓解不是根治。
3. 半衰期不是常数。 本实验的 AR 结构固定,所以 4.8 天的半衰期全程成立。真实价差的均值回归速度随市场状态剧烈变化——平静期 5 天,危机期可能 50 天(流动性撤退时没人来修复价差,2008 年和 2020 年 3 月的统计套利集体回撤都是这个机制)。用全样本估一个半衰期然后当常数用,是把策略的生死交给了最坏时期的资金承受力。
4. 本回测没有建模做空成本与保证金占用。 配对交易永远有一条空腿,A 股融券几乎不可行、港股部分标的券源紧张、美股 hard-to-borrow 名单的费率可以吃掉全部价差收益。落地时”能不能借到券、多少钱”往往比模型本身更决定成败。
六、什么时候该用 VECM#
适合: 有真实经济纽带的配对——同一公司的 A/H 股、股指期货与现货、同一产业链上下游商品(原油/汽油裂解价差)、ETF 与其成份篮子。这些对的协整有经济机制托底,不只是统计巧合。也适合宏观建模:消费与收入、汇率与利差这类理论上存在长期均衡的变量组。
不适合: 纯数据挖掘筛出来的配对——在 5000 只股票里两两做协整检验,5% 显著性水平下光靠运气就能”发现”60 多万对协整关系,其中绝大多数样本外即死。也不适合协整半衰期长于你的资金耐心的场景:半衰期 60 天的价差理论上也能做,但回撤深度和资金占用会让 Sharpe 毫无吸引力。
一句话总结:VECM 是少数把”长期均衡”这个经济学概念直接翻译成可交易信号的模型——误差修正项就是仓位方向,调整速度就是持仓周期,残差平稳性就是策略存活的体检指标。它的数学是七十年代的,但”先证明狗绳存在,再赌狗绳收紧”这个纪律,今天依然是统计套利的第一课。
本文实验代码基于 numpy 手写实现(EG 两步法 + ADF 检验 + 误差修正方程 + 状态机回测),Johansen 检验用 statsmodels 交叉验证,所有数字均为真实运行输出。文中回测为教学演示,不构成投资建议。