第 5 章 · 04 均值方差优化


文档摘要

第 5 章 · 04 均值方差优化 本节摘要:本节讲现代投资组合理论的基石——马科维茨均值方差优化(Mean-Variance Optimization, MVO)。1952 年马科维茨证明:组合方差不仅取决于各资产方差,还取决于资产间的协方差,因此可以通过分散配置把组合风险降到加权平均以下。本节讲清三个核心:组合方差的数学形式 ω⊤Σω、有效前沿的求解(给定目标收益求最小方差,或最大化夏普)、以及 Markowitz 诅咒——协方差估计极不稳定导致权重不可靠。代码用 scipy.optimize 求解,并对照 PyPortfolioOpt 库的简化用法。 内容来源:原项目 ,汉化并套用体系化模板。

第 5 章 · 04 均值方差优化

本节摘要:本节讲现代投资组合理论的基石——马科维茨均值方差优化(Mean-Variance Optimization, MVO)。1952 年马科维茨证明:组合方差不仅取决于各资产方差,还取决于资产间的协方差,因此可以通过分散配置把组合风险降到加权平均以下。本节讲清三个核心:组合方差的数学形式 ω⊤Σω、有效前沿的求解(给定目标收益求最小方差,或最大化夏普)、以及 Markowitz 诅咒——协方差估计极不稳定导致权重不可靠。代码用 scipy.optimize 求解,并对照 PyPortfolioOpt 库的简化用法。

内容来源:原项目 ch05/04_mean_variance_optimization.ipynb,汉化并套用体系化模板。

⚠️ 风险提示:均值方差优化对预期收益和协方差的估计极其敏感,「历史最优」组合往往是过拟合产物,实盘权重剧烈跳变。务必收缩估计或加稳健约束。

学习目标

阅读完本节,你应当能够:

  1. 写出组合方差公式 ω⊤Σω 并解释分散化原理。
  2. scipy.optimize.minimize 求解最小方差/最大夏普组合。
  3. 画出有效前沿并理解其含义。
  4. 解释 Markowitz 诅咒:为何历史最优权重不可靠。
  5. 知道 PyPortfolioOpt 库如何简化这一流程。

一、为什么分散化有效

直觉上,把鸡蛋放在多个篮子里风险更小。马科维茨把这个直觉数学化了:组合收益是各资产收益的加权和,但组合方差不是各资产方差的加权和——它还含协方差项:

\sigma^2_{\text{PF}} = \omega^\top \Sigma\, \omega

其中 ω 是权重向量,Σ 是协方差矩阵。展开看,组合方差由「自身方差项」和「交叉协方差项」组成。当资产间相关性 < 1 时,协方差项为负贡献,组合方差小于加权平均方差。这就是分散化的数学根源:相关越低,分散效果越好。

二、马科维茨优化问题

MVO 有两种等价的对偶形式:

  • 最小风险给定期望收益: min σ²PF = ω⊤Σω s.t. ω⊤μ = μ目标, ‖ω‖ = 1
  • 最大收益给定风险水平:镜像问题

实务中通常解第一个:扫一组目标收益,对每个解最小方差,得到一条「风险-收益」曲线,这就是有效前沿(efficient frontier)——前沿上的组合在任何风险水平下收益最高,或任何收益水平下风险最低。

三、用 scipy 求解

三个核心函数

import numpy as np from scipy.optimize import minimize periods_per_year = 52 # 周频 def portfolio_std(wt, rt=None, cov=None): """年化组合标准差""" return np.sqrt(wt @ cov @ wt * periods_per_year) def portfolio_returns(wt, rt, cov=None): """年化组合收益""" return (wt @ rt + 1) ** periods_per_year - 1 def portfolio_performance(wt, rt, cov): return portfolio_returns(wt, rt=rt), portfolio_std(wt, cov=cov)

最大夏普组合

最大化夏普 = 最小化负夏普,用 SLSQP 求解器,约束「权重绝对值之和 = 1」:

def neg_sharpe_ratio(weights, mean_ret, cov): r, sd = portfolio_performance(weights, mean_ret, cov) return -(r - rf_rate) / sd weight_constraint = {'type': 'eq', 'fun': lambda x: np.sum(np.abs(x)) - 1} def max_sharpe_ratio(mean_ret, cov, short=False): return minimize(fun=neg_sharpe_ratio, x0=x0, args=(mean_ret, cov), method='SLSQP', bounds=((-1 if short else 0, 1),) * n_assets, constraints=weight_constraint, options={'tol': 1e-10, 'maxiter': 10000})

bounds 控制能否做空:short=False 时权重 ∈ 0, 1,short=True 时 ∈ [-1, 1]。

有效前沿

扫一组目标收益,每个解一次最小方差:

def min_vol_target(mean_ret, cov, target, short=False): constraints = [{'type': 'eq', 'fun': lambda x: portfolio_returns(x, mean_ret) - target}, weight_constraint] bounds = ((-1 if short else 0, 1),) * n_assets return minimize(portfolio_std, x0=x0, args=(mean_ret, cov), method='SLSQP', bounds=bounds, constraints=constraints, options={'tol': 1e-10, 'maxiter': 1e4})

四、模拟随机组合验证

在求解前沿前,先用 Dirichlet 分布生成大量随机权重,画散点图直观感受风险-收益分布:

from numpy.random import dirichlet, choice def simulate_portfolios(mean_ret, cov, rf_rate, short=True): alpha = np.full(shape=n_assets, fill_value=0.05) weights = dirichlet(alpha=alpha, size=100000) # 10 万组随机权重 if short: weights *= choice([-1, 1], size=weights.shape) returns = (weights @ mean_ret.values + 1) ** periods_per_year - 1 std = (weights @ weekly_returns.T).std(1) * np.sqrt(periods_per_year) sharpe = (returns - rf_rate) / std return pd.DataFrame({'std': std, 'ret': returns, 'sharpe': sharpe}), weights

散点图上能清楚看到「最大夏普点」和「最小波动点」位于随机云的左上边界——它们就是有效前沿的端点。

五、Markowitz 诅咒

⚠️ 关键陷阱:MVO 对输入(μ 和 Σ)极其敏感。预期收益 μ 极难准确估计,协方差 Σ 略好但仍不稳。当资产高度相关时,Σ 的条件数飙升,求逆数值不稳,权重会出现极端的正负跳变(例如某资产今天 +30%、明天 -25%)。相关性越高,分散越需要,但权重越不可靠——这就是「Markowitz 诅咒」。

输入 估计可靠性 对权重的影响
均值收益 μ 极不可靠 主导权重方向,小扰动大跳变
协方差 Σ 中等 高相关时数值病态
无风险利率 rf 较可靠 仅影响夏普分母

实务对策:

  1. 收缩估计(Ledoit-Wolf):把 Σ 朝单位矩阵收缩,降条件数。
  2. 风险平价 / 等权:放弃均值,只基于风险配权,稳得多。
  3. Black-Litterman:用贝叶斯把「市场隐含均衡收益」当先验,叠加主观观点。
  4. 正则化约束:加权重上限、换手率约束、行业暴露约束。

六、PyPortfolioOpt 简化用法

PyPortfolioOpt 库把上述流程封装好,几行就能跑:

from pypfopt.efficient_frontier import EfficientFrontier from pypfopt import risk_models, expected_returns mu = expected_returns.mean_historical_return(prices, frequency=252) S = risk_models.sample_cov(prices, frequency=252) ef = EfficientFrontier(mu, S) weights = ef.max_sharpe() # 最大夏普组合 cleaned = ef.clean_weights() # 截断微小权重

risk_models 提供 Ledoit-Wolf 收缩、指数加权等多种协方差估计,expected_returns 提供 CAPM 收益率等。这套库与本系列另一份 PyPortfolioOpt 教程呼应,这里只是入门,深入用法见那篇。

本节要点回顾

  1. 分散化数学根源:组合方差 ω⊤Σω 含协方差项,相关性 <1 时组合方差小于加权平均。
  2. MVO 问题:给定期望收益求最小方差,或对偶地最大化夏普;扫描目标收益得到有效前沿。
  3. 求解:scipy.optimize.minimize + SLSQP,约束「权重绝对值和 = 1」,bounds 控制能否做空。
  4. Markowitz 诅咒:μ 难估、Σ 高相关时病态,权重剧烈跳变;实务用收缩、风险平价、Black-Litterman、约束稳健化。
  5. PyPortfolioOpt 把流程封装,几行出最大夏普组合,深入见专门教程。

下一节,我们看凯利公式——从胜率和赔率推导最优杠杆,理解「该用多大仓位」。


发布者: 作者: 灏天文库 转发
评论区 (0)
U