Risk Contribution Constraints in Portfolio Optimization
Summary
The document examines whether asset-level absolute risk contribution limits can be added to a return-maximizing portfolio optimization problem with a volatility cap. It defines portfolio volatility from the covariance matrix and weights, then derives marginal risk contributions by differentiating volatility. Multiplying each marginal contribution by its asset weight gives an absolute contribution; these contributions sum to total portfolio volatility by homogeneity.
The central finding is that a cap on each asset’s absolute contribution contains products of weights and covariance-weighted weights. That constraint is nonconvex, even when the overall volatility and marginal-contribution limits can be expressed as convex constraints under the stated assumption that the volatility cap binds. A standard convex modeling system therefore cannot represent the full problem under its convexity rules. The response suggests using a more general solver or investigating successive convex methods, while warning about local maxima. It also clarifies that an asset’s contribution is a derivative-based sensitivity to a small proportional position change, not the volatility change from removing the entire position.
Key ideas
- Portfolio volatility is the square root of the weights’ quadratic form with the return covariance matrix.
- Marginal risk contribution is the derivative of portfolio volatility with respect to an asset weight.
- Weight times marginal contribution gives an Euler risk contribution, and the contributions sum to total volatility.
- A cap on absolute asset risk contribution is nonconvex because it contains products of portfolio weights.
- A general solver may find local maxima, while successive convex methods are one possible avenue to explore.
Tags
Full text
# cvxpy portfolio optimization with risk budgeting
# cvxpy portfolio optimization with risk budgeting
I'm trying to do some portfolio construction in cvxpy in Python:
```
weight = Variable(n)
ret = mu.T * weight
risk = quad_form(weight, Sigma)
prob = Problem(Maximize(ret), [risk <= .01])
prob.solve()
```
However I would like to include asset level risk budgeting constraints e.g. no asset can contribute more than 1% risk to the total risk. This constraint would look like (mctr = marginal contribution to total risk, actr = absolute contribution to total risk)
```
mctr = Sigma * weight / 0.1
actr = mul_elemwise(mctr, weight)
prob = Problem(Maximize(ret), [risk <= .01, actr <=.01])
```
However, when I try to do this cvxpy errors out with
```
>> mul_elemwise(mctr, w)
*** ValueError: The first argument to mul_elemwise must be constant.
```
And then I tried reformulating the constraint as
```
actr = diag(mctr, weight.T)
```
but still an error:
```
(Pdb) prob.solve()
*** cvxpy.error.DCPError: Problem does not follow DCP rules.
```
Now I understand why I'm getting these errors, but I also know that these are fairly common constraints, so I'm wondering how to formulate them into cvxpy so I can solve my optimization. Thanks
## Answer by Matthew Gunn (score 14, accepted)
https://quant.stackexchange.com/a/37070
#### The underlying problem: your ACTR constraints aren't convex
The $i$th constraint on your risk contribution can be written:
$$ w_i \sum_j \sigma_{ij} w_j \leq c_i s$$ And this isn't a convex constraint because of the $w_j w_i$ terms (a function $g(x,y)=xy$ isn't convex in $x$ and $y$). They're not convex constraints, so you won't be able to write them as convex constraints in CVX's ruleset.
#### More detail on your optimization problem
Let $\mathbf{w}$ denote a vector of portfolio weights, $\boldsymbol{\mu}$ a vector of expected returns, $\Sigma$ a covariance matrix, $s$ the maximum standard deviation, $\mathbf{m}$ a vector of the maximum marginal contributions to risk, and $\mathbf{c}$ a vector of the the maximum contributions to risk.
Directly translating a maximize return subject to constraints on (1) standard deviation of portfolio returns, (2) marginal contribution to risk, and (3) marginal contribution to risk times portfolio weights where $\circ$ denotes the element wise product (i.e. hadammard product).
\begin{equation} \begin{array}{*2{>{\displaystyle}r}} \mbox{maximize (over $\mathbf{w}$)} & \boldsymbol{\mu}' \mathbf{w} \\ \mbox{subject to} & \sqrt{\mathbf{w}' \Sigma \mathbf{w}} \leq s\\ & \frac{1}{\sqrt{ \mathbf{w}' \Sigma \mathbf{w} }}\Sigma \mathbf{w} \leq \mathbf{m} \\ & \frac{1}{\sqrt{\mathbf{w}'\Sigma \mathbf{w}}}\left( \Sigma \mathbf{w} \right) \circ \mathbf{w} \leq \mathbf{c} \end{array} \end{equation}
Assuming the standard deviation constraint binds we have:
\begin{equation} \begin{array}{*2{>{\displaystyle}r}} \mbox{maximize (over $\mathbf{w}$)} & \boldsymbol{\mu}' \mathbf{w} \\ \mbox{subject to} & \sqrt{\mathbf{w}' \Sigma \mathbf{w}} \leq s\\ & \Sigma \mathbf{w} \leq s \mathbf{m} \\ & \left( \Sigma \mathbf{w} \right) \circ \mathbf{w} \leq s \mathbf{a} \quad \quad \text{<----- still not convex} \end{array} \end{equation}
We now have a convex optimization problem (i.e. convex objective subject to affine equality constraints and convex inequality constraints) EXCEPT for the last constraint! You won't be able to write the contribution to risk constraint as a convex constraint using CVX's ruleset because it is not convex!
What to do? One approach is to use a more generalized solver and be aware that you may encounter local maxima since the problem is not convex. You're right that these are common constraints. There are papers out there on this topic, and you could possibly examine some of the algorithms proposed. For example, the paper, "SCRIP: Successive Convex Optimization Methods for Risk Parity Portfolio Design" looks interesting, but I haven't read it closely enough to endorse it.
### Further background on the problem: why these constraints?
Let $\mathbf{w}$ be a vector representing portfolio weights of $n$ risky assets (i.e. excluding the risk free rate), and Let $\Sigma$ be the covariance matrix of their returns..
The standard deviation of portfolio returns $R_p = \mathbf{w}' \mathbf{R} + \left( 1 - \sum_i w_i\right) r_f $ as a function of weights $\mathbf{w}$ are given by:
\begin{align*} f (\mathbf{w}) &= \operatorname{Std}(R_p) \\ &= \sqrt{\mathbf{w}'\Sigma\mathbf{w} } \end{align*}
Take the partial derivative with respect to portfolio weights and you get:
$$ \frac{\partial f}{\partial \mathbf{w}} = \frac{1}{f (\mathbf{w})}\Sigma \mathbf{w}$$
Observe that the standard deviation of returns $f(\mathbf{w})$ is homogenous of degree one in weights $\mathbf{w}$ (i.e. $f (\lambda \mathbf{w}) = \lambda f(\mathbf{w})$ hence by Euler's homogeneous function theorem:
$$ f(\mathbf{w}) = w_1 \frac{\partial f}{\partial w_1} +w_2 \frac{\partial f}{\partial w_2}+ \ldots + w_n \frac{\partial f}{\partial w_n} $$
A lot of people call $w_i \frac{\partial f}{\partial w_i}$ asset $i$'s contribution to risk since they nicely adds up to the total. But note that $w_i\frac{\partial f}{\partial w_i}$ does NOT measure what would happen to the standard deviation of portfolio returns if the entire position in asset $i$ is excluded.
Rather, it's a derivative. Observe $\frac{\partial f}{\partial \log w_i} = w_i \frac{\partial f}{\partial w_i}$ hence the term relates the change in standard deviation to an infinitesimally small percent change in position size. (You can show taking $\frac{d}{\log x}$ gives the derivative with respect to a percent change in $x$.)Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.