范数约束组合优化:用权重范数上限间接实现收缩
Jagannathan & Ma(2003)的著名发现:给组合优化加约束——哪怕是'错误'的约束——往往改善样本外表现,因为约束数学上等价于对协方差矩阵做收缩。本文 30 资产实验实测:T=120 天时无约束样本 GMV 真实波动率 14.17%、杠杆 2.6 倍,加上 ‖w‖₁≤1.5 降到 13.59%——U 形曲线在 1.5~2.0 触底,太紧(long-only 14.31%)和太松都不行。与 Ledoit-Wolf 收缩的等价性同样实测:T=60 时范数约束(14.21%)与 LW 收缩(14.37%)几乎打平,两条完全不同的药方殊途同归;T=504 时两者都自动退场。Bootstrap 权重稳定性:无约束权重标准差 6.65pp,L1 约束砍到 3.09pp,L2 约束 2.00pp——换手率直接受益。L1 上限还有副产品:‖w‖₁≤1 等价 long-only 且自动稀疏化(30 资产只留 10 个非零)。诚实边界:约束上限 c 是要调的超参(不如 LW 的 δ* 有解析解)、约束绑定时最优性损失是结构性的、对期望收益误差无能为力。
Ledoit-Wolf 那篇的药方是修输入:把样本协方差往结构化目标拉一把,再喂给优化器。这一篇讲一个看起来完全不同、实际上殊途同归的药方:输入不动,在优化问题上直接加权重范数约束。
就多了一行 ,限制总杠杆不超过 。这行约束的深意来自 Jagannathan & Ma(2003)一个反直觉的发现:给优化器加约束——哪怕这个约束在真实参数下是”错误”的——往往改善样本外表现。他们证明了原因:带约束的优化在数学上等价于对协方差矩阵做了一次隐式收缩。
先上本文 30 资产实验的判决数字(T=120 天估计窗口,40 次蒙特卡洛中位数,“真实波动率”指用真实协方差评估的组合波动率):
| 组合 | 样本外真实波动率 | 总杠杆 |
|---|---|---|
| 无约束样本 GMV | 14.17% | 2.59 |
| ‖w‖₁ ≤ 1.5 | 13.59% | 1.50 |
| ‖w‖₁ ≤ 1(等价 long-only) | 14.31% | 1.00 |
| 等权 | 17.09% | 1.00 |
| 理论最优(真实协方差) | 12.26% | 1.83 |
砍掉 1 倍多杠杆,波动率反而降了 0.6 个百分点。优化器声称那 2.6 倍杠杆能降低风险——数据不够的时候,这个声称是幻觉。
一、约束为什么等价于收缩#
Jagannathan-Ma 的核心结果值得完整写出来。考虑加了空头约束()的最小方差问题,其 KKT 条件可以整理成:约束解等于在修改后的协方差矩阵上做无约束优化:
其中 是空头约束的拉格朗日乘子,只在约束绑定()的资产上非零。翻译成人话:优化器想做空资产 ,通常是因为 里它和某些资产的协方差被高估了(显得是绝佳对冲工具);禁止做空,等价于把它与所有资产的协方差整体调低 ——恰好是朝着修正高估的方向。约束在替你做了一次数据驱动的、只作用于”最可疑元素”的收缩。
L1 范数约束是这个逻辑的连续化推广(DeMiguel et al. 2009)。:
- 时(配合 )恰好等价于 long-only;
- 时允许总空头敞口 ,是”部分放松的空头约束”;
- 时退化回无约束。
一个旋钮在”完全信任优化器”和”完全不信”之间连续滑动——和 LW 收缩强度 δ 的角色一模一样,只是作用在权重端而非输入端。
二、U 形曲线:上限太紧太松都不行#
对 L1 上限 做扫描(T=120,40 次 MC):

左图是本文最重要的图。 从 1.0 放松到 5.0,样本外真实波动率先降后升:
- c=1.0(long-only):14.31%。约束太紧——真实最优解需要 1.83 倍杠杆做适度对冲,long-only 把有价值的空头也禁了;
- c=1.5
2.0:13.5813.59%,谷底。放开适度空头空间,同时掐死极端对冲对赌; - c≥3:14.17%,与无约束合流。右图显示无约束解的自然杠杆是 2.59,上限比它松就不再绑定,形同虚设。
右图还有个值得注意的细节: 在 1.0~2.0 之间时实际杠杆严格贴着上限走——约束全程绑定,说明优化器”想要”的杠杆远超健康水平,是约束在持续发力。
核心代码#
范数约束最小方差用 SLSQP 十几行就能写:
import numpy as np
from scipy.optimize import minimize
def gmv_norm(S, l1_cap=None, l2_cap=None):
"""最小方差组合,sum(w)=1,可选 L1/L2 范数约束"""
N = len(S)
cons = [{'type': 'eq', 'fun': lambda w: w.sum() - 1}]
if l1_cap is not None: # ||w||_1 <= c:总杠杆上限
cons.append({'type': 'ineq',
'fun': lambda w: l1_cap - np.abs(w).sum()})
if l2_cap is not None: # ||w||_2 <= c:集中度上限
cons.append({'type': 'ineq',
'fun': lambda w: l2_cap**2 - (w**2).sum()})
res = minimize(lambda w: w @ S @ w, np.ones(N)/N,
jac=lambda w: 2 * S @ w,
constraints=cons, method='SLSQP',
options={'maxiter': 500, 'ftol': 1e-12})
return res.x
# 使用:T=120 天样本协方差 + L1 上限 1.5
S_hat = np.cov(returns.T) * 252
w = gmv_norm(S_hat, l1_cap=1.5)python生产环境建议把 L1 约束改写成 LP/QP 标准形式( 拆正负部)交给 cvxpy/OSQP,SLSQP 在 N 上百时会慢且偶尔不收敛。本文 N=30 用 SLSQP 足够。
三、权重形态:约束顺手送了稀疏化#
同一份 T=120 数据下三种解的权重条形图:

无约束解(上)是熟悉的病态形态:±20% 的多空对赌铺满整个截面,其中大部分是优化器在高相关资产间玩对冲的采样噪声。L1≤1.5(中)把极端权重全部压扁。最有意思的是 L1≤1(下):30 个资产里 20 个权重精确为零。
这不是巧合,是 L1 几何的固有性质——和 Lasso 回归把系数压到精确零是同一个机制(约束区域的顶点在坐标轴上)。对组合管理这是白送的礼物:持仓从 30 只缩到 10 只,交易成本、监控成本、清算冲击全部受益。L2 约束()没有这个性质,它把权重均匀往等权拉但不清零——两种范数各有用途:L1 管杠杆和稀疏性,L2 管集中度。
四、与 Ledoit-Wolf 收缩的正面对决#
理论说范数约束≈隐式收缩,那就直接对比。四种方法,T 从 60 扫到 504(30 次 MC 中位数):

| T | 无约束 | ‖w‖₁≤1.6 | LW 收缩 | 收缩+范数 |
|---|---|---|---|---|
| 60 | 17.08% | 14.21% | 14.37% | 14.11% |
| 120 | 14.02% | 13.49% | 13.58% | 13.44% |
| 252 | 13.04% | 13.03% | 12.96% | 13.01% |
| 504 | 12.64% | 12.76% | 12.62% | 12.76% |
三个观察:
- T=60 时两条药方几乎打平(14.21% vs 14.37%)。一个修输入、一个约束输出,数学上的等价性在数据上兑现了;
- 叠加有一点点增益但不叠加翻倍(14.11%)——因为两者修的是同一种病(采样误差被优化器放大),重复吃药边际收益递减。这和收缩+重抽样的叠加逻辑不同:那两个修的是不同环节;
- T=504 时范数约束出现轻微反噬(12.76% vs 无约束 12.64%)。数据充足后无约束解的 2 倍杠杆是真实信息支撑的,固定上限 1.6 开始误伤。注意 LW 没有这个问题——δ* 随 T 自动衰减到 0.07 主动退场,而 是死的。这是范数约束相对 LW 最实质的劣势:上限不会自己退场。
五、权重稳定性:换手率的直接红利#
对同一份数据做 40 次 bootstrap 重抽样,看权重对输入扰动的敏感度:

| 方法 | 单资产权重 bootstrap 标准差 |
|---|---|
| 无约束 | 6.65 pp |
| ‖w‖₁ ≤ 1.5 | 3.09 pp |
| ‖w‖₂ ≤ 0.35 | 2.00 pp |
右图抽了同板块两个高相关资产:无约束解的权重在(+20%, −15%)和(−10%, +15%)之间大幅摇摆——这就是 NCO 那篇讲的对冲对赌在 bootstrap 下的现形,同一对资产这次做多 A 空 B、下次做多 B 空 A,纯由采样噪声决定方向。L1 约束把这团散点压缩到原点附近的小区域。
工程含义直接:权重对输入的敏感度就是月度再平衡的换手率。权重标准差砍一半,调仓换手大致砍一半,交易成本是每年实打实的基点。
六、诚实边界#
上限 c 是超参,没有解析解。 LW 收缩最漂亮的地方是 δ* 从数据里算出来、零调参;范数约束的 c 要么拍(1.5~2.0 是文献常见区间),要么交叉验证(小心用同一段数据调参又评估的过拟合)。DeMiguel et al.(2009)给了 c 的交叉验证框架,但工程上”拍一个 1.6 然后不动”往往就够——U 形曲线的谷底相当平坦。
约束绑定的最优性损失是结构性的。 T 大时固定 c 会误伤真实杠杆需求(上面 T=504 的反噬)。如果你的策略数据充足(T/N > 10),范数约束的价值大幅缩水,直接用收缩就好。粗略分工:T/N < 3 时范数约束几乎必赚;3~10 看情况;>10 让位给收缩。
只救协方差端,不救期望收益。 本文全程是最小方差组合。一旦把误差大一个数量级的期望收益放进目标函数,范数约束依然有帮助(它限制了优化器对任何输入误差的放大),但救不了根本——均值端要配自己的收缩。
约束不是免费的风控。 ‖w‖₁≤1.5 限制的是权重杠杆,不是风险杠杆——低波动资产上 1.5 倍权重杠杆的风险敞口可能远小于高波动资产满仓。如果你要控制的是风险预算而非名义杠杆,约束应该写在 或边际风险贡献上,那是另一个问题(风险平价的地盘)。
七、收尾:三条修病路线的全景#
到这篇为止,“优化器是误差最大化器”这个病已经有了三条完整的修病路线:
- 修输入:LW 收缩、MP 谱裁剪、Bayes-Stein 均值收缩;
- 修问题结构:NCO 分层、Michaud 重抽样;
- 修输出:本篇的范数约束——直接掐住权重不许放飞。
三条路线不互斥,但也不是全叠加就最好——它们大部分在修同一种病,叠加的边际收益递减。实务的常见配方是”收缩 + 一个温和的 L1 上限”:收缩管统计,范数管兜底,各出一半力。
本文实验:N=30 资产、单市场因子 + 3 板块因子 + 特质波动的真实协方差结构,理论最优 GMV 波动率 12.26%。所有”样本外波动率”均指在真实协方差下评估的组合波动率(消除评估噪声),蒙特卡洛 30~40 次取中位数。优化用 scipy SLSQP,解析梯度。