You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在CVXPY中定义软约束:投资组合优化场景的技术问询

在CVXPY中实现投资组合优化的软约束方案

针对你的投资组合优化场景,我来分享几种实用的软约束实现思路,直接结合你的现有代码来落地:

核心思路:将硬约束转化为"约束+惩罚"的形式

软约束的本质是允许约束被轻微违反,但违反的部分会作为惩罚项加入目标函数,让优化器在收益、风险和约束违反代价之间自动权衡。惩罚系数越大,约束越接近硬约束;系数越小,约束越容易被突破。

方案1:使用CVXPY内置函数快速实现软约束

我们可以直接利用pos()(取正值)、abs()等凸函数,把约束的违反量转化为惩罚项,加到原目标函数中。以下是修改后的完整代码:

from cvxpy import *
import numpy as np

np.random.seed(1)
n = 10
Sigma = np.random.randn(n, n)
Sigma = Sigma.T.dot(Sigma)  # 构造正定协方差矩阵
orig_weight = np.array([0.15,0.25,0.15,0.05,0.20,0,0.1,0,0.1,0])
w = Variable(n)
mu = np.abs(np.random.randn(n, 1))  # 随机生成预期收益

# 原目标:最大化收益 - 风险惩罚
lambda_ = 5  # 风险厌恶系数
ret = mu.T @ w
risk = quad_form(w, Sigma)

# ---------------------- 软约束相关定义 ----------------------
# 1. 资金全投约束:sum(w) == 1 → 允许偏差,惩罚偏差的绝对值
penalty_total = 10  # 总权重偏差的惩罚系数,越大越接近硬约束
dev_total = sum(w) - 1
penalty_total_term = penalty_total * abs(dev_total)

# 2. 无卖空约束:w >= 0 → 允许负权重,但惩罚负的部分
penalty_short = 20  # 卖空惩罚系数,越大越禁止卖空
penalty_short_term = penalty_short * sum(pos(-w))  # pos(-w)仅当w<0时取正值

# 3. 权重偏离约束:sum(abs(w-orig_weight)) <= 0.75 → 允许超过,惩罚超额部分
penalty_dev = 15  # 偏离原组合的惩罚系数
dev_deviation = sum(abs(w - orig_weight)) - 0.75
penalty_dev_term = penalty_dev * pos(dev_deviation)  # pos仅当超额时取正值

# 最终目标:最大化收益 - 风险惩罚 - 所有软约束惩罚
objective = Maximize(ret - lambda_ * risk - penalty_total_term - penalty_short_term - penalty_dev_term)

# 这里可以保留一些必须严格满足的硬约束(如果需要),比如完全禁止极端权重
constraints = []  # 若不需要硬约束可留空,也可以加w <= 0.5这类硬限制

# 求解
prob = Problem(objective, constraints)
prob.solve()

print("优化后的权重:", w.value.round(4))
print("总权重偏差:", (sum(w.value)-1).round(4))
print("卖空权重总和:", np.sum(np.minimum(w.value, 0)).round(4))
print("偏离原组合的L1范数:", np.sum(np.abs(w.value - orig_weight)).round(4))

方案2:引入辅助变量实现更灵活的软约束

如果需要对不同资产的约束违反设置差异化惩罚(比如某些资产卖空惩罚更重),可以引入辅助变量来拆解约束:

# 以无卖空软约束为例,给每个资产设置不同的卖空惩罚系数
penalty_short_per_asset = np.array([20, 30, 15, 25, 20, 10, 18, 22, 19, 21])
z = Variable(n)  # z[i]表示第i个资产允许的卖空额度
constraints = [w >= -z, z >= 0]  # w可以负,但不能小于-z
penalty_short_term = sum(penalty_short_per_asset * z)  # 每个资产的卖空惩罚单独计算

这种方式的优势是可以精细化控制每个约束的惩罚力度,适合对特定资产有特殊要求的场景。

参数调整技巧

  • 惩罚系数的大小需要根据业务场景调整:比如如果希望总权重尽可能接近1,就把penalty_total设大;如果几乎不能接受卖空,就把penalty_short调到很高。
  • 可以通过交叉验证或者网格搜索来找到最优的惩罚系数组合,平衡收益、风险和约束合规性。

内容的提问来源于stack exchange,提问作者ThatQuantDude

火山引擎 最新活动