4. 协整检验实战:Engle-Granger两步法、Johansen检验、Python代码实现协整检验

协整检验,说白了就是看看两个或多个价格序列,是不是在长期上「手拉手」一起走。

我刚开始做价差交易那会儿,总以为只要两个品种走势像,就能配对。结果亏了不少钱。后来才明白——走势像不代表有协整关系,可能是伪回归。嗯,这里要注意。

今天咱们就把协整检验的两种主流方法讲透:Engle-Granger两步法和Johansen检验。我会带上Python代码,直接跑给你看。

4.1 为什么需要协整检验?

先问个问题:两个时间序列,相关系数0.9,能不能做配对交易?

答案是不一定。相关系数高,可能只是巧合。比如两个完全不相关的随机游走,相关系数也可能很高。这就是伪回归。

协整检验要解决的就是这个问题。它检验的是:两个序列的线性组合,是不是平稳的。如果是,那它们就有长期均衡关系。价差偏离了,迟早会回来。

我个人习惯,做任何配对交易前,先跑协整检验。这一步省不了。

4.2 Engle-Granger两步法

这个方法很直观。说白了就是两步走:

  1. 第一步:估计长期关系。用OLS回归,把两个序列的关系找出来。
  2. 第二步:检验残差平稳性。对残差做单位根检验(ADF检验)。如果残差平稳,就说明有协整关系。

我在项目中遇到过一个问题:EG两步法对样本量敏感。样本太少,检验功效会下降。一般建议至少200个数据点。

4.2.1 第一步:OLS回归

假设我们有两个价格序列:yx。回归方程是:

y_t = α + β * x_t + ε_t

这里的 ε_t 就是残差,代表价差。

4.2.2 第二步:ADF检验

对残差 ε_t 做ADF检验。如果p值小于0.05,就拒绝「有单位根」的原假设,说明残差平稳,协整关系成立。

避坑指南: 我曾经犯过一个错误——直接用ADF检验的临界值来判断残差。实际上,残差的ADF检验临界值需要查专门的MacKinnon表,比标准ADF更严格。否则容易误判。

4.2.3 Python代码实现

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

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

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

# 第二步:ADF检验残差
adf_result = adfuller(residuals, autolag='AIC')
print(f'ADF统计量: {adf_result[0]:.4f}')
print(f'p值: {adf_result[1]:.4f}')

if adf_result[1] < 0.05:
    print('结论:残差平稳,存在协整关系')
else:
    print('结论:残差不平稳,不存在协整关系')

跑完这段代码,你会看到p值很小,说明协整关系成立。嗯,模拟数据嘛,肯定成立的。

4.3 Johansen检验

EG两步法有个局限:只能检验两个序列,而且不能处理多个协整关系。Johansen检验就解决了这个问题。

Johansen检验基于向量自回归模型(VAR),可以同时检验多个序列之间是否存在协整关系,还能告诉你存在几个协整向量。

我个人觉得,做多品种配对时,Johansen检验是首选。比如你要做一篮子股票和ETF的价差,用Johansen就对了。

4.3.1 检验原理

Johansen检验有两种统计量:

  • 迹统计量(Trace Statistic):检验协整秩(即协整关系的个数)
  • 最大特征值统计量(Max Eigenvalue Statistic):检验单个协整关系是否存在

一般先看迹统计量,再看最大特征值。两者结论一致时,结果更可靠。

4.3.2 Python代码实现

from statsmodels.tsa.vector_ar.vecm import coint_johansen

# 准备数据:至少两个序列
data = pd.DataFrame({
    'y': y,
    'x': x
})

# Johansen检验
johansen_result = coint_johansen(data, det_order=0, k_ar_diff=1)

# 输出迹统计量
print('迹统计量:')
print(johansen_result.lr1)
print('临界值(90%, 95%, 99%):')
print(johansen_result.cvt)

# 输出最大特征值统计量
print('\n最大特征值统计量:')
print(johansen_result.lr2)
print('临界值(90%, 95%, 99%):')
print(johansen_result.cvm)

输出结果中,如果迹统计量大于临界值,就拒绝原假设。比如 lr1[0] > cvt[0][1],说明至少存在一个协整关系。

实战技巧: 我建议你同时看迹统计量和最大特征值。如果两者都拒绝原假设,那协整关系基本稳了。如果只有一个显著,要小心,可能是样本量不够。

4.4 EG两步法 vs Johansen检验:怎么选?

对比维度 Engle-Granger两步法 Johansen检验
适用场景 两个序列 两个及以上序列
协整关系个数 只能检验是否存在 可以检验个数
计算复杂度 低,两步搞定 高,基于VAR
样本量要求 至少200个点 至少300个点
对残差假设 残差需独立同分布 更宽松

你想想看,如果只是做两个品种的配对,EG两步法够用了。但如果你要做多品种组合,比如3个以上,那就得上Johansen。

4.5 实战中的避坑指南

我做了这么多年量化,协整检验踩过的坑不少。给你总结几个:

  • 数据频率要一致:别拿日线和小时线混着检验,结果会乱套。
  • 注意结构性断点:如果市场发生了重大变化(比如政策突变),协整关系可能断裂。我建议分段检验。
  • 不要过度优化:有些人为了得到协整关系,反复调参数。这是数据挖掘,实盘会亏死你。
  • 协整不等于因果关系:两个序列协整,不代表一个能预测另一个。只是说它们长期同步。
核心要点: 协整检验是配对交易的基石。EG两步法简单实用,Johansen检验更强大。实战中,我建议先用EG两步法快速筛选,再用Johansen做精细验证。

4.6 本章知识体系图

协整检验知识体系 协整检验 Engle-Granger两步法 第一步:OLS回归 第二步:ADF检验残差 Johansen检验 迹统计量 最大特征值统计量 实战:先EG快速筛选,再Johansen验证

这张图把本章的核心逻辑串起来了。左边是EG两步法,右边是Johansen检验,底部是实战建议。你保存下来,以后做协整检验时对照着看。

好了,协整检验就讲到这里。代码都给你了,回去跑一跑,看看你的品种有没有协整关系。记住,检验通过只是第一步,后面还有参数估计、交易策略设计等着你。


公众号:蓝海资料掘金营,微信deep3321