quantlab.backtest.approximate#
The approximate backtest: every rebalance decided at once, the window simulated as arrays.
A backtest run (BaseBacktester.run()) decides its rebalances one bar at
a time with the holdings replayed under the Execution rules, and pays a
fixed cost for its report and run directory. The approximate backtest
(ADR 0045) is a second backtest for parameter sweeps: built once over a price dataset
(its window’s prices are read once), it is run many times on (predictions,
rule) pairs and returns each account in memory, writing nothing.
Kept from a backtest run: the rebalance schedule (every
rebalance_periods-th bar from the window’s first bar, never its last),
a weight decided at t filling at t + 1’s fill price, holdings marked at the
forward-filled valuation price and drifting with prices between fills,
tradability judged at the decision bar. Given up: rejected orders, locked
positions, delisting settlements (a delisted holding stays at its last
valuation, never turned into cash), the cash cap on buys and min_trade;
fees and slippage are one cost on traded weight. A fill price missing at
a fill bar falls back to the previous bar’s valuation.
The approximate backtest decides with its own implementations of the rules
it runs (quantlab.portfolio.predefined.approximate, chosen through the
portfolio layer’s quantlab.portfolio.approximate.implementation):
TopNConstructor, MeanVarianceOptimizer and ActiveRiskOptimizer,
chosen by the rule’s exact class and reading its config through a field
table, with a LedoitWolfEstimator or a
FactorRiskStoreEstimator as the covariance estimator; any other rule or
estimator, a subclass of one, or a config field it does not handle is
refused before any data is read. The rules’ own classes decide one bar at a
time for a backtest run and know nothing of those implementations. The decision
inputs are read through quantlab.portfolio.decision_inputs.DecisionInputs.panel,
so the point-in-time reads stay in one module. The window is cut into
chunks of chunk_bars bars, each decided once (the implementation’s
decide), in time order: a chunk is handed the book filled before it and each decision bar’s
valuation and fill prices (PanelPrices), so a rule whose decision reads
the holdings (a turnover penalty) drifts them and solves its bars forward,
each once, and a rule that does not solves them at once. An iterative
solver stops a bar when its residual falls to tolerance, or after
max_iterations, with a warning (Stopping). The simulation and the
drift are the execution layer’s (quantlab.execution.approximate),
compiled; this module only reads the prices and the schedule, calls the
implementations and the simulation, and computes the statistics.
The account is an account record (quantlab.runs.run_metrics.AccountRecord),
as a backtest run’s is: its fills, rebalance record and value. Its metric
blocks are run_metrics of it and its attribution block
quantlab.runs.backtest_attribution.attribution_metrics of it, the
functions a backtest run assembles its own blocks with, so the numbers mean
what a run’s metrics.json rows mean (ADR 0034). Given a
benchmark_dataset, the account is measured against the benchmark bought
and held.
Classes
The account an approximate backtest simulated: |
|
Decide every rebalance of a prediction panel at once and simulate the window as arrays. |