Skip to content

Commit

Permalink
added rolling_sharpe, rolling sortino, and rolling_volatility
Browse files Browse the repository at this point in the history
  • Loading branch information
ranaroussi committed Oct 1, 2021
1 parent 3dda309 commit 7156af7
Showing 1 changed file with 44 additions and 0 deletions.
44 changes: 44 additions & 0 deletions quantstats/stats.py
Expand Up @@ -209,6 +209,14 @@ def volatility(returns, periods=252, annualize=True):
return std


def rolling_volatility(returns, rolling_period=126, periods_per_year=252,
prepare_returns=True):
if prepare_returns:
returns = _utils._prepare_returns(returns, rolling_period)

return returns.rolling(rolling_period).std() * _np.sqrt(periods_per_year)


def implied_volatility(returns, periods=252, annualize=True):
""" calculates the implied volatility of returns for a period """
logret = _utils.log_returns(returns)
Expand Down Expand Up @@ -246,6 +254,26 @@ def sharpe(returns, rf=0., periods=252, annualize=True):
return res


def rolling_sharpe(returns, rf=0., rolling_period=126,
periods_per_year=252, annualize=True,
prepare_returns=True):

if rf != 0 and rolling_period is None:
raise Exception('Must provide periods if rf != 0')

if prepare_returns:
returns = _utils._prepare_returns(returns, rf, rolling_period)

res = returns.rolling(rolling_period).mean() / \
returns.rolling(rolling_period).std()

if annualize:
res = res * _np.sqrt(
1 if periods_per_year is None else periods_per_year)

return res


def sortino(returns, rf=0, periods=252, annualize=True):
"""
calculates the sortino ratio of access returns
Expand All @@ -272,6 +300,22 @@ def sortino(returns, rf=0, periods=252, annualize=True):
return res


def rolling_sortino(returns, rf=0, rolling_period=126, annualize=True,
periods_per_year=252, **kwargs):
if rf != 0 and rolling_period is None:
raise Exception('Must provide periods if rf != 0')

if kwargs.get("prepare_returns", True):
returns = _utils._prepare_returns(returns, rf, rolling_period)

downside = (returns[returns < 0] ** 2).sum() / len(returns)

This comment has been minimized.

Copy link
@kartiksubbarao

kartiksubbarao Oct 8, 2021

Contributor

This is incorrect because it calculates the downside for the entire series of returns, not just for the rolling period. A correct calculation would be something like this:
downside = returns.rolling(rolling_period).apply(lambda x: (x[x < 0]**2).sum())/rolling_period
This will be slower than other approaches, but I wanted to provide a simple example to illustrate the issue.

res = returns.rolling(rolling_period).mean() / _np.sqrt(downside)
if annualize:
res = res * _np.sqrt(
1 if periods_per_year is None else periods_per_year)
return res


def adjusted_sortino(returns, rf=0, periods=252, annualize=True):
"""
Jack Schwager's version of the Sortino ratio allows for
Expand Down

0 comments on commit 7156af7

Please sign in to comment.