quantlab.runs.run_metrics.run_metrics#
- quantlab.runs.run_metrics.run_metrics(account, *, engine_rows=None, split=None, benchmark=None, within=None)[source]#
Return the metric blocks of an account, in
metrics.json’s layout.The blocks, in order:
whole: over the whole account (withinomitted),engine_rowsfollowed by the three turnover rows,Total Orders(the number of fills) and the win rates; over a stretch (within), the slice rows below over that stretch, its first bar’s return included.execution:rejected_order_countandrejected_orders(over a stretch, only those whose fill bar is in it), then, over the whole account,max_target_deviation.in_sampleandout_of_sample(whensplithas slices,slice_ranges): the return statistics,Total Orders,Total Fees PaidandTraded Notionalof the fills inside the slice,Total Closed Trades(round trips closed inside it),Total Open Trades(open at each range’s end), the three turnover rows and the win rates;Nonefor a slice without a bar.benchmark(withbenchmark): itssymbol,axis_symboland return statistics overwholeand each slice.relative(withbenchmark): the account against the benchmark,backtest_stats.relative_statsand the win rates against it, overwholeand each slice.every key of
split, copied as it is.
Turnover counts the fills of
account.ordersbut its settlements, over the decided rebalances ofaccount.rebalances; the win rates’ holding periods start at the decided rebalances’ fill bars. Every row is annualized byaccount.year_freqoveraccount.bar_interval.- Parameters:
- accountAccountRecord
What the account did.
- engine_rowsMapping, optional
The engine’s own whole-window rows (vectorbt’s portfolio statistics), which open
whole. Required over the whole account, refused withwithin.- splitMapping, optional
The run’s split keys (
training_window,in_sample_rangeorin_sample_ranges,out_of_sample_ranges); without one there is no slice.- benchmarkBenchmarkRecord, optional
The benchmark on the account’s bars.
- within(str, str), optional
Inclusive bar labels of the stretch measured as
wholeinstead of the whole account: arun_cv()fold of its stitched account (ADR 0033).
- Returns:
- dict
The blocks listed above.
- Raises:
- ValueError
If
engine_rowsis missing over the whole account or given withwithin.
Examples
With the account of
AccountRecord’s example: one rebalance decided on the first bar, filled on the second.>>> bars = pd.bdate_range("2024-01-01", periods=3) >>> on_bars = dict(dims="timestamp", coords={"timestamp": bars}) >>> account = AccountRecord( ... value=xr.DataArray([100.0, 110.0, 99.0], **on_bars), ... returns=xr.DataArray([0.0, 0.1, -0.1], **on_bars), ... orders=xr.Dataset({ ... "timestamp": ("order", bars[[1]].values), "symbol": ("order", ["AAA"]), ... "size": ("order", [10.0]), "price": ("order", [10.0]), "fees": ("order", [0.0]), ... }), ... rebalances=xr.Dataset({ ... "scheduled": ("timestamp", [True, False, False]), ... "decided": ("timestamp", [True, False, False]), ... }, coords={"timestamp": bars}), ... init_cash=100.0, bar_interval="1D", ... year_freq=backtest_stats.year_freq("1D", 252, 390), ... ) >>> metrics = run_metrics(account, engine_rows={"End Value": 99.0}) >>> list(metrics) ['whole', 'execution'] >>> list(metrics["whole"]) ['End Value', 'Turnover per Rebalance [%]', 'Total Turnover [%]', 'Annualized Turnover [%]', 'Total Orders', 'Rebalance Win Rate [%]', 'Monthly Win Rate [%]'] >>> metrics["whole"]["Total Turnover [%]"], metrics["whole"]["Total Orders"] (100.0, 1) >>> split = {"training_window": None, "in_sample_range": None, ... "out_of_sample_ranges": [("2024-01-02", "2024-01-03")]} >>> stretch = run_metrics(account, split=split, within=("2024-01-02", "2024-01-03")) >>> round(stretch["out_of_sample"]["Total Return [%]"], 6), stretch["out_of_sample"]["Total Orders"] (-1.0, 1)