私は cvxpy を使用して、いくつかの単純なポートフォリオ最適化問題に取り組んでいます。私が理解できない唯一の制約は、ゼロ以外のポートフォリオ保有数のカーディナリティ制約です。MIP アプローチと従来の凸型アプローチの 2 つのアプローチを試しました。
これは、動作する従来の例のダミー コードです。
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 にすることでした。不等式の方向を順番に変更できないことはわかっています。しかし、問題をシンプルに保ちながら問題を制限する巧妙な方法を知っている人がいるかもしれません。
私の 2 番目のアイデアは、これを混合整数問題にすることでした。
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 などの範囲に制約を加えたいと考えています。
また、MIP に関する cvxpy のドキュメントは非常に短いものです。ありがとう