Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python rolling Sharpe ratio with Pandas or NumPy

I am trying to generate a plot of the 6-month rolling Sharpe ratio using Python with Pandas/NumPy.

My input data is below:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style("whitegrid")

# Generate sample data
d = pd.date_range(start='1/1/2008', end='12/1/2015')
df = pd.DataFrame(d, columns=['Date'])
df['returns'] = np.random.rand(d.size, 1)
df = df.set_index('Date')
print(df.head(20))

             returns
Date                
2008-01-01  0.232794
2008-01-02  0.957157
2008-01-03  0.079939
2008-01-04  0.772999
2008-01-05  0.708377
2008-01-06  0.579662
2008-01-07  0.998632
2008-01-08  0.432605
2008-01-09  0.499041
2008-01-10  0.693420
2008-01-11  0.330222
2008-01-12  0.109280
2008-01-13  0.776309
2008-01-14  0.079325
2008-01-15  0.559206
2008-01-16  0.748133
2008-01-17  0.747319
2008-01-18  0.936322
2008-01-19  0.211246
2008-01-20  0.755340

What I want

The type of plot I am trying to produce is this or the first plot from here (see below). enter image description here

My attempt

Here is the equation I am using:

def my_rolling_sharpe(y):
    return np.sqrt(126) * (y.mean() / y.std()) # 21 days per month X 6 months = 126

# Calculate rolling Sharpe ratio
df['rs'] = calc_sharpe_ratio(df['returns'])

fig, ax = plt.subplots(figsize=(10, 3))
df['rs'].plot(style='-', lw=3, color='indianred', label='Sharpe')\
        .axhline(y = 0, color = "black", lw = 3)

plt.ylabel('Sharpe ratio')
plt.legend(loc='best')
plt.title('Rolling Sharpe ratio (6-month)')
fig.tight_layout()
plt.show()

enter image description here

The problem is that I am getting a horizontal line since my function is giving a single value for the Sharpe ratio. This value is the same for all the Dates. In the example plots, they appear to be showing many ratios.

Question

Is it possible to plot a 6-month rolling Sharpe ratio that changes from one day to the next?

like image 903
edesz Avatar asked Mar 04 '18 01:03

edesz


People also ask

How to compute Sharpe ratio in Python?

The Sharpe Ratio is measured by first finding the expected rate of return, or the average return over a specified time period, then subtracting the risk-free rate. This is the reward portion of the Sharpe Ratio, which will then be divided by the standard deviation of the returns (the risk portion).

What is rolling Sharpe ratio?

It is the ratio of the expectation of the excess returns of the strategy to the standard deviation of those excess returns. In essence it captures the ratio of reward-to-risk, where risk is defined as returns volatility.

How do you calculate Sharpe ratio from daily return?

Sharpe ratio is calculated by dividing the difference between the daily return of Sundaram equity hybrid fund and the daily return of 10 year G Sec bonds by the standard deviation of the return of the hybrid fund. Consequently, the Sharpe ratio based on the daily return is calculated as 0.272.


2 Answers

Approximately correct solution using df.rolling and a fixed window size of 180 days:

df['rs'] = df['returns'].rolling('180d').apply(my_rolling_sharpe)

This window isn't exactly 6 calendar months wide because rolling requires a fixed window size, so trying window='6MS' (6 Month Starts) throws a ValueError.

To calculate the Sharpe ratio for a window exactly 6 calendar months wide, I'll copy this super cool answer by SO user Mike:

df['rs2'] = [my_rolling_sharpe(df.loc[d - pd.offsets.DateOffset(months=6):d, 'returns']) 
             for d in df.index]

# Compare the two windows
df.plot(y=['rs', 'rs2'], linewidth=0.5)

Sharpe ratio comparison

like image 77
Peter Leimbigler Avatar answered Sep 28 '22 16:09

Peter Leimbigler


I have prepared an alternative solution to your question, this one is based on using solely the window functions from pandas.

Here I have defined "on the fly" the calculation of the Sharpe Ratio, please consider for your solution the following parameters:

  • I have used a Risk Free rate of 2%
  • The dash line is just a Benchmark for the rolling Sharpe Ratio, the value is 1.6

So the code is the following

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style("whitegrid")

# Generate sample data
d = pd.date_range(start='1/1/2008', end='12/1/2015')
df = pd.DataFrame(d, columns=['Date'])
df['returns'] = np.random.rand(d.size, 1)
df = df.set_index('Date')

df['rolling_SR'] = df.returns.rolling(180).apply(lambda x: (x.mean() - 0.02) / x.std(), raw = True)
df.fillna(0, inplace = True)
df[df['rolling_SR'] > 0].rolling_SR.plot(style='-', lw=3, color='orange', 
                                         label='Sharpe', figsize = (10,7))\
                                         .axhline(y = 1.6, color = "blue", lw = 3,
                                                 linestyle = '--')

plt.ylabel('Sharpe ratio')
plt.legend(loc='best')
plt.title('Rolling Sharpe ratio (6-month)')
plt.show()

print('---------------------------------------------------------------')
print('In case you want to check the result data\n')
print(df.tail()) # I use tail, beacause of the size of your window.

You should get something similar to this picture

rolling sharpe ratio

like image 35
Lautaro Parada Opazo Avatar answered Sep 28 '22 16:09

Lautaro Parada Opazo