The Nobel Prize Winner Theory To Gain Higher Returns In Your Investment

A good portfolio is more than a long list of good stocks and bonds. It is a balanced whole, providing the investor with protections and opportunities with respect to a wide range of contingencies. — Harry Markowitz

The Modern Portfolio Theory of Nobel prize winner, Harry Markowitz can be implemented by using optimisation routines.

“The theory provides a firm foundation for the intuition that you should not put all your eggs in one basket and shows investors how to combine securities to minimize risk” (Burton G. Malkiel).

This article will document the following three key points:

  1. Understanding Of Efficient Frontier
  2. A quick overview of SciPy package
  3. How efficient portfolios can be generated in Python?

Let’s consider you have $10’000 of cash available and you are interested in investing it. Your aim is to invest the money for a year. Like any rational investor, you expect the final amount in a years time to be higher than the $10’000 amount you want to invest.

The last thing you want is to lose the $10’000 you started your investment with.

So far, so good!

1.1 Understanding Risk-Return Relationship

There are many investment options available, such as buying a T-bill or company shares, etc. Some of the investment options are riskier than the others because they attract us to gain higher returns.

Hence, the point to note is that there exists a risk-return trade-off.

As an investor, our sole aim might be to invest in the least risky investment option that yields the highest return.

If we buy a number of assets such as shares of different companies then the total risk of the portfolio can be reduced due to diversification. This means that an investor can reduce the total risk and increase the return by choosing different assets with different proportions in a portfolio. This is due to the fact that the assets can be correlated with each other.

1.1 A — Portfolio Return

Now, if we compute the return of the portfolio as:

where each Asset Expected Return is:

And the returns are calculated as:

1.1 B — Portfolio Risk

We can calculate the risk of the portfolio as the volatility of the assets:

The volatility is computed by calculating the standard deviation of the returns of each stock along with the covariance between each pair of the stocks and the weights of the stocks.

This means that the weights can change the risk of the portfolio.

1.2 The Theory Of Efficient Frontier

We understood that the allocations (weights) of the assets can change the risk of the portfolio. Hence, we can generate 1000s of portfolios randomly where each portfolio will contain a different set of weights for the assets.

We know that as we increase the number of portfolios, we will get closer to the real optimum portfolio. This is the brute force approach and it can turn out to be a time-consuming task. Furthermore, there is no guarantee that we will find the right allocations.

If we plot the risk and return for each of the portfolios on a chart then we will see an arch line at the top of the portfolios.

We can see that the chart formed an arch at the top of the portfolios which I marked with the black pen.

This line is essentially pointing at the portfolios that are the most efficient. This line is known as the efficient frontier.

The efficient frontier is a set of portfolios that give us the highest return for the lowest possible risk.

Every other portfolio that does not reside on the efficient frontier is not as efficient because it offers the same return as a portfolio on the efficient frontier but by taking a higher risk.

Any other portfolio is therefore inferior to the portfolios on the efficient frontier. As a result, we can literally ignore the portfolios that are not on the efficient frontier line.

There are a number of libraries available in Python that can perform optimisation routines on a function such as CVXPY and SciPy.

In this section, I will provide a quick overview of the SciPy package which is one of the key Python packages to get familiar with. In particular, I will explain the function that we will execute to compute the efficient portfolios and what each of the parameters means.

Optimisation techniques help us find a solution to a function faster without gathering a large amount of data and without using analytical techniques.

Constraints can be imposed on the optimisation. We can also use the optimisation techniques to find the minimum and maximum values of x.

The way it works is that the optimiser attempts to find the value of our target variable x in such a way that minimises the differences between the actual and observed values by staying within the specified boundaries.

Please read this article if you want to understand the concept:

2.1 SciPy Optimize

The scipy.optimize module, within the SciPy package, offers a variety of optimisation algorithms. The module includes un/constrained algorithms, global optimisation routines, least-squares minimisation, scalar and multivariate minimisers etc.

It offers Newton-Krylov, Newton Conjugate Gradient, SLSQP, curve fit and dual annealing algorithms amongst others.

2.2 SciPy minimize function

There is a minimize function within the scipy.optimize module that performs the minimisation of a scalar function of one or more variables. The minimize function makes it easier for us to execute the required algorithm on an objective function.

The signature of the method is:

scipy.optimize.minimize(fun, x0, args=(), method=None, jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, callback=None, options=None)[source]

The key arguments are:

  • fun: This is the objective function which we want to minimise. In our case, our portfolio is composed of a number of assets. We want to find the allocation of each asset that gives us the least amount of risk. The first parameter of the function is the 1-D array of allocations. We can also pass in a tuple of other parameters to the function too.
  • x0: This is the initial guess. We can assign a value of 1/number of assets, as the initial value of x.
  • args: This is a tuple that can contain the extra optional arguments. As an instance, if our target risk function takes in the covariance matrix then we can pass it in the args tuple.
  • method: This is a string argument where we can pass in the algorithm name such as SLSQP
  • constraints: This is where we will pass in the constraints such as the sum of allocations should be 1.
  • bounds: These are essentially the minimum and maximum pairs of each element in x. As an instance, we can indicate that we don’t want the value of an allocation to be negative implying that we don’t want to sell an asset.

2.3 SLSQP Algorithm

To perform constrained minimisation for multivariate scalar functions, we can use the minimize function using the SLSQP algorithm.

SLSQP stands for Sequential Least SQuares Programming. The idea is to minimise a function of x subject to functions of constraints. The constraints can be linear and non-linear. They are defined as dictionaries.

The keys of the dictionary include:

  • type: This specifies the type of the constraint such as ineq (inequality) or eq (equality)
  • fun: The function of the constraint such as the sum of allocations of assets in the portfolio should be equal to 1.

The last section of the article will use the knowledge that was explained above to build a set of efficient portfolios.

3.1 The 7 Steps Of Efficient Frontier

We need to perform the following 7 steps:

  1. The first stage (step 1–3) is to calculate the daily returns of our stocks.
  2. The second stage is step 4 whereby we need to optimise the allocations to retrieve the best portfolio for each of our target returns.
  3. The last stage is about using the allocations to calculate the risk and return and plot the portfolios.

3.2 Implement Efficient Frontier In Python

  1. Once, we have retrieved the stock prices, we would need to compute the expected mean return for each stock:
import numpy as np
def asset_return_function(stock_prices):
returns = np.log(stock_prices / stock_prices.shift(1))
return returns.mean()

2. Then for each of the targets, we are going to get the optimiser to minimise the risk (our objective function) and give us the allocations of the assets.

The risk of the portfolio is calculated as:

import numpy as np
from functools import reduce
def risk_function(allocations, cov):
return np.sqrt(reduce(, [allocations, cov, allocations.T]))

The return of a portfolio is calculated as:

def return_function(returns, allocations):
return sum(returns * allocations)

3. Lastly, this code snippet shows how we can use the SciPy optimiser.

I have generated random returns and covariance so that we can focus on how the optimiser works with the bounds and the constraints!

#initialise returns & covariance
returns = np.random.rand(3)
covariance = np.random.rand(3,3)#set variables
portfolio_size = len(returns)
risk_free_rate=0for my_return in [0.1,1.0,2.6,5.0]:

x0 = np.ones(portfolio_size) * (1.0 / portfolio_size)
bounds = ((0, 1),) * (portfolio_size)constraints=[]
constraints.append({'type': 'eq', 'fun': lambda inputs: 1.0 - np.sum(inputs)})
constraints.append({'type': 'eq', 'args': (returns,),
'fun': lambda allocations, returns:
my_return - return_function(returns, allocations)})#optimised allocations
allocations = minimize(risk_function, x0,
args=(covariance), method='SLSQP',
#prints covergence msgs
options={'disp': True},
bounds=bounds).xexpectedreturns = return_function(returns, allocations)
print('Allocations For Target Return '+str(my_return)+': '+str(allocations))
#Calculate volatility
volatility = risk_function(allocations, covariance)
sharpe_ratio = calculate_sharpe_ratio(volatility, expectedreturns, risk_free_rate)

The Sharpe ratio is computed as:

def calculate_sharpe_ratio(risk, returns, risk_free_rate):
return (returns-risk_free_rate)/risk

Once we run the code above, it produces the following output:

We can see that the optimisation routine ran four times; one for each target return. We specified lower bound of 0 and upper bound of 1 on each of the allocations. Constraints on the allocations are added which ensure that we maximise return and the sum of the allocations is 1.

Within each optimisation routine, the optimiser ran the iterations multiple times until it achieved the optimised allocations. These allocations gave us our best portfolios which are known as the efficient frontier.

For each target, it returned the most optimum portfolio. The array of allocations are the weights (proportions) of the assets which make up the portfolio for each of our target return

I am going to implement an end to end solution showing how we can run the efficient frontier in Python from fetching the stock prices to plotting an efficient frontier. Please let me know if you are interested.

This article documented the following three sections:

  1. Understanding Of Efficient Frontier
  2. A quick overview of SciPy package
  3. How efficient portfolios can be generated in Python?

If you are interested in seeing an end-to-end solution of the efficient frontier in Python then let me know.

Source link