Building the Captial Asset Pricing Model (CAPM) with Python

A comprehensive guide to using Python for enhancing financial decision-making through quantitative analysis

In this blog, we will cover the below topics

  • What is Capital Asset Pricing Model (CAPM)?
  • Systematic risk and unsystematic risk
  • Market returns and sensitivity
  • Overvalued and undervalued stocks
  • Calculation of the portfolio returns and beta (β)
  • Assumptions of CAPM
  • Implementing CAPM using Python

What is a Capital Asset Pricing Model (CAPM)?

The Capital Asset Pricing Model is a mathematical model that calculates the expected return on a given investment by establishing a linear relationship with the risk of the market.

There are a few parameters that play a key role in determining the returns from the asset.

Risk-free rate

It is the theoretical rate of an investment that has zero risk. Eg: government bonds that are backed by the government meaning irrespective of the market conditions, macro/microeconomic conditions, the return is absolutely certain. Note that as a standard, the risk-free is taken as zero.

Types of risks

  • Systematic risk — This is the risk associated with the market as a whole and is not specific to any asset. eg: If the inflation is high then its effect will be reflected in all aspects of financials irrespective of the industry or sector. In case of recession, investments become riskier compare to the normal market conditions. In all such scenarios, a portfolio/fund manager tries to manage systematic risk and allocate investments for higher returns.
  • Unsystematic risk — This risk is specific to an asset, unlike systematic risk. The reasons are business related specifically to a company. Eg: Labor-related issues impacting manufacturing, a business decision that had a negative impact on the company.

Market return (rₘ)

This includes returns from all the assets in the market. A typical example in the Indian market would be Sensex which has the top 30 stocks or Nifty which has the top 50 stocks. These are indexes that measure the overall market movement/sentiment. The US equivalent would be S&P 500 which has the 500 largest US publicly traded companies. In calculating the expected returns using CAPM, the given asset is measured against such indexes.

Sensitivity (β)

The return from an asset (stock) depends on how sensitive the asset is relative to the market and this factor is known as β (beta). The β is the slope in the linear relation.

  • If β = 1, then the asset’s return is the same as the market return
  • If β > 1, then the asset’s return is higher than the market return. The asset is more volatile than the market.
  • If β < 1, then the asset’s return is lesser than the market return indicating that the asset is less volatile than the market.

Now, that we understand various factors, let us put them in an equation.

rᵢ = rf + βᵢ * (rₘ−rf)

rᵢ = Expected return from the portfolio
rf = Risk-free return rate
rₘ = Market return
βᵢ = Risk relative to the market
(rₘ−rf) = Risk premium

Example: If the risk-free rate is zero, the β is 1.2 and the average market return is 12.5 then the expected return would be 15%

rᵢ = 0% + 1.2 * (12.5% — 0%) = 15%

This means investors should expect a 15% return for the additional risk taken.

Interpreting the beta(β) of the portfolio

The equation in the previous section is the same as the equation of the line which is y= mx + c meaning there is a linear relation between the expected return and the β which is presented below.

Source: Wiki | Security Market Line
  • The market β is always 1 which gives us a return of E(Rₘ) — dotted line
  • The stocks that are above the lines are undervalued because, for a given risk, the returns are higher than the market returns
  • The stocks that are below the lines are overvalued because, for a given risk, the returns are lower than the market returns

Implementing CAPM using Python

In this section, we will apply our learning and build a CAPM model using python. We will consider the Indian stocks for this blog but the methodology would remain the same for U. S stocks / S&P 500.

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 matplotlib.pyplot as plt
from datetime import date
from nsepy import get_history as gh

Load the data and initial settings

Let us select Tata Motors, Dabur, ICICI Bank, Wipro, Infosys, and NIFTY for the last 5 years’ data starting from Feb 2018 to Feb 2023 for this blog.

start_date = date(2018,2,2)
end_date = date(2023,2,2)
tickers = ['TATAMOTORS','DABUR', 'ICICIBANK','WIPRO','INFY']

def load_stock_data(start_date, end_date, ticker):
df = pd.DataFrame()
for i in range(len(ticker)):
data = gh(symbol=ticker[i],start= start_date,
end=end_date)[['Symbol','Close']]
...
...
return df

df_stock = load_stock_data(start_date, end_date, tickers)
df_nifty = gh(symbol = 'NIFTY',start = date(2018,2,2), end = date(2023,2,2), index= True)[['Close']]
df_nifty.rename(columns = {'Close':'NIFTY'}, inplace = True)
df_port = pd.concat([df_stock, df_nifty], axis = 1)
             TATAMOTORS   DABUR   ICICIBANK   WIPRO   INFY
Date
2018-02-02 383.75 344.45 335.1 300.60 1143.25
2018-02-05 395.80 339.10 329.7 298.75 1138.20
2018-02-06 375.45 339.25 330.7 294.65 1107.75
.....
2023-01-31 452.10 557.75 831.90 398.85 1533.75
2023-02-01 446.65 561.95 847.95 402.40 1551.10
2023-02-02 444.80 554.45 857.90 409.45 1583.75

Exploratory data analysis — EDA

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

plt.figure(figsize=(10, 10))
plt.subplots_adjust(hspace=0.5)
plt.suptitle("Daily closing prices", fontsize=18, y=0.95)
for n, ticker in enumerate(tickers):
ax = plt.subplot(3, 2, n + 1)
df_stock[ticker].plot(ax= ax)
ax.set_title(ticker.upper())
Source: Author | Close Price Trends Of All Stocks
df_returns = df_port.pct_change().dropna().reset_index()
plt.figure(figsize=(10, 10))
plt.subplots_adjust(hspace=0.5)
plt.suptitle("Daily Returns", fontsize=18, y=0.95)
for n, ticker in enumerate(tickers):
ax = plt.subplot(3, 2, n + 1)
df_returns[ticker].plot(ax= ax)
ax.set_title(ticker.upper())
Source: Author | Returns Trends Of All Stocks

Calculating alpha and beta (β)

There are 5 stocks in the portfolio and we will loop through each and calculate the coefficients. In the end, we will have a linear equation for each of the stocks and plot the regression line.

beta = []
alpha = []

for i in df_returns.columns:
if i != 'Date' and i != 'NIFTY':
df_returns.plot(kind = 'scatter', x = 'NIFTY', y = i)
b, a = np.polyfit(df_returns['NIFTY'], df_returns[i], 1)
plt.plot(df_returns['NIFTY'], b * df_returns['NIFTY'] + a, '-',
color = 'r')
beta.append(b)
alpha.append(a)

OUTPUT:
beta: [1.4488, 0.5953, 1.3592, 0.7008, 0.8208]

Calculating the expected returns

We have all the required data like the risk-free rate, the beta(β), and the market return (Rₘ). Let’s calculate the returns for each of the stocks and also for the portfolio.

ER = []
rf = 0
rm = df_returns['NIFTY'].mean() * 252
print(f'Market return is {rm}%')

for i in beta:
ER_tmp = rf + (i * (rm-rf))
ER.append(ER_tmp)
print(f'Expected return based on CAPM for {i} is {ER_tmp}')

portfolio_weights = 1/len(tickers) * np.ones(len(tickers))
ER_portfolio = sum(ER * portfolio_weights)
print(f'Portfolio expected return is {round(ER_portfolio,2)} %')


OUTPUT:
Market return is 11.93%

Expected return based on CAPM for TATAMOTORS is 17.29 %
Expected return based on CAPM for DABUR is 7.1 %
Expected return based on CAPM for ICICIBANK is 16.22 %
Expected return based on CAPM for WIPRO is 8.36 %
Expected return based on CAPM for INFY is 9.8 %

Portfolio expected return is 11.76 %

The portfolio return is 11.76% which is mimicking the market (NIFTY) which is 11.93%. If we take the simple average of the five β values in the portfolio, it turns out to be 0.98 meaning the portfolio return would be marginally less than the market return.

Assumptions of CAPM

  • All investors are risk-averse by nature.
  • There is some time period to evaluate information
  • Risk and return are linearly related
  • There are no additional costs
  • The risk-free rate of return

Closing thoughts

The CAPM can be used to determine if the stocks are fairly valued or not and is based on the modern portfolio theory. The simplicity of the models helps us understand the relationship between risk and returns which lets investors strike the right balance in investment decisions. In this blog, we learned the basics of the Capital Asset Pricing Model (CAPM), the factors involved, and the interpretation of the β. We accomplished all this in python right from the loading of the data, the EDA, calculating daily returns, and portfolio returns. There are many other models for building Asset Pricing models like the Three- factors, and five-factor models which are worth exploring.

Note that we didn’t optimize the portfolio, instead had equal weights for all the stocks in the portfolio (just to keep it simple). Please feel free to explore How To Build A Financial Portfolio Using Python for ideas to improve the portfolio returns further.

I hope you liked the article and found it helpful.

You can connect with me — on Linkedin and Github

Disclaimer

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

References

Investopedia

Leave a Reply

Your email address will not be published. Required fields are marked *