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)