第1章:均值-方差优化——马科维茨模型、有效前沿、最大夏普比率组合、约束条件处理

1.1 马科维茨模型:现代投资组合理论的基石

说起资产配置,绕不开一个人——马科维茨。他老人家在1952年提出的均值-方差模型,说白了就是一句话:别把所有鸡蛋放在一个篮子里,但怎么放,得算清楚

我刚开始做量化那会儿,觉得这模型太简单了。不就是算个期望收益和协方差矩阵嘛。后来在实盘中吃了亏,才明白它的精妙之处。

马科维茨模型的核心逻辑是这样的:

  • 收益用期望收益率衡量,越高越好
  • 风险用收益率的方差(或标准差)衡量,越低越好
  • 目标:在给定风险下最大化收益,或在给定收益下最小化风险

数学上,我们要求解这样一个优化问题:

min  w^T Σ w
s.t. w^T μ = μ_target
     sum(w) = 1
     w_i ≥ 0  (可选,不允许做空)

其中w是权重向量,Σ是协方差矩阵,μ是预期收益向量。嗯,这里要注意,协方差矩阵的估计质量直接决定了模型的好坏。我在项目中遇到过,用过去3年的数据算协方差,结果市场风格一变,模型立马失效。

关键点:马科维茨模型是静态的,它假设收益和风险是稳定的。但现实世界哪有这么简单?所以后面我们会讲动态调整。

1.2 有效前沿:那条最美的曲线

有效前沿是什么?你想想看,把所有可能的投资组合画在风险-收益平面上,那些在相同风险下收益最高、或相同收益下风险最低的点连起来,就是有效前沿。

它长什么样?是一条向左上方凸起的曲线。为什么?因为资产之间的相关性不是完美的,组合能带来分散化收益。

我习惯用Python来画这条曲线。代码其实不复杂:

import numpy as np
import matplotlib.pyplot as plt

def efficient_frontier(mu, sigma, num_portfolios=10000):
    n_assets = len(mu)
    results = np.zeros((3, num_portfolios))
    
    for i in range(num_portfolios):
        weights = np.random.random(n_assets)
        weights /= np.sum(weights)
        
        port_return = np.dot(weights, mu)
        port_risk = np.sqrt(np.dot(weights.T, np.dot(sigma, weights)))
        
        results[0, i] = port_return
        results[1, i] = port_risk
        results[2, i] = port_return / port_risk  # 夏普比率
    
    return results

这段代码随机生成权重,计算每个组合的收益和风险。跑个一万次,你就能看到有效前沿的轮廓了。不过说实话,随机采样效率不高,真正做研究时我会用凸优化直接求解。

实战技巧:有效前沿的左侧区域是无效的——同样的风险下,你明明可以拿到更高的收益。所以,我们只关注前沿上的点。

1.3 最大夏普比率组合:最优的那个点

有效前沿上有无数个点,哪个最好?这取决于你的风险偏好。但有一个点很特殊——最大夏普比率组合

夏普比率 = (组合收益 - 无风险利率) / 组合风险。它衡量的是每单位风险能带来多少超额收益。最大夏普比率组合,就是有效前沿上斜率最大的那个点。

怎么找?数学上,它是有效前沿与从无风险利率出发的射线的切点。代码实现也很直接:

def max_sharpe_portfolio(mu, sigma, rf=0.02):
    n = len(mu)
    
    # 用优化求解
    def neg_sharpe(weights):
        port_return = np.dot(weights, mu)
        port_risk = np.sqrt(np.dot(weights.T, np.dot(sigma, weights)))
        return -(port_return - rf) / port_risk
    
    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bounds = tuple((0, 1) for _ in range(n))
    
    result = minimize(neg_sharpe, 
                      n * [1./n], 
                      method='SLSQP',
                      bounds=bounds,
                      constraints=constraints)
    
    return result.x

我曾经用这个模型给一个FOF产品做配置,回测效果不错。但实盘时发现,最大夏普比率组合对输入参数特别敏感。预期收益稍微变一点,权重就天翻地覆。这就是所谓的“估计误差最大化”问题。

避坑指南:我曾经因为过度依赖最大夏普比率组合,导致换手率极高,交易成本吃掉了一大半收益。后来我学会了加约束条件,比如限制单个资产权重的上下限,或者限制行业集中度。

1.4 约束条件处理:让模型更接地气

纯数学上的马科维茨模型,允许你做空、允许你全仓一只股票。但现实中呢?

  • 公募基金通常不允许做空
  • 单个股票持仓不能超过10%
  • 行业配置不能偏离基准太多
  • 换手率要控制在合理范围

这些约束条件,说白了就是让模型从“理想”走向“现实”。处理起来也不复杂,在优化时加上bounds和constraints就行。

举个例子,假设我们要求:

  • 每个资产权重在5%~30%之间
  • 总权重为1
  • 不做空
bounds = tuple((0.05, 0.30) for _ in range(n))
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})

你想想看,加了这些约束后,有效前沿会怎样?它会向内收缩——因为可行域变小了。但换来的是更稳健、更可执行的组合。

我个人习惯,在实盘前至少加三类约束:

  1. 权重上下限:防止过度集中
  2. 行业暴露:控制风格漂移
  3. 换手率约束:降低交易成本

核心总结:均值-方差优化不是万能药,但它提供了一个清晰的框架。理解它,你就能看懂市面上80%的资产配置模型。后面的章节,我们会在这个基础上加入动态调整、风险平价、Black-Litterman等进阶方法。

知识体系图:本章核心逻辑

均值-方差优化知识体系 输入数据 预期收益 μ 输入数据 协方差矩阵 Σ 约束条件 权重上下限/行业限制 均值-方差优化求解 min w^T Σ w, s.t. w^T μ = μ_target 有效前沿 风险-收益最优曲线 最大夏普比率组合 最优风险调整收益 约束组合 实际可执行 核心目标:在风险与收益之间找到最优平衡

我的建议:刚开始学均值-方差优化,别急着上复杂模型。先用Excel或Python跑一个简单的两资产案例,把有效前沿画出来。亲眼看到那条曲线,比看一百页理论都管用。


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