3. 非线性规划投资组合优化建模
问题设定与数据
选取 4 只资产(示例数据,年化收益率与协方差矩阵均为假设值,用于演示建模流程):
| 资产 | 预期年化收益 μ | 说明 |
|---|---|---|
| A 股票 | 0.12 | 高收益高波动 |
| B 股票 | 0.10 | 中高收益 |
| C 债券 | 0.05 | 低波动 |
| D 货币 | 0.03 | 近似无风险 |
协方差矩阵(年化,单位:方差/协方差):
Σ = [[0.0400, 0.0150, 0.0020, 0.0000],
[0.0150, 0.0300, 0.0015, 0.0000],
[0.0020, 0.0015, 0.0100, 0.0000],
[0.0000, 0.0000, 0.0000, 0.0005]]
马科维茨均值-方差模型:在给定目标收益 μp 下最小化组合方差,权重非负且和为 1。目标函数 wTΣw 关于 w 是二次型,属于非线性规划。
非线性规划模型构建
决策变量 w = (wA, wB, wC, wD),模型为:
min f(w) = w^T Σ w
s.t. μ^T w ≥ μ_target (收益约束)
Σ w_i = 1 (预算约束)
w_i ≥ 0 (不允许卖空)
目标函数是凸二次型(Σ 正定),约束为线性,因此是凸二次规划,局部最优即全局最优。求解时可用 scipy.optimize.minimize 的 SLSQP 方法,或直接调用 cvxpy 的二次规划接口。
求解实现(Python)
import numpy as np
from scipy.optimize import minimize
mu = np.array([0.12, 0.10, 0.05, 0.03])
Sigma = np.array([
[0.0400, 0.0150, 0.0020, 0.0000],
[0.0150, 0.0300, 0.0015, 0.0000],
[0.0020, 0.0015, 0.0100, 0.0000],
[0.0000, 0.0000, 0.0000, 0.0005]])
def solve_portfolio(mu_target):
n = len(mu)
def obj(w):
return w @ Sigma @ w
def obj_grad(w):
return 2 * Sigma @ w
cons = [
{'type': 'eq', 'fun': lambda w: np.sum(w) - 1, 'jac': lambda w: np.ones(n)},
{'type': 'ineq', 'fun': lambda w: mu @ w - mu_target, 'jac': lambda w: mu}
]
bounds = [(0, 1)] * n
w0 = np.ones(n) / n
res = minimize(obj, w0, jac=obj_grad, method='SLSQP',
bounds=bounds, constraints=cons,
options={'ftol': 1e-12, 'maxiter': 500})
return res
for target in [0.05, 0.08, 0.10]:
res = solve_portfolio(target)
w = res.x
ret = mu @ w
risk = np.sqrt(w @ Sigma @ w)
print(f"目标收益 {target:.2f} -> 实际收益 {ret:.4f}, 风险 {risk:.4f}")
print(" 权重:", np.round(w, 4))
预期输出(示例,实际数值以运行结果为准):目标收益 0.08 时,权重会向 A、B 倾斜,C、D 保留少量以分散风险;风险随目标收益提高而单调上升,这正是有效前沿的体现。
风险-收益权衡分析
通过扫描不同目标收益 μtarget(如 0.04 到 0.12,步长 0.005),记录每个解的风险 σp,即可绘制有效前沿。关键判读:
- 目标收益低于最小方差组合收益时,约束不起作用,解退化为最小方差组合;
- 目标收益越高,权重越集中于高收益资产,风险加速上升(前沿曲线变陡);
- 若某资产权重长期为 0,说明在当前参数下它被其他资产支配,可考虑剔除。
验证方法:检查求解器返回的 res.success 是否为 True;用 KKT 条件核对活跃约束;将目标收益提高 0.001,观察风险增量是否为正且递增,以确认前沿单调性。
协方差矩阵必须正定;若估计误差大,最优权重对输入敏感(误差放大效应),实际应用需做稳健性检验或加入权重上限约束。