Skip to content

Commit 691a147

Browse files
committed
docs: recommend recalculate_backtests_in_directory; mark in-memory variant deprecated
1 parent 57dd33d commit 691a147

1 file changed

Lines changed: 54 additions & 28 deletions

File tree

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

Lines changed: 54 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -84,46 +84,51 @@ report.show()
8484

8585
## Recalculating Metrics
8686

87-
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:
87+
When metric calculations are updated in a newer framework version, previously saved backtests may have stale metrics. Use `recalculate_backtests_in_directory` to recompute all per-run and summary metrics from the raw portfolio snapshots and trades**directly on disk**, without ever loading the full set of backtests into memory:
8888

8989
```python
90-
from investing_algorithm_framework import BacktestReport, recalculate_backtests
90+
from investing_algorithm_framework import recalculate_backtests_in_directory
9191

92-
report = BacktestReport.open(directory_path="./my_backtests")
93-
94-
# Recalculate all metrics for all backtests
95-
recalculate_backtests(report.backtests)
96-
97-
report.show()
92+
# Rewrites every bundle in ./my_backtests in place
93+
recalculate_backtests_in_directory("./my_backtests")
9894
```
9995

100-
You can specify a custom risk-free rate (otherwise each backtest's stored rate is used):
96+
Each backtest is loaded, recalculated, and written back **inside a worker process**, so the parent process's memory footprint stays flat regardless of how many backtests are processed. This is the recommended approach for any non-trivial batch (hundreds to thousands of backtests with portfolio snapshots and trades can otherwise consume tens of GB).
97+
98+
Write to a different directory instead of in place:
10199

102100
```python
103-
recalculate_backtests(report.backtests, risk_free_rate=0.04)
101+
recalculate_backtests_in_directory(
102+
src_dir="./my_backtests",
103+
dst_dir="./my_backtests_v2",
104+
)
104105
```
105106

106-
Or limit which metrics are recomputed:
107+
Use a custom risk-free rate (otherwise each backtest's stored rate is used):
107108

108109
```python
109-
recalculate_backtests(
110-
report.backtests,
111-
metrics=["cagr", "sharpe_ratio", "max_drawdown", "win_rate"]
112-
)
110+
recalculate_backtests_in_directory("./my_backtests", risk_free_rate=0.04)
113111
```
114112

115-
`recalculate_backtests` works on any list of `Backtest` objects, not just those loaded from disk:
113+
Limit which metrics are recomputed, or tune parallelism:
116114

117115
```python
118-
from investing_algorithm_framework import recalculate_backtests
119-
120-
backtests = [backtest_a, backtest_b, backtest_c]
121-
recalculate_backtests(backtests, risk_free_rate=0.027)
116+
recalculate_backtests_in_directory(
117+
"./my_backtests",
118+
metrics=["cagr", "sharpe_ratio", "max_drawdown", "win_rate"],
119+
workers=4,
120+
show_progress=True,
121+
)
122122
```
123123

124124
For each backtest, the function:
125125
1. Recomputes per-run `BacktestMetrics` from raw `portfolio_snapshots` and `trades`
126126
2. Regenerates `BacktestSummaryMetrics` by aggregating the updated per-run metrics
127+
3. Writes the updated bundle back to disk and (by default) refreshes `index.parquet`
128+
129+
:::warning Deprecated: `recalculate_backtests(List[Backtest])`
130+
The in-memory variant `recalculate_backtests(backtests)` is **deprecated since 8.7.2** and will be removed in a future major release. Holding many backtests in the parent process is memory-unsafe — each `Backtest` carries portfolio snapshots, trades and timeseries, so a list of a few thousand backtests can easily consume tens of GB before any work starts. Use `recalculate_backtests_in_directory(src_dir, ...)` instead.
131+
:::
127132

128133
## Saving Reports
129134

@@ -191,7 +196,8 @@ Toggle between dark and light mode using the sun icon in the top-right corner.
191196
```python
192197
from datetime import datetime, timezone
193198
from investing_algorithm_framework import (
194-
create_app, BacktestDateRange, BacktestReport, recalculate_backtests
199+
create_app, BacktestDateRange, BacktestReport,
200+
recalculate_backtests_in_directory,
195201
)
196202

197203
app = create_app()
@@ -211,18 +217,18 @@ date_ranges = [
211217
),
212218
]
213219

214-
backtests = app.run_vector_backtests(
220+
app.run_vector_backtests(
215221
strategies=my_strategies,
216222
backtest_date_ranges=date_ranges,
217223
initial_amount=1000,
218224
backtest_storage_directory="./backtests"
219225
)
220226

221-
# Optional: recalculate metrics with updated calculations
222-
recalculate_backtests(backtests, risk_free_rate=0.04)
227+
# Optional: recalculate metrics with updated calculations (memory-safe, on disk)
228+
recalculate_backtests_in_directory("./backtests", risk_free_rate=0.04)
223229

224230
# Generate and save the comparison report
225-
report = BacktestReport(backtests=backtests)
231+
report = BacktestReport.open(directory_path="./backtests")
226232
report.save("comparison_report.html")
227233
report.show(browser=True)
228234
```
@@ -239,7 +245,29 @@ report.show(browser=True)
239245
| `report.show(browser=False)` | Display the report. In Jupyter: renders inline. Otherwise: opens browser. Set `browser=True` to force browser. |
240246
| `report.save(path)` | Save the report as a self-contained HTML file |
241247

242-
### `recalculate_backtests`
248+
### `recalculate_backtests_in_directory`
249+
250+
Stream-recalculates every backtest bundle on disk inside worker processes. The full `Backtest` never crosses the process boundary, so parent memory stays flat.
251+
252+
| Parameter | Type | Description |
253+
|-----------|------|-------------|
254+
| `src_dir` | `str \| Path` | Directory containing `.iafbt` bundles (and/or legacy backtest directories) |
255+
| `dst_dir` | `str \| Path`, optional | Output directory. If `None`, bundles are rewritten in place inside `src_dir` |
256+
| `risk_free_rate` | `float`, optional | Override risk-free rate. If `None`, uses each backtest's stored rate |
257+
| `metrics` | `List[str]`, optional | Specific metrics to compute. If `None`, computes all default metrics |
258+
| `workers` | `int`, optional | Number of parallel worker processes. Defaults to `min(8, cpu_count)`. Pass `1` for serial |
259+
| `show_progress` | `bool` | Display a tqdm progress bar (default `False`) |
260+
| `include_ohlcv` | `bool` | Re-emit attached OHLCV data with the bundle (default `False`) |
261+
| `max_tasks_per_child` | `int`, optional | Recycle each worker after this many tasks so RSS stays bounded (default `16`) |
262+
| `update_index` | `bool` | Rewrite `index.parquet` in the destination directory (default `True`) |
263+
264+
**Returns:** `int` — the number of backtests recalculated.
265+
266+
### `recalculate_backtests` *(deprecated)*
267+
268+
:::warning Deprecated since 8.7.2
269+
Use [`recalculate_backtests_in_directory`](#recalculate_backtests_in_directory) instead. This in-memory variant will be removed in a future major release.
270+
:::
243271

244272
| Parameter | Type | Description |
245273
|-----------|------|-------------|
@@ -248,5 +276,3 @@ report.show(browser=True)
248276
| `metrics` | `List[str]`, optional | Specific metrics to compute. If `None`, computes all default metrics |
249277

250278
**Returns:** `List[Backtest]` — the same backtest objects with updated metrics.
251-
252-
Recalculates all per-run `BacktestMetrics` from raw portfolio snapshots and trades, then regenerates `BacktestSummaryMetrics` for each backtest.

0 commit comments

Comments
 (0)