Modern Portfolio Theory

Gabriel Pereira
Analytics Vidhya
Published in
5 min readOct 25, 2020

My interest in finance started in the second half of 2019. I was talking with a friend, and he was telling me about financial markets, and talking how people could make money from that, since then I started my own study, buying books, watching big hedge fund managers talking on youtube or tv, and watching Damodaran online course available on youtube and in his own site.(The link for his website is inside this story)

I actually created a twitter to follow some finance guys, on what we call ‘fintwit’ (it’s a lot of people putting their opinions and sometimes explaining some interesting stuff), and one day this user called by femisapien answered some guys with the following study:

Efficient Frontier Portfolio Optimisation in Python by Ben Kim

I actually found very interesting the study, and very useful for creating a portfolio, since I like to challenge myself, and I’ve actually had a class of Python in my first semester, I decided to try and see if I could apply what I’ve learned so I start building the program.

Modern Portfolio Theory definition

Modern Portfolio Theory, is a theory developed by Harry Markowitz in his paper “Portfolio Selection”. It is a theory on how risk-averse investors can be to construct a portfolio with maximized expected return. So basically it shows that the investor can build a portfolio with multiple assets maximizing his expected return, or given an a certain level of risk, how can he build the portfolio with minimum risk.

Understanding Risk and looking backwards issues

There is a chinese word that professor Aswath Damodaran showed that actually means crisis, but describes for me very well risk definition

“风险” it means danger and opportunity.

There is an issue by doing what we are going to do. The problem is that we are comparing the past, when our risk is related to the future.

Building the code

  • First let’s import some libraries:
import yfinance as yf
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

We are going to extract data for our stocks from yahoo finance. I am using 6 stocks listed on B3 Brazil.

data = yf.download(“FLRY3.SA EGIE3.SA ITSA4.SA ENBR3.SA KLBN4.SA BBDC4.SA ”, start=”2018–01–01", end=”2019–01–01)
returns = data['Adj Close'].pct_change()

For our study we just need the closing prices for each stock.

data[‘Adj Close’]

Risk Free Rate

Measuring risk free rate in some countries are not actually easy, because they don’t actually have a risk free bond. If the country has not a default free entity one way to estimate the risk free is to use a long term bond minus the cds(credit default spread). Since I do not have access to more sophisticated platforms I’m using a site called trading economics to get my 10y bond, and for my cds , since Brazil has Baa2 rating I’m using professor Damodaran website to pick the default spread that he found. Here is the link for his website:

http://pages.stern.nyu.edu/~adamodar/

10y Bond = 7.60%

cds = 3.53%

rf = 0.0407

Monte Carlo Method

Monte Carlo Method is any method that uses statistics that are based in huge random samples. In Modern Portfolio Theory we are going to use to simulate 50 thousand portfolios with different weights to see which one has the best sharpe ratio, and the lowest volatility.

num_portfolios = 50000#WR (Weights record)
WR = []
for i in range(0,(num_portfolios)):
weights = np.random.random(6)
weights /= np.sum(weights)
WR.append(weights)

Sharpe Ratio

Sharpe Ratio was developed by William F. Sharpe, it is used to measure the return of an investment compared to its risk. It’s formula is given by:

I’ll give an example to make easier to understand:

Suppose you have two portfolios A and B with the same return 20%, but the A has a volatility of 10% and the B 15%. Imagining a risk free rate of 5% (pure imagination here). Following the sharpe ratio, the A has a 1.5 sharpe ratio and B has a 1 sharpe ratio, that means that the return of the portfolio A was better given by it’s risk.

How to measure portfolio volatility

Volatily in a portfolio can be given by the standart deviation of each asset, their weights, and the correlation on the assets. To my code I needed to put this in a matrix structure so I found an article called:

Assessing risks and return with probabilities of events in python by Bernard Brenyah

In this article he actually shows how we can write the portfolio volatility in a matrix structure. It can be written in this way:

Weights transposed * (Covariance matrix * Weights)

mean_returns = returns.mean()cov_matrix = returns.cov()

Creating an empty list and filling it up

For our code we’ll be working with lists so we are going create an empty one with 3 lineas and 50 thousand rows. We are using a simple for to do that:

portfolio = np.zeros((3, num_portfolios))
#vol (volatility)
#PER (Portfolio expected return)
for i in range(num_portfolios):
vol = np.sqrt(np.dot(WR[i].T, (np.dot(cov_matrix,WR[i]))))*np.sqrt(245)
PER = np.dot(mean_returns, WR[i])*245
sharpe = (PER-rf)/vol
portfolio[0][i] = vol
portfolio[1][i] = PER
portfolio[2][i] = sharpe
  • Portfolio expected return is given by the mean returns along a year, for an annualized mean return we multiply by 245 ( it’s more or less the days that the markets are opened), we do the same to obtain an annualized volatility.

Getting back to the code

min_vol_indice = np.argmin(portfolio[0])VOLXmin, PERYmin = portfolio[0][min_vol_indice], portfolio[1][min_vol_indice]max_sharpe_indice = np.argmax(portfolio[2])VOLX, PERY = portfolio[0][max_sharpe_indice], portfolio[1][max_sharpe_indice]plt.figure(figsize=(15, 7))
plt.scatter(portfolio[0,],portfolio[1,],c=portfolio[2,:],cmap='YlGnBu',marker='o', s=15, alpha=0.4)
plt.scatter(VOLX,PERY,marker='*',color='y',s=500, label='Maximum Sharpe ratio')
plt.scatter(VOLXmin,PERYmin,marker='*',color='r',s=500, label='Minimum Volatility')
plt.legend(labelspacing=0.8, fontsize= 15)
plt.ylabel('annualised return', fontsize=12)
plt.xlabel('annualised volatility', fontsize=12)
maxsharpeallocation = WR[max_sharpe_indice]
minvolallocation = WR[min_vol_indice]
print("-"*100)
print(" ")
print("Weights for the Maximum Sharpe Ratio")
print("FLRY3.SA =", "{:.2f}".format(maxsharpeallocation[0]*100),'%')
print("EGIE3.SA =", "{:.2f}".format(maxsharpeallocation[1]*100),'%')
print("ITSA4.SA =", "{:.2f}".format(maxsharpeallocation[2]*100),'%')
print("ENBR3.SA =", "{:.2f}".format(maxsharpeallocation[3]*100),'%')
print("KLBN4.SA =", "{:.2f}".format(maxsharpeallocation[4]*100),'%')
print("BBDC4.SA =", "{:.2f}".format(maxsharpeallocation[5]*100),'%')
print("Sharpe Ratio=","{:.2f}".format(portfolio[2][np.argmax(portfolio[2])]))print(" ")
print("-"*100)
print("")
print("Weights for the Minimum Volatility")
print("FLRY3.SA =", "{:.2f}".format(minvolallocation[0]*100),'%')
print("EGIE3.SA =", "{:.2f}".format(minvolallocation[1]*100),'%')
print("ITSA4.SA =", "{:.2f}".format(minvolallocation[2]*100),'%')
print("ENBR3.SA =", "{:.2f}".format(minvolallocation[3]*100),'%')
print("KLBN4.SA =", "{:.2f}".format(minvolallocation[4]*100),'%')
print("BBDC4.SA =", "{:.2f}".format(minvolallocation[5]*100),'%')
print("Sharpe Ratio=","{:.2f}".format(portfolio[2][np.argmin(portfolio[0])]))
print(" ")
print("")

Thank you for reading! If you want the written code or have any questions just leave a comment.

--

--

Gabriel Pereira
Analytics Vidhya

I’m a civil engineering student. Finance, python, valuation, is what I like most