quantlab.runs.backtest_report.write_backtest_report#
- quantlab.runs.backtest_report.write_backtest_report(account, path, *, title, metrics=None, weights=None, config=None, benchmark=None, folds=None, extras=None)[source]#
Write the HTML report of one backtest run to
path, drawn from its record.The page opens with a header (the run, its window and benchmark), a sidebar of sections and a row of headline numbers. Each section holds its charts beside the tables that explain them: Overview (the windows timeline, in-sample against out-of-sample when the run has an in-sample part, the Performance chart of NAV, drawdown, monthly returns and the monthly heatmap, and the strategy against the benchmark by group), Excess (cumulative excess return with a log / arithmetic toggle, the excess drawdown, and the excess over the benchmark), Rolling (one-year panels), Portfolio (turnover, holdings and exposure per rebalance, and trading), Holdings (each bar’s targets, holdings and cash, when the account has holdings), Attribution and Factor attribution (from
extras) and Setup & notes. Every headline number, metric row and chart explains itself on hover. The headline numbers and the main tables are the out-of-sample slice when the run has an in-sample part, else the whole window. Drawdown isvalue / running max - 1, negative below a peak, in every table, card and chart. A section, card or table whose input is missing is left off the page, and a metric the page does not know is still shown, in an “Other” table.Every chart input is derived from the arguments: the in-sample range (shaded) and the notes from the metrics; the turnover per rebalance fill bar (
backtest_stats.turnoverof the account’s fills, its settlements left out); the decided rebalances from its rebalance record; the Rolling window (year_freqover the bar interval); the deepest drawdown, marked from its valley to its recovery (backtest_stats.drawdown_spanof the value); the timeline; and the benchmark’s curve.- Parameters:
- accountAccountRecord
What the account did (
quantlab.runs.run_metrics): its value (drawn as is, so the page and the persisted equity carry the same numbers), returns, fills, settlements, rebalance record, initial cash, bar interval and year, and its holdings (each symbol’s value at each bar’s close over the book’s value), which give the page a Holdings section.- pathstr | Path
The
report.htmlto write.- titlestr
Page title, typically the run directory name.
- metricsMapping, optional
The run’s metrics, as
metrics.jsonholds them: the sliceswhole,in_sampleandout_of_sample,benchmarkandrelative,executionandportfolio_construction, the split keys (in_sample_rangeis shaded),trained_checkpointandnotes(listed in the Notes section). Arun_cv()run’s mapping (stitched,folds,notes) is read throughstitched, and itsfoldsare the timeline’s rows.- weightsxarray.DataArray, optional
Target weights on
(timestamp, symbol), an all-NaN row on a bar that holds; the Portfolio section draws the holdings and exposure of the decided rebalances’ rows (a NaN cell counted at that symbol’s last target) and the Holdings section the targets in force.- configMapping, optional
The run’s config mapping (
BaseBacktester.get_config(), a run directory’sconfig.json), read for the Setup lines:Bar interval;Benchmarkwith itssource; the deepest drawdown;Model mode(orSignalfor a run without a model);Rebalance every;Portfolio construction(the rule’srepr), orTop NandDirection;Fees;Trained checkpoint. Every key is read with.get(). Without it the page has only the lines ofextras.setup.- benchmarkBenchmarkRecord, optional
The benchmark (
quantlab.runs.run_metrics), drawn beside the portfolio and named by the metrics’benchmarksymbol (else its ownsymbol, else “benchmark”); its curve is itsvalue, orinit_cash * cumprod(1 + returns)(bought and held from the account’s capital) when it has none. A benchmark that does not cover the account’s bars is left off.- foldssequence of Mapping, optional
The timeline’s rows of a run traded by several models, each with
fold(its number),training_window,traded(its first and last traded bar label) andin_sample_range. Default: the rows ofmetrics["folds"](arun_cv()run), else one “model” row when the metrics have atraining_window, else none.- extrasReportExtras, optional
What only some runs have (attribution, extra tables, Setup lines, the Holdings section’s names and prices).
Examples
>>> import pandas as pd, xarray as xr >>> from quantlab.runs.run_metrics import AccountRecord >>> bars = pd.bdate_range("2024-01-01", periods=5) >>> on_bars = dict(dims="timestamp", coords={"timestamp": bars}) >>> account = AccountRecord( ... value=xr.DataArray([100.0, 104.0, 98.0, 103.0, 110.0], **on_bars), ... returns=xr.DataArray([0.0, 0.04, -0.0577, 0.051, 0.068], **on_bars), ... orders=xr.Dataset(), ... rebalances=xr.Dataset({"scheduled": ("timestamp", [False] * 5), ... "decided": ("timestamp", [False] * 5)}, coords={"timestamp": bars}), ... init_cash=100.0, bar_interval="1D", year_freq=pd.Timedelta(days=252), ... ) >>> write_backtest_report( ... account, "demo.html", title="demo_run", ... metrics={"whole": {"Total Return [%]": 10.0}, "notes": ["No borrow cost is modelled."]}, ... config={"rebalance_periods": 5, "fees": 0.001}, ... ) >>> page = open("demo.html").read() >>> "<h1>demo_run</h1>" in page, "<td>5 bars</td>" in page (True, True)