## A comprehensive guide to using the Sharpe Ratio as a tool for optimizing and balancing your financial portfolio

As a pre-requisite, I recommend reading my previous blog *How To Build A Financial Portfolio Using Python*** . **This would help with a basic understanding of the financial portfolio, calculation of returns, building a portfolio, and optimization but please feel free to continue reading.

In this blog, we will cover the below topics

- What is a Sharpe Ratio?
- What is an Efficient Frontier?
- Data loading and exploratory data analysis — EDA
- Calculation of Sharpe Ratio and its interpretation
- Building a portfolio of banking stocks
- Optimizing the portfolio for better returns at reasonable risk
- Comparing different portfolios

# What is a Sharpe Ratio?

The Sharpe ratio (also known Sharpe index) is a ratio to measure the performance of an investment such as a portfolio. It was proposed by William Sharpe in 1966 as a ratio that is a difference in the returns on the portfolio and risk-free rate to the volatility of the portfolio. The risk-free return is the theoretical return that has zero risk or it can be an industry benchmark eg: government bonds etc where risk is minimal or close to zero. It helps us determine how much the excess return is for a unit of volatility. In short, the higher Sharpe ratio indicates that for a lower risk, the portfolio had higher returns. In this blog, we assume the risk-free rate to be zero.

Sharpe Ratio = (Rₚ — Rₑ) / SDₚ

Rₚ = return of the portolio

Rₑ = risk-free returns

SDₚ = Standard deviation of the portfolio

# What is an Efficient Frontier?

Later in this blog, we will build a few thousand portfolios to arrive at the most optimal weights for the stocks in the portfolio. Remember, we have assigned equal weightage earlier. Once we build this portfolio, there will be a set of portfolios that would give higher returns either for a defined level of risk or minimum risk. This leads us to a theory called Efficient Frontier introduced by Harry Markowitz in 1952. The theory graphically represents the distribution of portfolios that maximize the returns for defined risk.

The curve in the Efficient Frontier graph shows the benefits of diversification and the portfolio’s risk-to-reward trade-off. The optimal portfolio is the one with the highest return for reasonable (acceptable) risk. An investor with a high-risk appetite would incline towards the right side of the curve with high risk and conservative ones would prefer to be on the left side of the frontier with lesser risk. All the portfolios that fall on the frontier line are efficient and any portfolio that is either below or above is not optimal because they offer either a lesser return for the same risk or a higher risk for the same return. Our objective will be to create an Efficient Frontier chart and find a combination of weights for each stock to build an optimal portfolio.

# Exploratory data analysis (EDA)

We will be downloading and working on a year of data from Feb 2022 to Feb 2023.

**Load the libraries**

We will use ** nsepy **to load the data for all the stocks. The rest of the libraries has standard usage for data loading, data transformation, and visualization.

import numpy as np

import pandas as pd

import warnings

import matplotlib.pyplot as plt

import matplotlib.patches as mpatches

from statistics import NormalDist

import statistics

import seaborn as sns

from datetime import date

from nsepy import get_history as gh

from mplcursors import cursor

**Load the data and set the initial allocation**

We have an investment amount of 1,00,000 and plan to invest in five different banking stocks i.e Axis Bank, HBFC Bank, ICICI Bank, Kotak Bank, and SBI. As we do not know how much to allocate in each of the stocks right now, let’s start with an equal proportion i.e, 20% into each of the stocks. Later, we will calculate the right allocation (%) for each of the stocks to maximize the returns at reasonable risk. Ideally, a portfolio should have a mix of stocks from various sectors but for this blog let us have stocks from the banking sector.

initial_investment: int = 100000

start_date = date(2022,2,2)

end_date = date(2023,2,2)

stocksymbols = ['AXISBANK', 'HDFCBANK', 'ICICIBANK', 'KOTAKBANK', 'SBIN']

weights = np.array([0.2, 0.2, 0.2, 0.2, 0.2])

**Calculate the daily returns**

def load_stock_data(start_date, end_date, investment: int, ticker: str):

df = pd.DataFrame()

for i in range(len(ticker)):

data = gh(symbol=ticker[i],start= start_date, end=end_date)

[['Symbol','Close']]

data.rename(columns={'Close':data['Symbol'][0]},inplace=True)

data.drop(['Symbol'], axis=1,inplace=True)

if i == 0:

df = data

if i != 0:

df = df.join(data)

return df

df_stockPrice = load_stock_data(start_date, end_date,

initial_investment, stocksymbols)

df_returns = df_stockPrice.pct_change().dropna()

Stock price Output:

AXISBANK HDFCBANK ICICIBANK KOTAKBANK SBIN

Date

2022-02-02 804.10 1531.20 813.75 1942.60 539.8

2022-02-03 799.55 1515.35 808.95 1909.05 540.1

2022-02-04 798.55 1524.00 805.05 1884.20 530.3

.....

Returns Output:

AXISBANK HDFCBANK ICICIBANK KOTAKBANK SBIN

Date

2022-02-03 -0.005659 -0.010351 -0.005899 -0.017271 0.000556

2022-02-04 -0.001251 0.005708 -0.004821 -0.013017 -0.018145

2022-02-07 -0.011208 -0.036647 -0.023166 -0.029588 0.005563

.....

Let’s visualize the price and the cumulative trends of all the stock

# Calculation of Sharpe Ratio

We will calculate the weighted returns and take a summation along the columns

df_returns['Portfolio'] = (weights * df_returns.values).sum(axis=1)

OUTPUT:

AXISBANK HDFCBANK ICICIBANK KOTAKBANK SBIN Portfolio

Date

2022-02-03 -0.005659 -0.010351 -0.005899 -0.017271 0.000556 -0.008825

2022-02-04 -0.001251 0.005708 -0.004821 -0.013017 -0.018145 -0.006149

2022-02-07 -0.011208 -0.036647 -0.023166 -0.029588 0.005563 -0.021400

## Calculate the mean and standard deviation

# Average daily return

df_returns['Portfolio'].mean()

OUTPUT:

0.0001426

# Standard deviation of the portfolio

df_returns['Portfolio'].std()

OUTPUT:

0.0127614

## calculate the Sharpe ratio

# Sharpe ratio

sharpe_ratio = df_returns['Portfolio'].mean() /

df_returns['Portfolio'].std()

OUTPUT:

0.0111790

# Finding the right balance for the portfolio

We had initially assigned equal weights to the stocks. Now that we understand the shape ratio, let’s build a few thousand portfolios with varying weightage for each of the stocks but at the same time ensure that the sum of all the weights adds up to 1. We will calculate the portfolio return, risk, weights assigned, and shape ratio in each iteration.

def sim_portfolio(weights):

# port_stdev = np.sqrt(weights.T.dot(cov_matrix).dot(weights))

# return port_stdev

port_mean = (weights * df_returns.values).sum(axis=1)

# Annualized mean

port_mean = port_mean * 252

port_sd = np.sqrt(weights.T.dot(df_returns.cov() * 252 ).dot(weights))

port_var = np.percentile(port_mean, 5, interpolation = 'lower')

port_var_95.append(port_var)

port_volatility.append(port_sd)

mc_sim_sr = (port_mean.mean() / port_sd)

return mc_sim_sr

Please refer to the complete code on *Github*

At the end of the 25k iteration, we have a summary of the simulation in a tabular form where each row represents an iteration with parameters associated with it.

Returns Risk Sharpe Ratio Weights

0 0.006322 0.203214 0.078392 [0.05091, 0.26731, 0.13599, 0.35021, 0.19558]

1 0.020290 0.209528 0.244030 [0.17965, 0.30068, 0.10195, 0.08729, 0.33043]

2 0.017599 0.212385 0.208811 [0.31511, 0.16065, 0.04037, 0.17625, 0.30762]

3 0.022703 0.220802 0.259110 [0.35485, 0.02419, 0.21121, 0.10095, 0.3088]

....

....

24998 0.020777 0.210912 0.248245 [0.29097, 0.03917, 0.34305, 0.19782, 0.12899]

24999 0.014266 0.202581 0.177462 [0.16349, 0.21943, 0.19902, 0.26292, 0.15515]

Our interest is to find the portfolio that has the maximum value for the Sharpe ratio and this happens to be portfolio number 8618 with a Sharpe ratio of 0.4364 and weights as [0.51593, 0.39851, 0.07618, 0.00189, 0.0075].

It is also to be noted that the initial Sharpe ratio was 0.011179 where we had not factored in any weights and the revised Sharpe ratio is 0.4364

sr_max = df_risk[df_risk['Sharpe Ratio'] == df_risk['Sharpe Ratio'].max()]

OUTPUT:

Returns Risk Sharpe Ratio Weights

8618 0.038822 0.224159 0.436432 [0.51593, 0.39851, 0.07618, 0.00189, 0.0075]

So there we have our revised weights for each of the stocks in the portfolio.

AxisBank = 0.5159

HDFCBank = 0.39851

ICICIBANK = 0.07618

KOTAK BANK = 0.00189

SBI = 0.0075

Let us visualize the relation between volatility and returns along with the Sharpe ratio to get a better picture. Also, highlight the data point that represents the highest Sharpe ratio.

plt.figure(figsize=(12,8))

plt.scatter(port_volatility,

port_returns,

c=sharpe_ratio,

cmap='plasma')

plt.plot(sr_max['Risk'], sr_max['Returns'], marker = 'p',

ms = 10, color = 'r')

plt.text(sr_max['Risk']+0.001, sr_max['Returns'], 'Max Sharpe Ratio')

plt.colorbar(label='Sharpe Ratio')

plt.xlabel('Volatility')

plt.ylabel('Return')

The optimized portfolio has a return of 3.8% with a Sharpe ratio of 0.44 or a value at risk at a 95% probability is 2.2% meaning the portfolio loss will not be more than 2.2%.

# Comparing different Portfolios

In our previous blog, ** How To Build A Financial Portfolio Using Python**,

**we built a different portfolio and optimized it with a simulation to minimize the risk of the portfolio but we didn’t use the Sharpe ratio instead we used value at risk (VaR). Let us apply the Sharpe ratio approach to that portfolio and check if the weights of each of the stock change significantly or remain the same.**

initial_investment = 100000

startdate = date(2022,2,2)

end_date = date(2023,2,2)

stocksymbols = ['TATAMOTORS','DABUR', 'ICICIBANK','WIPRO','INFY']

Returns Risk Sharpe Ratio Weights

2889 0.01705 0.189345 0.226913 [0.03087, 0.3918, 0.52679, 0.00689, 0.04365]

Weights

Previous Current

Stocks

TATAMOTORS 0.0529 0.0308

DBAUR 0.3400 0.3918

ICICIBank 0.3098 0.5267

WIPRO 0.1863 0.0068

INFY 0.1108 0.0436

With the VaR approach, we got a return of 16.9 % with a risk of 18.2% at a 95% confidence interval. With the Sharpe ratio, we got a return of 17.05% with a risk of 18.9%. Well, we do see noticeable changes in the weights, especially for WIPRO and INFY but the return and risk trade-off is almost similar. There is a 0.15 % increase in returns with the Sharpe ratio approach which is marginal but with a large fund and long investment period, this might just be the preferred one.

# Closing thoughts

There are various methods for portfolio optimization and in this blog, we learned the application of the Sharpe ratio and the Efficient Frontier to build an optimal portfolio. The Sharpe ratio is widely used in comparing portfolios that are similar and as the ratio is very intuitive, it is easy to interpret as well. Also, in the last section of the blog, we compared different portfolios to verify performance.

I hope you liked the article and found it helpful.

You can connect with me — on ** Linkedin** and

*Github*# Disclaimer

The blog is only for educational purposes and should not be used as professional advice for making any real-world financial decisions.