4. 多资产配对
任务目标
本案例针对多资产组合,使用最小方差法(Minimum Variance Hedging)计算对冲比率,构建市场中性组合。核心任务是:给定一组资产的历史价格序列,确定做多资产与做空资产之间的最优对冲比率,使得组合收益率的方差最小化,从而剥离市场风险,保留统计套利机会。
方法原理
最小方差对冲比率通过最小化组合方差来求解。设现货资产收益率为 r_s,对冲资产收益率为 r_f,对冲比率为 h(每单位现货对应 h 单位对冲资产),则组合收益率为 r_p = r_s - h × r_f。最小化 Var(r_p) 可得最优对冲比率:
h* = Cov(r_s, r_f) / Var(r_f)
对于多资产组合,我们将其拆分为多个单资产对冲对,分别计算每个资产相对于共同对冲工具(如指数ETF或期货)的最优对冲比率,然后按等权重或市值权重合成最终的市场中性组合。
环境依赖
本案例使用 Python 3.8+,依赖 numpy、pandas、matplotlib。安装命令:
pip install numpy pandas matplotlib
完整实现代码
import numpy as np
import pandas as pd
# ========== 1. 生成模拟价格数据(3个资产 + 1个对冲工具) ==========
np.random.seed(42)
dates = pd.date_range('2023-01-01', periods=500, freq='D')
# 对冲工具(如指数):随机游走
index_ret = np.random.normal(0.0005, 0.01, 500)
index_price = 100 * np.exp(np.cumsum(index_ret))
# 三个资产:每个与指数有不同beta,并带有独立噪声
assets = {}
betas = {'Asset_A': 1.2, 'Asset_B': 0.8, 'Asset_C': 1.5}
for name, beta in betas.items():
idio_noise = np.random.normal(0, 0.005, 500) # 特质波动
asset_ret = beta * index_ret + idio_noise
assets[name] = 100 * np.exp(np.cumsum(asset_ret))
# 合并为DataFrame
price_df = pd.DataFrame(assets, index=dates)
price_df['Hedge_Index'] = index_price
# ========== 2. 计算日收益率 ==========
ret_df = price_df.pct_change().dropna()
# ========== 3. 最小方差对冲比率计算 ==========
def min_var_hedge_ratio(asset_ret, hedge_ret):
"""计算单资产相对于对冲工具的最小方差对冲比率"""
cov = np.cov(asset_ret, hedge_ret)[0, 1]
var_hedge = np.var(hedge_ret, ddof=1)
return cov / var_hedge
hedge_ratios = {}
for asset_name in assets.keys():
h = min_var_hedge_ratio(ret_df[asset_name], ret_df['Hedge_Index'])
hedge_ratios[asset_name] = round(h, 4)
print("=== 最小方差对冲比率 ===")
for k, v in hedge_ratios.items():
print(f"{k}: {v}")
# ========== 4. 构建市场中性组合 ==========
# 等权重配置:做多每个资产1单位,做空对应h单位对冲工具
# 组合日收益率 = (1/N) * Σ(r_asset_i - h_i * r_hedge)
N = len(assets)
portfolio_ret = pd.Series(0.0, index=ret_df.index)
for asset_name in assets.keys():
h = hedge_ratios[asset_name]
hedged_ret = ret_df[asset_name] - h * ret_df['Hedge_Index']
portfolio_ret += hedged_ret / N # 等权重
# ========== 5. 验证:组合方差 vs 未对冲组合方差 ==========
unhedged_ret = ret_df[list(assets.keys())].mean(axis=1) # 等权未对冲
var_hedged = portfolio_ret.var(ddof=1)
var_unhedged = unhedged_ret.var(ddof=1)
variance_reduction = (1 - var_hedged / var_unhedged) * 100
print(f"\n=== 方差对比 ===")
print(f"未对冲组合年化方差: {var_unhedged * 252:.6f}")
print(f"对冲后组合年化方差: {var_hedged * 252:.6f}")
print(f"方差缩减比例: {variance_reduction:.2f}%")
# ========== 6. 输出组合累计净值 ==========
cum_nav = (1 + portfolio_ret).cumprod()
print(f"\n=== 组合表现 ===")
print(f"期末净值: {cum_nav.iloc[-1]:.4f}")
print(f"组合日收益率均值: {portfolio_ret.mean():.6f}")
print(f"组合日收益率标准差: {portfolio_ret.std():.6f}")
运行与验证
运行方式:将上述代码保存为 min_var_hedge.py,在终端执行 python min_var_hedge.py。
验证路径与通过条件:
- 对冲比率合理性:观察输出的对冲比率,Asset_A(beta=1.2)的比率应接近1.2,Asset_B(beta=0.8)接近0.8,Asset_C(beta=1.5)接近1.5。由于存在特质噪声,实际值会有小幅偏差,但应明显区分且方向正确。
- 方差缩减有效性:对冲后组合的方差应显著低于未对冲组合,方差缩减比例通常应大于70%。若缩减比例过低,说明对冲比率计算有误或数据生成逻辑不一致。
- 市场中性特征:对冲后组合的累计净值曲线应明显比单一资产平稳,日收益率均值接近0(通常在±0.001以内),表明市场风险已被剥离。
关键说明
本案例使用模拟数据验证方法正确性。实际应用中,将 price_df 替换为真实行情数据(如从 Yahoo Finance 或 Wind 获取),并注意:
- 收益率计算需对齐时间戳,剔除停牌日;
- 对冲比率应使用滚动窗口(如60日)动态计算,以适应时变相关性;
- 实际交易中需考虑交易成本与对冲工具的可交易性(如做空限制)。
判定标准:若对冲比率与预设beta方向一致且方差缩减超过70%,则证明最小方差对冲成功构建了市场中性组合,案例目标达成。