6. 协整关系检验:Engle-Granger两步法、Johansen检验,判断期货与现货的长期均衡
好,咱们接着聊。前面我们找到了价差,也做了平稳性检验。但有个问题——如果两个价格序列本身是非平稳的,但它们的线性组合却是平稳的,这该怎么处理?
这就是协整关系要解决的问题。说白了,协整就是两个“疯跑”的序列,它们之间有一条看不见的绳子牵着。期货和现货,就是典型的例子。
6.1 为什么需要协整检验?
我个人习惯,在开始任何配对交易之前,先问自己一个问题:这两个品种真的会“回归”吗?
如果只是单纯看相关性,很容易掉坑里。我记得有一次,我拿螺纹钢期货和热卷期货做分析,相关系数高达0.95。但一跑协整检验,发现根本不协整。后来行情一波动,价差越拉越大,亏得我直拍大腿。
所以,协整检验的核心目的就一个:验证期货和现货之间是否存在长期均衡关系。如果存在,价差就会围绕均值来回摆动,我们就能在偏离时入场,回归时离场。
核心观点: 相关性高 ≠ 协整。协整才是套利交易的真正基石。
6.2 Engle-Granger两步法
这个方法很直观,我最早做量化时用的就是它。说白了,就两步。
第一步:建立回归方程
把现货价格(S)对期货价格(F)做回归:
S_t = α + β * F_t + ε_t
这里的β就是套保比率,ε_t就是残差,也就是我们常说的“价差”。
嗯,这里要注意:回归时一定要用普通最小二乘法(OLS)。我见过有人用带趋势项的回归,结果把协整关系都搞没了。
第二步:检验残差的平稳性
对残差序列ε_t做ADF检验。如果残差是平稳的,就说明S和F存在协整关系。
from statsmodels.tsa.stattools import adfuller
import numpy as np
import statsmodels.api as sm
# 假设我们有期货价格futures和现货价格spot
# 第一步:OLS回归
futures_with_const = sm.add_constant(futures)
model = sm.OLS(spot, futures_with_const).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('残差不平稳,不存在协整关系')
避坑指南: 我曾经犯过一个低级错误——直接用原始价格做回归,没检查数据对齐。结果期货和现货的交易日不一致,残差里全是噪声。记住,数据对齐是第一步。
6.3 Johansen检验
Engle-Granger两步法虽然简单,但有个硬伤——它只能处理一对变量。如果你手里有多个品种,比如同时看螺纹钢、热卷、铁矿石,那就得用Johansen检验了。
Johansen检验的核心思想,是通过向量自回归(VAR)模型,检验多个时间序列之间是否存在共同的随机趋势。说白了,就是看它们是不是被同一根绳子牵着。
6.3.1 检验原理
Johansen检验有两种统计量:
- 迹统计量(Trace Statistic):检验协整秩(即协整关系的个数)是否小于等于r
- 最大特征值统计量(Max Eigenvalue Statistic):检验协整秩是否等于r
我个人习惯,两个统计量都看。如果它们结论一致,那基本就稳了。如果矛盾,我会倾向于相信迹统计量,因为它对样本量更鲁棒。
6.3.2 Python实现
from statsmodels.tsa.vector_ar.vecm import coint_johansen
# 假设我们有多个价格序列,存在data DataFrame中
# data的每一列是一个品种的价格
def johansen_test(data, det_order=0, k_ar_diff=1):
"""
det_order: 确定性趋势的阶数
-1: 无确定性趋势
0: 常数项
1: 线性趋势
k_ar_diff: VAR模型的滞后阶数(差分形式)
"""
result = coint_johansen(data, det_order, k_ar_diff)
print('迹统计量:')
print(result.lr1)
print('迹统计量临界值(90%, 95%, 99%):')
print(result.cvt)
print('\n最大特征值统计量:')
print(result.lr2)
print('最大特征值临界值(90%, 95%, 99%):')
print(result.cvm)
# 判断协整秩
r = 0
for i in range(len(result.lr1)):
if result.lr1[i] > result.cvt[i, 1]: # 使用95%置信水平
r += 1
else:
break
print(f'\n协整秩(协整关系个数): {r}')
return r
# 使用示例
# johansen_test(data[['futures', 'spot', 'another_asset']])
重要提醒: Johansen检验对滞后阶数非常敏感。我建议用AIC或BIC准则来选择最优滞后阶数,别拍脑袋定。另外,样本量最好在100以上,否则检验功效会大打折扣。
6.4 两种方法的对比与选择
| 对比维度 | Engle-Granger两步法 | Johansen检验 |
|---|---|---|
| 适用场景 | 两个品种(如期货vs现货) | 多个品种(如期货、现货、相关商品) |
| 计算复杂度 | 低,两步搞定 | 高,需要估计VAR模型 |
| 对样本量的要求 | 较低,30个样本以上即可 | 较高,建议100个样本以上 |
| 能否处理多个协整关系 | 不能 | 能,给出协整秩 |
| 对变量顺序的敏感性 | 敏感(谁做因变量有影响) | 不敏感 |
你想想看,如果你只是做最简单的期现套利,Engle-Granger完全够用。但如果你要做多品种的统计套利,比如同时交易螺纹钢、热卷、铁矿石,那Johansen就是必须的了。
6.5 实战中的注意事项
嗯,这里有几个坑,我替你们踩过了:
- 数据频率要一致:别拿日线期货和分钟线现货做协整,那是在自欺欺人。
- 注意结构性突变:2015年股灾、2020年疫情,这些事件会打破原有的协整关系。我建议用滚动窗口重新检验。
- 协整不等于因果关系:两个品种协整,不代表一个能预测另一个。它只说明它们有共同的长期趋势。
- 别忘了经济含义:如果两个品种理论上就不该有关系,那协整检验结果再漂亮也别信。我见过有人把比特币和猪肉价格做协整,结果还通过了检验——纯属数据挖掘。
我的经验: 在实际项目中,我会先用Engle-Granger快速筛选候选对,再用Johansen做精细化分析。这样既快又准。
6.6 本章知识体系
下面这张图,是我自己总结的协整检验全流程。每次做新策略前,我都会过一遍:
这张图把整个流程串起来了。从数据准备开始,到平稳性检验,再到方法选择,最后到结果判断。每一步都不能跳过。
好了,协整检验就讲到这里。记住一句话:没有协整,就没有套利。这是整个基差交易模型的根基。