3、协整理论入门:从直觉到检验

各位同学,今天我们来聊聊协整。说实话,我刚入行那会儿,听到「协整」这个词,第一反应是——这又是什么高大上的数学概念?后来做多了统计套利,才发现它其实就是个「找对象」的过程。你想想看,两只股票的价格走势,就像一对情侣,短期可能各走各的,但长期来看,总得步调一致才行。

3.1 协整的直观理解:价格会「回家」

先讲个我自己的经历。2018年我在做A股配对交易时,盯上了茅台和五粮液。这两只股票,单看价格,一个200多,一个50多,完全不在一个量级。但它们的价差,却总在一个区间里晃悠。涨多了就跌回来,跌多了就涨回去。这就是协整的直观表现——两个非平稳的时间序列,它们的线性组合却是平稳的

说白了,协整就是告诉你:虽然单个价格像醉汉走路,东倒西歪,但两个醉汉绑在一起,反而能走直线。这个「绑在一起」的线性组合,就是我们的套利机会。

核心思想:协整 ≠ 相关性。相关性高不代表协整,比如两只股票都跟着大盘涨跌,但它们之间可能没有长期均衡关系。协整强调的是「长期均衡」——价差会均值回归。

3.2 平稳性与单位根检验(ADF检验)

要理解协整,先得搞懂什么是平稳性。我习惯这么跟团队新人讲:平稳序列就像个乖孩子,均值、方差都不随时间变化,始终围绕一个固定值波动。而非平稳序列呢?就像个叛逆少年,越走越远,没有回头的意思。

金融时间序列,比如股票价格,几乎都是非平稳的。但它们的收益率(一阶差分)往往是平稳的。这就是所谓的「一阶单整」,记作 I(1)。

单位根检验:判断是否平稳

最常用的就是 ADF 检验(Augmented Dickey-Fuller Test)。它的原理我不打算细讲,你只要记住:ADF 检验的原假设是「存在单位根,即序列非平稳」。如果 p 值小于 0.05,就拒绝原假设,认为序列平稳。

嗯,这里要注意:ADF 检验的滞后阶数选择很关键。选少了,自相关没消除;选多了,检验功效下降。我个人习惯用 AIC 准则自动选阶。

import pandas as pd
import numpy as np
from statsmodels.tsa.stattools import adfuller

# 模拟一个随机游走(非平稳)
np.random.seed(42)
random_walk = np.cumsum(np.random.randn(1000))

# ADF检验
result = adfuller(random_walk, autolag='AIC')
print(f'ADF统计量: {result[0]:.4f}')
print(f'p值: {result[1]:.4f}')
print(f'临界值: {result[4]}')

# 输出示例:
# ADF统计量: -1.2345
# p值: 0.6543
# 临界值: {'1%': -3.437, '5%': -2.864, '10%': -2.568}

你看,p值0.65,远大于0.05,不能拒绝原假设——序列非平稳。这就是典型的随机游走。

避坑指南:我曾经在实盘策略中犯过一个低级错误——直接用价格做回归,没做平稳性检验。结果回测曲线漂亮得不行,实盘一跑就崩。后来才发现,那只是伪回归。记住:非平稳序列之间做回归,t统计量会严重失真

3.3 Engle-Granger两步法:最经典的协整检验

这个方法,说白了就是两步走:

  1. 第一步:用 OLS 回归估计长期均衡关系。比如 y = α + βx + ε,得到残差 ε。
  2. 第二步:对残差 ε 做 ADF 检验。如果残差平稳,就说明 y 和 x 协整。

听起来简单吧?但坑也不少。我当年第一次用 EG 两步法时,就踩了个坑——回归方向会影响结果。你用 y 对 x 回归,和用 x 对 y 回归,得到的残差不一样,协整结论也可能不同。所以,我建议你两个方向都试一下,或者用 Johansen 检验来验证。

import statsmodels.api as sm

# 模拟两个协整序列
np.random.seed(42)
x = np.cumsum(np.random.randn(1000))
y = 0.8 * x + np.random.randn(1000) * 0.5  # 协整关系

# 第一步:OLS回归
X = sm.add_constant(x)
model = sm.OLS(y, X).fit()
residuals = model.resid

# 第二步:对残差做ADF检验
result = adfuller(residuals, autolag='AIC')
print(f'残差ADF p值: {result[1]:.4f}')

# 输出示例:
# 残差ADF p值: 0.0000

p值接近0,说明残差平稳,两个序列协整。这就是我们的套利基础。

个人经验:EG两步法适合两个序列的协整检验。如果多于两个,建议直接用 Johansen 检验。另外,EG 两步法有个隐含假设——协整向量是唯一的。如果存在多个协整关系,它只能找到一个。

3.4 Johansen检验简介:多序列协整的利器

Johansen 检验,说白了就是 EG 两步法的升级版。它基于 VAR 模型,可以同时检验多个协整关系。我习惯把它想象成一个「协整探测器」——不仅能告诉你有没有协整,还能告诉你存在几个协整关系。

Johansen 检验有两种统计量:迹统计量(Trace)最大特征值统计量(Max-Eigen)。两者结论通常一致,如果矛盾,我一般以迹统计量为准。

from statsmodels.tsa.vector_ar.vecm import coint_johansen

# 模拟三个序列,其中两个协整
np.random.seed(42)
z1 = np.cumsum(np.random.randn(1000))
z2 = 0.6 * z1 + np.random.randn(1000) * 0.3
z3 = np.cumsum(np.random.randn(1000))  # 独立随机游走

data = np.column_stack([z1, z2, z3])

# Johansen检验
result = coint_johansen(data, det_order=0, k_ar_diff=1)
print(f'迹统计量: {result.lr1}')
print(f'迹统计量临界值(95%): {result.cvt[:, 1]}')
print(f'最大特征值统计量: {result.lr2}')
print(f'最大特征值临界值(95%): {result.cvm[:, 1]}')

# 输出示例:
# 迹统计量: [45.23, 12.56, 1.23]
# 迹统计量临界值(95%): [29.80, 15.49, 3.84]
# 最大特征值统计量: [32.67, 11.33, 1.23]
# 最大特征值临界值(95%): [21.13, 14.26, 3.84]

你看,迹统计量第一个值 45.23 > 29.80,拒绝「r=0」的原假设;第二个值 12.56 < 15.49,不能拒绝「r≤1」。说明存在1个协整关系。这跟我们的模拟设定一致——z1和z2协整,z3是独立的。

关键点:Johansen 检验对滞后阶数敏感。我建议用 AIC 或 BIC 准则选择最优滞后阶数,然后做残差自相关检验,确保模型设定正确。

知识体系总览

下面这张图,是我自己梳理的协整检验流程。你跟着走一遍,基本不会出错。

协整检验知识体系 时间序列数据 平稳性检验(ADF) 序列平稳 → 直接建模 非平稳 → 差分或协整 协整检验(EG / Johansen) 存在协整 → 构建配对交易策略

这张图把整个流程串起来了。你从数据出发,先做平稳性检验。如果平稳,直接建模;如果不平稳,考虑差分或协整。协整检验用 EG 两步法(两个序列)或 Johansen 检验(多个序列)。如果存在协整关系,恭喜你,可以构建配对交易策略了。

我的建议:初学者先从两个序列的 EG 两步法入手,跑通流程。等理解了残差平稳性的含义,再上 Johansen 检验。别一上来就搞复杂的,容易把自己绕晕。

好了,协整理论就讲到这里。记住一句话:协整不是万能的,但没有协整,统计套利就是空中楼阁。下一节,我们会把这些理论落地到代码里,真正跑一个配对交易策略出来。

专注资料整理