第一步:确定协整回归方程
好,咱们直接进入正题。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,果断放弃这个组合。
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("残差不平稳,协整关系不成立")
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两步法虽然经典,但它有个缺点——只能处理一对品种。如果你想做多品种组合的协整分析,那得用Johansen检验。不过那是后面章节的内容了。
今天就到这儿。代码可以直接复制到你的Jupyter Notebook里跑,数据换成你自己的品种就行。