FMP

Sep 11, 2023 5:40 PM - Rajnish Katharotiya

Portfolio optimization is the process to identify the best possible portfolio from a set of portfolios. But how do we define the best portfolio?

The answer depends on the investor profile. We may have investors pursuing different objectives when optimizing their portfolio. For example, young investors may prefer to find portfolios maximizing expected return. While older investors could aim to find portfolio minimizing the risk.

Photo by Pixabay on Pexels

One of the most relevant theories on portfolio optimization was developed by Harry Markowitz. His theory, known as modern portfolio theory, states that investors can build portfolios which maximize expected return given a predefine level of risk.

The goal according to this theory is to select a level of risk that an investor is comfortable with. Then find a portfolio that maximizes returns based on the selected risk level.

Another approach to find the best possible portfolio is to use the Sharpe Ratio. The Sharpe ratio of a portfolio helps investors to understand the return of a portfolio based on the level of risk taken.

Below is the Sharpe ratio formula where Rp is the return of the portfolio. Rf is the risk free rate and Op is the standard deviation (i.e. portfolio risk) of the portfolio.

*Sharpe Ratio = (Rp - Rf) / Op*

The last element in the Sharpe Ratio is the Risk free rate (Rf). A common proxy for the risk free rate is to use Treasury Bill yields.

The higher the Sharpe Ratio, the better a portfolio returns have been relative to the taken risk. If we could choose between multiple portfolio options with similar characteristics, we should select the portfolio with the highest Sharpe Ratio.

In the next section we are going to calculate the Sharpe Ratio for multiple random generated portfolios.

Now that we know a bit more about portfolio optimization lets find out how to optimize a portfolio using Python.

To keep things consistent, I will follow the same methodology that we applied in my previous post in order to calculate portfolio returns and portfolio risk. Therefore, I will not go into the details on how to do this part.

See below a summary of the Python portfolio optimization process that we will follow:

NVS, AAPL, MSFT and GOOG.

We will generate 2000 random portfolios. That is 2000 portfolios containing our 4 stocks with different weights. We will calculate portfolio returns, portfolio risk and the Sharpe Ratio for each of the random generated portfolios.

Then, we will visualize the portfolio returns, risks and Sharpe Ratio using Matplotlib.

Finally, we will find out what is the portfolio with the highest return, lowest risk and highest Sharpe Ratio.

So let's start coding.

import requests

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

stocks = ['NVS','AAPL','MSFT','GOOG']

empresas = {}

api_key = 'your api key'

#Get all prices into a dataframe

for stock in stocks:

prices = requests.get(f'https://financialmodelingprep.com/api/v3/historical-price-full/{stock}?serietype=line&apikey={api_key}').json()

prices = prices['historical'][-900:]

prices = pd.DataFrame(prices)

empresas[stock] = prices.set_index('date')

empresas[stock] = empresas[stock]['close']

portfolio = pd.concat(empresas, axis=1)

return_stocks = portfolio.pct_change()

return_stocks

Next, we are going to generate 2000 random portfolios (i.e. random weights) and calculate the returns, risk and Sharpe Ratio for each of them.

We start by defining empty lists where we will append the calculated portfolio returns, risk and Sharpe Ratio for each of the random portfolios. The calculation will happen in a for loop. Note that we use Numpy to generate random arrays containing each of the portfolio weights.

number_of_portfolios = 2000

RF = 0

portfolio_returns = []

portfolio_risk = []

sharpe_ratio_port = []

portfolio_weights = []

for portfolio in range (number_of_portfolios):

weights = np.random.random_sample((len(stocks)))

print(type(weights))

print(weights)

#below line ensures that the sum of our weights is 1

weights = weights / np.sum(weights)

#outcome

[0.78253875 0.43725429 0.11399585 0.44219616]

For simplicity reasons we have assumed a Risk free rate of 0. Having our portfolio weights, we can move on to calculate the annualised portfolio returns, risk and Sharpe Ratio. If you are unfamiliar with the calculation, feel free to have a look at my previous post where portfolio risk calculation is explained in details.

annualize_return = np.sum((return_stocks.mean() * weights) * 252)

portfolio_returns.append(annualize_return)

#variance

matrix_covariance_portfolio = (return_stocks.cov())*252

portfolio_variance = np.dot(weights.T,np.dot(matrix_covariance_portfolio, weights))

portfolio_standard_deviation= np.sqrt(portfolio_variance)

portfolio_risk.append(portfolio_standard_deviation)

#sharpe_ratio

sharpe_ratio = ((annualize_return- RF)/portfolio_standard_deviation)

sharpe_ratio_port.append(sharpe_ratio)

#keep weights as well to find out later the weights from the optimized portfolio

portfolio_weights.append(weights)

Finally, we convert our list into Numpy arrays:

#convert to arrays

portfolio_risk = np.array(portfolio_risk)

portfolio_returns = np.array(portfolio_returns)

sharpe_ratio_port = np.array(sharpe_ratio_port)

Now that we have created 2000 random portfolios, we can visualize them using a Scatter plot in Matplotlib:

plt.figure(figsize=(10, 5))

plt.scatter(portfolio_risk, portfolio_returns, c=portfolio_returns / portfolio_risk)

plt.xlabel('volatility')

plt.ylabel('returns')

plt.colorbar(label='Sharpe ratio')

In the output graph, each point represents a portfolio. We see that portfolios with the higher Sharpe Ratio are shown as yellow. Yellow coloured portfolios are preferable since they offer better risk adjusted returns.

But how can we identify which portfolio (i.e. portfolio weights) has the highest Sharpe Ratio? And what about the portfolio with the highest return? And lowest risk?

We can find the answer to that questions by transforming our data into a Pandas DataFrame and performing some basic queries.

porfolio_metrics = [portfolio_returns,portfolio_risk,sharpe_ratio_port, portfolio_weights]

#from Python list we create a Pandas DataFrame

portfolio_dfs = pd.DataFrame(porfolio_metrics)

portfolio_dfs = portfolio_dfs.T

#Rename the columns:

portfolio_dfs.columns = ['Port Returns','Port Risk','Sharpe Ratio','Portfolio Weights']

#convert from object to float the first three columns.

for col in ['Port Returns', 'Port Risk', 'Sharpe Ratio']:

portfolio_dfs[col] = portfolio_dfs[col].astype(float)

portfolio_dfs

By looking into the DataFrame, we see that each row represents a different portfolio. For example, row 1 contains a portfolio with 18% weight in NVS, 45% in AAPL, etc.

Now, we are ready to use Pandas methods such asidmax and idmin. They will allow us to find out which portfolio has the highest returns and Sharpe Ratio and minimum risk:

#portfolio with the highest Sharpe Ratio

Highest_sharpe_port = portfolio_dfs.iloc[portfolio_dfs['Sharpe Ratio'].idxmax()]

#portfolio with the minimum risk

min_risk = portfolio_dfs.iloc[portfolio_dfs['Port Risk'].idxmin()]

print(Highest_sharpe_port)

print(min_risk)

#Highest Sharpe Ratio

Port Returns 0.342024

Port Risk 0.26507

Sharpe Ratio 1.29032

Portfolio Weights [0.055480947132996186, 0.20213618958420174, 0....

#Minimum Risk

Port Returns 0.114196

Port Risk 0.195615

Sharpe Ratio 0.58378

Portfolio Weights [0.7672050820919301, 0.00958106941668406, 0.02...

Within seconds, our Python code returns the portfolio with the highest Sharpe Ratio as well as the portfolio with the minimum risk.

By altering the variables a bit, you should be able to reuse the code to find the best portfolio using your favourite stocks.

Sep 11, 2023 - Rajnish Katharotiya

Price to Earnings is one of the key metrics use to value companies using multiples. The P/E ratio and other multiples are relative valuation metrics and they cannot be looked at in isolation. One of the problems with the P/E metric is the fact that if we are in the peak of a business cycle, earni...

Sep 11, 2023 - Rajnish Katharotiya

Price-to-Earnings ratio is a relative valuation tool. It is used by investors to find great companies at low prices. In this post, we will build a Python script to calculate Price Earnings Ratio for comparable companies. Photo by Skitterphoto on Pexels Price Earnings Ratio and Comparable Compa...

Oct 17, 2023 - Davit Kirakosyan

Shares of VMware (NYSE:VMW) witnessed a sharp drop of 12% intra-day today due to rising concerns about China's review of the company's significant sale deal to Broadcom. Consequently, Broadcom's shares also saw a dip of around 4%. Even though there aren’t any apparent problems with the proposed solu...