13、多产品组合利润优化:相关性矩阵、组合VaR、资本配置优化

做市商手里通常不止一个产品。你想想看,我们同时做ETF期权、股指期货、甚至还有几个商品期货的做市。每个产品单独看都赚钱,但合在一起,风险就复杂了。

我早年吃过一次亏。当时几个产品单独看风险都不大,结果市场一波动,它们居然一起跌。那天的亏损,让我记住了组合风险管理的分量。今天我们就聊聊多产品组合的利润优化,核心就是三件事:相关性矩阵、组合VaR、资本配置。

13.1 为什么单产品风控不够用?

单产品做市,你盯着自己的希腊字母就行。Delta大了就对冲,Gamma高了就小心。但多产品组合,问题就来了——产品之间会互相影响。

举个简单的例子:

  • 你同时做多沪深300ETF期权和做空沪深300股指期货
  • 表面上看,两个头寸方向相反,风险对冲了
  • 但实际呢?期权有非线性特征,期货是线性的
  • 市场大涨时,期权Gamma会放大收益,期货只是线性亏损
  • 结果组合风险并不像你想象的那么小

这就是相关性在作怪。产品之间的相关性不是固定的,它会随着市场状态变化。我习惯用滚动窗口计算相关性矩阵,而不是用全样本的静态数据。

核心观点: 多产品组合的风险,不等于各产品风险的简单加总。相关性矩阵是理解组合风险的第一把钥匙。

13.2 相关性矩阵:从数据到洞察

相关性矩阵说白了就是一个表格,告诉你每两个产品之间是怎么联动的。值在-1到1之间,1代表完全同向,-1代表完全反向,0代表没关系。

但这里有个坑。我记得有一次,我用日收益率算相关性,结果发现两个产品相关性高达0.85。我差点就以为它们是一回事。后来我换成15分钟的高频数据算,相关性只有0.3。为什么?因为日线掩盖了日内波动的细节。

我建议的做法是:

  1. 选择合适的时间窗口:做市商关注的是日内风险,用30分钟或1小时的收益率更合适
  2. 滚动计算:用过去20个交易日的窗口,每天更新一次相关性矩阵
  3. 关注极端相关性:市场压力下,相关性会急剧上升。我习惯单独算一个“压力相关性矩阵”,只用市场大跌时的数据

下面是一个简单的Python示例,计算两个产品的滚动相关性:

import numpy as np
import pandas as pd

# 假设有两个产品的收益率序列
returns_product1 = np.random.randn(1000) * 0.01
returns_product2 = np.random.randn(1000) * 0.01

# 滚动计算相关性,窗口为50个数据点
window = 50
rolling_corr = []
for i in range(window, len(returns_product1)):
    corr = np.corrcoef(
        returns_product1[i-window:i],
        returns_product2[i-window:i]
    )[0, 1]
    rolling_corr.append(corr)

# 看看最近的相关性
print(f"最近的相关性: {rolling_corr[-1]:.3f}")
我的小技巧: 相关性矩阵不要只看数字。我习惯把它可视化,用热力图展示。颜色越深代表相关性越强。一眼就能看出哪些产品是“风险共同体”。

13.3 组合VaR:把风险量化出来

有了相关性矩阵,我们就可以算组合VaR了。VaR(Value at Risk)就是“在给定置信水平下,未来一段时间内可能的最大损失”。

组合VaR的计算公式其实不复杂:

组合VaR = sqrt( w^T * Σ * w ) * z * sqrt(T)

其中:
w = 各产品的权重向量
Σ = 协方差矩阵(由相关性矩阵和标准差算出)
z = 置信水平对应的分位数(95%对应1.645,99%对应2.326)
T = 持有期(天数)

但这里有个问题。这个公式假设收益率是正态分布的。现实中的数据往往有厚尾特征——极端事件发生的概率比正态分布预测的要高。我见过太多人用这个公式算出来VaR是100万,结果一天亏了300万。

所以我建议用历史模拟法算VaR。方法很简单:

  1. 取过去500个交易日的组合收益率数据
  2. 按收益率从小到大排序
  3. 取第5%分位数(95%置信水平)对应的值

这个方法不需要假设分布,直接看历史数据。虽然也有缺点(历史不会完全重复),但至少比纯正态假设靠谱。

注意: 历史模拟法假设“过去发生的未来还会发生”。但市场结构会变,比如2020年疫情后,很多产品的相关性都变了。我建议每季度重新校准一次历史数据窗口。

13.4 资本配置优化:把钱放到最赚钱的地方

做市商有资本金限制。你不能把所有钱都押在一个产品上。资本配置优化的目标就是:在给定风险预算(比如组合VaR不超过1000万)的前提下,最大化预期收益。

这个问题可以转化为一个优化问题:

最大化: 预期收益 = w^T * μ
约束条件: 组合VaR ≤ 风险预算
           w^T * 1 = 1 (权重之和为1)
           w_i ≥ 0 (不允许做空,视情况而定)

其中μ是各产品的预期收益率向量。但这里有个现实问题——预期收益率很难准确估计。我见过有人用历史平均收益率,结果优化出来的权重全集中在过去涨得好的产品上,然后市场风格一变就亏惨了。

我个人的做法是:

  • 用隐含波动率的变化来估计预期收益,而不是历史收益率
  • 加入“分散度约束”,限制单个产品的最大权重不超过30%
  • 定期再平衡,比如每周调整一次权重

下面是一个简单的优化示例,用scipy求解:

from scipy.optimize import minimize
import numpy as np

# 假设有3个产品
expected_returns = np.array([0.05, 0.03, 0.04])  # 预期收益率
cov_matrix = np.array([
    [0.01, 0.002, 0.001],
    [0.002, 0.008, 0.0015],
    [0.001, 0.0015, 0.009]
])  # 协方差矩阵
risk_budget = 0.02  # 风险预算(2%的VaR)

def portfolio_var(weights):
    return np.sqrt(weights.T @ cov_matrix @ weights)

def objective(weights):
    return -weights.T @ expected_returns  # 最大化收益 = 最小化负收益

# 约束条件
constraints = [
    {'type': 'eq', 'fun': lambda w: np.sum(w) - 1},  # 权重之和为1
    {'type': 'ineq', 'fun': lambda w: risk_budget - portfolio_var(w)}  # VaR不超过预算
]

# 初始权重
initial_weights = np.array([1/3, 1/3, 1/3])

# 求解
result = minimize(objective, initial_weights, constraints=constraints)
print(f"最优权重: {result.x}")
print(f"组合VaR: {portfolio_var(result.x):.4f}")
关键点: 资本配置优化不是一次性的工作。市场在变,相关性在变,预期收益也在变。我习惯每天跑一次优化,但只在实际偏离超过5%时才调整头寸。这样可以减少交易成本。

13.5 实战中的避坑指南

说了这么多,最后分享几个我踩过的坑:

  • 相关性会突变:2020年3月,几乎所有资产的相关性都飙到了0.8以上。平时算的分散化效果,在危机时刻基本失效。我后来加了一个“压力测试”模块,专门模拟极端情况。
  • 不要过度优化:有一次我优化出来的权重是47.3%、32.1%、20.6%,看起来特别精确。结果第二天市场一波动,这些数字就全变了。我现在只保留到整数百分比,给自己留点容错空间。
  • 交易成本是隐形的杀手:优化模型通常不考虑交易成本。但实际做市时,调整头寸是要花钱的。我建议在优化目标中加入一个“换手率惩罚项”,避免频繁调整。

嗯,多产品组合的利润优化,说到底就是在风险和收益之间找平衡。相关性矩阵给你地图,组合VaR给你指南针,资本配置优化就是你的路线规划。三者缺一不可。

多产品组合利润优化核心逻辑 相关性矩阵 • 滚动窗口计算 • 高频数据更准 • 压力场景分析 组合VaR • 历史模拟法 • 厚尾风险处理 • 多时间维度 资本配置优化 • 风险预算约束 • 预期收益估计 • 分散度约束 输出:最优权重 + 风险预算分配 每日更新 | 偏离5%触发再平衡 | 压力测试验证 关键原则: 1. 相关性是动态的,不是静态的 2. VaR不是万能的,需要配合压力测试 3. 优化结果要留有余地,别太精确

最后说一句,这套方法不是万能的。市场永远有黑天鹅。但有了相关性矩阵、组合VaR和资本配置优化,至少你能在大部分时间里,把风险控制在可接受的范围内。剩下的,就看你的经验和运气了。