如何使用cvxopt进行带约束的均值方差优化?
我可以使用cvxopt来计算有效前沿,具体可以参考文档:
http://cvxopt.org/examples/book/portfolio.html
不过,我不太明白怎么添加一个限制条件,让某个资产的最大权重有个上限。用cvxopt可以做到这一点吗?
这是我目前的代码,它生成了一个没有限制条件的有效前沿,除了我认为的b,它设置了权重总和的最大值为1。我不太明白G、h、A和mus的作用,文档里也没有详细解释。公式中mus的10**(5.0*t/N-1.0)是从哪里来的呢?
from math import sqrt
from cvxopt import matrix
from cvxopt.blas import dot
from cvxopt.solvers import qp, options
# Number of assets
n = 4
# Convariance matrix
S = matrix( [[ 4e-2, 6e-3, -4e-3, 0.0 ],
[ 6e-3, 1e-2, 0.0, 0.0 ],
[-4e-3, 0.0, 2.5e-3, 0.0 ],
[ 0.0, 0.0, 0.0, 0.0 ]] )
# Expected return
pbar = matrix([.12, .10, .07, .03])
# nxn matrix of 0s
G = matrix(0.0, (n,n))
# Convert G to negative identity matrix
G[::n+1] = -1.0
# nx1 matrix of 0s
h = matrix(0.0, (n,1))
# 1xn matrix of 1s
A = matrix(1.0, (1,n))
# scalar of 1.0
b = matrix(1.0)
N = 100
mus = [ 10**(5.0*t/N-1.0) for t in range(N) ]
options['show_progress'] = False
xs = [ qp(mu*S, -pbar, G, h, A, b)['x'] for mu in mus ]
returns = [ dot(pbar,x) for x in xs ]
risks = [ sqrt(dot(x, S*x)) for x in xs ]
#Efficient frontier
plt.plot(risks, returns)
4 个回答
我觉得被标记为正确的回复其实给了一个错误的例子。covxopt 矩阵是按列优先排列的,所以示例中的 G 和 h 需要进行转置。
主要的目的是整理你的不等式和等式约束。比如,如果你想允许对两个资产进行卖空,那么就需要满足 -1<=x(i)<=1 以及 sum(x(i))=1 的条件。为了处理不等式,你有4个不等式,所以 G 矩阵的大小应该是 4x2,而 h 则是 4x1。你可以检查一下……G=[I/-I],这里的 I 是一个全是1的矩阵,也就是说 G=[[1,0],[0,1],[-1,0],[0,-1]] 乘以 [x1,x2],而 h=[1,1,1,1]。如果你使用 Gx<=h,你会得到 x1<=1,x2<=1,x1>=-1 和 x2>=-1 的结果。接下来是等式部分,Ax=b,b=1,A=[1,1]。再检查一下,x1 + x2 = 1,这符合约束条件。P 和 Q 你已经有了。现在你准备好去解决这个问题了。
我知道这个问题有点老了,但很难找到一个好的约束均值方差的例子。
其实约束的部分并不是这样工作的。
在这个例子中,G矩阵应该是4行4列,而h矩阵应该是1行4列,像下面这样。如果需要设置一个最小阈值,可以在"h"矩阵中输入,比如我下面的例子中是20%。不过,我还是没能成功添加最大约束。
G = matrix([[-1.0, 0.0, 0.0, 0.0],
[0.0, -1.0, 0.0, 0.0],
[0.0, 0.0, -1.0, 0.0],
[0.0, 0.0, 0.0, -1.0]])
h = matrix([-0.2, 0.0, 0.0, 0.0])
你正在使用cvxopt包中的二次规划求解器,可以查看一下文档。
从公式中可以看到,Gx <= h
是表示不等式约束的,而Ax = b
是表示等式约束的。这里的G
和A
是矩阵,而h
和b
是向量。
假设你想把第一个资产的权重限制在2%到5%之间,你可以这样来表示:
G = matrix([[-1, 0, 0, 0],
[ 1, 0, 0, 0]])
h = matrix([[-0.02],
[0.05]])
注意,第一行通过乘以-1把不等式条件变成了Gx >= h
。
你上面设定的条件将所有资产的权重限制在0%到100%之间,这是一种常见的禁止卖空的条件。
你使用的公式在这里有解释:你的mu
在维基百科文章中对应q
,它是一个风险承受能力的参数。把它放在协方差或收益部分其实都没关系。这只是意味着你在每个mu
值下,可能是从右上角走到左下角,或者反过来。所以它只是一个函数,给你一个从非常小到非常大的风险承受能力。我觉得这里有个错误,序列是从0.1开始的,但其实应该从0开始。