4、配对交易策略(Pairs Trading)
配对交易,说白了就是找两个「长得像」的资产,等它们价格跑偏了再出手。我刚开始做量化那会儿,觉得这玩意儿挺玄乎的——两个不同的股票,凭什么说它们会回归?后来踩过几次坑才明白,核心不在于它们长得像不像,而在于它们之间有没有稳定的数学关系。
配对交易的核心思想
配对交易的核心思想其实很简单:找一对相关性高的资产,做多弱的,做空强的。你想想看,如果两个资产长期走势高度一致,那它们之间的价差就应该在一个合理范围内波动。一旦价差跑出这个范围,就说明市场出现了暂时的定价错误——这时候就是我们的机会。
我记得2018年做过一个银行股的配对,招商银行和兴业银行。那段时间两者价差突然拉大,我按策略做多便宜的、做空贵的,结果一周内价差就回归了。嗯,那种感觉确实挺爽的。
如何选择配对
选配对是个技术活。我见过有人随便找两个同行业的股票就开干,结果亏得底裤都不剩。选配对,主要看两个指标:相关性和协整性。
相关性
相关性衡量的是两个资产价格变动的同步程度。取值范围在-1到1之间,越接近1说明同涨同跌越明显。但这里有个坑——相关性高不代表协整性高。
我曾经用两个科技股做过测试,相关系数高达0.95,结果一跑协整检验,P值0.3,根本不协整。为什么?因为相关性可能只是巧合,比如两者都受大盘影响,但本身没有稳定的长期关系。
| 相关系数范围 | 含义 |
|---|---|
| 0.8 - 1.0 | 强正相关 |
| 0.5 - 0.8 | 中等正相关 |
| 0.0 - 0.5 | 弱相关或无相关 |
协整性
协整性才是配对交易的灵魂。它检验的是两个时间序列之间是否存在长期稳定的线性关系。说白了,就是看它们的价差是否会在偏离后回归均值。
常用的检验方法是Engle-Granger两步法:
import statsmodels.api as sm
import numpy as np
# 假设price_a和price_b是两个资产的价格序列
# 第一步:回归
X = sm.add_constant(price_b)
model = sm.OLS(price_a, X).fit()
residuals = model.resid
# 第二步:对残差做单位根检验
from statsmodels.tsa.stattools import adfuller
result = adfuller(residuals)
print(f'ADF统计量: {result[0]:.4f}')
print(f'P值: {result[1]:.4f}')
# P值小于0.05,说明残差平稳,即存在协整关系
if result[1] < 0.05:
print('恭喜!这两个资产存在协整关系')
else:
print('不协整,换个配对试试吧')
价差序列的构建与标准化
找到协整对之后,下一步就是构建价差序列。价差说白了就是两个资产价格的线性组合。用回归得到的系数,我们可以算出:
# 构建价差序列
spread = price_a - model.params[0] - model.params[1] * price_b
# 或者直接用回归系数
hedge_ratio = model.params[1] # 对冲比率
spread = price_a - hedge_ratio * price_b
价差序列构建好之后,我们需要对它做标准化。为什么要标准化?因为不同时间段的价差波动幅度不一样,直接用原始价差没法设统一的阈值。
标准化的方法就是Z-score:
# 计算Z-score
mean_spread = spread.rolling(window=60).mean()
std_spread = spread.rolling(window=60).std()
z_score = (spread - mean_spread) / std_spread
Z-score告诉我们当前价差偏离均值多少个标准差。比如Z-score=2,说明当前价差比均值高了两个标准差,属于比较极端的情况。
交易信号的生成(Z-score阈值)
有了Z-score,交易信号就水到渠成了。我们设定两个阈值:开仓阈值和平仓阈值。
常见的做法是:
- 开仓信号: 当Z-score超过2或低于-2时,开仓
- 平仓信号: 当Z-score回归到0附近(比如±0.5)时,平仓
- 止损信号: 当Z-score超过3或低于-3时,止损
具体怎么操作?举个例子:
# 生成交易信号
def generate_signals(z_score, entry_threshold=2.0, exit_threshold=0.5):
signals = []
position = 0 # 0:空仓, 1:做多价差, -1:做空价差
for z in z_score:
if position == 0:
if z > entry_threshold:
position = -1 # 价差过高,做空价差(做空贵的,做多便宜的)
elif z < -entry_threshold:
position = 1 # 价差过低,做多价差(做多贵的,做空便宜的)
else:
if abs(z) < exit_threshold:
position = 0 # 价差回归,平仓
elif abs(z) > 3.0:
position = 0 # 极端情况,止损
signals.append(position)
return signals
这里要注意一个细节:开仓方向。当Z-score为正且很大时,说明价差偏高,意味着price_a相对price_b太贵了。这时候我们应该做空price_a、做多price_b,赌价差会缩小。反过来也一样。
知识体系总览
下面这张图是我自己整理的配对交易知识体系,你可以对照着看:
嗯,以上就是配对交易策略的核心内容。从选配对到构建价差,再到生成信号,每一步都有讲究。我个人觉得,配对交易最难的不是技术实现,而是找到真正协整的配对——这需要大量的数据挖掘和行业知识积累。
公众号:蓝海数据掘金营,微信deep3321