Strategy Tearsheet
SkillDev toolsGenerate comprehensive performance reports from backtest returns. Use when summarizing backtest results for review or comparison.
Available today. Use it from your connected AI after setup.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the Strategy Tearsheet skill
What this skill tells your AI
The instructions your AI receives, as published by ml4t/skills in backtest/tearsheet/SKILL.md and read by ahel’s review.
A single metric hides more than it reveals. A tearsheet shows cumulative returns, drawdowns, rolling Sharpe, monthly heatmap, and a metrics table - exposing regime dependence, tail risk, and decay that one number cannot.
The Problem
Reporting only Sharpe ratio misses critical failure modes. A Sharpe of 1.5 could come from steady 10 bps/day or from one massive gain followed by slow bleed. Max drawdown reveals survival risk. Rolling Sharpe reveals whether alpha is decaying. Monthly returns reveal seasonality. You need all of them.
The Pattern
WRONG
# Single number - hides everything important
sharpe = returns.mean() / returns.std() * np.sqrt(252)
print(f"Sharpe: {sharpe:.2f}") # "Looks great!" - but is the strategy dying?
CORRECT
import numpy as np
import matplotlib.pyplot as plt
def tearsheet(returns: np.ndarray, periods: int = 252):
"""Minimal tearsheet: 4 panels + metrics table."""
cum = (1 + returns).cumprod()
peak = np.maximum.accumulate(cum)
dd = (cum - peak) / peak
# Key metrics
sharpe = returns.mean() / returns.std() * np.sqrt(periods)
max_dd = dd.min()
calmar = (cum[-1] ** (periods / len(returns)) - 1) / abs(max_dd) if max_dd else 0
win_rate = (returns > 0).mean()
profit_factor = returns[returns > 0].sum() / abs(returns[returns < 0].sum())
fig, axes = plt.subplots(3, 1, figsize=(10, 8), sharex=True)
axes[0].plot(cum, linewidth=1)
axes[0].set_title("Cumulative Returns")
axes[1].fill_between(range(len(dd)), dd, 0, alpha=0.5, color="red")
axes[1].set_title("Drawdown")
# Rolling mean over rolling std. Dividing a rolling SUM by a rolling sum of
# squared deviations inflates the result by sqrt(window) - 7.9x at 63 days.
window = np.lib.stride_tricks.sliding_window_view(returns, 63)
rolling = window.mean(1) / window.std(1, ddof=1) * np.sqrt(periods)
axes[2].plot(rolling, linewidth=1)
axes[2].axhline(0, color="gray", linewidth=0.5)
axes[2].set_title("Rolling Sharpe (63-day)")
print(f"Sharpe: {sharpe:>8.2f}")
print(f"Max Drawdown: {max_dd:>8.1%}")
print(f"Calmar: {calmar:>8.2f}")
print(f"Win Rate: {win_rate:>8.1%}")
print(f"Profit Factor: {profit_factor:>8.2f}")
return fig
Required Metrics
| Metric | Formula | Red Flag |
|---|---|---|
| Sharpe | $(\mu - r_f) / \sigma \times \sqrt{252}$ | < 0.5 |
| Max Drawdown | $\max(\text{peak} - \text{trough}) / \text{peak}$ | > 25% |
| Calmar | CAGR / |Max DD| | < 0.5 |
| Win Rate | $N_{\text{win}} / N_{\text{total}}$ | < 40% for trend |
| Profit Factor | $\sum \text{gains} / | \sum \text{losses} |
Always report gross and net (after costs). A gross Sharpe of 1.5 that drops to 0.3 net means costs dominate alpha.
Guardrails
- Annualize with the correct frequency: 252 (daily), 52 (weekly), 12 (monthly)
- Report net-of-cost metrics alongside gross - the gap is the cost burden
- Compare strategy Sharpe to a passive benchmark, not zero
- Use Deflated Sharpe Ratio when selecting among multiple strategies (corrects for multiple testing)
Production Implementation
ml4t-backtest generates tearsheets from BacktestResult:
from ml4t.backtest import Engine
result = Engine(feed, strategy, config).run()
equity_df = result.to_equity_dataframe()
daily_returns = result.to_daily_returns()
Checklist
- Cumulative return, drawdown, and rolling Sharpe plotted
- Sharpe, max drawdown, Calmar, win rate, profit factor reported
- Both gross and net metrics shown
- Annualization matches data frequency
- Compared to benchmark (not just absolute)
Signals
- GitHub stars
- 20
- Forks
- 11
- Last commit
- Sep 2026
Advanced
- Item type
- skill
- Key
ml4t-tearsheet- Source
- github.com/ml4t/skills