I am trying to build a portfolio optimization algorithm that minimizes Expected Shortfall (CVaR) subject to weighting boundaries and return constraint. While it already works without minimum return requirement, adding return constraint results in the following error: "all the input arrays must have same number of dimensions".
I've spent hours now looking through different forums and examples and still don't know what's causing the error here.
Thank you for your advice!
Code:
#Inputs
w_mkt = np.array([[.5203, .1439, .3358]])
mu = np.array([[.005, .003, .002]])
vol = np.array([[.02, .03, .01]])
rho = np.array([[1.00, 0.50, 0.25],
[0.50, 1.00, 0.60],
[0.25, 0.60, 1.00]])
sd_matrix = np.zeros((3,3))
np.fill_diagonal(sd_matrix, vol)
sigma = np.dot(sd_matrix, np.dot(rho, sd_matrix.T))
#Function to be optimized:
def C_VaR(w, mu, sigma, alpha=0.99):
w = np.matrix(w)
mu = np.matrix(mu)
cvar = -np.dot(mu, w.T) + sqrt(np.dot(w, np.dot(sigma, w.T)))/(1-alpha)*norm.pdf(norm.ppf(alpha))
return cvar
#Boundaries:
b_ = [(0.0, 1.0) for i in range(mu.shape[1])]
b_
#Constraints (return constraint is achivable):
c_ = ({'type':'eq', 'fun': lambda w: sum(w) - 1}, #weights sum up to zero
{'type':'eq',
'fun': lambda w, mu: np.matrix(w).dot(mu.T) - .0036,
'args': (mu,)}) #return requirement
c_
#Finally, optimization function:
minCVAR = optimize.minimize(C_VaR,
w_mkt,
args=(mu, sigma),
method="SLSQP",
bounds=tuple(b_),
constraints=c_)
Error:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-157-be7467bdec1d> in <module>()
4 method="SLSQP",
5 bounds=tuple(b_),
----> 6 constraints=c_)
~/miniconda3/lib/python3.6/site-packages/scipy/optimize/_minimize.py in minimize(fun, x0, args, method, jac, hess, hessp, bounds, constraints, tol, callback, options)
609 elif meth == 'slsqp':
610 return _minimize_slsqp(fun, x0, args, jac, bounds,
--> 611 constraints, callback=callback, **options)
612 elif meth == 'trust-constr':
613 return _minimize_trustregion_constr(fun, x0, args, jac, hess, hessp,
~/miniconda3/lib/python3.6/site-packages/scipy/optimize/slsqp.py in _minimize_slsqp(func, x0, args, jac, bounds, constraints, maxiter, ftol, iprint, disp, eps, callback, **unknown_options)
385 if cons['eq']:
386 c_eq = concatenate([atleast_1d(con['fun'](x, *con['args']))
--> 387 for con in cons['eq']])
388 else:
389 c_eq = zeros(0)
ValueError: all the input arrays must have same number of dimensions
Changing constraint to 'fun': lambda w, mu: (np.matrix(w).dot(mu.T) - .0036)[0,0]
solved the problem.