Skip to content
All library documents

Using Bisection to Solve for Risk Aversion in Mean–Variance Optimization

Article Quant Q&A · Author: DGMS89

Summary

The document describes solving for the risk-aversion parameter in a mean–variance portfolio setup. Portfolio weights are expressed as a function of the parameter, expected returns, the covariance matrix, and a budget constraint. Those weights are substituted into a target equation involving expected portfolio return and a volatility adjustment based on a normal quantile. The resulting scalar function is then evaluated at candidate parameter values.

The suggested approach is to find a bracket and use bisection, rather than relying on derivative-based optimization, which the author reports can fail when the function becomes nearly flat at large parameter values. A randomly generated four-asset example illustrates the procedure and reports a solution for a chosen target and probability level. This is an implementation example, not evidence that the function is well behaved for every input: bisection requires a valid sign-changing bracket, and the example does not establish uniqueness or address invalid covariance matrices or other constraints.

Key ideas

  • Portfolio weights are written as a function of the risk-aversion parameter and model inputs.
  • Substituting those weights produces a scalar equation for the target portfolio measure.
  • Bisection can solve the scalar equation when a sign-changing bracket is available.
  • The example reports that derivative-based methods may struggle in a flat region.
  • The random example does not establish uniqueness or guarantee a suitable bracket for other portfolios.

Tags

Full text
# Solving a system of two equations with non-convex matrix multiplication for MV optimization


# Solving a system of two equations with non-convex matrix multiplication for MV optimization












Scenario: I am trying to do a variation of the MV optimization for a portfolio. In this instance, I already have a vector of mean returns ($\mu$), a vector of ones, a covariance matrix ($\Sigma$), and $\phi^{-1}$ which is the inverse of the standard normal cumulative distribution function (function of probability alpha).

Problem: From the two equations stated below, I am going to input: $\mu$, $\Sigma$, 1 (vector of ones), $H$, and $\alpha$, and try to get a value for $\gamma$ (also, the ' represents the transpose of the vector).

Equations:

$$ H = w(\gamma)'\mu + \Phi^{−1}(α)[w(\gamma)' \Sigma w(γ)]^{1/2}$$ $$ w(\gamma) = \frac{1}{\gamma}\Sigma^{-1}\Big[\mu − \Big(\frac{\mathbf{1}' \Sigma^{-1} \mu-\gamma}{\mathbf{1}' \Sigma^{-1} \mathbf{1}}\Big) \mathbf{1}\Big]$$

What I already tried: I am trying to solve this system using a python solver. But I am not able to do it since the matrix multiplication apparently becomes non-convex.

Question: How to solve this problem?

Obs: This question comes from the article Portfolio Optimization with mental accounts from Sanjiv Das, Harry Markowitz, Jonathan Scheid, and Meir Statman, Equations (7) and (8). The article is found at: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.410.8747&rep=rep1&type=pdf

## Answer by caverac (score 2, accepted)

https://quant.stackexchange.com/a/36202

I will use a case in which I randomly generate both $\Sigma$ and $\mu$ randomly in 4 dimensions

```
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
from scipy.optimize import bisect

n = 4
np.random.seed(0)

S = np.random.uniform(0, 1, [n, n])
S = 0.5 * (S + S.transpose())
mu = np.random.uniform(-1, 1, n)
```

The trick with the transpose is just there to ensure that `S` is symmetric. I will choose $\alpha = 0.90$, and define the function $H$ as

```
Sinv = np.linalg.inv(S)
ones = np.ones_like(mu)

def H(gamma):

    # w
    w = (ones.dot(Sinv).dot(mu) - gamma) / (ones.dot(Sinv).dot(ones))
    w = Sinv.dot(mu - w) / gamma

    # H
    H = w.dot(mu) + norm.ppf(alpha) * np.sqrt(w.dot(S).dot(w))

    return H
```

This is a plot of $H = H(\gamma)$.

```
 g = np.linspace(4, 50, num = 500)
 h = np.array(map(H, g))
 i = h > 0
 plt.plot(g[i], h[i])
 plt.show()
```

The function is indeed sort of problematic for large values of $\gamma$ in the sense that any optimization algorithm (pretty much all of them) that uses derivatives will fail. But still you can use bisection to find the root

As an example I will use $H = 1.04$ (up in the flat region)

```
f = lambda x: H(np.exp(x)) - 1.04
r = bisect(f, 1.5, 6, xtol = 1e-12)
g0 = np.exp(r)
print g0, H(g0)
```

which generates the output

```
231.206991393 1.04
```

So the root is $\gamma = 231.20699$

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.