第 4 章 · 03 min_volatility


文档摘要

第 4 章 · 03 minvolatility 本节摘要:本节详解 ——求全局最小方差组合(Global Minimum Variance, GMV)。它不依赖期望收益 μ,只在约束下最小化组合方差 ,因此是「最保守」的均值-方差组合。本节拆解它的源码实现:目标函数是 ,加上「权重和为 1」的约束即可,相比 maxsharpe 不需要变量替换,因此与额外目标完全兼容。重点讲一个反直觉的实证发现——大量研究(Kritzman et al. 2010 等)表明,GMV 组合样本外常常跑赢 maxsharpe 组合,因为后者依赖极不稳定的 μ。这使得 在「没有可靠收益预测」时成为更稳的默认选择。本节还讲它与「长短最小方差」的搭配。

第 4 章 · 03 min_volatility

本节摘要:本节详解 EfficientFrontier.min_volatility——求全局最小方差组合(Global Minimum Variance, GMV)。它不依赖期望收益 μ,只在约束下最小化组合方差 wᵀ Σ w,因此是「最保守」的均值-方差组合。本节拆解它的源码实现:目标函数是 objective_functions.portfolio_variance,加上「权重和为 1」的约束即可,相比 max_sharpe 不需要变量替换,因此与额外目标完全兼容。重点讲一个反直觉的实证发现——大量研究(Kritzman et al. 2010 等)表明,GMV 组合样本外常常跑赢 max_sharpe 组合,因为后者依赖极不稳定的 μ。这使得 min_volatility 在「没有可靠收益预测」时成为更稳的默认选择。本节还讲它与「长短最小方差」的搭配。

内容来源:原项目源码 pypfopt/efficient_frontier/efficient_frontier.pypypfopt/objective_functions.py、文档 docs/MeanVariance.rstdocs/UserGuide.rstcookbook/2-Mean-Variance-Optimisation.ipynb,汉化并套用体系化模板。

学习目标

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

  1. min_volatility()全局最小方差组合
  2. 解释它为何不需要 μ(只优化方差)。
  3. 对比它与 max_sharpe样本外表现上的差异。
  4. 知道它与额外目标完全兼容(无变量替换)。
  5. EfficientFrontier(None, S) + min_volatility 跑「纯风险优化」。

一、全局最小方差组合

在「收益-风险」平面上,有效前沿是一条向右上的曲线。这条曲线上最左边的点(风险最小的点)就是全局最小方差组合(GMV)——它在所有可行组合里方差最小。

minimize wᵀ Σ w (组合方差) subject to wᵀ 1 = 1 (权重和为 1) weight_bounds (边界约束)

注意:目标里没有 μ。GMV 完全由协方差矩阵 Σ 决定,与期望收益无关。这是它与 max_sharpe 最大的区别。

💡 核心心法:GMV 是「不求最高收益,只求最稳」的组合。它放弃了对 μ 的依赖——而 μ 恰恰是均值-方差优化里最难估、最不稳定的输入。这种「主动放弃不可靠输入」的设计,让 GMV 在样本外往往表现更稳。

二、源码逐行解析

打开 efficient_frontier.py,定位 min_volatility(源码 195-211 行):

def min_volatility(self): """ Minimise volatility. Returns OrderedDict of asset weights. """ self._objective = objective_functions.portfolio_variance( self._w, self.cov_matrix ) for obj in self._additional_objectives: self._objective += obj self.add_constraint(lambda w: cp.sum(w) == 1) return self._solve_cvxpy_opt_problem()

极其简洁:

  1. 目标:objective_functions.portfolio_variance(w, Σ)——查 objective_functions.py,它就是 cp.quad_form(w, Σ, assume_PSD=True),即 wᵀ Σ w
  2. 累加额外目标:把 add_objective 加的所有项 += 到主目标上。这是 min_volatility 与额外目标完全兼容的关键(对比 max_sharpe 的变量替换会破坏这种兼容)。
  3. 唯一硬约束:cp.sum(w) == 1(权重和为 1)。注意 weight_bounds 已经在构造时由 _map_bounds_to_constraints 转成 w >= lowerw <= upper 加入约束列表了。
  4. 求解:委托给父类的 _solve_cvxpy_opt_problem,cvxpy 用默认求解器解这个标准凸二次规划。

💡 为何这么简单:相比 max_sharpe 的变量替换凸化,min_volatility 本身就是标准凸二次规划——目标 wᵀ Σ w 是凸的(Σ 半正定),约束都是线性的。无需任何数学技巧,直接交给 cvxpy。

三、portfolio_variance 目标函数

打开 objective_functions.py,看 portfolio_variance(源码 64-81 行):

def portfolio_variance(w, cov_matrix): variance = cp.quad_form(w, cov_matrix, assume_PSD=True) return _objective_value(w, variance)

cp.quad_form(w, Σ, assume_PSD=True) 是 cvxpy 的二次型原子函数,计算 wᵀ Σ wassume_PSD=True 跳过 PSD 检查以加速(Σ 已经由 risk_models 保证 PSD)。

_objective_value(w, obj) 是个辅助函数:

  • w 是 np.ndarray(已求解):返回 obj.value(标量)。
  • wcp.Variable(未求解):返回 obj(cvxpy 表达式)。

这种「同一个函数,既能算具体值、又能构造优化表达式」的设计,让目标函数既可在优化器内部用,也可在外部独立计算某个权重组的方差。

四、为何样本外常胜

这是一个反直觉但被反复验证的实证发现。docs/UserGuide.rst 明确写:

有大量研究表明,最小方差组合(ef.min_volatility())样本外持续跑赢最大夏普组合——即便用夏普比率来衡量——因为预测期望收益太困难。

docs/RiskModels.rst 也引用 Kritzman, Page & Turkington (2010) 的研究:

最小方差组合(不提供期望收益直接优化)实际上样本外表现好得多。

直觉解释:

维度 max_sharpe min_volatility
依赖 μ 是(放大 μ 错误)
在前沿上的位置 切点(最尖端,对输入敏感) 最左端(最稳)
μ 估计噪声的影响 极大(切点漂移)
样本外稳健性

max_sharpe 在找前沿的「最尖端」——那里对 μ、Σ 的微小变化极度敏感,输入稍有偏差,切点位置剧烈漂移。而 GMV 在前沿的「最左端」——它只依赖 Σ(相对 μ 更可估),位置稳定。

💡 作者的隐藏建议:UserGuide 的「改进表现」一节明确推荐:若回测不理想,试着「放弃期望收益,只用 min_volatility,或用 HRP」。这是经验之谈,不是教科书教条。

五、用法示例

5.1 标准 GMV

from pypfopt import EfficientFrontier, risk_models S = risk_models.CovarianceShrinkage(df).ledoit_wolf() ef = EfficientFrontier(None, S) # μ=None,只优化方差 ef.min_volatility() weights = ef.clean_weights() ef.portfolio_performance(verbose=True)

输出:

Annual volatility: 18.5% # 注意没有 expected return 与 sharpe

因为 μ=None,portfolio_performance 只输出波动率,不算收益与夏普。

5.2 长/短 GMV

cookbook 2 的招牌示例——允许做空的 GMV:

S = risk_models.CovarianceShrinkage(prices).ledoit_wolf() ef = EfficientFrontier(None, S, weight_bounds=(None, None)) ef.min_volatility() weights = ef.clean_weights() ef.portfolio_performance(verbose=True)

weight_bounds=(None, None) 等价于 (-1, 1),允许任意多空。这是「研究显示样本外好」的那类组合。

5.3 GMV + L2 正则

由于 min_volatility 与额外目标完全兼容,可直接加 L2 正则:

from pypfopt import objective_functions ef = EfficientFrontier(None, S) ef.add_objective(objective_functions.L2_reg, gamma=1) ef.min_volatility()

这会减少零权重,让组合更分散(详见第 5 章第 02 节)。

5.4 GMV + 行业约束

ef = EfficientFrontier(None, S) ef.add_sector_constraints(sector_mapper, sector_lower, sector_upper) ef.min_volatility()

无需担心 max_sharpe 那种「变量替换破坏额外目标」的问题。

六、min_volatility 与 max_sharpe 的对比

维度 min_volatility max_sharpe
目标 最小化 wᵀ Σ w 最大化 (wᵀ μ - R_f)/σ
需要 μ
在前沿上位置 最左端(GMV) 切点
凸化技巧 无(本就是凸 QP) 变量替换
与额外目标兼容 完全兼容 不兼容(警告)
输入敏感度 低(只依赖 Σ) 高(μ 与 Σ 都敏感)
样本外稳健性
推荐度 实证更稳 直觉更美

💡 务实选择:如果你没有自研的收益预测模型(多数散户与机构都没有稳定可盈利的 α),min_volatility 几乎总是比 max_sharpe 更好的默认。它会牺牲一些样本内「理论最优」,换样本外的稳健性。

本节要点回顾

  1. 目标:最小化 wᵀ Σ w,得全局最小方差组合(GMV),位于有效前沿最左端。
  2. 不需要 μ:可传 EfficientFrontier(None, S),只优化方差;portfolio_performance 只输出波动率。
  3. 源码简洁:目标 portfolio_variance + 约束 sum(w)==1,本就是凸 QP,无需凸化技巧。
  4. 与额外目标完全兼容:无变量替换,L2 正则、行业约束、交易成本都正常工作。
  5. 样本外常胜:研究(Kritzman 2010 等)表明 GMV 样本外常跑赢 max_sharpe,因为它不依赖极不稳定的 μ。
  6. 务实默认:无可靠 μ 时,优先 min_volatility 或 HRP,而非 max_sharpe

下一节,我们看 efficient_riskefficient_return——给定目标波动求最大收益、给定目标收益求最小风险,二者描出整条有效前沿。


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