4. 价差计算与统计:价差序列计算、均值回归检验、协整检验、半衰期计算、布林带与Z-score
各位同学,欢迎来到跨交易所套利策略的核心环节。前面我们聊了数据清洗和同步,那都是准备工作。真正的硬菜,从价差计算开始。
说白了,套利交易赚的就是价差回归的钱。你想想看,同一个东西在两个地方卖不同价,你低价买、高价卖,差价就是利润。但问题来了——这个价差是随机的,还是有规律的?它会不会越走越远,让你爆仓?
嗯,这就是本章要解决的核心问题。我会带你一步步走完价差计算的完整流程,包括统计检验、参数估计,以及最终如何用布林带和Z-score来生成交易信号。
核心逻辑一句话:找到一对价格走势高度相关的品种,计算它们的价差,验证这个价差是否具有均值回归特性,然后利用统计工具捕捉回归机会。
4.1 价差序列计算
价差计算听起来简单,就是A价格减B价格嘛。但实际项目中,我踩过不少坑。
最常见的价差形式有三种:
- 简单价差:P₁ - P₂。适用于价格水平相近的品种,比如同一只股票在不同交易所的现货价格。
- 对数价差:ln(P₁) - ln(P₂)。适用于价格差异较大的品种,对数变换能让序列更平稳。我个人习惯用这个,尤其是在做加密货币套利时。
- 比率价差:P₁ / P₂。适用于价格存在倍数关系的品种,比如股指期货和ETF之间。
这里有个关键点——协整系数。如果两个品种的价格不是1:1的关系,比如螺纹钢和热卷,它们的价差公式应该是 P₁ - β × P₂。这个β怎么算?用最小二乘法(OLS)回归。
import numpy as np
import pandas as pd
import statsmodels.api as sm
# 假设df包含两列:'asset_a' 和 'asset_b'
def calc_spread(df, method='simple'):
if method == 'simple':
spread = df['asset_a'] - df['asset_b']
beta = 1.0
elif method == 'log':
spread = np.log(df['asset_a']) - np.log(df['asset_b'])
beta = 1.0
elif method == 'regression':
# OLS回归求协整系数
X = sm.add_constant(df['asset_b'])
model = sm.OLS(df['asset_a'], X).fit()
beta = model.params['asset_b']
spread = df['asset_a'] - beta * df['asset_b']
return spread, beta
避坑指南:我曾经在计算股指期货价差时,直接用简单价差,结果发现价差序列一直在漂移。后来才发现,两个合约的乘数不同,必须用回归系数调整。从那以后,我养成了先做回归再算价差的习惯。
4.2 均值回归检验
价差算出来了,然后呢?你得先确认它是不是会回归。如果价差是个随机游走,那做套利就是送钱给市场。
均值回归检验,说白了就是看价差序列是否平稳。平稳的序列会围绕一个均值上下波动,不会越走越远。
我常用的方法有两个:
- ADF检验(Augmented Dickey-Fuller Test):最经典的单位根检验。p值小于0.05,说明序列平稳,存在均值回归特性。
- PP检验(Phillips-Perron Test):对序列自相关和异方差更稳健。我一般两个都跑,取交集。
from statsmodels.tsa.stattools import adfuller, coint
def check_mean_reversion(spread):
# ADF检验
adf_result = adfuller(spread, autolag='AIC')
adf_stat = adf_result[0]
adf_pvalue = adf_result[1]
# 判断是否平稳
is_stationary = adf_pvalue < 0.05
return {
'adf_statistic': adf_stat,
'adf_pvalue': adf_pvalue,
'is_stationary': is_stationary
}
注意:ADF检验的滞后阶数选择很关键。选少了,自相关没消除;选多了,检验功效下降。我建议用AIC准则自动选择,或者根据数据频率固定一个值——日线数据用5阶,小时线用12阶。
4.3 协整检验
均值回归检验是针对价差本身的。但有时候,两个品种单独看都不平稳,它们的线性组合却可能是平稳的。这就是协整。
协整检验,说白了就是验证两个非平稳序列之间是否存在长期均衡关系。如果存在,那价差就会围绕均衡值波动,套利就有基础。
最常用的方法是Engle-Granger两步法:
- 第一步:用OLS回归估计协整系数β
- 第二步:对残差(也就是价差)做ADF检验
不过,statsmodels直接提供了协整检验函数,一步到位:
def check_cointegration(price_a, price_b):
# 协整检验
coint_result = coint(price_a, price_b)
coint_t = coint_result[0]
coint_pvalue = coint_result[1]
crit_values = coint_result[2]
is_cointegrated = coint_pvalue < 0.05
return {
'coint_statistic': coint_t,
'coint_pvalue': coint_pvalue,
'critical_values': crit_values,
'is_cointegrated': is_cointegrated
}
个人经验:我在做商品期货套利时,发现豆粕和菜粕的协整关系非常稳定,p值经常在0.001以下。但换了样本区间后,协整关系可能消失。所以,我建议用滚动窗口做协整检验,比如每60个交易日重新检验一次,确保关系没有断裂。
4.4 半衰期计算
半衰期,这个概念来自物理,但在量化里指的是价差偏离均值后,回归到均值一半所需的时间。说白了,就是告诉你——这个套利机会要等多久才能赚钱。
半衰期越短,套利频率越高,资金利用率越好。半衰期太长,你可能等不起,或者中间被波动震出局。
计算半衰期的方法基于均值回归过程:
- 对价差序列做一阶自回归:ΔSₜ = α + θ × Sₜ₋₁ + εₜ
- 半衰期 = ln(2) / |θ|
def calc_half_life(spread):
# 构建滞后序列
spread_lag = spread.shift(1).dropna()
spread_diff = spread.diff().dropna()
# 对齐数据
y = spread_diff.values
x = spread_lag.values
# OLS回归
x = sm.add_constant(x)
model = sm.OLS(y, x).fit()
theta = model.params[1]
# 计算半衰期
half_life = -np.log(2) / theta if theta < 0 else np.inf
return half_life
经验阈值:我个人认为,半衰期在5-20个周期(日线就是5-20天)是最理想的。太短了,交易成本占比高;太长了,资金占用成本高。如果半衰期超过60个周期,我建议放弃这对品种。
4.5 布林带与Z-score
好了,前面做了那么多检验,终于到了实战环节——生成交易信号。
布林带和Z-score,本质上都是标准化价差,告诉你当前价差处于什么位置。
布林带:以移动平均线为中心,上下各加减k倍标准差。当价差触及上轨时做空价差,触及下轨时做多价差。
Z-score:直接计算当前价差偏离均值多少个标准差。公式很简单:Z = (当前价差 - 均值) / 标准差。
我个人更偏爱Z-score,因为它更直观,而且可以灵活设置阈值。比如Z-score超过2就开仓,回到0就平仓。
def calc_bollinger_zscore(spread, window=20, num_std=2):
# 计算移动均值和标准差
rolling_mean = spread.rolling(window=window).mean()
rolling_std = spread.rolling(window=window).std()
# 布林带
upper_band = rolling_mean + num_std * rolling_std
lower_band = rolling_mean - num_std * rolling_std
# Z-score
zscore = (spread - rolling_mean) / rolling_std
return {
'upper_band': upper_band,
'lower_band': lower_band,
'zscore': zscore,
'rolling_mean': rolling_mean
}
注意:布林带的窗口长度和标准差倍数需要根据品种特性调整。我见过有人直接用20天2倍标准差,结果在波动率突变时频繁止损。我的做法是:先用半衰期作为窗口长度,再用历史回测优化标准差倍数。
4.6 知识体系总览
为了让你更直观地理解本章的知识结构,我画了一张流程图:
这张图把整个流程串起来了。从价格输入开始,经过价差计算、统计检验、参数估计,最后到信号生成。每一步都有对应的Python代码实现,你可以直接拿去用。
嗯,本章的内容就到这里。记住,价差计算只是工具,真正的核心是理解背后的统计逻辑。只有通过了均值回归检验和协整检验,你的套利策略才有理论支撑。否则,再漂亮的布林带也只是花架子。
最后一句:我在实战中见过太多人跳过检验直接上策略,结果亏得血本无归。别急,慢就是快。把检验做扎实了,后面的路就好走了。