查看全集:💎Quantopia量化分析56讲
数据准备与工具:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import yfinance as yf
from sklearn.covariance import LedoitWolf
import seaborn as sns
import statsmodels.api as sm
# 数据获取函数
def get_stock_data(tickers, start, end):
data = yf.download(tickers, start=start, end=end)
return data['Close'] # 仅使用收盘价
在构建交易策略时,系统性风险是需要重点管理的对象。这类风险无法通过分散投资消除,需要通过构建对冲来降低影响。本文将通过三个逐步优化的案例,展示如何通过Beta对冲和行业对冲来降低资产间的相关性,提升策略的有效性。
关键概念:
tickers = ['WFC', 'JPM', 'USB', 'XOM', 'BHI', 'SLB']
start = '2015-01-01'
end = '2017-02-22'
# 获取数据
prices = get_stock_data(tickers, start, end)
returns = prices.pct_change().dropna()
# 计算协方差矩阵
lw = LedoitWolf().fit(returns)
cov_matrix = lw.covariance_
# 转换为相关系数
def cov_to_corr(cov):
d = np.sqrt(np.diag(cov))
return cov / np.outer(d, d)
corr_matrix = cov_to_corr(cov_matrix)
# 可视化
plt.figure(figsize=(12,6))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm',
xticklabels=tickers, yticklabels=tickers)
plt.title('无对冲策略相关系数矩阵(平均相关系数:0.56)')
现象观察:金融股(WFC、JPM、USB)与能源股(XOM、BHI、SLB)形成明显聚类,组内相关性高达0.7-0.8
tickers += ['SPY']
prices = get_stock_data(tickers, start, end)
returns = prices.pct_change().dropna()
# 分离市场收益
market_returns = returns['SPY']
stock_returns = returns.drop('SPY', axis=1)
# 计算市场Beta残差
residuals = pd.DataFrame()
for stock in stock_returns:
model = sm.OLS(stock_returns[stock], sm.add_constant(market_returns))
results = model.fit()
residuals[stock] = results.resid
# 计算对冲后相关系数
lw = LedoitWolf().fit(residuals)
corr_matrix_beta = cov_to_corr(lw.covariance_)
# 可视化对比
fig, axes = plt.subplots(1,2, figsize=(16,6))
sns.heatmap(corr_matrix, ax=axes[0], cmap='coolwarm',
annot=True, vmin=-1, vmax=1)
sns.heatmap(corr_matrix_beta, ax=axes[1], cmap='coolwarm',
annot=True, vmin=-1, vmax=1)
关键改进:
sector_etf = {'金融': 'XLF', '能源': 'XLE'}
tickers = ['WFC', 'JPM', 'USB', 'XOM', 'BHI', 'SLB', 'SPY', 'XLF', 'XLE']
prices = get_stock_data(tickers, start, end)
returns = prices.pct_change().dropna()
# 市场对冲
market_ret = returns['SPY']
sector_rets = {
'金融': returns['XLF'] - market_ret * sm.OLS(returns['XLF'], sm.add_constant(market_ret)).fit().params[1],
'能源': returns['XLE'] - market_ret * sm.OLS(returns['XLE'], sm.add_constant(market_ret)).fit().params[1]
}
# 分行业二次对冲
final_residuals = pd.DataFrame()
for sector in ['金融', '能源']:
sector_stocks = ['WFC','JPM','USB'] if sector == '金融' else ['XOM','BHI','SLB']
sector_ret = sector_rets[sector]
for stock in sector_stocks:
# 市场对冲
model_mkt = sm.OLS(returns[stock], sm.add_constant(market_ret))
res_mkt = model_mkt.fit().resid
# 行业对冲
model_sector = sm.OLS(res_mkt, sm.add_constant(sector_ret))
final_residuals[stock] = model_sector.fit().resid
# 计算最终相关系数
lw = LedoitWolf().fit(final_residuals)
corr_matrix_full_hedge = cov_to_corr(lw.covariance_)
效果呈现:
Buckle公式
其中N为资产数量,ρ为平均相关系数
def effective_breadth(N, rho):
return N / (1 + rho*(N-1))
cases = [
('无对冲', 0.56),
('Beta对冲', 0.22),
('行业对冲', 0.028)
]
plt.figure(figsize=(10,6))
x = np.linspace(0, 1, 100)
for label, rho in cases:
plt.plot(x, effective_breadth(6, x),
label=f'{label} (实际ρ={rho})' if label else None)
plt.legend()
plt.title('不同对冲策略的有效广度对比')
plt.xlabel('平均相关系数ρ')
plt.ylabel('有效广度BR');
结论:
# 练习参考答案
# 1. 更换行业ETF代码为XLK(科技)和XLV(医疗)
# 2. 验证函数:
assert np.isclose(effective_breadth(10, 0), 10)
# 3. 苹果微软对冲分析:
tickers = ['AAPL', 'MSFT', 'SPY', 'XLK']
# ...重复上述对冲步骤...
在(下)篇中,我们将深入探讨:
通过本教程,我们验证了系统性风险对冲对提升策略有效性的重要作用。在实际操作中,建议在策略研发初期就纳入风险管理模块,而非事后补救。有效降低资产间相关性可以显著提升策略的夏普比率,为获取alpha收益创造更有利的条件。