期货多策略资金分配实战:从等权到风险平价构建稳健加权方案

发布时间:2026/10/5 3:44:10
期货多策略资金分配实战:从等权到风险平价构建稳健加权方案 做期货量化的人早晚都会撞上一面墙单策略的回测曲线再漂亮实盘跑半年你就会发现资金曲线要么在宽幅震荡里来回坐电梯要么在某一波趋势行情里突然回撤超过心理防线。我见过太多朋友把一个策略的参数优化到极致然后重仓All in结果一波反向跳空直接打回原形。真正让资金曲线变得平滑的往往不是某个策略有多强而是多个策略之间怎么分钱。我自己在实盘里从一个策略吃满仓走到多策略组合风险预算分配经历过不少试错踩过相关性失效的坑也踩过协方差矩阵估计不稳的坑。这篇就把我最终沉淀下来的一套多策略资金分配方法完整拆开讲从最基础的等权分配到风险平价再到带约束的目标风险贡献每一层都讲清楚原理、代码和为什么会这么做最后给出一套可以直接上手的稳健加权方案。适合已经能独立开发单策略、想做组合平滑的量化交易者参考。1. 单策略的隐痛为什么资金分配比挑策略更影响最终收益先说一个我在实盘中反复验证的结论两个单独看都还不错的策略用不同的资金分配方式组合在一起最终的收益风险比差距可能超过40%。而大多数人把精力全花在策略信号优化上对资金分配这件事基本是拍脑袋——要么等权各分一半要么哪个策略最近表现好就多给它钱。这两种做法都忽略了组合管理的核心风险结构。1.1 资金曲线波动率的复利杀伤力期货交易里收益的复利效应和回撤的修复难度是极度不对等的。账户回撤20%需要后续盈利25%才能回到前高回撤50%需要盈利100%才能回本。所以资金分配的第一目标不是最大化收益而是控制组合级别的回撤深度。假设你有两个完全不相关的策略年化收益都是20%单策略最大回撤都是15%。如果你把全部资金压在一个策略上你的账户就要承受完整的15%回撤。但如果两个策略各占50%资金且回撤在时间上错开组合的最大回撤可能只有8%到10%。同样的收益水平回撤深度直接腰斩——这就是资金分配最朴素的价值。这个逻辑说起来简单但实盘里很多人的操作恰恰相反。我见过一个朋友手上有趋势策略和套利策略原本组合得很好后来趋势策略连续三个月大赚他一激动把趋势策略的资金权重从50%提到80%。结果接下来趋势策略遇到连续止损两个月把之前的浮盈回吐了大半而套利策略这边因为仓位被压缩本该贡献的对冲价值基本没起到作用。1.2 单一策略的天花板与组合的免费午餐单个策略的收益风险比是有天花板的。你做趋势跟踪就要承受震荡期的连续磨损你做套利就要承受价差不波动时的资金闲置。这些都不是策略参数能解决的而是策略逻辑本身的风险收益特征决定的。多策略组合的价值是在不改变任何一个策略内部逻辑的前提下通过资金分配改变账户整体的风险收益结构。这相当于在资产配置层面做了一次免费的风险再平衡。不同策略之间的低相关性就是这笔免费午餐的来源。但这里有个关键问题相关性是会漂移的。后面我会专门讲这个因为我在实盘里就吃过相关性失效的大亏——两个策略在三年回测里相关性只有0.2结果在某个极端行情窗口里相关性瞬间跳到0.85组合风险瞬间集中暴露。2. 分配方法谱系等权、波动率倒数、风险平价与均值方差的适用边界多策略资金分配的方法论从简单到复杂大致有四档。我在不同阶段都用过先把这个谱系梳理清楚你才知道风险平价到底解决的是什么问题。2.1 等权分配最稳健的基准线等权分配就是把资金平均分给每个策略N个策略各占1/N。这个方法看起来太简单但它有一个非常重要的优点完全不需要任何参数估计不存在估计出错导致配置恶化的风险。在组合优化领域有一个著名结论等权组合在样本外的表现往往优于复杂的均值方差优化组合。原因很简单复杂的优化模型需要估计预期收益和协方差矩阵而这两个参数的估计误差在实盘里造成的损失常常比模型本身的理论优势还要大。我自己的经验是等权分配适合作为一切组合方案的起点和基准。每当你跑出一个更高级的资金分配方案时第一件事就是拿它和等权方案对比看是否真的在样本外有所提升。如果没有宁可继续用等权。2.2 波动率倒数加权简单有效的第一层改进波动率倒数加权的基本思想是波动率越大的策略给它的资金越少。每个策略的权重与自身波动率的倒数成正比。这个方法的逻辑很直觉——既然高波动的策略会给组合带来更大的风险那就降低它的仓位。相比等权方案它只需要估计每个策略的波动率而单个策略的波动率估计比协方差矩阵的估计要稳定得多所以在实盘里这个方案通常能跑赢等权。但波动率倒数加权有一个结构性的盲区它完全忽略了策略之间的相关性。两个高度相关的策略即便各自波动率都不高叠加起来也会产生很大的组合风险。这正是风险平价要解决的问题。2.3 风险平价从资金等权到风险等权风险平价的核心理念是让每个策略对组合总风险的贡献相等而不是让每个策略的资金量相等。我之前跑过一组实盘方案组合里有三个策略一个趋势策略波动率高达25%两个套利策略波动率只有8%左右。等权分配下趋势策略虽然只占1/3资金却贡献了组合风险的70%以上。这意味着表面上我在分散投资实际上账户命运还是系在一个策略身上。风险平价通过求解一个优化问题调整资金权重最终让每个策略的风险贡献趋近于相等。这样无论哪一个策略进入不利行情对整个账户的冲击都受控。关于风险平价的数学原理和Python实现我放在下一章详细拆解这是全文的核心重点。2.4 均值方差优化理论上最优实盘里最难用马科维茨的均值方差优化在理论上是最优雅的框架通过最大化组合的夏普比率来确定权重。但实盘里我越来越不喜欢用这个方案因为它需要估计每个策略的预期收益率——这是整个金融里最难估计的参数几乎必然带噪声。在期货策略场景下单策略的预期收益率的估计误差稍微大一点优化结果就会蹦出一个极端的权重解某个策略仓位变成0另一个策略仓位变成80%。这种解在回测里非常好看但实盘里往往脆弱得不堪一击。我曾经花了两周时间用均值方差框架给四个策略做资金分配回测结果夏普比从1.8提升到了2.4。结果一上实盘前两周跑得还行第三周某个策略预期收益的假设被行情证伪整个组合的权重结构瞬间变得极其别扭。后来我彻底放弃了这个方向转向风险预算框架。下面这个表是我对四种方法在实盘适用性上的总结方法参数依赖相关性考虑实盘稳定性适用场景等权分配无无非常稳定策略样本少、参数不可靠时的兜底方案波动率倒数单策略波动率无较稳定策略间相关性较低时的简单改进风险平价协方差矩阵有较稳定相关性结构相对清晰、需要控制单策略风险暴露均值方差预期收益协方差矩阵有较差对收益预测有极高信心时或做纯理论推演3. 风险平价的数学原理与Python实现从协方差矩阵到目标风险贡献这一章是硬核内容但我会用最直白的方式来拆解。你不需要很强的数学背景只要跟着步骤走就能在Python里把风险平价跑通。3.1 风险贡献的数学拆解组合风险如何分摊到每个策略先建立基本记号。假设你有N个策略资金权重向量为 w [w₁, w₂, ..., w_N]策略收益率的协方差矩阵为 Σ。组合的波动率为σ_p sqrt(wᵀ Σ w)这里的关键是边际风险贡献。对第i个策略它的边际风险贡献是指该策略权重增加一个微小单位组合波动率增加多少数学上是组合波动率对w_i求偏导MRC_i (Σ w)_i / σ_p再乘上该策略自身的权重就得到总风险贡献TRC_i w_i × MRC_i w_i × (Σ w)_i / σ_p可以验证所有策略的总风险贡献之和恰好等于组合波动率σ_p Σ TRC_i这意味着组合的总风险被干净地分解为每个策略贡献的部分之和。风险平价的求解目标就是找到一个权重向量w使得所有TRC_i相等TRC₁ TRC₂ ... TRC_N这个条件看起来很复杂但有一个重要的凸优化性质风险平价问题的解是唯一且凸的这意味着我们可以用标准的数值优化器稳定求解不会像均值方差那样陷入局部最优解。3.2 用Solver求解风险平价scipy最小化实现风险平价的标准数值解法是把它转化为一个最小化问题。定义目标函数为所有策略风险贡献与平均风险贡献之差的平方和f(w) Σ (TRC_i - TRC_mean)²用scipy.optimize.minimize来求解这个最小化问题加上权重和为1的约束import numpy as np import pandas as pd from scipy.optimize import minimize def risk_parity_weights(cov_matrix): 通过数值优化求解风险平价权重 cov_matrix: 策略收益率的协方差矩阵 (N x N) n cov_matrix.shape[0] # 目标函数风险贡献均匀化 def objective(w): w np.array(w) sigma_p np.sqrt(w cov_matrix w) # 边际风险贡献 MRC mrc (cov_matrix w) / sigma_p # 总风险贡献 TRC trc w * mrc # 风险贡献与平均值的偏差平方和 return np.sum((trc - np.mean(trc))**2) # 约束条件权重之和为1 constraints [{type: eq, fun: lambda w: np.sum(w) - 1.0}] # 边界约束权重在0和1之间 bounds [(0.0, 1.0) for _ in range(n)] # 初始值等权 w0 np.ones(n) / n result minimize( objective, w0, methodSLSQP, boundsbounds, constraintsconstraints, options{maxiter: 1000, ftol: 1e-12} ) if not result.success: raise ValueError(f优化失败: {result.message}) return result.x这段代码的核心逻辑非常直观不断调整每个策略的权重直到每个策略对组合风险的贡献都一样。我在实盘里用下来SLSQP求解器对于几十个策略以内的规模表现稳定一般几百次迭代就能收敛。3.3 滚动窗口与协方差矩阵估计风险平价成败的关键环节上面的求解函数看起来简单但真正决定风险平价实盘效果的不是求解器而是你喂给它的协方差矩阵。协方差矩阵估计得越贴合当前市场状态得到权重就越合理。我的做法是采用滚动窗口估计窗口长度选择过去60到120个交易日。太短了协方差估计噪声大权重三个月大改一次交易成本上去太长了又跟不上策略相关性结构的变化。数据频率优先使用日频率的收益率。日内30分钟级别的收益率数据会让协方差矩阵带上微观结构噪声。权重再平衡频率我的默认设置是每20个交易日约一个月重新计算一次权重。趋势策略和套利策略的相关性结构不会一周一变太频繁的再平衡只会增加交易成本。下面是滚动估计风险平价权重的完整代码def rolling_risk_parity(returns, window90, rebalance_days20): 滚动风险平价权重计算 returns: DataFrame, 各策略的日收益率序列 window: 协方差矩阵估计窗口 rebalance_days: 再平衡频率 weights_history [] n returns.shape[1] for i in range(len(returns)): if i window: weights_history.append(np.ones(n) / n) continue # 每rebalance_days天重算一次权重其余日期沿用上一次权重 if i % rebalance_days ! 0: weights_history.append(weights_history[-1]) continue # 提取窗口内的收益率数据 window_data returns.iloc[i-window:i] # 协方差矩阵 cov window_data.cov() # 求解风险平价权重加一个小的正则项防止矩阵奇异 cov_reg cov np.eye(n) * 1e-8 w risk_parity_weights(cov_reg) weights_history.append(w) return pd.DataFrame(weights_history, indexreturns.index)这里有个细节值得注意协方差矩阵的正则化。如果两个策略的收益率序列几乎完全同步协方差矩阵可能接近奇异数值优化会出现问题。我在协方差矩阵上加了一个微小的单位矩阵倍数相当于给每个策略的方差增加一个极小的正数保证矩阵可逆。这个技巧做风险平价之前一定要记得加。3.4 风险平价和等权的实盘对比一组我在期货策略上的测试数据为了让你对风险平价的效果有直观感受放一组我之前在螺纹钢、铁矿、PTA、甲醇四个品种的日内策略组合上的测试数据。用30万本金同时跑了三个方案等权、波动率倒数加权、风险平价。回测周期是一年扣除手续费和滑点。方案年化收益最大回撤夏普比卡玛比等权分配22.4%9.8%1.682.29波动率倒数24.1%8.5%1.872.84风险平价25.6%7.2%2.133.56两个关键观察结果。一是风险平价的年化收益并非最高均值方差方案在回测里能做到28%以上但它的最大回撤显著低于其他两个方案所以卡玛比收益回撤比优势明显。二是在盘中拉升行情里等权方案因为高波动策略仓位过重单日回撤经常突破2%而风险平价方案的日内波动明显收敛。这些结果和我后来实盘半年的感受基本一致。唯一的意外是风险平价方案在策略相关性上升的震荡行情里权重调整会比较频繁这个我下章展开讲。4. 风险平价的两个隐蔽盲区与工程化补救风险平价很好用但如果你以为一个协方差矩阵就能解决所有问题那就太天真了。我在实盘里至少踩过两个隐蔽的坑这一章把完整的排查过程和补救方案都说清楚。4.1 盲区一收益来源同向化——风险等权不等于风险分散第一次踩坑是在2023年的一波黑色系行情里。我的组合里有三个策略一个螺纹钢日内趋势、一个铁矿石套利、一个PTA隔夜趋势。在风险平价框架下它们的权重分配很均匀各自风险贡献几乎相等。看起来一切正常但有一天黑色系集体暴涨螺纹钢涨停、铁矿石大涨PTA也跟着化工板块走强。当天组合的回撤达到了历史极值。我复盘的时候把三个策略的当日收益率拉出来一看相关系数全部超过0.8。问题出在哪三个策略虽然方法不同、品种不同但在宏观层面共享同一个风险因子商品市场的系统性方向。螺纹钢趋势策略在做多黑色铁矿石套利也在做多黑色PTA虽然不在黑色系但在系统性风险偏好回暖时也和商品指数同向波动。这种深层的收益来源同向性协方差矩阵捕捉不到。协方差矩阵能捕捉的是统计相关性而统计相关性是历史数据的产物。在极端行情里所有策略可能同时向同一个因子暴露历史平均相关性会低估这种尾部情形下的真实相关性。这个坑的补救思路我放在后面第5章讲核心是用收益归因来拆解策略的真实风险因子暴露。4.2 盲区二协方差矩阵的参数漂移与权重跳跃第二个坑更像是工程问题。我的协方差矩阵估计窗口是90天但我在复盘时发现每当我更新权重后如果遇到某几天市场结构变化协方差矩阵会剧烈变化导致风险平价权重出现跳跃式调整。举个例子某个月初算出来的权重是A策略45%、B策略55%。一个月后因为B策略连续大涨导致波动率上升协方差矩阵变化后权重直接跳成A策略70%、B策略30%。30%仓位的大幅调整光是滑点成本就吃掉了一部分收益。理论上这恰恰是风险平价想达到的效果——降低波动率变大的策略权重。但问题是短期波动率的飙升可能只是噪声并非结构性变化。跟着噪声调整权重等于自己给自己制造交易成本。针对这个问题我的工程化补救有三个具体手段。其一对协方差矩阵中的方差项做缩尾处理。把每个策略的方差数据按1%和99%分位数做Winsorize避免极值过度影响结果。其二在优化约束中加入权重上下限。单策略权重最小不低于15%最大不超过50%这样即使协方差矩阵波动再大权重不会出现极端解。其三引入再平衡死区。新计算的目标权重和当前权重的差异如果小于5个百分点就不调整直接沿用现有权重。这样微小的协方差变化不会触发交易。def risk_parity_with_constraints(cov_matrix, w_prevNone, min_w0.15, max_w0.50, dead_zone0.05): 带工程约束的风险平价权重 min_w: 单策略最小权重 max_w: 单策略最大权重 dead_zone: 再平衡死区阈值 w_prev: 当前持仓权重用于判断是否需要调整 n cov_matrix.shape[0] def objective(w): w np.array(w) sigma_p np.sqrt(w cov_matrix w) mrc (cov_matrix w) / sigma_p trc w * mrc return np.sum((trc - np.mean(trc))**2) constraints [ {type: eq, fun: lambda w: np.sum(w) - 1.0}, ] bounds [(min_w, max_w) for _ in range(n)] w0 np.ones(n) / n if w_prev is not None: w0 w_prev result minimize(objective, w0, methodSLSQP, boundsbounds, constraintsconstraints) w_new result.x # 再平衡死区判断 if w_prev is not None and np.max(np.abs(w_new - w_prev)) dead_zone: return w_prev return w_new这套带有约束和死区的方案让我在实盘里很大程度上抑制了频繁调仓的问题。后面第5章会给出更完整的方案设计思路。4.3 峰度与尾部风险波动率不是风险的全貌除了上面两个坑还有一个容易忽略的技术细节。传统风险平价只优化波动率的贡献但期货策略的收益分布常有厚尾特征。两个策略的波动率相同一个的收益分布接近正态另一个偶尔出现极端的单日大亏后者的尾部风险显著更大。所以在评估策略的风险特征时我除了看方差还会额外关注两个指标。一是最大回撤单策略的历史最大回撤是比波动率更贴近实盘感受的指标。二是偏度和峰度偏度越负、峰度越高的策略尾部风险越大在权重分配时可以做保守调整。你可以简单地把峰度理解为这个策略带来惊喜或惊吓的频率。峰度高的策略每隔一段时间就会出现一次极端大回撤这种策略在组合里天然不适合承担过重的风险预算。5. 一个可直接上手的稳健加权方案代码、参数与实盘注意事项前面讲了原理也讲了坑这一章直接给出我目前在用的、相对稳健的一套资金分配方案。它基于风险平价框架融合了收益归因、权重约束和再平衡死区三个工程手段并且加入了一定的风险因子分散逻辑。5.1 整体方案设计从风险贡献到风险预算在纯风险平价框架里所有策略的风险贡献被强制设为相等。但实盘中你往往有主观倾向有些策略你更信任愿意给它更高的风险预算。这时候就需要用目标风险贡献Risk Budgeting来替代严格的风险平价。目标风险贡献的数学表述很简单指定一组风险预算向量 b [b₁, b₂, ..., b_N]满足每个元素大于等于0且和为1然后求解权重w使得TRC_i / σ_p b_i。当所有b_i 1/N时目标风险贡献就退化为经典风险平价。如果某个策略你特别看好可以把它的风险预算设为0.4其他策略共享剩下的0.6。从数学角度看目标风险贡献的求解目标函数变为f(w) Σ (TRC_i / σ_p - b_i)²其余的求解方式和标准风险平价完全一致。5.2 完整代码目标风险贡献收益归因修正工程约束下面代码整合了我上面说到的所有手段包含了风险预算、权重上下限、再平衡死区、以及收益归因的风险乘数修正import numpy as np import pandas as pd from scipy.optimize import minimize # 第一步基于收益归因的风险乘数修正 def factor_exposure_adjust(returns, factor_returns, exposure_threshold0.7): 通过线性回归计算每个策略对共同风险因子的暴露并返回修正后的风险预算 returns: DataFrame, 各策略日收益率 factor_returns: DataFrame, 共同风险因子如商品指数 exposure_threshold: 暴露度超过该值的策略风险预算下调 n returns.shape[1] risk_multiplier np.ones(n) for i in range(n): strategy returns.iloc[:, i] # 与风险因子回归取R平方作为暴露度 valid pd.concat([strategy, factor_returns], axis1).dropna() if len(valid) 50: continue x valid.iloc[:, 1].values y valid.iloc[:, 0].values corr np.corrcoef(x, y)[0, 1] if abs(corr) exposure_threshold: # 暴露度越高风险预算系数越低 risk_multiplier[i] 1.0 - (abs(corr) - exposure_threshold) return risk_multiplier # 第二步目标风险贡献权重求解 def target_risk_budget_weights(cov_matrix, risk_budget, w_prevNone, min_w0.10, max_w0.55, dead_zone0.04): 目标风险贡献组合优化 cov_matrix: 策略协方差矩阵 risk_budget: 风险预算向量和为1 n cov_matrix.shape[0] risk_budget np.array(risk_budget) # 确保预算和为1 risk_budget risk_budget / risk_budget.sum() def objective(w): w np.array(w) sigma_p np.sqrt(w cov_matrix w) mrc (cov_matrix w) / sigma_p trc w * mrc risk_contribution trc / sigma_p return np.sum((risk_contribution - risk_budget) ** 2) constraints [{type: eq, fun: lambda w: np.sum(w) - 1.0}] bounds [(min_w, max_w) for _ in range(n)] w0 np.ones(n) / n if w_prev is not None: if np.all(w_prev min_w) and np.all(w_prev max_w): w0 w_prev result minimize(objective, w0, methodSLSQP, boundsbounds, constraintsconstraints, options{maxiter: 2000, ftol: 1e-12}) if not result.success: # 回退到波动率倒数加权 diag_vol np.sqrt(np.diag(cov_matrix)) inv_vol 1.0 / diag_vol w_fallback inv_vol / inv_vol.sum() return w_fallback w_new result.x # 再平衡死区判断和现持仓相比权重变化太小就不调 if w_prev is not None and np.max(np.abs(w_new - w_prev)) dead_zone: return w_prev return w_new # 第三步主流程 def robust_weight_allocation(returns, factor_returns, w_prevNone): 完整的多策略资金分配主流程 # 计算协方差矩阵加正则项 returns returns.tail(90) cov returns.cov().values n returns.shape[1] cov cov np.eye(n) * 1e-8 # 计算风险乘数 multipliers factor_exposure_adjust(returns, factor_returns) # 基准风险预算平均分配 base_budget np.ones(n) / n # 风险乘数修正预算 adjusted_budget base_budget * multipliers adjusted_budget adjusted_budget / adjusted_budget.sum() # 求解权重 w target_risk_budget_weights(cov, adjusted_budget, w_prevw_prev) return w这套组合方案的核心逻辑是三层叠加。第一层在风险预算层面用收益归因找出对共同因子暴露过高的策略主动降低它的预算权重。第二层在权重求解层面用目标风险贡献优化在协方差矩阵和预算之间寻找均衡。第三层在工程执行层面用上下限约束和再平衡死区控制调仓频率。5.3 实盘中的关键参数与再平衡规则这套方案里有几个参数用对了是利器用错了反而添乱。我把每一步的参数设定逻辑说清楚。协方差矩阵估计窗口选90个交易日这个窗口长度我试过60、90、120。60天噪声太大协方差矩阵每期变化剧烈权重跳跃明显120天又太慢策略相关性的变化需要很久才能反映到权重里。90天是相对稳妥的中间值。策略相关性变化快的场景窗口可以缩到60天。比如一个组合里全是短线高频类策略相关性结构本身就不稳定短窗口能更快跟踪到变化。如果是低频趋势策略窗口可以放到120天因为趋势策略的相关性变化节奏本身就慢。权重上下限设10%到55%。上限55%保证没有策略能完全主导组合风险下限10%保证每个策略都保留最低限度的参与权重避免某些策略长期空仓导致样本外数据不足。权重上下限的设置要参考策略数量策略越多上下限区间应该越宽。再平衡死区设4%。这个数值的原理是这样的权重调整个4%对应到资金上对总收益的影响可能不到0.5%但产生的交易成本是实实在在的。赚不到的钱不折腾是资金管理的朴素智慧。5.4 纪律与频率再平衡的该动的时机和不该动的时机最后聊点代码之外的东西。资金分配方案再精妙执行时如果缺乏纪律效果也会大打折扣。我的原则是固定频率再平衡不轻易被行情波动干扰。默认每20个交易日做一次权重校准。特殊情况下才触发临时再平衡比如某个策略的当日回撤超过10%或者组合层面的回撤接近历史最大值的80%。这两种情况说明风险结构发生了本质变化固定频率的再平衡可能来不及调整风险暴露。还有一个更容易被忽视的点新策略纳入组合后不要急着给它分配太多风险预算。我的习惯是先给一个小于标准预算的权重运行60到90天确认它在实盘里的收益特征和回测基本吻合后再逐步提升到标准水平。我见过太多人因为一个策略回测数据好看就大步调仓结果实盘表现差异直接带崩整个组合。保守不亏钱激进会亏大钱这句话放在资金分配上同样成立。如果想在这个方案的基础上进一步扩展有两个方向值得探索。一个是把波动率从等权历史方差升级为EWMA动态波动率让近期的市场状态在权重里占更高权重。另一个是在风险预算上叠加Black-Litterman式的观点调整框架把你对每个策略的主观判断以结构化的方式引入权重求解。这两个方向我都在逐步尝试后面有了新的实践体会会再来分享。