The repo now emits summary HTML reports only. Individual per-market HTML report generation has been removed. Summary reports can still include per-market rows, per-market lines, fill markers, and comparison panels when the selected panel set asks for them.
Scaling Model
Think about plotting as one shared report for a run:
- Single-market runners can still emit a summary report with one market.
- Basket runners emit one joint-portfolio summary report.
- Per-market drilldown should happen through report panels and tables, not separate generated HTML files.
Summary reports are built from summary-series artifacts returned by the
backtest. Runner controls live inline in build_replay_experiment(...):
MarketReportConfig(summary_report=True)MarketReportConfig(summary_report_path="output/...html")MarketReportConfig(summary_plot_panels=(...))return_summary_series=Trueonbuild_replay_experiment(...)
The full public basket panel set is:
(
"total_equity",
"equity",
"market_pnl",
"periodic_pnl",
"yes_price",
"allocation",
"total_drawdown",
"drawdown",
"total_rolling_sharpe",
"rolling_sharpe",
"total_cash_equity",
"cash_equity",
"monthly_returns",
"total_brier_advantage",
"brier_advantage",
)
For large baskets, prefer portfolio-wide panels first:
total_equitytotal_drawdowntotal_rolling_sharpetotal_cash_equitytotal_brier_advantageperiodic_pnlmonthly_returns
Add per-market panels like equity, market_pnl, yes_price, and
allocation only when the basket is small enough that the lines remain
readable.
Downsampling
The plotting layer downsamples large time series before Bokeh serialization. This keeps report size bounded when replay windows contain hundreds of thousands of book events.
The downsampler preserves:
- first and last points
- fill bars
- equity peak and max-drawdown points
- evenly spaced remaining points up to the target budget
Summary artifact construction also downsamples price points before building dense equity curves. This avoids constructing full-resolution portfolio timelines only to downsample them again in the chart layer.
The terminal summary table is separate from the HTML report. It prints
per-market replay counts, fills, fill quantity/notional, PnL, coverage, and any
return-series statistics available in the result payload. Joint runs also print
a portfolio-level Nautilus stats block from BacktestResult.stats_pnls and
BacktestResult.stats_returns; those values are not repeated on per-market
rows because Nautilus computes them for the shared engine account.
Output Types
The active output type is the aggregate summary report. It is a real report built from run artifacts, not a concatenation of individual market pages.
Typical basket setup:
build_replay_experiment(
...,
report=MarketReportConfig(
count_key="book_events",
count_label="Book Events",
pnl_label="PnL (pUSD)",
summary_report=True,
summary_report_path="output/polymarket_book_joint_portfolio_runner_joint_portfolio.html",
summary_plot_panels=(
"total_equity",
"equity",
"market_pnl",
"periodic_pnl",
"yes_price",
"allocation",
"total_drawdown",
"drawdown",
"total_rolling_sharpe",
"rolling_sharpe",
"total_cash_equity",
"cash_equity",
"monthly_returns",
"total_brier_advantage",
"brier_advantage",
),
),
return_summary_series=True,
)
Known-but-unavailable panels are skipped. Unknown panel ids raise immediately so runner typos do not silently produce incomplete reports.
Output Paths
Public runners use explicit report paths under output/:
output/polymarket_book_joint_portfolio_runner_joint_portfolio.htmloutput/polymarket_telonex_book_joint_portfolio_runner_joint_portfolio.htmloutput/polymarket_book_ema_optimizer_leaderboard.csvoutput/polymarket_book_ema_optimizer_summary.json
The shared runner layer resolves relative paths from the repo root, so direct
script execution writes into this checkout's output/ directory regardless of
the shell's current working directory.
Supported panel ids:
total_equitytotal_drawdowntotal_rolling_sharpetotal_cash_equitytotal_brier_advantageequitymarket_pnlperiodic_pnlyes_priceallocationdrawdownrolling_sharpecash_equitymonthly_returnsbrier_advantage
Example Summary Output
Run a public basket runner:
uv run python backtests/polymarket_book_joint_portfolio_runner.py
uv run python backtests/polymarket_telonex_book_joint_portfolio_runner.py
Expected artifacts:
- one terminal summary table
- one summary HTML report when
MarketReportConfig(summary_report=True)is set - no per-market HTML files
Multi-Market References
Current multi-market examples:
backtests/polymarket_book_joint_portfolio_runner.pybacktests/polymarket_telonex_book_joint_portfolio_runner.pybacktests/pmxt_book_joint_portfolio_runner.ipynbbacktests/telonex_book_joint_portfolio_runner.ipynb
These runners use one shared Nautilus account and one shared portfolio path for the whole basket. Optimizer drawdown uses the summed equity curve, not the sum of per-market drawdowns.