我正在使用 cvxpy 进行简单的投资组合优化。
我实现了以下虚拟代码
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 = [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))
ret = mu.T*w
lambda_ = Parameter(sign='positive')
lambda_ = 5
risk = quad_form(w, Sigma)
constraints = [sum_entries(w) == 1, w >= 0, sum_entries(abs(w-orig_weight)) <= 0.750]
prob = Problem(Maximize(ret - lambda_ * risk), constraints)
prob.solve()
print 'Solver Status : ',prob.status
print('Weights opt :', w.value)
我限制完全投资,只做多,营业额<= 75%。但是,我想将营业额用作“软”约束,因为求解器将尽可能少地使用但尽可能多地使用,目前求解器将几乎完全最大化营业额。
我基本上想要这样的东西,它是凸的并且不违反 DCP 规则
sum_entries(abs(w-orig_weight)) >= 0.05
我认为这应该设置一个最小阈值(此处为 5%),然后使用尽可能多的营业额,直到找到可行的解决方案。
我尝试将我的目标函数重写为
prob = Problem(Maximize(lambda_ * ret - risk - penalty * max(sum_entries(abs(w-orig_weight))+0.9,0)) , constraints)
其中惩罚是例如2,我的约束对象仍然看起来像
constraints = [sum_entries(w) == 1, w >= 0, sum_entries(abs(w-orig_weight)) <= 0.9]
我从未使用过软约束,任何解释都将不胜感激。
编辑:中间解决方案
from cvxpy import *
import numpy as np
np.random.seed(1)
n = 10
Sigma = np.random.randn(n, n)
Sigma = Sigma.T.dot(Sigma)
w = Variable(n)
mu = np.abs(np.random.randn(n, 1))
ret = mu.T*w
risk = quad_form(w, Sigma)
orig_weight = [0.15,0.2,0.2,0.2,0.2,0.05,0.0,0.0,0.0,0.0]
min_weight = [0.35,0.0,0.0,0.0,0.0,0,0.0,0,0.0,0.0]
max_weight = [0.35,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]
lambda_ret = Parameter(sign='positive')
lambda_ret = 5
lambda_risk = Parameter(sign='positive')
lambda_risk = 1
penalty = Parameter(sign='positive')
penalty = 100
penalized = True
if penalized == True:
print '-------------- RELAXED ------------------'
constraints = [sum_entries(w) == 1, w >= 0, w >= min_weight, w <= max_weight]
prob = Problem(Maximize(lambda_ * ret - lambda_ * risk - penalty * max_entries(sum_entries(abs(w-orig_weight)))-0.01), constraints)
else:
print '-------------- HARD ------------------'
constraints = [sum_entries(w) == 1, w >= 0, w >= min_weight, w <= max_weight, sum_entries(abs(w-orig_weight)) <= 0.40]
prob = Problem(Maximize(lambda_ret * ret - lambda_risk * risk ),constraints)
prob.solve()
print 'Solver Status : ',prob.status
print('Weights opt :', w.value)
all_in = []
for i in range(n):
all_in.append(np.abs(w.value[i][0] - orig_weight[i]))
print 'Turnover : ', sum(all_in)
上面的代码将强制增加 item[0] 的权重,这里是 +20%,以保持 sum() =1 约束,必须通过 -20% 的减少来抵消,因此我知道它需要至少需要 40% 的营业额才能做到这一点,如果使用 penalized = False 运行代码,则必须对 <= 0.4 进行硬编码,任何小于该值的代码都会失败。penalized = True 案例将找到 40% 的最低要求营业额并解决优化问题。我还没有弄清楚如何在宽松的情况下设置最小阈值,即至少设置 45%(如果需要,可以设置更多)。
我在第 37 页的第 4.6 章中找到了有关该问题的一些解释。