3. 协整检验:Engle-Granger两步法与Johansen检验
协整检验,说白了就是判断两个或多个非平稳时间序列之间是否存在长期稳定的线性关系。嗯,这里要注意,我们做多资产组合,最核心的假设就是这些资产虽然各自乱跑,但它们的某种组合是稳定的。如果这个假设不成立,那后面的回测全是白搭。
我个人习惯把协整检验分成两个流派:一个是针对两两资产的Engle-Granger两步法,另一个是针对多资产组合的Johansen检验。今天咱们就把这两个方法掰开揉碎了讲清楚。
核心思想:如果两个或多个非平稳序列的线性组合是平稳的,那它们就存在协整关系。这个线性组合的系数,就是我们构建配对交易或组合策略的权重。
3.1 Engle-Granger两步法
这个方法是我最早接触协整时用的。当时我在做股指期货和ETF的配对交易,发现IF和沪深300ETF之间总有个价差在均值附近来回摆动。但怎么量化这个关系?EG两步法就是干这个的。
它的逻辑非常直观,分两步走:
- 第一步:估计长期关系。用OLS回归,把两个序列的线性关系拟合出来。比如Y对X做回归,得到残差序列。
- 第二步:检验残差的平稳性。对残差做ADF检验。如果残差是平稳的,说明Y和X存在协整关系。
我曾经踩过一个坑:直接用原始价格做回归,结果残差看起来平稳,但换了个样本期就不行了。后来发现,回归前必须确认两个序列都是I(1)的,也就是一阶单整。如果一个是I(1),另一个是I(2),那EG两步法就失效了。
避坑指南:我曾经在测试商品期货跨品种套利时,直接用EG两步法检验螺纹钢和热卷。结果残差ADF检验通过,但实盘回测亏得一塌糊涂。后来发现,两个序列的阶数不一致——螺纹钢是I(1),热卷是I(2)。所以,做EG之前,一定先用单位根检验确认阶数。
下面是一个完整的Python实现:
import numpy as np
import pandas as pd
import statsmodels.api as sm
from statsmodels.tsa.stattools import adfuller
def engle_granger_test(y, x):
"""
Engle-Granger两步法协整检验
y: 被解释变量序列
x: 解释变量序列
返回:协整检验统计量和p值
"""
# 第一步:OLS回归
x_with_const = sm.add_constant(x)
model = sm.OLS(y, x_with_const).fit()
residuals = model.resid
# 第二步:对残差做ADF检验
# 注意:这里要用无常数项的ADF,因为残差均值理论上为0
adf_stat, p_value, _, _, critical_values, _ = adfuller(residuals, maxlag=1, autolag='AIC')
return {
'adf_statistic': adf_stat,
'p_value': p_value,
'critical_values': critical_values,
'hedge_ratio': model.params[1], # 对冲比率
'residuals': residuals
}
# 示例:检验两只股票是否协整
# 假设我们有两只股票的日收盘价
np.random.seed(42)
dates = pd.date_range('2020-01-01', periods=500, freq='D')
stock_a = np.cumsum(np.random.randn(500)) + 100
stock_b = stock_a * 0.8 + np.random.randn(500) * 0.5 + 20
result = engle_granger_test(stock_a, stock_b)
print(f"ADF统计量: {result['adf_statistic']:.4f}")
print(f"p值: {result['p_value']:.4f}")
print(f"对冲比率: {result['hedge_ratio']:.4f}")
print(f"1%临界值: {result['critical_values']['1%']:.4f}")
个人经验:EG两步法虽然简单,但有个致命缺陷——它假设协整关系是唯一的,而且回归方向会影响结果。你试试把Y和X互换,得到的对冲比率可能完全不同。所以,我一般会做两次检验,取统计量更显著的那个方向。
3.2 Johansen检验
Johansen检验就高级多了。它基于VAR模型,可以同时检验多个资产之间的协整关系,而且能找出所有可能的协整向量。说白了,EG是单挑,Johansen是群殴。
它的核心思想是:通过特征值分解,判断协整秩(即协整关系的个数)。如果秩为0,说明没有协整关系;秩为1,说明存在一个协整关系;秩为2,说明存在两个,以此类推。
我记得第一次用Johansen检验时,面对输出结果里的特征值和迹统计量,整个人是懵的。后来慢慢摸清了门道:
- 迹检验(Trace Test):检验协整秩是否小于等于r。从r=0开始,如果拒绝,则检验r≤1,以此类推。
- 最大特征值检验(Max Eigenvalue Test):检验协整秩是否恰好为r,而不是r+1。
你想想看,如果我们要构建一个包含5只股票的多资产组合,用EG两步法得两两检验10次,而且结果还不一致。但Johansen一次就能搞定,直接告诉你这5只股票里存在几个协整关系。
from statsmodels.tsa.vector_ar.vecm import coint_johansen
def johansen_test(data, det_order=0, k_ar_diff=1):
"""
Johansen协整检验
data: 多资产价格矩阵,每列一个资产
det_order: 确定性趋势类型,0=无截距,1=有截距,-1=有趋势
k_ar_diff: VAR模型的滞后阶数(差分形式)
返回:检验结果
"""
result = coint_johansen(data, det_order, k_ar_diff)
# 迹统计量
trace_stat = result.trace_stat
trace_crit = result.trace_stat_crit_vals
# 最大特征值统计量
max_eigen_stat = result.max_eig_stat
max_eigen_crit = result.max_eig_stat_crit_vals
# 协整向量(标准化后的)
coint_vecs = result.evec
return {
'trace_stat': trace_stat,
'trace_crit_90': trace_crit[:, 0],
'trace_crit_95': trace_crit[:, 1],
'trace_crit_99': trace_crit[:, 2],
'max_eigen_stat': max_eigen_stat,
'max_eigen_crit_90': max_eigen_crit[:, 0],
'max_eigen_crit_95': max_eigen_crit[:, 1],
'max_eigen_crit_99': max_eigen_crit[:, 2],
'coint_vectors': coint_vecs
}
# 示例:检验三只股票是否协整
np.random.seed(123)
dates = pd.date_range('2020-01-01', periods=500, freq='D')
stock1 = np.cumsum(np.random.randn(500)) + 100
stock2 = stock1 * 0.6 + np.random.randn(500) * 0.3 + 40
stock3 = stock1 * 0.4 + stock2 * 0.3 + np.random.randn(500) * 0.2 + 30
data_matrix = np.column_stack([stock1, stock2, stock3])
johansen_result = johansen_test(data_matrix, det_order=1, k_ar_diff=2)
print("迹统计量检验结果:")
for i in range(len(johansen_result['trace_stat'])):
print(f" 秩≤{i}: 统计量={johansen_result['trace_stat'][i]:.4f}, "
f"95%临界值={johansen_result['trace_crit_95'][i]:.4f}")
print("\n协整向量(第一列为主向量):")
print(johansen_result['coint_vectors'][:, 0])
关键点:Johansen检验的滞后阶数选择很敏感。我一般用AIC或BIC准则来确定最优滞后阶数,但要注意,阶数选太大容易过拟合,选太小又可能遗漏自相关。实践中,日频数据我通常选1-3阶。
3.3 两种方法的对比与选择
在实际项目中,我一般这样选:
| 维度 | Engle-Granger两步法 | Johansen检验 |
|---|---|---|
| 适用场景 | 两两资产配对 | 多资产组合(3个以上) |
| 计算复杂度 | 低,两步OLS | 高,需要解特征值 |
| 协整关系数量 | 只能检验是否存在 | 能找出所有协整关系 |
| 对方向敏感 | 是,Y和X互换结果不同 | 否,对称处理 |
| 小样本表现 | 偏差较大 | 相对稳健 |
| 实际应用 | 股票配对、期现套利 | 多资产组合、统计套利篮子 |
我个人习惯是:做配对交易时用EG两步法,简单直接;做多资产组合时用Johansen,一次搞定。但不管用哪种,一定要做样本外验证。我曾经在沪深300成分股里找到一组看起来协整的股票,结果样本外一个月就崩了——协整关系是时变的,不是永恒的。
小技巧:如果你用Johansen检验发现多个协整向量,怎么选?我的做法是:选特征值最大的那个向量,因为它对应的协整关系最稳定。或者,你也可以用经济意义来筛选——比如对冲比率不能太离谱,不能出现负的权重等。
3.4 协整检验的完整流程
下面这张图是我自己总结的协整检验流程,每次做新组合时我都会过一遍:
嗯,以上就是协整检验的核心内容。EG两步法适合快速验证两个资产的关系,Johansen则适合多资产组合的全面分析。我个人建议,初学者先从EG两步法入手,把单对单的协整逻辑搞明白,再上Johansen。毕竟,地基打不牢,楼盖得再高也是危房。
最后提醒:协整关系不是一成不变的。我见过太多人找到一个协整组合就以为找到了印钞机,结果市场结构一变,组合就崩了。建议定期(比如每季度)重新检验协整关系,或者用滚动窗口的方式动态更新。
公众号:蓝海资料掘金营,微信deep3321