第19章 多品种基差组合:投资组合优化、相关性矩阵分析、风险平价配置
做基差交易做到一定程度,你会发现一个尴尬的事——单品种做久了,回撤曲线跟过山车似的。我早年吃过这个亏,重仓螺纹钢基差,结果政策一出来,三天亏掉半年的利润。从那以后,我开始认真思考一个问题:怎么把多个品种的基差机会组合起来,让收益更稳、回撤更小?
说白了,这就是投资组合理论在基差交易里的应用。但基差交易有个特殊性——它不是纯粹的资产价格波动,而是期限结构、库存逻辑、资金成本的综合体现。所以,组合优化的思路得调整。
19.1 为什么需要多品种组合?
单品种基差交易,你赚的是这个品种从「不合理」回归到「合理」的钱。但问题是,这个回归过程可能很曲折。我见过一个甲醇的基差交易,逻辑完全正确,但硬是等了两个月才回归,中间浮亏20%。
多品种组合的好处在于:
- 分散非系统性风险——某个品种的基差走反了,其他品种可能正好在回归
- 平滑资金曲线——不同品种的基差波动周期不同,组合起来整体波动会降低
- 提高资金利用率——可以同时捕捉多个机会,而不是死磕一个
核心观点:基差组合不是简单地把几个品种拼在一起,而是利用它们之间的相关性结构,让组合的「风险调整后收益」最大化。
19.2 相关性矩阵分析——先搞清楚品种之间的关系
做组合之前,第一件事就是算相关性矩阵。我习惯用过去60个交易日的基差数据来计算,为什么是60天?因为基差的均值回归周期通常在1-3个月,太短了噪声大,太长了反应滞后。
举个例子,我拿几个常见的工业品来演示:
| 品种 | 螺纹钢 | 热卷 | 铁矿石 | 焦炭 | 甲醇 |
|---|---|---|---|---|---|
| 螺纹钢 | 1.00 | 0.85 | 0.62 | 0.55 | 0.12 |
| 热卷 | 0.85 | 1.00 | 0.58 | 0.50 | 0.08 |
| 铁矿石 | 0.62 | 0.58 | 1.00 | 0.72 | 0.05 |
| 焦炭 | 0.55 | 0.50 | 0.72 | 1.00 | 0.03 |
| 甲醇 | 0.12 | 0.08 | 0.05 | 0.03 | 1.00 |
看到没?螺纹钢和热卷相关性高达0.85,铁矿石和焦炭也有0.72。但甲醇跟这些黑色系品种几乎不相关。这意味着什么?如果你同时做螺纹钢和热卷的基差,其实没起到分散作用——它们涨跌基本同步。
我的经验:相关性矩阵不是算一次就完事了。我每周都会重新算一遍,因为市场结构在变。比如2021年限产政策出来后,螺纹钢和热卷的相关性一度降到0.6以下,因为热卷的供需逻辑变了。
计算相关性的代码其实很简单,用Python的pandas就能搞定:
import pandas as pd
import numpy as np
# 假设df是包含各品种基差数据的DataFrame
# 列名:'RB'(螺纹钢), 'HC'(热卷), 'I'(铁矿石), 'J'(焦炭), 'MA'(甲醇)
df_basis = pd.read_csv('basis_data.csv', index_col=0, parse_dates=True)
# 计算60日滚动相关性
corr_matrix = df_basis.rolling(60).corr().iloc[-60:].mean()
print(corr_matrix)
# 或者直接用最近60天的数据
corr_latest = df_basis.tail(60).corr()
print(corr_latest)
19.3 投资组合优化——从均值-方差到基差特化
传统的马科维茨均值-方差模型,说白了就是找一条「有效前沿」——在给定风险下收益最高,或者给定收益下风险最低。但直接套用到基差交易上,会出问题。
为什么?因为基差交易的收益分布不是正态的。基差有上下限(受持仓成本、交割机制约束),而且经常出现「尖峰厚尾」——大部分时间波动不大,但一旦爆发就是大行情。
我个人习惯用改进的均值-方差框架,加入两个约束:
- 基差上下限约束——每个品种的基差不可能无限大,历史极值就是参考
- 流动性约束——基差大的品种往往流动性差,仓位不能太重
优化目标函数是这样的:
import scipy.optimize as opt
def portfolio_optimization(expected_returns, cov_matrix,
basis_bounds, liquidity_limits):
"""
基差组合优化
expected_returns: 各品种预期基差收益
cov_matrix: 协方差矩阵
basis_bounds: 基差上下限约束
liquidity_limits: 流动性约束(最大仓位比例)
"""
n = len(expected_returns)
# 目标函数:最大化夏普比率
def neg_sharpe(weights):
port_return = np.dot(weights, expected_returns)
port_vol = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights)))
return -port_return / port_vol
# 约束条件
constraints = [
{'type': 'eq', 'fun': lambda x: np.sum(x) - 1}, # 权重和为1
]
# 边界条件
bounds = tuple([(0, min(0.3, liq)) for liq in liquidity_limits])
# 优化求解
result = opt.minimize(neg_sharpe,
n * [1./n],
method='SLSQP',
bounds=bounds,
constraints=constraints)
return result.x
注意:预期收益的估计是最大的坑。我早期直接用历史平均基差收益来算,结果优化出来的权重全压在了历史表现最好的品种上。后来我改用「基差分位数 + 基本面判断」来估计预期收益,效果好了很多。
19.4 风险平价配置——让每个品种「平等贡献风险」
均值-方差优化有个毛病——它对输入参数特别敏感。预期收益稍微变一点,权重就天翻地覆。你想想看,这在实际交易中多可怕?
所以我更倾向于用风险平价来做基差组合的底仓配置。风险平价的核心思想很简单:让每个品种对组合总风险的贡献度相等。
具体来说,就是调整权重,使得:
- 品种A的风险贡献 = 品种B的风险贡献 = ... = 品种N的风险贡献
- 所有风险贡献之和 = 组合总风险
数学上,风险贡献的计算公式是:
def risk_contribution(weights, cov_matrix):
"""计算每个品种的风险贡献"""
portfolio_vol = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights)))
marginal_contrib = np.dot(cov_matrix, weights) / portfolio_vol
risk_contrib = weights * marginal_contrib
return risk_contrib / portfolio_vol # 返回百分比
def risk_parity_weights(cov_matrix):
"""风险平价权重求解"""
n = cov_matrix.shape[0]
def risk_parity_objective(weights):
rc = risk_contribution(weights, cov_matrix)
target_rc = 1.0 / n
return np.sum((rc - target_rc) ** 2)
constraints = [
{'type': 'eq', 'fun': lambda x: np.sum(x) - 1},
{'type': 'ineq', 'fun': lambda x: x} # 权重非负
]
result = opt.minimize(risk_parity_objective,
n * [1./n],
method='SLSQP',
constraints=constraints)
return result.x
举个例子,假设我们有三个品种:螺纹钢、铁矿石、甲醇。它们的波动率分别是:
- 螺纹钢:年化波动率 25%
- 铁矿石:年化波动率 35%
- 甲醇:年化波动率 30%
如果用等权重(各33%),风险贡献会严重偏向铁矿石——因为它波动最大。风险平价会怎么做?它会降低铁矿石的权重,提高螺纹钢的权重,让三个品种的风险贡献都变成33.3%。
实际效果:我回测过2018-2023年的数据,风险平价组合的夏普比率比等权重组合高出约0.3,最大回撤降低了15%。代价是年化收益稍微低了一点,但持有体验好太多了。
19.5 实战中的动态调整
理论说完了,聊聊实战中怎么用。我自己的流程是这样的:
- 每周一算相关性矩阵——用过去60个交易日的数据,看看品种间关系有没有变化
- 根据基差分位数调整预期收益——基差在历史90%分位以上,预期收益就高;在10%分位以下,预期收益就低
- 跑风险平价得到底仓权重——这是「慢变量」,一般一个月调整一次
- 叠加均值-方差优化做「战术调整」——当某个品种出现极端基差机会时,临时超配
举个例子,2022年10月,甲醇的基差突然拉到历史极值(现货比期货高500块),但风险平价给的权重只有15%。我临时把甲醇的权重提到30%,等基差回归后再降回来。这一波操作,组合多赚了8%。
避坑指南:我曾经在2020年3月犯过一个错——原油暴跌时,我看到所有品种的基差都在扩大,以为相关性会保持稳定,结果所有品种一起崩,组合回撤超过20%。后来我加了一个「极端行情保护」机制:当组合中超过一半品种的基差同时处于历史极端位置时,强制减仓到50%。
19.6 一个完整的组合框架图
下面这张图是我自己用的基差组合管理流程,你可以参考:
19.7 几个实战要点
最后,分享几个我在实战中总结的要点:
- 别过度优化——我见过有人用100多个品种做风险平价,结果任何一个品种出问题,组合都要大调。我个人建议5-10个品种就够了
- 关注基差的「共性因子」——比如所有品种的基差都受资金面影响,当资金面收紧时,基差会系统性走阔。这个因子没法分散,只能通过仓位管理来控制
- 定期再平衡——我习惯每月第一个交易日做一次再平衡,如果某个品种的权重偏离目标超过5%,就提前调整
- 留足现金——基差交易经常需要追加保证金,组合中至少要留10%的现金头寸
最后提醒一句:任何优化模型都是基于历史数据的,而市场会变。2023年之后,很多品种的基差波动特征都变了——因为交割制度改了、仓储成本变了。所以,模型要定期回测验证,别迷信过去的参数。
好了,这一章的内容就到这里。多品种基差组合的核心就三件事:算清楚相关性、用风险平价打底、用均值-方差做战术调整。剩下的,就是执行和纪律了。