Skip to content

Commit 616fffa

Browse files
committed
feat: add recalculate_backtests, redesign compare page, update docs
- Add recalculate_backtests() to recompute all per-run and summary metrics from raw portfolio snapshots and trades - Redesign compare page: Key Metrics, Trading Activity, Return Scenarios ranking tables (overview style) - Merge Monthly Returns + Monthly Return Distribution into single component with Returns/Growth x Rows/Heatmap toggles + year filter - Add trades_per_month/week metrics to BacktestMetrics and summary - Add Recovery Factor and Volatility to Key Metrics table - Update backtest-reports.md docs with recalculate_backtests API and updated dashboard feature descriptions - Add test_recalculate_backtests.py with idempotency and consistency tests - Wire recalculate_backtests into examples/open.py
1 parent 91c87b5 commit 616fffa

16 files changed

Lines changed: 3541 additions & 254 deletions

File tree

docusaurus/docs/Getting Started/backtest-reports.md

Lines changed: 84 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@ report.show()
4545
```
4646

4747
This generates a multi-strategy comparison dashboard with:
48-
- Strategy ranking table (sortable by CAGR, Sharpe, Max DD, etc.)
48+
- Strategy ranking tables (Key Metrics, Trading Activity)
49+
- Return Scenarios projections (Good/Average/Bad/Very Bad Year)
4950
- Normalized equity curves overlay
5051
- Per-strategy detail pages with Summary, Runs, and Performance tabs
51-
- Compare mode for selected strategies
52+
- Compare mode with monthly return distribution (Rows/Heatmap × Returns/Growth toggles)
5253

5354
### From Saved Backtests on Disk
5455

@@ -59,7 +60,7 @@ report = BacktestReport.open(directory_path="./my_backtests")
5960
report.show()
6061
```
6162

62-
The `open()` method recursively finds all valid backtest directories (containing `results.json` and `metrics.json`) and loads them into a single report.
63+
The `open()` method recursively finds all valid backtest directories (containing `algorithm_id.json` and a `runs/` folder) and loads them into a single report.
6364

6465
You can also combine disk and in-memory backtests:
6566

@@ -71,6 +72,49 @@ report = BacktestReport.open(
7172
report.show()
7273
```
7374

75+
## Recalculating Metrics
76+
77+
When metric calculations are updated in a newer framework version, previously saved backtests may have stale metrics. Use `recalculate_backtests` to recompute all per-run and summary metrics from the raw portfolio snapshots and trades:
78+
79+
```python
80+
from investing_algorithm_framework import BacktestReport, recalculate_backtests
81+
82+
report = BacktestReport.open(directory_path="./my_backtests")
83+
84+
# Recalculate all metrics for all backtests
85+
recalculate_backtests(report.backtests)
86+
87+
report.show()
88+
```
89+
90+
You can specify a custom risk-free rate (otherwise each backtest's stored rate is used):
91+
92+
```python
93+
recalculate_backtests(report.backtests, risk_free_rate=0.04)
94+
```
95+
96+
Or limit which metrics are recomputed:
97+
98+
```python
99+
recalculate_backtests(
100+
report.backtests,
101+
metrics=["cagr", "sharpe_ratio", "max_drawdown", "win_rate"]
102+
)
103+
```
104+
105+
`recalculate_backtests` works on any list of `Backtest` objects, not just those loaded from disk:
106+
107+
```python
108+
from investing_algorithm_framework import recalculate_backtests
109+
110+
backtests = [backtest_a, backtest_b, backtest_c]
111+
recalculate_backtests(backtests, risk_free_rate=0.027)
112+
```
113+
114+
For each backtest, the function:
115+
1. Recomputes per-run `BacktestMetrics` from raw `portfolio_snapshots` and `trades`
116+
2. Regenerates `BacktestSummaryMetrics` by aggregating the updated per-run metrics
117+
74118
## Saving Reports
75119

76120
Save the report as a standalone HTML file you can share or open later:
@@ -96,27 +140,38 @@ report.show(browser=True) # Also opens in the browser
96140
## Dashboard Features
97141

98142
### Overview Page
99-
- **KPI cards**: Strategies count, backtest windows, best CAGR, best Sharpe, lowest max drawdown
100-
- **Backtest windows table**: Date ranges, duration, number of strategies per window
101-
- **Strategy ranking table**: Sortable by any metric, with best-in-class highlighting
102-
- **Equity curves**: Normalized percentage growth overlay for all strategies
143+
- **KPI cards**: Best CAGR, best Sharpe, lowest max drawdown (with dual values when a window is selected)
144+
- **Window Coverage**: Strategy × window matrix showing data coverage
145+
- **Key Metrics table**: Sortable ranking with CAGR, Sharpe, Sortino, Calmar, Max DD, Volatility, Recovery Factor, Net Gain %
146+
- **Trading Activity table**: Profit Factor, Win Rate, Trades/yr, Trades/mo, Trades/wk, # Trades, Avg Return, Avg Duration
147+
- **Return Scenarios**: Good/Average/Bad/Very Bad Year projections based on CAGR ± volatility
148+
- **Equity curves**: Normalized percentage growth overlay
149+
- **Collapsible cards**: All chart sections can be collapsed/expanded
103150

104151
### Strategy Pages
105152
Each strategy gets a dedicated page with three tabs:
106153

107154
| Tab | Contents |
108155
|-----|----------|
109-
| **Summary** | Full KPI grid (CAGR, Sharpe, Sortino, Calmar, Max DD, Profit Factor, Win Rate, Volatility, etc.) |
156+
| **Summary** | Full KPI grid (CAGR, Sharpe, Sortino, Calmar, Max DD, Profit Factor, Win Rate, Volatility, Recovery Factor, etc.) |
110157
| **Runs** | Backtest run comparison table, equity overlay across runs |
111-
| **Performance** | Monthly returns heatmap, yearly returns bar chart |
158+
| **Performance** | Monthly returns heatmap, yearly returns bar chart, return distribution |
112159

113160
Use the run selector pills to switch between summary view and individual backtest runs.
114161

115162
### Compare Mode (Multi-Strategy)
116-
Select strategies via checkboxes in the ranking table, then click **Compare Selected** to see:
117-
- Side-by-side equity curves
118-
- Metric bar charts (CAGR, Sharpe, Max DD, Win Rate)
119-
- Monthly and yearly return comparisons
163+
Open the strategy selection modal to pick strategies for comparison. You can set a challenger strategy for highlighting. The compare page includes:
164+
- **Key Metrics** and **Trading Activity** ranking tables
165+
- **Return Scenarios** projections
166+
- **Monthly Returns** with four view modes (Returns/Growth × Rows/Heatmap), plus a year filter
167+
- Side-by-side equity curves and drawdown overlays
168+
- Metric bar charts (CAGR, Sharpe, Sortino, Calmar, Max DD, Win Rate, Profit Factor)
169+
- Return distribution histograms and correlation matrix
170+
- Rolling Sharpe ratio chart
171+
- Yearly returns bar charts
172+
173+
### Sticky Navigation
174+
The page title bar with the window selector stays visible as you scroll.
120175

121176
### Dark / Light Theme
122177
Toggle between dark and light mode using the sun icon in the top-right corner.
@@ -126,7 +181,7 @@ Toggle between dark and light mode using the sun icon in the top-right corner.
126181
```python
127182
from datetime import datetime, timezone
128183
from investing_algorithm_framework import (
129-
create_app, BacktestDateRange, BacktestReport
184+
create_app, BacktestDateRange, BacktestReport, recalculate_backtests
130185
)
131186

132187
app = create_app()
@@ -153,6 +208,9 @@ backtests = app.run_vector_backtests(
153208
backtest_storage_directory="./backtests"
154209
)
155210

211+
# Optional: recalculate metrics with updated calculations
212+
recalculate_backtests(backtests, risk_free_rate=0.04)
213+
156214
# Generate and save the comparison report
157215
report = BacktestReport(backtests=backtests)
158216
report.save("comparison_report.html")
@@ -170,3 +228,15 @@ report.show(browser=True)
170228
| `BacktestReport.open(directory_path=..., backtests=[...])` | Load backtests from disk and/or combine with in-memory backtests |
171229
| `report.show(browser=False)` | Display the report. In Jupyter: renders inline. Otherwise: opens browser. Set `browser=True` to force browser. |
172230
| `report.save(path)` | Save the report as a self-contained HTML file |
231+
232+
### `recalculate_backtests`
233+
234+
| Parameter | Type | Description |
235+
|-----------|------|-------------|
236+
| `backtests` | `List[Backtest]` | The backtests to recalculate (mutated in place and returned) |
237+
| `risk_free_rate` | `float`, optional | Override risk-free rate. If `None`, uses each backtest's stored rate (falls back to `0.0`) |
238+
| `metrics` | `List[str]`, optional | Specific metrics to compute. If `None`, computes all default metrics |
239+
240+
**Returns:** `List[Backtest]` — the same backtest objects with updated metrics.
241+
242+
Recalculates all per-run `BacktestMetrics` from raw portfolio snapshots and trades, then regenerates `BacktestSummaryMetrics` for each backtest.

examples/open.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import os
2-
from investing_algorithm_framework import BacktestReport
2+
from investing_algorithm_framework import BacktestReport, recalculate_backtests
33

44

55
batch_one_path = os.path.join("examples", "batch_one")
66

77
if __name__ == "__main__":
88
report = BacktestReport.open(directory_path=batch_one_path)
9+
recalculate_backtests(report.backtests)
910
report.show()

investing_algorithm_framework/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
get_current_average_trade_loss, get_negative_trades, \
5757
get_positive_trades, get_number_of_trades, get_current_win_rate, \
5858
get_current_win_loss_ratio, create_backtest_metrics_for_backtest, \
59-
TradeTakeProfitService, TradeStopLossService
59+
recalculate_backtests, TradeTakeProfitService, TradeStopLossService
6060

6161

6262
__all__ = [
@@ -201,6 +201,7 @@
201201
"save_backtests_to_directory",
202202
"DataError",
203203
"create_backtest_metrics_for_backtest",
204+
"recalculate_backtests",
204205
"TakeProfitRule",
205206
"StopLossRule",
206207
"TradeStopLossService",

0 commit comments

Comments
 (0)