4. 协整模型构建:Engle-Granger两步法、Johansen检验、误差修正模型

协整,说白了就是两个或多个不平稳的时间序列,它们的线性组合却变得平稳了。这在套利里意味着什么?意味着价差会围绕一个均值来回摆动——高了就跌回去,低了就涨回来。这就是我们做配对交易的数学基础。

我个人习惯把协整比作「拴在一根绳上的蚂蚱」。两个资产各自乱跑,但彼此之间总有个约束。一旦跑远了,绳子就会把它们拉回来。嗯,这个「拉回来」的力度,就是我们套利的利润来源。

4.1 为什么需要协整?

先问个问题:两个股票的价格都在随机游走,你能直接拿它们的价差做交易吗?

答案是不能。因为两个独立的随机游走,价差也是随机游走。你看到的「均值回归」很可能是幻觉。我在项目中遇到过这种情况——回测时曲线漂亮得不行,实盘一跑就崩了。后来才发现,那只是两个随机序列偶然的「假回归」。

协整检验就是帮我们识别:这个价差是真的会回归,还是只是随机游走的假象。

4.2 Engle-Granger两步法

这个方法很直观,我最早做套利时用的就是它。说白了就两步:

  1. 第一步:做回归——把两个价格序列跑一个OLS回归,得到协整系数
  2. 第二步:检验残差——对回归的残差做单位根检验(ADF检验),看它是否平稳

如果残差是平稳的,就说明两个序列存在协整关系。

核心逻辑:协整关系 = 长期均衡关系。回归得到的系数就是「对冲比率」,残差就是「价差」。

代码实现其实很简单:

import statsmodels.api as sm
import numpy as np

# 假设 y 和 x 是两个价格序列
def engle_granger(y, x):
    # 第一步:OLS回归
    x_with_const = sm.add_constant(x)
    model = sm.OLS(y, x_with_const).fit()
    hedge_ratio = model.params[1]  # 协整系数
    spread = model.resid           # 价差
    
    # 第二步:对残差做ADF检验
    adf_result = sm.tsa.stattools.adfuller(spread, maxlag=1)
    p_value = adf_result[1]
    
    return hedge_ratio, spread, p_value

# 使用示例
# hedge_ratio, spread, p_value = engle_granger(price_a, price_b)
# if p_value < 0.05:
#     print("存在协整关系,可以做配对交易")

避坑指南:我曾经犯过一个错误——直接用价格做回归,没考虑滞后阶数。结果ADF检验的p值总是偏小,导致很多假阳性。后来我习惯在ADF检验里加上合适的滞后阶数(比如用AIC准则选择),效果就好多了。

不过Engle-Granger有个明显的缺点:它只能处理两个变量之间的协整关系。而且第一步回归时,选择哪个变量作为因变量会影响结果。你想想看,如果我把y和x互换,得到的协整系数可能不一样。这就有点尴尬了。

4.3 Johansen检验

Johansen检验解决了上面那个问题。它可以同时检验多个变量之间的协整关系,而且不依赖变量的顺序。

我个人觉得Johansen检验更像一个「系统级」的方法。它不先做回归,而是直接看整个系统的特征根。如果特征根显著不为零,就说明存在协整关系。

它的核心思想是这样的:

  • 把多个价格序列放在一起,构成一个向量自回归模型(VAR)
  • 然后看这个VAR模型的系数矩阵的秩
  • 秩为r,就说明存在r个独立的协整关系

代码实现:

from statsmodels.tsa.vector_ar.vecm import coint_johansen

def johansen_test(data, det_order=0, k_ar_diff=1):
    """
    data: 多列价格序列,每列一个资产
    det_order: 确定性趋势的阶数(0=无趋势,1=有常数项)
    k_ar_diff: 差分后的滞后阶数
    """
    result = coint_johansen(data, det_order, k_ar_diff)
    
    # 迹统计量检验
    trace_stat = result.lr1
    trace_crit = result.cvt[:, 1]  # 5%显著性水平
    
    # 最大特征值检验
    max_eigen_stat = result.lr2
    max_eigen_crit = result.cvm[:, 1]
    
    # 协整向量(即对冲比率)
    coint_vectors = result.evec
    
    return trace_stat, trace_crit, max_eigen_stat, max_eigen_crit, coint_vectors

# 使用示例
# data = np.column_stack([price_a, price_b, price_c])
# trace_stat, trace_crit, _, _, vectors = johansen_test(data)
# print(f"迹统计量: {trace_stat}, 临界值: {trace_crit}")

注意:Johansen检验对滞后阶数的选择很敏感。我建议用AIC或BIC准则来选择最优滞后阶数,而不是随便设一个。另外,样本量太小(比如少于100个交易日)时,检验结果不太可靠。

Johansen检验还有一个好处:它直接给出了所有可能的协整向量。比如三个资产之间可能存在两个协整关系,它都能找出来。这在构建多资产套利组合时特别有用。

4.4 误差修正模型(ECM)

好,现在我们已经找到了协整关系。但还有一个问题:当价差偏离均值时,它具体是怎么回归的?回归的速度有多快?

这就是误差修正模型要回答的。ECM把价格的变化分解成两部分:

  • 短期波动:由过去的价格变化驱动
  • 长期修正:由当前价差偏离均衡的程度驱动

说白了就是:如果价差偏离了均衡,下一期价格就会往均衡方向「拉」一下。这个「拉」的力度,就是误差修正项系数。

数学形式是这样的:

Δy_t = α * (y_{t-1} - β * x_{t-1}) + γ * Δx_t + ε_t

其中:
- Δy_t 是 y 在 t 时刻的变化量
- (y_{t-1} - β * x_{t-1}) 是上一期的价差(误差修正项)
- α 是修正速度(负值表示回归)
- γ 是短期影响系数

代码实现:

import pandas as pd
import statsmodels.api as sm

def estimate_ecm(y, x, hedge_ratio):
    """
    y, x: 原始价格序列
    hedge_ratio: 协整系数(来自EG或Johansen)
    """
    # 计算价差(误差修正项)
    spread = y - hedge_ratio * x
    
    # 计算差分
    dy = y.diff().dropna()
    dx = x.diff().dropna()
    spread_lag = spread.shift(1).dropna()
    
    # 对齐数据
    data = pd.concat([dy, dx, spread_lag], axis=1).dropna()
    data.columns = ['dy', 'dx', 'spread_lag']
    
    # 回归:Δy = α * spread_lag + γ * Δx + ε
    X = data[['spread_lag', 'dx']]
    X = sm.add_constant(X)
    y_var = data['dy']
    
    model = sm.OLS(y_var, X).fit()
    
    alpha = model.params['spread_lag']  # 修正速度
    gamma = model.params['dx']          # 短期影响
    
    return alpha, gamma, model

# 使用示例
# alpha, gamma, model = estimate_ecm(price_a, price_b, 1.5)
# print(f"修正速度: {alpha:.4f}")  # 应该为负值

关键解读

  • α 为负值且显著 → 存在均值回归,可以做套利
  • α 的绝对值越大 → 回归速度越快,套利机会窗口越短
  • α 不显著 → 即使协整检验通过了,回归速度也可能很慢,不适合短线套利

我在项目中遇到过这样的情况:协整检验通过了,但ECM的α系数只有-0.01。这意味着价差偏离后,每天只回归1%。如果价差偏离了2个标准差,需要200天才能完全回归——这种套利基本没法做,资金成本都覆盖不了。

4.5 三者的关系

我把这三者的关系总结一下:

方法 解决的问题 适用场景 输出
Engle-Granger 两个资产是否存在协整 简单配对交易 协整系数、价差
Johansen 多个资产是否存在协整 多资产套利组合 协整向量个数、具体向量
误差修正模型 价差如何回归均衡 交易策略参数设定 修正速度、短期影响

我个人习惯的流程是:先用Johansen检验看整体协整关系,再用EG方法快速验证,最后用ECM确定交易参数。三个方法配合使用,比单独用任何一个都靠谱。

一个小技巧:在做协整检验之前,先确认每个序列都是I(1)的(即一阶差分后平稳)。如果序列是I(2)的,协整检验的结果可能不可靠。我一般先用ADF检验确认每个序列的平稳性,再开始协整分析。

最后说一句:协整模型不是万能的。它假设价差围绕一个固定的均值波动,但现实中这个均值可能会漂移。所以每隔一段时间(比如每3个月)重新估计一次协整关系,是个好习惯。

协整模型构建流程 第一步:数据准备 确认序列为I(1)过程 第二步:协整检验 EG两步法 / Johansen检验 第三步:ECM建模 估计修正速度α Engle-Granger两步法 • 适用:两个资产 • 输出:协整系数 + 价差 • 局限:变量顺序影响结果 Johansen检验 • 适用:多个资产 • 输出:协整向量个数 + 具体向量 • 优势:不依赖变量顺序 输出:套利组合参数 对冲比率 + 价差序列 + 回归速度

专注资料整理