Backtest Showcase
import marimo as mo
import polars as pl
import quantwave # registers LazyFrame.bt namespace
from quantwave.backtest import BacktestEngine, BacktestConfig
mo.md(
"""
# QuantWave Backtest Engine — Full `.bt` Tour
Link: [Capability Matrix](../../guides/backtest/capability_matrix.md)
"""
)
df_synthetic = pl.DataFrame({
"timestamp": list(range(80)),
"close": [100.0 + i * 0.5 + (i % 3) for i in range(80)],
"feature_col": [i % 5 for i in range(80)],
})
mo.md("## Section A — Basic backtest + metrics")
df_a = df_synthetic.with_columns(
(pl.col("feature_col") > 2).cast(pl.Float64).alias("signal")
)
report_a = df_a.lazy().bt.backtest_with_report(
signal="signal",
commission_bps=0.0,
slippage_bps=0.0,
)
assert report_a.result.trades.height >= 1
metrics_keys = list(report_a.metrics().keys())
mo.md("## Section B — Costs, filters, sizing")
df_b = df_synthetic.with_columns(
(pl.col("feature_col") > 2).cast(pl.Float64).alias("signal"),
(pl.col("feature_col") > 3).alias("entry_filter"),
(pl.col("feature_col") * 2).alias("size"),
)
report_b = df_b.lazy().bt.backtest_with_report(
signal="signal",
entry_filter_col="entry_filter",
size_multiplier_col="size",
commission_bps=5.0,
)
mo.md("## Section C — Fast metrics path")
metrics_c = df_a.lazy().bt.backtest_metrics(signal="signal")
mo.md("## Section D — Param sweep (pre-built cols)")
df_d = df_synthetic.with_columns(
(pl.col("feature_col") > 2).cast(pl.Float64).alias("signal_1"),
(pl.col("feature_col") > 3).cast(pl.Float64).alias("signal_2"),
(pl.col("feature_col") > 4).cast(pl.Float64).alias("signal_3"),
)
sweep_df = df_d.lazy().bt.sweep(
param_name="threshold",
param_values=[1.0, 2.0, 3.0],
signal_cols=["signal_1", "signal_2", "signal_3"],
commission_bps=0.0,
slippage_bps=0.0,
)
mo.md("## Section E — Param sweep (callback rebuild)")
def build_fn(ldf, params):
thresh = params["thresh"]
return ldf.with_columns(
(pl.col("feature_col") > thresh).cast(pl.Float64).alias("signal")
)
sweep_cb_df = df_synthetic.lazy().bt.sweep_callback(
param_grid={"thresh": [2.0, 3.0, 4.0]},
build_fn=build_fn,
signal="signal",
commission_bps=0.0,
slippage_bps=0.0,
)
mo.md("## Section F — Walk-forward OOS")
wfo_folds = df_a.lazy().bt.walk_forward(
signal="signal",
train_bars=40,
test_bars=20,
commission_bps=0.0,
slippage_bps=0.0,
)
mo.md("## Section G — Walk-forward optimize")
def build_fn_wfo(ldf, params):
thresh = params["thresh"]
return ldf.with_columns(
(pl.col("feature_col") > thresh).cast(pl.Float64).alias("signal")
)
wfo_opt = df_synthetic.lazy().bt.walk_forward_optimize(
param_grid={"thresh": [2.0, 3.0]},
build_fn=build_fn_wfo,
signal="signal",
train_bars=40,
test_bars=20,
objective="total_return",
commission_bps=0.0,
slippage_bps=0.0,
)
mo.md("## Section H — Cross-sectional panel")
panel_df = pl.DataFrame({
"timestamp": list(range(10)) * 3,
"symbol": ["A"] * 10 + ["B"] * 10 + ["C"] * 10,
"close": [100 + i for i in range(30)],
"factor": [i % 3 for i in range(30)],
})
report_cs = panel_df.lazy().bt.cross_sectional_backtest(
factor_col="factor",
transform="zscore",
commission_bps=0.0,
slippage_bps=0.0,
)
Section I — Monte Carlo
See quantwave_backtest::monte_carlo_trade_bootstrap and monte_carlo_return_paths in Rust for bootstrap and return-path VaR/CVaR.
Section J — PA moat pointer
See PA Flag Breakout for canonical PA E2E.
Section K — Parity callout
QuantWave guarantees exact parity between streaming and batch mode. See Batch & Streaming and ML Feature Parity.