DS Concepts DS Languages

Leverage Effect using Python: FA12

 

Leverage Effect using Python

Hi All! In our previous tutorial, we had covered Stylized fact 4: Decreasing auto-correlation trend in squared/absolute returns. In this tutorial, we’ll continue exploring stylized fact and will go through Stylized fact 5: understanding leverage effect using Python. If you want to learn what are stylized facts, please go here. If you’re new to Financial Analytics, I suggest you start from here.

Stylized fact 5: Understanding Leverage Effect using Python

What is Leverage effect?

Leverage effect refers to negative correlation between asset’s returns and the changes in its volatility. Thus, whenever we see rise in returns, there will be decrease in volatility. Let’s see it by MSFT example. We will be using log returns in this case.

 

Leverage Effect using Python

We will fetch MSFT stocks from yahoo finance using yfinance library of Python and find out rolling standard deviation for different windows.
In [1]:
# Importing libraries
import pandas as pd
import yfinance as yf
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import scipy.stats as scs
import statsmodels.api as sm
import statsmodels.tsa.api as smt
In [2]:
# Downloading MSFT data from yfinance from 1st January 2010 to 31st March 2020
msftStockData = yf.download( 'MSFT',
                        start = '2010-01-01',
                        end = '2020-03-31',
                        progress = False)
In [3]:
# Checking what's in there the dataframe by loading first 5 rows
msftStockData.head()
Out[3]:
Open High Low Close Adj Close Volume
Date
2009-12-31 30.980000 30.990000 30.480000 30.480000 23.925440 31929700
2010-01-04 30.620001 31.100000 30.590000 30.950001 24.294369 38409100
2010-01-05 30.850000 31.100000 30.639999 30.959999 24.302216 49749600
2010-01-06 30.879999 31.080000 30.520000 30.770000 24.153070 58182400
2010-01-07 30.629999 30.700001 30.190001 30.450001 23.901886 50559700
In [4]:
# Checking what's in there the dataframe by loading last 5 rows
msftStockData.tail()
Out[4]:
Open High Low Close Adj Close Volume
Date
2020-03-24 143.750000 149.600006 141.270004 148.339996 148.339996 82516700
2020-03-25 148.910004 154.330002 144.440002 146.919998 146.919998 75638200
2020-03-26 148.399994 156.660004 148.369995 156.110001 156.110001 64568100
2020-03-27 151.750000 154.889999 149.199997 149.699997 149.699997 57042300
2020-03-30 152.440002 160.600006 150.009995 160.229996 160.229996 63420300
In [5]:
# Calculating log returns and obtaining column to contain it
msftStockData['Log Returns'] = np.log(msftStockData['Adj Close']/msftStockData['Adj Close'].shift(1)) 
In [6]:
# Checking what's in there the dataframe by loading first 5 rows
msftStockData.head()
Out[6]:
Open High Low Close Adj Close Volume Log Returns
Date
2009-12-31 30.980000 30.990000 30.480000 30.480000 23.925440 31929700 NaN
2010-01-04 30.620001 31.100000 30.590000 30.950001 24.294369 38409100 0.015302
2010-01-05 30.850000 31.100000 30.639999 30.959999 24.302216 49749600 0.000323
2010-01-06 30.879999 31.080000 30.520000 30.770000 24.153070 58182400 -0.006156
2010-01-07 30.629999 30.700001 30.190001 30.450001 23.901886 50559700 -0.010454
In [7]:
# Using back fill method to replace NaN values
msftStockData['Log Returns'] = msftStockData['Log Returns'].fillna(method = 'bfill')
msftStockData.head()
Out[7]:
Open High Low Close Adj Close Volume Log Returns
Date
2009-12-31 30.980000 30.990000 30.480000 30.480000 23.925440 31929700 0.015302
2010-01-04 30.620001 31.100000 30.590000 30.950001 24.294369 38409100 0.015302
2010-01-05 30.850000 31.100000 30.639999 30.959999 24.302216 49749600 0.000323
2010-01-06 30.879999 31.080000 30.520000 30.770000 24.153070 58182400 -0.006156
2010-01-07 30.629999 30.700001 30.190001 30.450001 23.901886 50559700 -0.010454
In [8]:
# Taking monthly window - average of 21 days per month is taken in the trading world, 
# This is the time span for which particular stock exchange is open
# We have on average 21 trading days in a month
msftStockData['21_day_mstd'] = msftStockData[['Log Returns']].rolling(window=21).std()

# Taking yearly window - average of 252 days per year is taken in the trading world, 
# This is the time span for which particular stock exchange is open
# We have on average 252 trading days in an year
msftStockData['252_day_mstd'] = msftStockData[['Log Returns']].rolling(window=252).std()
In [9]:
# Plotting MSFT Adj Close, daily log returns, 21_day_mstd and 252_day_mstd 
# Distributing in 3 subplots
# sharex controls sharing of properties among x-axis.
# That is, all three subplots will use same x-axis
fig, ax = plt.subplots(3, 1, figsize=(20, 15), sharex=True) 

# Subplot 1 - Daily Adj Close trend
msftStockData['Adj Close'].plot(ax=ax[0])
# Setting title and ylabel
ax[0].set(title='MSFT Adj Close', ylabel='Adjusted Close Price')

# Subplot 2 - Daily log returns
msftStockData['Log Returns'].plot(ax=ax[1])
# Setting title and ylabel
ax[1].set(title='MSFT Log Returns', ylabel='Log returns')

# Subplot 3 - 21 days and 252 days windows to calculate rolling standard deviations
msftStockData['252_day_mstd'].plot(ax=ax[2], color='g', label='Rolling yearly standard deviation/volatility')
msftStockData['21_day_mstd'].plot(ax=ax[2], color='b', label='Rolling monthly standard deviation/volatility')
ax[2].set(ylabel='Rolling standard deivation/volatility', xlabel='Date')
ax[2].legend()

 

Leverage effect

From the graph, we can see that when log returns decrease, the volatility shoots up. Hence, our stylized fact 5: Leverage effect gets verified here.

So guys, with this I conclude this tutorial. If you like our blog posts, please follow our blog to stay updated on what’s going on latest in the world of data science, machine learning and business intelligence. Also, please check out our YouTube channel here. Stay tuned!

Leave a Reply

Back To Top
%d bloggers like this: