I'm trying to solve a problem that I submitted to QSE, https://quant.stackexchange.com/questions/65680/find-k-of-n-assets-that-minimize-the-correlation-matrix/, but I'm running into an issue using the cvxpy lib. Namely, what I believe to be a convex binary programming problem, cvxpy is saying "does not follow DCP rules".
The problem I'm trying to solve is: "from a given 10 risky assets, find the 5 least correlated". My current methodology to solve this is
- Grab each asset's returns
- Find the correlation matrix,
C
, for these returns - Formulate the convex optimization problem as
x
is a binary vector- the sum of the entries of
x
is 5 C' = transpose(C * x) * x
is a matrix where thei
th row andi
th column ofC
is "zero'd out" when thei
th entry ofx
is 0 (and not zero'd out otherwise). Note: I wonder if this is where my issue arises. This was the best way that I could come up with to remove entries from the correlation matrixC
that correspond to the "rejected" assets.- Finally, I want to minimize the sum of squares of
C'
. This will give me something like a portfolio of the 5 least correlated assets.
The following is the non-working code that I have so far.
import pandas as pd
import pandas_datareader as web
import datetime as dt
import cvxpy as cvx
stocks = ['SHW', 'GOOG', 'AMZN', 'WMT', 'XOM', 'JNJ', 'UPS', 'AMT', 'AAPL', 'NEE']
start = dt.datetime(2015, 1, 1)
end = dt.datetime(2020, 1, 1)
d = web.DataReader(stocks, 'yahoo', start, end)['Adj Close']
corr = d.corr().to_numpy()
x = cvx.Variable(len(stocks), boolean=True)
cost = cvx.sum_squares((corr @ x).T @ x)
prob = cvx.Problem(cvx.Minimize(cost), [cvx.sum(x) == 5])
prob.solve(solver='ECOS_BB')
And the error it produces
DCPError: Problem does not follow DCP rules. Specifically:
The objective is not DCP. Its following subexpressions are not:
# The corr array
I've also tried to reformulate this in a number of ways that have't worked including
- Using a cvxp variable matrix
X
that has cvxpy attributes boolean and symmetric. If it's symmetric and each row sums to 5, then I have a matrix for which I can do element-wise multiplication to findC'
. This doesn't work because a variable is only allowed one attribute (strange cvxpy limitation). - Using a cvxp variable binary matrix
X
and a cvxp variable symmetric matrixY
and including a constraint thatX == Y
(to get around the 2-attribute limitation). I can't remember why this didn't work. - Using a cvxp variable binary matrix
X
and constraints that the sum of everyi
th row is 5 and that thei
th row is equal to thej
th column. I had trouble with this because testingX[i] == X[:i]
produces a boolean array that I didn't know how to reduce with cvxpy. - I've also tried using a non-binary cvxpy variable vector
x
and attempting to constrain thei
th value ofx
to be 0 or 1 but the constraintx[i] == 0 || x[i] == 1
wasn't valid because of||
--I also couldn't find a cvxpy logical-or condition.
So I've tried to reformulate this in a few different ways but I keep running into issues with each strategy. I'm wondering if someone can help me
- Determine if this actually is a problem that cvxpy can solve. If it's not, how can I change it to solve essentially what I want? If it is something that cvxpy can solve
- What can I do with my current code to correct its issues?
Thanks for your time.