4. 协整理论详解:平稳性检验(ADF检验)、Engle-Granger两步法、Johansen检验
各位同学,欢迎来到第四章。这一章我们聊聊协整理论。
说实话,协整是我个人在统计套利中最喜欢用的工具之一。为什么?因为它能帮我们找到那些表面上随机游走、实际上却“手拉手”走在一起的资产对。你想想看,两只股票各自都在乱跑,但它们的价差却始终围绕一个均值波动——这不就是套利机会吗?
好,我们一步步来拆解。先讲平稳性,再讲两步法,最后讲多变量场景下的Johansen检验。
4.1 平稳性检验:ADF检验
平稳性,说白了就是一个时间序列的统计性质不随时间改变。均值不变、方差不变、自相关结构也不变。嗯,这里要注意:金融价格序列几乎都不是平稳的,但它们的差分(收益率)往往是平稳的。
为什么要先讲平稳性?因为协整的前提是:两个序列本身是非平稳的,但它们的线性组合是平稳的。所以第一步,你得先确认每个序列是不是非平稳的。
ADF检验(Augmented Dickey-Fuller Test)是最常用的单位根检验方法。它的原假设是“序列存在单位根”,也就是非平稳。p值小于0.05,我们就拒绝原假设,认为序列平稳。
我在项目中遇到过这样的情况:两个看起来高度相关的股票,ADF检验一做,一个是一阶单整,另一个是二阶单整。嗯,那就别费劲了,它们不可能有长期均衡关系。
下面是一个Python实现ADF检验的示例:
import numpy as np
import pandas as pd
from statsmodels.tsa.stattools import adfuller
# 模拟两个非平稳序列
np.random.seed(42)
n = 500
epsilon = np.random.randn(n)
x = np.cumsum(epsilon) # 随机游走,I(1)
y = 0.8 * x + np.random.randn(n) * 0.5 # 与x协整
# ADF检验
def adf_test(series, name=''):
result = adfuller(series, autolag='AIC')
print(f'{name} ADF统计量: {result[0]:.4f}')
print(f'p值: {result[1]:.4f}')
print(f'临界值:')
for key, value in result[4].items():
print(f' {key}: {value:.4f}')
if result[1] < 0.05:
print(f'结论: {name} 平稳')
else:
print(f'结论: {name} 非平稳')
print('---')
adf_test(x, 'x')
adf_test(y, 'y')
输出结果会告诉你,x和y都是非平稳的。但它们的残差呢?我们后面再验证。
4.2 Engle-Granger两步法
这是最经典的协整检验方法。说白了就是两步走:
- 第一步: 用OLS回归估计长期均衡关系。比如 y = α + βx + ε,得到残差序列。
- 第二步: 对残差做ADF检验。如果残差平稳,说明x和y协整。
你想想看,如果x和y真的存在长期均衡关系,那么它们的价差(残差)应该围绕0波动,不会越走越远。这就是协整的本质。
下面是一个完整的Engle-Granger两步法实现:
import statsmodels.api as sm
# 第一步:OLS回归
X = sm.add_constant(x)
model = sm.OLS(y, X).fit()
residuals = model.resid
print(f'回归系数: alpha={model.params[0]:.4f}, beta={model.params[1]:.4f}')
# 第二步:对残差做ADF检验
adf_test(residuals, '残差')
如果残差的ADF检验p值小于0.05,恭喜你,找到了一个协整对。这时候就可以考虑用价差的均值回归特性做套利了。
我记得有一次做商品期货的跨品种套利,用两步法检验螺纹钢和热卷的协整关系。第一次回归残差的p值是0.06,差一点。换了个方向重新做,p值变成0.03,通过了。所以别偷懒,两个方向都试试。
4.3 Johansen检验
当你有多个资产时(比如3只股票、5只期货),Engle-Granger两步法就不够用了。这时候需要Johansen检验。
Johansen检验的核心思想是:基于向量自回归模型(VAR),通过特征值分解来判断协整关系的个数。它给出两个统计量:迹统计量和最大特征值统计量。
说白了,Johansen检验能告诉你:这组资产中,存在几个协整关系?是1个、2个,还是根本没有?
下面是一个Python实现:
from statsmodels.tsa.vector_ar.vecm import coint_johansen
# 模拟三个协整序列
np.random.seed(123)
n = 500
z1 = np.cumsum(np.random.randn(n)) # I(1)
z2 = 0.6 * z1 + np.random.randn(n) * 0.3 # 与z1协整
z3 = 0.4 * z1 + 0.3 * z2 + np.random.randn(n) * 0.2 # 与z1、z2协整
data = np.column_stack([z1, z2, z3])
# Johansen检验
johansen_result = coint_johansen(data, det_order=0, k_ar_diff=1)
print('迹统计量:', johansen_result.lr1)
print('迹统计量临界值(95%):', johansen_result.cvt[:, 1])
print('最大特征值统计量:', johansen_result.lr2)
print('最大特征值临界值(95%):', johansen_result.cvm[:, 1])
# 判断协整秩
r = 0
for i in range(len(johansen_result.lr1)):
if johansen_result.lr1[i] > johansen_result.cvt[i, 1]:
r += 1
print(f'协整秩: {r}')
输出结果会告诉你协整秩是多少。比如协整秩为2,意味着这3个资产之间存在2个独立的协整关系。
为什么会这样?因为Johansen检验本质上是基于VAR模型的,滞后阶数选错了,残差的自相关没处理好,检验结果就不可靠。嗯,这里要特别注意。
4.4 三种方法的对比
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| ADF检验 | 单个序列的平稳性判断 | 简单、快速、成熟 | 只能判断是否平稳,不能直接检验协整 |
| Engle-Granger两步法 | 两个资产之间的协整检验 | 直观、容易理解、计算量小 | 只能处理一对变量;回归方向影响结果 |
| Johansen检验 | 多个资产之间的协整检验 | 能同时检验多个协整关系;基于VAR更稳健 | 计算复杂;对滞后阶数敏感 |
我个人习惯是:做配对交易时用Engle-Granger两步法,做多资产组合时用Johansen检验。ADF检验则是每个项目开始前的必备热身。
4.5 知识体系图
下面这张图总结了本章的核心逻辑:
这张图把整个流程串起来了。从ADF检验开始,确认资产都是I(1),然后根据资产数量选择方法,最后确认协整关系。每一步都有坑,但每一步也都有对应的解决方案。
好了,这一章就到这里。协整理论是统计套利的基石,把这块啃下来,后面的策略构建就水到渠成了。
公众号:蓝海资料掘金营,微信deep3321