4. 均值-方差模型详解:模型假设、目标函数与约束条件、二次规划求解方法、Python实现与可视化

均值-方差模型,说白了就是马科维茨那套理论。我当年刚接触量化时,觉得这玩意儿太理论了,直到自己真金白银往里砸,才发现——嗯,不懂这个,你连风险怎么量化都不知道。

这一章,咱们把它的底裤扒干净。从假设到求解,再到Python手撸一遍,最后画个漂亮的有效前沿。

4.1 模型假设:理想世界里的投资组合

任何模型都有前提。均值-方差模型也不例外。我个人习惯先列清楚假设,不然跑出来的结果你敢信?

  • 投资者是理性的:追求给定风险下的最大收益,或者给定收益下的最小风险。
  • 市场无摩擦:没有交易成本、没有税收、可以任意买卖(包括做空)。
  • 资产收益率服从正态分布:均值和方差就能完全描述收益特征。
  • 投资者用期望收益率和方差做决策:只看这两个指标,别的不管。
⚠️ 我曾经踩过的坑: 现实中收益率根本不服从正态分布。尾部风险、肥尾效应,这些模型里没考虑。所以用均值-方差算出来的最优组合,只能当参考,别全信。

4.2 目标函数与约束条件:数学怎么描述“最优”?

咱们要解决的问题是:给定N个资产,怎么分配权重,让组合在风险最小的情况下收益最大?

数学上,目标函数长这样:

min  σ²_p = w^T Σ w
s.t. w^T μ = μ_target
     w^T 1 = 1

解释一下:

  • w 是权重向量,每个资产投多少。
  • Σ 是协方差矩阵,衡量资产间怎么联动。
  • μ 是期望收益率向量。
  • μ_target 是你想要的目标收益。
  • 1 是全1向量,保证权重加起来等于1。

你想想看,这其实就是一个带约束的二次优化问题。目标函数是二次的(方差),约束是线性的。

💡 核心要点: 均值-方差模型本质上是在“收益”和“风险”之间做权衡。你每多要一点收益,就得承受更多风险。这个权衡曲线,就是有效前沿。

4.3 二次规划求解方法:怎么算?

求解这个优化问题,最经典的方法就是二次规划。Python里用scipy.optimize.minimize或者cvxopt都能搞定。

我个人习惯用scipy,因为接口更友好。求解步骤:

  1. 定义目标函数:组合方差。
  2. 定义约束条件:收益约束 + 权重和约束。
  3. 调用优化器,得到最优权重。

这里要注意:协方差矩阵必须是正定的,不然优化会出问题。我遇到过协方差矩阵奇异的情况,结果算出来的权重全是NaN……后来发现是数据里有重复的资产。

4.4 Python实现与可视化:动手撸代码

光说不练假把式。咱们用Python实现一个完整的均值-方差优化,并画出有效前沿。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.optimize import minimize

# 模拟数据:5个资产的收益率和协方差
np.random.seed(42)
n_assets = 5
mu = np.array([0.12, 0.10, 0.08, 0.06, 0.04])
Sigma = np.random.randn(n_assets, n_assets)
Sigma = Sigma @ Sigma.T  # 保证正定

# 目标函数:组合方差
def portfolio_variance(weights, Sigma):
    return weights.T @ Sigma @ weights

# 约束条件
def portfolio_return(weights, mu):
    return weights.T @ mu

# 优化:给定目标收益,最小化方差
def optimize_portfolio(mu_target, mu, Sigma):
    n = len(mu)
    constraints = [
        {'type': 'eq', 'fun': lambda w: portfolio_return(w, mu) - mu_target},
        {'type': 'eq', 'fun': lambda w: np.sum(w) - 1}
    ]
    bounds = [(0, 1) for _ in range(n)]  # 不允许做空
    initial_guess = np.ones(n) / n
    result = minimize(portfolio_variance, initial_guess, args=(Sigma,),
                      method='SLSQP', bounds=bounds, constraints=constraints)
    return result.x

# 计算有效前沿
target_returns = np.linspace(0.04, 0.12, 50)
frontier_vols = []
frontier_weights = []

for r in target_returns:
    w = optimize_portfolio(r, mu, Sigma)
    vol = np.sqrt(portfolio_variance(w, Sigma))
    frontier_vols.append(vol)
    frontier_weights.append(w)

# 可视化
plt.figure(figsize=(10, 6))
plt.plot(frontier_vols, target_returns, 'b-', linewidth=2, label='有效前沿')
plt.scatter(np.sqrt(np.diag(Sigma)), mu, c='red', marker='o', label='单个资产')
plt.xlabel('风险(标准差)')
plt.ylabel('期望收益率')
plt.title('均值-方差有效前沿')
plt.legend()
plt.grid(True)
plt.show()
💡 小技巧: 画有效前沿时,记得把单个资产的点也标出来。这样你能直观看到——组合确实比单个资产更“划算”。

4.5 知识体系结构图

下面这张图,把本章的核心逻辑串起来了。我建议你多看几遍,理解每个模块之间的关系。

均值-方差模型知识体系 模型假设 目标函数 约束条件 二次规划求解 Python实现 可视化(有效前沿)

4.6 避坑指南:我踩过的那些坑

最后,分享几个实战中容易翻车的地方:

  • 协方差矩阵不稳定:历史数据算出来的协方差,未来可能完全不一样。我建议用滚动窗口或者收缩估计。
  • 权重过于集中:有时候优化结果会把大部分权重给一个资产。这时候要加个分散度约束。
  • 忽略交易成本:频繁调仓会吃掉收益。我一般会在目标函数里加个惩罚项。
⚠️ 重要提醒: 均值-方差模型是基础,但不是万能药。它假设收益率是正态分布,但市场经常给你“惊喜”。用的时候,心里要有数。

好了,这一章就到这儿。代码拿回去跑一跑,看看有效前沿长什么样。下一章咱们聊聊更实用的东西——Black-Litterman模型,怎么把主观观点融入优化里。


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