Skipy.optimize - How to set constraints in portfolio optimization such that each element in vector is identical?

Viewed 521

I am Building a risk Parity Portfolio where the risk contribution ("RC") of each asset to Portfolio risk should be identical. Given the 3 asset example below, the constraint should be something like this:

def constraint2(x):
    return RC[0] = RC[1] = RC[2]

The contribution of each asset to Portfolio risk should be equal for each element in the RC vector. How can I implement constraints like these using scipy.optimize?

Using Excel sover I got the following Portfolio weights: A = 15%, B = 73%, C = 12%.

Any help is highly appreciated! :) Please find my sample Code below.

def risk_contribution(w):
    pf_var = np.matrix(w) * np.matrix(cova) * np.transpose(np.matrix(w)) #calculate Portfolio variance
    MRC = np.matrix(cova) * np.transpose(np.matrix(w)) #Marginal risk contribution
    RC = np.multiply(np.transpose(np.matrix(w)),np.matrix(MRC)) #Risk contribution
    sum_RC = np.sum(np.matrix(RC)) 
    return sum_RC
    RW = np.divide(np.matrix(RC),np.matrix(pf_var)) 

def constraint1(w):
    return np.sum(w) - 1


w0 = np.matrix([0.333, 0.333, 0.333])
cova = [0.04,0.002,0.03],[0.002,0.003,0.001],[0.03,0.001,0.063]

con1 = {"type": "eq", "fun": constraint1}
cons = [con1]

b = (0,None)
bnds = (b,b,b)
print(minimize(risk_contribution, w0, method="SLSQP", bounds=bnds, constraints=cons)) 

EDIT: So I came up with the following Code, which is slightly different from the previous Code since it minimizes the squared difference between each asset risk contribution and the risk target. I get the same result for the objective J as in Excel, but when running the optimization, the optimal weights are different then the solution in excel. I get x: array([3.46944695e-18, 5.00000000e-01, 5.00000000e-01]) in python as compared to the (correct) solution in Excel (15%,73%,12%). So I assume there must be something wrong with the optimization since the objective function itself seems to be correct. Can't figure out what it could be, however.

def objective(w, V, x_t): 
vol = ((w*V)*np.transpose(w))[0,0] #Portfolio variance
sig = np.sqrt(vol) #stimmt
risk_target = np.matrix(np.multiply(sig,x_t))
MRC = V*np.transpose(w)
RC = np.multiply(MRC,np.transpose(w)) 
RC = RC/ sig 
RC = (np.multiply(MRC,w.T))/ sig #bis hierhin stimmt alles überein
J = sum(np.square(RC - risk_target.T))[0, 0] 

def constraint1(w):
    return np.sum(w) - 1

w0 = np.matrix([1/3, 1/3, 1/3]) #initial weights
V = [0.04,0.0015,0.03],[0.0015,0.0025,0.000625],[0.03,0.000625,0.0625] #sample covariance matrix
x_t = [1/3, 1/3, 1/3] # risk budget percent of total portfolio risk

cons = ({"type":"eq", "fun": constraint1}) #constraint 1 that weights add up to 1
b = (0,None) #constraint 2 that weights >= 0
bnds = (b,b,b)

res = minimize(objective, w0, args=(V, x_t), method='SLSQP', bounds=bnds, constraints=cons)
print(res)
0 Answers
Related