Skip to content

Instantly share code, notes, and snippets.

@raposatech
Created February 18, 2022 16:01
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raposatech/4edab5c77bb58d9f8a82710e1b88bddd to your computer and use it in GitHub Desktop.
Save raposatech/4edab5c77bb58d9f8a82710e1b88bddd to your computer and use it in GitHub Desktop.
Helper functions to calculate backtest returns and strategy stats.
# A few helper functions
def calcReturns(df):
# Helper function to avoid repeating too much code
df['returns'] = df['Close'] / df['Close'].shift(1)
df['log_returns'] = np.log(df['returns'])
df['strat_returns'] = df['position'].shift(1) * df['returns']
df['strat_log_returns'] = df['position'].shift(1) * \
df['log_returns']
df['cum_returns'] = np.exp(df['log_returns'].cumsum()) - 1
df['strat_cum_returns'] = np.exp(
df['strat_log_returns'].cumsum()) - 1
df['peak'] = df['cum_returns'].cummax()
df['strat_peak'] = df['strat_cum_returns'].cummax()
return df
def getStratStats(log_returns: pd.Series,
risk_free_rate: float = 0.02):
stats = {} # Total Returns
stats['tot_returns'] = np.exp(log_returns.sum()) - 1
# Mean Annual Returns
stats['annual_returns'] = np.exp(log_returns.mean() * 252) - 1
# Annual Volatility
stats['annual_volatility'] = log_returns.std() * np.sqrt(252)
# Sortino Ratio
annualized_downside = log_returns.loc[log_returns<0].std() * \
np.sqrt(252)
stats['sortino_ratio'] = (stats['annual_returns'] - \
risk_free_rate) / annualized_downside
# Sharpe Ratio
stats['sharpe_ratio'] = (stats['annual_returns'] - \
risk_free_rate) / stats['annual_volatility']
# Max Drawdown
cum_returns = log_returns.cumsum() - 1
peak = cum_returns.cummax()
drawdown = peak - cum_returns
max_idx = drawdown.argmax()
stats['max_drawdown'] = 1 - np.exp(cum_returns[max_idx]) \
/ np.exp(peak[max_idx])
# Max Drawdown Duration
strat_dd = drawdown[drawdown==0]
strat_dd_diff = strat_dd.index[1:] - strat_dd.index[:-1]
strat_dd_days = strat_dd_diff.map(lambda x: x.days).values
strat_dd_days = np.hstack([strat_dd_days,
(drawdown.index[-1] - strat_dd.index[-1]).days])
stats['max_drawdown_duration'] = strat_dd_days.max()
return {k: np.round(v, 4) if type(v) == np.float_ else v
for k, v in stats.items()}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment