第一步:确定协整回归方程

好,咱们直接进入正题。Engle-Granger两步法,名字听着挺唬人,其实逻辑特别朴素。说白了就是:先猜两个品种之间有关系,然后验证这个关系是不是真的稳定。

第一步要做的,就是找到那个“关系”。

1.1 什么是协整回归方程?

协整回归方程,本质上就是一个线性回归模型。我拿螺纹钢和热卷举个例子:

热卷价格 = α + β × 螺纹钢价格 + ε

这里的α是截距项,β是协整系数,ε是残差。你想想看,如果这两个品种真的存在长期均衡关系,那么残差ε就应该是一个平稳序列——它会在0附近来回波动,不会越跑越远。

嗯,这里要注意:回归之前,得先确认两个序列都是同阶单整的。我见过不少新手上来就跑回归,结果两个序列一个I(1)一个I(2),那残差肯定不平稳,白费功夫。

1.2 用OLS估计协整系数

实际操作中,我们直接用最小二乘法(OLS)来估计β。Python里用statsmodels就能搞定:

import statsmodels.api as sm
import numpy as np

# 假设rb_price和hc_price已经是一阶差分平稳的序列
X = sm.add_constant(rb_price)  # 加截距项
model = sm.OLS(hc_price, X)
result = model.fit()

beta = result.params[1]  # 协整系数
alpha = result.params[0]  # 截距项
residuals = result.resid  # 残差序列

print(f"协整方程: 热卷 = {alpha:.4f} + {beta:.4f} × 螺纹钢")

我个人习惯在跑回归之前,先画个散点图看看。如果两个价格序列的走势明显背离,那协整关系大概率不成立。我在项目中遇到过这种情况:螺纹钢和热卷的价差突然拉大,回归出来的R²只有0.3,果断放弃这个组合。

避坑指南: 我曾经犯过一个错误——直接用原始价格做回归,没检查单整阶数。结果残差看起来挺平稳,但其实是伪回归。后来我养成了习惯:先做ADF检验,再决定要不要继续。

1.3 协整系数的经济含义

β的数值其实很有讲究。比如β=1.2,意味着螺纹钢涨1块钱,热卷平均涨1.2块钱。这个比例反映了两个品种之间的成本传导关系。

我一般会结合基本面来验证β的合理性。比如螺纹钢和热卷的生产成本差异,如果β偏离常识太多,那可能是数据有问题,或者样本期太短。

β值范围 经济含义 常见品种对
0.8 - 1.2 强替代/互补关系 螺纹钢-热卷
1.5 - 2.5 成本传导型关系 原油-沥青
< 0.5 或 > 3.0 弱协整或伪回归 谨慎对待

第二步:检验残差平稳性

方程建好了,残差算出来了。接下来就是关键一步:检验这个残差是不是平稳的。

为什么?因为如果残差不平稳,说明两个品种的价差会越走越远,套利策略根本没法做。你想想看,价差都不回归,你开仓了怎么平?

2.1 ADF检验的注意事项

检验残差平稳性,最常用的就是ADF检验。但这里有个坑:残差是从回归模型里估计出来的,不是原始数据。所以直接用标准的ADF临界值会偏保守。

我建议用MacKinnon(1991)的修正临界值表。不过在实际工作中,我一般直接用p值小于0.05作为判断标准,简单粗暴,效果也还行。

from statsmodels.tsa.stattools import adfuller

# 对残差做ADF检验
adf_result = adfuller(residuals, autolag='AIC')
adf_stat = adf_result[0]
p_value = adf_result[1]
critical_values = adf_result[4]

print(f"ADF统计量: {adf_stat:.4f}")
print(f"p值: {p_value:.4f}")
print(f"1%临界值: {critical_values['1%']:.4f}")
print(f"5%临界值: {critical_values['5%']:.4f}")

if p_value < 0.05:
    print("残差平稳,协整关系成立")
else:
    print("残差不平稳,协整关系不成立")
重要提醒: 如果p值刚好在0.05附近,别急着下结论。我建议多试几个滞后阶数,或者用KPSS检验交叉验证。我曾经就因为一个0.048的p值贸然开仓,结果回测表现很差。

2.2 残差平稳性的可视化判断

除了数值检验,我习惯画个残差时序图。如果残差看起来像白噪声——围绕0轴上下波动,没有明显趋势——那基本稳了。

import matplotlib.pyplot as plt

plt.figure(figsize=(12, 4))
plt.plot(residuals, label='残差序列', color='#2E86AB')
plt.axhline(y=0, color='red', linestyle='--', alpha=0.5)
plt.title('协整回归残差序列')
plt.xlabel('时间')
plt.ylabel('残差值')
plt.legend()
plt.show()

嗯,这里有个小技巧:如果残差图看起来有周期性波动,比如每20个交易日出现一个波峰,那可能是季节性因素没处理好。我建议加入滞后项或者差分项再试试。

2.3 协整关系的强度评估

通过了ADF检验,不代表协整关系就强。我一般还会看两个指标:

  • 半衰期(Half-life): 价差偏离后回归到均值所需时间的一半。半衰期越短,套利机会越多。
  • 回归R²: 虽然协整不要求高R²,但如果R²太低(比如小于0.3),说明两个品种的联动性很弱。

半衰期的计算其实很简单:

# 计算半衰期
import numpy as np

# 对残差做一阶自回归
lag_residuals = residuals.shift(1).dropna()
current_residuals = residuals[1:]
theta = np.polyfit(lag_residuals, current_residuals, 1)[0]

half_life = -np.log(2) / np.log(theta)
print(f"半衰期: {half_life:.2f} 个交易日")

我个人习惯:半衰期超过20个交易日的组合,基本就不碰了。等它回归黄花菜都凉了。

核心要点总结:
  • 第一步:用OLS估计协整方程,得到残差序列
  • 第二步:用ADF检验残差平稳性,p值<0.05为通过
  • 补充:用半衰期和R²评估协整关系的实用性

好了,Engle-Granger两步法的核心内容就这些。说白了就是:先找关系,再验证关系。听起来简单,但实际做起来坑不少。我建议你拿到数据后,先画图、再检验、最后建模,一步一步来,别跳步。

Engle-Granger两步法流程图 第一步:确定协整回归方程 OLS估计:热卷 = α + β × 螺纹钢 + ε 第二步:检验残差平稳性 ADF检验:p值 < 0.05 为通过 检查单整阶数 OLS回归估计 ADF检验 半衰期评估 通过? ✅ 协整关系成立 可进行套利策略设计 ❌ 协整关系不成立 重新选择品种对 注:半衰期 < 20 个交易日为实用标准

最后说一句:Engle-Granger两步法虽然经典,但它有个缺点——只能处理一对品种。如果你想做多品种组合的协整分析,那得用Johansen检验。不过那是后面章节的内容了。

今天就到这儿。代码可以直接复制到你的Jupyter Notebook里跑,数据换成你自己的品种就行。

专注资料整理