4. 权重法求解:线性加权法、目标规划法在投资组合中的应用与局限性
说到多目标优化,很多人第一反应就是「给每个目标加个权重,然后求和」。嗯,这确实是最直观的思路。我刚开始做量化的时候,也是这么干的。但后来发现,事情没那么简单。
今天我们就来聊聊两种最经典的权重法:线性加权法和目标规划法。它们在实际投资组合中怎么用?坑在哪里?我踩过的雷,你最好别踩。
4.1 线性加权法:最朴素的多目标处理方式
线性加权法的思路很简单:给每个目标函数分配一个权重,然后加起来变成一个单目标问题。
数学上长这样:
min w₁ * f₁(x) + w₂ * f₂(x) + ... + wₙ * fₙ(x)
s.t. x ∈ S
其中 wᵢ ≥ 0,且 Σwᵢ = 1。
在投资组合里,我们通常有两个目标:最大化收益和最小化风险。写成加权形式就是:
min -λ * E(R) + (1-λ) * σ²
s.t. Σwᵢ = 1, wᵢ ≥ 0
这里的 λ 就是权重,从0到1变化。λ=1 时只关注收益,λ=0 时只关注风险。
关键点:改变 λ 值,就能得到一组不同的投资组合。把这些组合画在风险-收益图上,就是那条著名的「有效前沿」。
我个人习惯用 Python 快速扫一遍 λ 从0到1的效果。代码大概长这样:
import numpy as np
from scipy.optimize import minimize
def weighted_portfolio(returns, cov, lambda_):
n = len(returns)
def objective(w):
ret = -lambda_ * np.sum(w * returns)
risk = (1 - lambda_) * np.sqrt(w @ cov @ w)
return ret + risk
constraints = ({'type': 'eq', 'fun': lambda w: np.sum(w) - 1})
bounds = [(0, 1) for _ in range(n)]
result = minimize(objective, x0=np.ones(n)/n,
bounds=bounds, constraints=constraints)
return result.x
# 扫一遍 lambda
lambdas = np.linspace(0, 1, 20)
portfolios = [weighted_portfolio(returns, cov, l) for l in lambdas]
跑完之后,你就能看到一条漂亮的曲线。但这里有个坑——权重怎么定?
⚠ 避坑指南:我曾经在一个项目中,拍脑袋定了 λ=0.6,觉得「收益优先一点」。结果回测出来夏普比率惨不忍睹。后来才发现,不同资产类别的收益和风险量级差太多,同样的 λ 值效果天差地别。
说白了,线性加权法有两个硬伤:
- 权重主观性太强——你定 λ=0.5 和 λ=0.6,结果可能完全不同
- 无法处理非凸问题——如果帕累托前沿不是凸的,加权法根本找不到某些最优解
你想想看,如果两个目标之间存在严重的冲突(比如收益和回撤),加权法只能给出一个「折中」,但没法告诉你「哪个折中更好」。
4.2 目标规划法:先定目标,再找方案
目标规划法的思路不太一样。它不搞「加权求和」,而是先给每个目标设定一个「理想值」,然后想办法让实际值尽量靠近这个理想值。
数学形式:
min Σ (dᵢ⁺ + dᵢ⁻)
s.t. fᵢ(x) - dᵢ⁺ + dᵢ⁻ = targetᵢ
dᵢ⁺, dᵢ⁻ ≥ 0
x ∈ S
其中 dᵢ⁺ 是超出目标的部分,dᵢ⁻ 是未达到目标的部分。我们想最小化这些偏差的总和。
在投资组合里,比如你希望年化收益达到 15%,最大回撤不超过 10%。那就可以写成:
min d₁⁻ + d₂⁺
s.t. E(R) + d₁⁻ ≥ 0.15
MaxDrawdown - d₂⁺ ≤ 0.10
d₁⁻, d₂⁺ ≥ 0
Σwᵢ = 1, wᵢ ≥ 0
这里 d₁⁻ 表示收益没达到 15% 的缺口,d₂⁺ 表示回撤超过 10% 的部分。我们想让这两个「遗憾」尽量小。
💡 实战技巧:我在做 FOF 组合时,经常用目标规划法。因为客户会直接说「我要年化8%以上,最大回撤不超过5%」。这种场景下,目标规划法比加权法更直观——客户能理解「目标没达到,差了多少」。
目标规划法还有一个变种叫分层目标规划。就是给目标排个优先级,先保证最重要的目标,再考虑次要的。
比如:
- 第一优先级:风险不能超过某个阈值(这是底线)
- 第二优先级:在满足风险约束下,尽量提高收益
- 第三优先级:如果还有余地,降低换手率
代码实现也不复杂:
from scipy.optimize import linprog
# 第一优先级:风险约束
c1 = [0] * n + [1] # 最小化风险偏差
A_ub = [[...]] # 风险约束矩阵
b_ub = [risk_limit]
res1 = linprog(c1, A_ub=A_ub, b_ub=b_ub)
# 第二优先级:在风险约束下最大化收益
c2 = [-returns] # 最大化收益
constraints = [...] # 加上第一优先级的结果作为约束
res2 = linprog(c2, constraints=constraints)
但目标规划法也有自己的问题:
- 目标值怎么定?定得太高,永远达不到;定得太低,没有挑战性
- 优先级冲突时怎么办?有时候低优先级的目标会完全被牺牲掉
⚠ 我曾经踩过的坑:有一次做多资产配置,我把「控制回撤」设为第一优先级,「提高收益」设为第二优先级。结果优化出来的组合全是债券,收益低得可怜。后来我加了第三优先级「最低收益要求」,才把权益仓位拉回来。
4.3 两种方法的对比与选择
说了这么多,到底什么时候用加权法,什么时候用目标规划法?
| 维度 | 线性加权法 | 目标规划法 |
|---|---|---|
| 核心思想 | 折中与权衡 | 逼近理想值 |
| 输入要求 | 权重 wᵢ | 目标值 targetᵢ |
| 输出形式 | 一个帕累托最优解 | 偏差最小的可行解 |
| 适用场景 | 目标可量化、权重可协商 | 有明确目标值、客户有偏好 |
| 主要局限 | 权重敏感、非凸失效 | 目标值主观、优先级僵化 |
我个人习惯是:先用加权法扫一遍帕累托前沿,看看有哪些可能的组合;再用目标规划法,根据客户的具体要求做微调。这样既能看到全局,又能满足个性化需求。
核心结论:权重法简单直观,但主观性太强。它们适合做「初步探索」和「快速原型」,但真正要落地到实盘,我建议结合更高级的方法(比如进化算法或贝叶斯优化)。
嗯,关于权重法就聊到这里。记住一点:没有完美的权重,只有合适的权衡。下次你遇到多目标优化问题,不妨先问问自己——我是想「折中」,还是想「逼近目标」?答案会帮你选对方法。