第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 实战中的动态调整

理论说完了,聊聊实战中怎么用。我自己的流程是这样的:

  1. 每周一算相关性矩阵——用过去60个交易日的数据,看看品种间关系有没有变化
  2. 根据基差分位数调整预期收益——基差在历史90%分位以上,预期收益就高;在10%分位以下,预期收益就低
  3. 跑风险平价得到底仓权重——这是「慢变量」,一般一个月调整一次
  4. 叠加均值-方差优化做「战术调整」——当某个品种出现极端基差机会时,临时超配

举个例子,2022年10月,甲醇的基差突然拉到历史极值(现货比期货高500块),但风险平价给的权重只有15%。我临时把甲醇的权重提到30%,等基差回归后再降回来。这一波操作,组合多赚了8%。

避坑指南:我曾经在2020年3月犯过一个错——原油暴跌时,我看到所有品种的基差都在扩大,以为相关性会保持稳定,结果所有品种一起崩,组合回撤超过20%。后来我加了一个「极端行情保护」机制:当组合中超过一半品种的基差同时处于历史极端位置时,强制减仓到50%。

19.6 一个完整的组合框架图

下面这张图是我自己用的基差组合管理流程,你可以参考:

多品种基差组合管理流程 基差数据输入 相关性矩阵分析(60日滚动) 风险平价配置(底仓) 均值-方差优化(战术调整) 最终组合权重(底仓+战术) 执行交易 & 风控

19.7 几个实战要点

最后,分享几个我在实战中总结的要点:

  • 别过度优化——我见过有人用100多个品种做风险平价,结果任何一个品种出问题,组合都要大调。我个人建议5-10个品种就够了
  • 关注基差的「共性因子」——比如所有品种的基差都受资金面影响,当资金面收紧时,基差会系统性走阔。这个因子没法分散,只能通过仓位管理来控制
  • 定期再平衡——我习惯每月第一个交易日做一次再平衡,如果某个品种的权重偏离目标超过5%,就提前调整
  • 留足现金——基差交易经常需要追加保证金,组合中至少要留10%的现金头寸

最后提醒一句:任何优化模型都是基于历史数据的,而市场会变。2023年之后,很多品种的基差波动特征都变了——因为交割制度改了、仓储成本变了。所以,模型要定期回测验证,别迷信过去的参数。

好了,这一章的内容就到这里。多品种基差组合的核心就三件事:算清楚相关性、用风险平价打底、用均值-方差做战术调整。剩下的,就是执行和纪律了。

公众号:蓝海资料掘金营,微信 deep3321