Introduction Python III: portfolio optimisation

In this notebook, we learn some basic optimisation techniques. We illustrate our example with (simple) portfolio optimisation.

To get the data for the market, we use the import function from yfinance.

If you do not have the package yfinance, please run in a Terminal (for Mac and Linux users, if you have Windows, open an Anaconda Prompt or the command prompt) pip install yfinance

You should then quit Jupyter and relaunch everything.

1/ Load data

We are interested in the following assets: Apple, Microsoft, Nvidia, Activision, Coca Cola.

We load the data from 2021 (the Open Position price for instance).

(you can try with the data from 2022, but the market was down...).

Let us have a look at our Dataframe.

Exercice: How many days are there in the table? Is it normal?

Exercice: Plot the evolution of the market

2. ultra-basic portfolio theory

An asset $i$ can be seen as a random variable $X_i$, corresponding to the capital gain per day. We can define

Let $N$ be the number of assets. A strategy is a vector $w = (w_1, \cdots, w_N)$ with $0 \le w_i \le 1$ and $\sum_i w_i = 1$. The weight $w_i$ corresponds the proportion of asset $i$ in our portfolio.

The goal is to find the best strategy, that is the best vector $W$. There are several criteria for that, that we detail now.

The gain of a strategy is $G(W) := \sum_{i=1}^n w_i r_i$.

The risk of a strategy is $R(W) := w^T C w$.

In practice, we want the highest gain, with the minimum risk.

Exercice: Draw $M = 10000$ strategies at random, and scatter plot the corresponding gains as a function of the risk.

Exercice: According to your plot, for a risk 0.0005, what is the highest gain one can expect?

Exercice: With a daily gain of 0.003%, what is my yearly gain? (Remember that there are only 252 market days per year)

2. Optimisation of the Sharpe's ratio

In this section, we look for a simple criterion to optimise. We try to optimise the Sharpe's ratio

$$ S(W) := \frac{G(W)}{\sqrt{R(W)}}.$$

Exercice: On the random portfolios you draw in the last question, which one has the best Sharpe's ratio? What is the corresponding ratio? Place this point in the previous plot.

Let us now find the optimum with a concrete algorithm.

Exercice: Prove that there is $r \in \mathbb{R}^n$ and $C \in \mathcal{M}(\mathbb{R})$ so that $$ S(w) = \dfrac{r^T w}{\sqrt{w^T C w}}, \quad \text{and that} \quad \nabla_w S (w) = \dfrac{r}{\sqrt{w^T C w}} - \dfrac{(r^Tw) Cw}{2 (w^T C w)^{3/2}}. $$ Code these functions as S and dS respectively.

We use a simple gradient ascent to find the optimum. Recall that this sequence is defined by $$ w_{n+1} = w_n + \alpha \nabla S (w_n). $$ Exercice: Find the optimal strategy with the gradient descente. Take $\alpha = 0.5$ and $w_0$ at random

WARNING: No while loops!

Exercice Create a nice Series for the best portfolio you have found, and plot it with bars

In practice, one can use an optimisation function from Python. These are given in the scipy package. See the doc here.

If you can, always choose the BFGS method.

3. Optimisation with constraints

Your best portfolio has a problem: it has negative values, it has values bigger than $1$, and the sum is not $1$...

Hopefully, one can tell the minimize function of scipy that we want $w$ to satisfies some bounds and/or constraints.

Exercice: find the best portfolio with $w \in [0, 1]^N$ and $\sum w_i = 1$.

Hint: read the documentation for optimize.minimize

Exercice: What is the daily gain and the risk of this portfolio?

4. Optimisation of the gain

We now look for a better criterion than Sharpe's ratio. We would like to have the highest possible gain with a maximum risk allowed.

Exercice Write a function which returns the best portfolio with maximum risk maxRsk. You can use scipy.optimize.

Exercice: Compute the best portfolios for a range of maxRsk, and display the results nicely.