我正在使用 cvxpy 来解决一些简单的投资组合优化问题。我无法理解的唯一约束是非零投资组合持有数量的基数约束。我尝试了两种方法,一种 MIP 方法和一种传统的凸方法。
这是一个有效的传统示例的一些虚拟代码。
import numpy as np
import cvxpy as cvx
np.random.seed(12345)
n = 10
k = 6
mu = np.abs(np.random.randn(n, 1))
Sigma = np.random.randn(n, n)
Sigma = Sigma.T.dot(Sigma)
w = cvx.Variable(n)
ret = mu.T*w
risk = cvx.quad_form(w, Sigma)
objective = cvx.Maximize(ret - risk)
constraints = [cvx.sum_entries(w) == 1, w>= 0, cvx.sum_smallest(w, n-k) >= 0, cvx.sum_largest(w, k) <=1 ]
prob = cvx.Problem(objective, constraints)
prob.solve()
print prob.status
output = []
for i in range(len(w.value)):
output.append(round(w[i].value,2))
print 'Number of non-zero elements : ',sum(1 for i in output if i > 0)
我有想法使用 sum_smallest 和 sum_largest ( cvxpy manual ) 我的想法是将最小的 nk 个条目限制为 0 并让我的目标范围 k 总和为 1,我知道我不能按顺序改变不等式的方向保持凸面,但也许任何人都知道一种在保持简单的同时约束问题的聪明方法。
我的第二个想法是把它变成一个混合整数问题,s.th沿着线
import numpy as np
import cvxpy as cvx
np.random.seed(12345)
n = 10
k = 6
mu = np.abs(np.random.randn(n, 1))
Sigma = np.random.randn(n, n)
Sigma = Sigma.T.dot(Sigma)
w = cvx.Variable(n)
binary = cvx.Bool(n)
integer = cvx.Int(n)
ret = mu.T*w
risk = cvx.quad_form(w, Sigma)
objective = cvx.Maximize(ret - risk)
constraints = [cvx.sum_entries(w) == 1, w>= 0, cvx.sum_entries(binary) == k ]
prob = cvx.Problem(objective, constraints)
prob.solve()
print prob.status
output = []
for i in range(len(w.value)):
output.append(round(w[i].value,2))
print sum(1 for i in output if i > 0)
for i in range(len(w.value)):
print round(binary[i].value,2)
print output
查看我的二进制向量,它似乎在做正确的事情,但 sum_entries 约束不起作用,查看二进制向量值我注意到 0 不是 0 它非常小,例如 xxe^-20 我认为这会搞砸向上。如果这是正确的方法,任何人都可以给我任何指导吗?如果有帮助,我可以使用标准求解器以及 Mosek。我更喜欢非 MIP 实现,因为我知道这是一个组合问题,对于更大的问题会变得非常慢。最终,我想限制目标持股的确切数量或范围,例如 20-30。
cvxpy 中围绕 MIP 的文档也很短。谢谢