第二章:价差分析工具——从数据到信号的完整链路
做跨期套利,核心就一句话:找到价差的规律,然后利用它赚钱。
但价差不是凭空产生的。你得先把它算出来,然后分析它的脾气——均值多少、波动多大、有没有自相关性、是不是平稳的。这一套下来,你才能判断:这个价差能不能用来做策略?
我个人习惯把这套流程叫做「价差分析四步走」。今天咱们就一步步拆开来看。
2.1 价差序列的构建
说白了,价差就是两个合约价格之间的差值。但怎么算,有讲究。
最常见的构建方式:
- 简单价差:
spread = P_near - P_far(近月减远月) - 对数价差:
spread = ln(P_near) - ln(P_far)(适合价格波动剧烈时) - 标准化价差:
spread = (P_near - P_far) / P_far(消除绝对价格影响)
我在项目中遇到过一个问题:用简单价差做螺纹钢的跨期套利,结果发现价差序列随着价格整体上涨而不断变大,策略频繁开仓。后来换成对数价差,这个问题就解决了。你想想看,对数价差天然消除了价格水平的影响,更适合做均值回归分析。
核心原则:价差构建方式取决于品种特性。股指期货用简单价差就够,商品期货建议用对数价差。
import numpy as np
import pandas as pd
# 构建价差序列
def build_spread(near_price, far_price, method='log'):
if method == 'simple':
spread = near_price - far_price
elif method == 'log':
spread = np.log(near_price) - np.log(far_price)
elif method == 'normalized':
spread = (near_price - far_price) / far_price
else:
raise ValueError("method must be 'simple', 'log', or 'normalized'")
return spread
# 示例:螺纹钢近月与远月数据
near = pd.Series([3800, 3810, 3795, 3820, 3835])
far = pd.Series([3750, 3760, 3745, 3770, 3785])
spread_log = build_spread(near, far, method='log')
print(spread_log)
2.2 价差的统计特征
价差序列建好了,接下来就是「摸清它的底细」。我一般会看三个指标:均值、方差、自相关。
2.2.1 均值与方差
均值告诉你价差的中枢在哪里。方差告诉你价差波动的幅度有多大。
嗯,这里要注意:均值是会漂移的。我记得有一次做豆粕的跨期套利,用了过去半年的均值作为开仓依据,结果市场结构变了,均值从50块漂到了80块,策略直接亏了一周。后来我改用滚动窗口计算均值,才稳住。
# 计算滚动均值与标准差
window = 20
rolling_mean = spread.rolling(window=window).mean()
rolling_std = spread.rolling(window=window).std()
# 开仓信号:价差偏离均值2个标准差
z_score = (spread - rolling_mean) / rolling_std
signal = (z_score.abs() > 2).astype(int)
2.2.2 自相关
自相关衡量的是「今天的价差和昨天的价差有没有关系」。如果自相关系数很高,说明价差有趋势性,不适合做均值回归策略。
我曾经踩过一个坑:用铁矿石的价差做策略,自相关检验显示0.8,我心想「没关系,先跑跑看」。结果回测曲线一路向下,根本没法回归。后来才明白,自相关高的序列,你开仓后它还会继续往那个方向走,止损都来不及。
避坑指南:自相关系数超过0.5的价差序列,不建议直接用均值回归策略。可以考虑先做差分,或者改用趋势跟踪策略。
from statsmodels.tsa.stattools import acf
# 计算自相关系数
lag = 10
acf_values = acf(spread.dropna(), nlags=lag)
print(f"滞后1期自相关: {acf_values[1]:.3f}")
print(f"滞后5期自相关: {acf_values[5]:.3f}")
2.3 价差平稳性检验(ADF检验)
这是整个分析中最关键的一步。为什么?因为只有平稳的价差序列,才能用均值回归策略去套利。
平稳性说白了就是:价差的均值、方差不会随着时间发生系统性变化。如果价差不平稳,你设定的开仓阈值今天有效,明天可能就失效了。
ADF检验的判断逻辑:
- 原假设H0:序列存在单位根(不平稳)
- 备择假设H1:序列平稳
- p值 < 0.05 → 拒绝H0 → 序列平稳
我个人经验:ADF检验的p值最好小于0.01才放心用。0.05的边缘情况,我建议你再做一次KPSS检验交叉验证。
from statsmodels.tsa.stattools import adfuller
def adf_test(series, name=''):
result = adfuller(series.dropna(), autolag='AIC')
print(f"{name} ADF检验结果:")
print(f" ADF统计量: {result[0]:.4f}")
print(f" p值: {result[1]:.4f}")
print(f" 临界值(1%): {result[4]['1%']:.4f}")
print(f" 临界值(5%): {result[4]['5%']:.4f}")
if result[1] < 0.05:
print(" → 结论:序列平稳,适合均值回归策略")
else:
print(" → 结论:序列不平稳,需要进一步处理")
return result
# 测试价差序列
adf_test(spread_log, name='螺纹钢价差')
2.4 协整关系检验
有时候单个价差不平稳,但两个合约价格之间存在长期均衡关系——这就是协整。
协整检验回答的问题是:近月合约和远月合约的价格,是不是「手拉手」一起走的?如果是,那么即使价差暂时偏离,最终也会回归。
常用的协整检验方法:
- Engle-Granger两步法:先回归,再检验残差平稳性
- Johansen检验:可以检验多个协整关系
我记得有一次做原油的跨期套利,ADF检验显示价差不平稳,但协整检验通过。这说明近月和远月虽然各自在波动,但它们之间的差距是「有边界」的。这种情况下,用价差的Z-score做开仓信号,效果反而比直接用价差更好。
from statsmodels.tsa.stattools import coint
# Engle-Granger协整检验
def cointegration_test(y1, y2):
score, pvalue, _ = coint(y1, y2)
print(f"协整检验p值: {pvalue:.4f}")
if pvalue < 0.05:
print("→ 存在协整关系,可以构建配对交易策略")
else:
print("→ 不存在协整关系,不建议做配对交易")
return pvalue
# 示例:近月与远月价格
cointegration_test(near, far)
2.5 知识体系总览
下面这张图,是我自己画的一个价差分析流程。每次做新品种之前,我都会按这个流程走一遍,确保没有遗漏。
我的小建议:刚开始做价差分析时,别急着上复杂模型。先把ADF检验和自相关这两个指标吃透,能解决80%的问题。协整检验是锦上添花,不是雪中送炭。
好了,价差分析工具的核心内容就这些。下一章我们会把这些工具串起来,构建一个完整的跨期套利策略框架。到时候你会看到,这些看似零散的分析步骤,是如何变成一套可执行的交易系统的。
公众号:蓝海资料掘金营,微信deep3321