Guides

Rolling Sharpe ratio in Python, annualised correctly for 24/7 crypto

Crypto trades 365 days a year. Annualising with 252 understates crypto volatility and Sharpe by about 17%.

Why it happens

Sharpe = mean(r) / std(r) × √(periods per year). For 5-minute crypto bars that's 365 × 288 = 105,120 periods, not 252 × 78. Use min_periods so the first values aren't based on two data points.

Fix it with plain pandas

import numpy as np

ppy = 365 * 288                       # 5-minute bars, 24/7
window = 288 * 7                      # one week
roll = returns.rolling(window, min_periods=window // 2)
rolling_sharpe = roll.mean() / roll.std() * np.sqrt(ppy)

Or with Deptho

Deptho infers the bar spacing, annualises for 24/7 markets by default, and charts rolling Sharpe and Sortino side by side:

import deptho as dp

ppy = dp.metrics.infer_periods_per_year(returns.index)   # 105120.0 for 5m bars
rs = dp.metrics.rolling_sharpe(returns, window=2016, periods_per_year=ppy)

Related