查看全集:💎Quantopia量化分析56讲
配对交易通过捕捉两个相关资产的价格偏差获利。如同用弹簧连接的两个小球:
协整关系可表示为:
Yt=α+βXt+ϵtY_t = \alpha + \beta X_t + \epsilon_tYt=α+βXt+ϵt
其中残差项ϵt\epsilon_tϵt满足:
ϵt=Yt−(α+βXt)\epsilon_t = Y_t - (\alpha + \beta X_t)ϵt=Yt−(α+βXt)
需通过ADF检验验证ϵt\epsilon_tϵt的平稳性(p<0.05)
# 传统静态对冲(2010年前主流)
beta = 固定值
# 滚动窗口对冲(2010-2015常用)
rolling_beta = 30日滚动回归系数
# 状态空间模型(现代方法)
from statsmodels.tsa.statespace.sarimax import SARIMAX
model = SARIMAX(Y, exog=X, order=(1,0,0)).fit()
import yfinance as yf
import pandas as pd
# 获取数据(以麦当劳与百胜集团为例)
symbols = ['MCD', 'YUM']
data = yf.download(symbols, start='2018-01-01', end='2023-12-31')['Close']
# 数据清洗
data = data.dropna()
log_prices = np.log(data) # 对数处理平稳化
# 可视化验证
data.plot(subplots=True, figsize=(12,6), title='Price Series')
from statsmodels.tsa.stattools import coint
def enhanced_coint_test(s1, s2):
# 执行三次检验防止假阳性
p1 = coint(s1, s2)[1]
p2 = coint(s2, s1)[1]
p3 = coint(s1.diff().dropna(), s2.diff().dropna())[1]
return max(p1, p2), min(p1, p2), p3
p_max, p_min, p_diff = enhanced_coint_test(log_prices['MCD'],
log_prices['YUM'])
print(f"最大协整p值: {p_max:.4f}, 差分序列p值: {p_diff:.4f}")
# 滚动120天计算对冲比率
rolling_period = 120
hedge_ratios = []
for i in range(rolling_period, len(log_prices)):
X = sm.add_constant(log_prices['MCD'].iloc[i-rolling_period:i])
model = sm.OLS(log_prices['YUM'].iloc[i-rolling_period:i], X).fit()
hedge_ratios.append(model.params['MCD'])
# 创建对冲比率序列
hedge_ratio_series = pd.Series(
index=log_prices.index[rolling_period:],
data=hedge_ratios
)
# 计算动态价差
spread = log_prices['YUM'] - hedge_ratio_series * log_prices['MCD']
# 自适应布林通道
def adaptive_bollinger(series, window=30):
ma = series.rolling(window).mean()
std = series.rolling(window).std()
upper = ma + std*(1 + 0.1*(window//30)) # 波动率放大
lower = ma - std*(1 + 0.1*(window//30))
return (series - ma)/std, upper, lower
zscore, upper, lower = adaptive_bollinger(spread.dropna())
# 信号规则
signals = pd.DataFrame(index=zscore.index)
signals['entry_short'] = zscore > 1.5
signals['entry_long'] = zscore < -1.5
signals['exit'] = abs(zscore) < 0.5
# 头寸管理
positions = pd.DataFrame(index=signals.index)
positions['MCD'] = 0
positions['YUM'] = 0
# 信号执行(考虑交易延迟)
positions.loc[signals['entry_short'], 'MCD'] = 1
positions.loc[signals['entry_short'], 'YUM'] = -1
positions.loc[signals['entry_long'], 'MCD'] = -1
positions.loc[signals['entry_long'], 'YUM'] = 1
positions = positions.shift(1) # 避免前瞻偏差
# 收益计算
returns = log_prices.pct_change().dropna()
strategy_returns = (positions['MCD'] * returns['MCD'] +
positions['YUM'] * returns['YUM'])
# 可视化
(1 + strategy_returns).cumprod().plot(title='Enhanced Strategy Performance')
# 断点检测(以2020年疫情为例)
from changepoint import Pelt
model = Pelt("rbf").fit(spread.values.reshape(-1,1))
change_points = model.predict(pen=10)
# 标记结构变化点
plt.plot(spread)
for cp in change_points:
plt.axvline(x=spread.index[cp], color='r', linestyle='--')
# 交易成本模型
def apply_transaction_cost(returns, positions, cost=0.0005):
trades = positions.diff().abs()
return returns - trades * cost
net_returns = apply_transaction_cost(strategy_returns, positions)
获取CVX(雪佛龙)和XOM(埃克森美孚)2015-2020年数据:
在原有策略中加入:
# 使用SPY判断市场趋势
spy = yf.download('SPY', start='2018-01-01')['Close']
market_up = spy.pct_change(30) > 0.03
# 只在市场震荡期交易
signals['valid'] = ~market_up
# 动态跟踪止损
max_drawdown = 0.05 # 5%最大回撤
peak = (1 + strategy_returns).cumprod().cummax()
drawdown = (peak - (1 + strategy_returns).cumprod())/peak
signals['stop_loss'] = drawdown > max_drawdown
# 波动率倒数加权
volatility = returns.rolling(30).std()
position_size = 1 / volatility
position_size = position_size.div(position_size.sum(axis=1), axis=0)
通过本案例,您可系统掌握配对交易的实现要点与优化方向。建议在QuantConnect平台进行实时市场验证,并参考《Pairs Trading: Quantitative Methods and Analysis》深化理论理解。