quantlab.runs.backtest_run.BacktestRun#
- class quantlab.runs.backtest_run.BacktestRun(path, kind, written_at, window, market, annualization, data_fingerprint, code=None, folds=(), index=None, _trained_run=None, _benchmark_source=None, _components=<factory>, _recipe_dir=None)[source]#
Bases:
objectOne backtest run directory, as its
run.jsondescribes it.- Attributes:
- pathPath
The run’s directory.
- kindstr
"run","run_cv","run_weights"or"fold".- written_atstr
When
run.jsonwas written, an ISO 8601 UTC timestamp.- windowtuple of str
The first and last bar simulated, as bar labels.
- marketMarket
The price columns the backtester filled and valued at.
- annualizationAnnualization
How its statistics were annualized.
- data_fingerprintdict
What the run read, by component path, as its
DataRecorderrecorded it: arun_cvrun’s stitched pass, what a fold’s prediction read.- codedict or None
The code record of the backtester’s tree when the run was written (
git,modules,libraries); a fold’s is its run’s.- foldstuple of BacktestRun
A
run_cvrun’s folds, in fold order; empty otherwise.- indexint or None
A fold’s index in the walk; None for other kinds.
Examples
>>> cv = BacktestRun.open(cv_result.run_dir) >>> cv.kind, [fold.index for fold in cv.folds][:3] ('run_cv', [0, 1, 2]) >>> cv.trained_run().kind 'walk_forward'
- property backtester_class#
The import path of the backtester class that wrote the run.
Examples
>>> BacktestRun.open(run_dir).backtester_class.rsplit(".", 1)[-1] 'USEquityCrossectionSelectStockVectorBt'
- property benchmark_source#
Where the benchmark was read from: its store, or the dataset held in memory.
None for a run without a benchmark. Recorded when the run was written, as its report names it.
Examples
>>> BacktestRun.open(run_dir).benchmark_source '/data/market/sharadar/sharadar_spy_1d/sharadar_spy_1d.zarr'
- equity()[source]#
The equity curve:
valueandreturns, plus the benchmark’s when one ran.A fold’s is its
run_cvrun’s, cut to the fold’s window.Examples
>>> sorted(BacktestRun.open(run_dir).equity().data_vars) ['returns', 'value']
- property execution#
How orders were sized and charged:
sizing_basis,fees,slippage.Examples
>>> BacktestRun.open(run_dir).execution ExecutionSettings(sizing_basis='fill', fees=0.001, slippage=0.0)
- factor_attribution()[source]#
The per-bar factor attribution, or None for a run without a risk model.
Examples
>>> BacktestRun.open(run_dir).factor_attribution()["contribution"].dims ('timestamp', 'term')
- property has_predictions#
Whether the run has a prediction panel (a run with a model), without reading it.
Examples
>>> BacktestRun.open(run_dir).has_predictions True
- holdings()[source]#
The simulated holdings, or None for a run written without them.
A fold’s are its
run_cvrun’s, cut to the fold’s window.A
holdingpanel on(timestamp, symbol): each symbol’s value at each bar’s close over the book’s value, cash included, on every bar of the window; 0 where nothing is held.Examples
>>> BacktestRun.open(run_dir).holdings()["holding"].dims ('timestamp', 'symbol')
- property init_cash#
The cash the simulation started with.
Examples
>>> BacktestRun.open(run_dir).init_cash 1000000.0
- log_report(tracking_run)[source]#
Attach the run’s HTML report to
tracking_run(itslog_file).- Parameters:
- tracking_runquantlab.tracking.base.TrackingRun
The open tracking run of the backtest.
Examples
A backtester attaches its report to the tracking run it opened:
BacktestRun.open(result.run_dir).log_report(tracking_run)
- metrics()[source]#
The run’s metrics, as the backtester returned them (NaN as None).
Examples
>>> sorted(BacktestRun.open(run_dir).metrics())[:2] ['execution', 'in_sample']
- classmethod open(path)[source]#
Read the backtest run at
path, with its folds.- Parameters:
- pathPath or str
The run’s directory, or a file in it.
- Returns:
- BacktestRun
- Raises:
- FileNotFoundError
If
pathdoes not exist.- ValueError
If the run, or one of its folds, has no
run.json, anotherformat_version, or is not a backtest run.
Examples
>>> BacktestRun.open(result.run_dir).kind 'run'
- predictions()[source]#
The predictions the rule read, or None for a run without a model or a fold.
Examples
>>> [spec.name for spec in BacktestRun.open(run_dir).predictions().labels] ['fwd_ret_1']
- property rebalance_periods#
The number of bars between rebalances.
Examples
>>> BacktestRun.open(run_dir).rebalance_periods 5
- rebuild(name)[source]#
Rebuild the component the run’s config holds in the field
name.Datasets recorded under the run directory are read from it.
- Parameters:
- namestr
A config field declared to hold a component (
"price_dataset","model","constructor", …), or several.
- Returns:
- object
The rebuilt component, a list of them, or None for an empty field.
- Raises:
- ValueError
If
nameis not a field declared to hold components.
Examples
>>> BacktestRun.open(run_dir).rebuild("constructor") TopNConstructor(direction='long_only', top_n=2, score_label=None)
- rebuild_backtester(**overrides)[source]#
Rebuild the backtester that wrote the run, with some fields replaced.
The recipe is rebuilt by the component rule, datasets recorded under the run directory read from it, and the run’s data fingerprint is set as the backtester’s
expected_fingerprint(and each fold’s asexpected_fold_fingerprints), so a re-run warns when its data differs, naming the fold. A train-mode run also sets its trained unit’s training record asexpected_training_fingerprint, so the retrained unit is compared with the one the run used; not when an override replacesmodelormodel_mode, since the unit then describes another model. The rebuilt tree’s code record is compared with the run’scoderight away; a component an override replaces is left out of both comparisons, data and code, on both sides, and a train-mode run’s trained unit’s code is set asexpected_training_code; differences only warn.- Parameters:
- **overrides
Values keyed by config field name, used in place of the recorded ones: objects for component fields (
model=None,tracker=...), plain values otherwise (output_dir=...).
- Returns:
- BaseBacktester
- Raises:
- ValueError
If an override names no config field, or the run is a fold (rebuild its
run_cvrun).
Examples
>>> run = BacktestRun.open(result.run_dir) >>> weights_only = run.rebuild_backtester(model=None, model_mode=None, checkpoint=None) >>> replay = weights_only.run_weights(run.weights())
- recipe()[source]#
The run’s rebuild recipe, the backtester’s
get_config()as recorded.For presentation that takes a config mapping (the
configofquantlab.runs.backtest_report.write_backtest_report, its Setup lines); a component is rebuilt withrebuild(field)and the backtester withrebuild_backtester.Examples
>>> BacktestRun.open(run_dir).recipe()["rebalance_periods"] 5
- report()[source]#
The run’s self-contained HTML report, as text.
Examples
>>> "<html" in BacktestRun.open(run_dir).report() True
- settlements()[source]#
The delisted holdings settled into cash during the simulation.
A fold’s are its
run_cvrun’s settled inside the fold’s window.Examples
>>> BacktestRun.open(run_dir).settlements() []
- trained_run()[source]#
The trained unit the backtest used, or None for a
run_weightsrun.Examples
>>> BacktestRun.open(run_dir).trained_run().kind 'model'
- weights()[source]#
The simulated target weights, a
weightpanel on(timestamp, symbol), with the rebalance record.The record is
scheduled(the bars the rebalance schedule named) anddecided(those the rule decided; a held bar is scheduled and not decided), booleans ontimestamp. A fold’s are itsrun_cvrun’s, cut to the fold’s window.Examples
>>> BacktestRun.open(run_dir).weights()["weight"].dims ('timestamp', 'symbol') >>> sorted(BacktestRun.open(run_dir).weights().data_vars) ['decided', 'scheduled', 'weight']