Generate reports
lean report runs a standalone .NET Report Creator against a backtest result JSON. It does not import project Python files, so multiple algorithms in one workspace are not a problem.
For a report that supports custom market SIDs without preprocessing, use the native QRT reporter:
import qrt as q
report = q.bt.report(
"backtests/",
title="Sweden 20/100 SMA",
output="sma-report.html",
)
report.display()This reads recorded LEAN charts and tables directly and does not replay orders. The newest timestamped folder containing a completed result is selected; provide an exact result JSON when you need a particular historical run. report.display() embeds the report in an iframe, which prevents its standalone CSS from overriding notebook colors. Use report.display(height=1200) to change the viewport; use report.to_html() when you need the HTML string rather than notebook output. The sections below document the upstream Report Creator.
Ordinary built-in markets
Generate the latest report:
uv run lean report --overwriteOr specify the exact result JSON:
uv run lean report \
--backtest-results backtests/<timestamp>/<algorithm-id>.json \
--report-destination report.html \
--overwrite--backtest-results requires a file, not a backtest directory. lean report has --update but no --no-update; it uses the local image unless --update is supplied.
Custom Sweden market
The Report Creator starts in a separate process and never runs:
Market.add("sweden", 900)It therefore cannot deserialize native Sweden SIDs directly. Prepare a separate compatibility result:
cd /home/hi/qrt
cd lean/demo-generated-data
uv run python source/prepare_report.py \
backtests/2026-07-26_13-41-40/1641330887.json \
report-results/1641330887-report.json
uv run lean report \
--backtest-results report-results/1641330887-report.json \
--report-destination sma-report.html \
--strategy-name "Sweden 20/100 SMA" \
--strategy-description "Synthetic 100-asset XSTO daily-universe SMA crossover" \
--overwriteThe helper never modifies the original result. It:
- aliases custom market bits to a built-in market only in the copy;
- uses USD only for Report’s internal 1:1 replay metadata;
- preserves original SEK charts, runtime values, numeric statistics, closed trades, and parameters;
- omits the copied order dictionary by default.
Orders are omitted because current Report PortfolioLooper cannot register custom markets and leaves TradingDaysPerYear unset during a large replay. Returns-per-trade and other closed-trade statistics remain available; the reconstructed asset-allocation chart has no order input.
Use prepare_report.py --keep-orders ... only when allocation reconstruction is more important than the upstream replay warning.
Custom templates
The official Report/template.html controls layout and placeholders. Pass a replacement with:
uv run lean report --html custom-template.html --overwriteA custom template cannot solve SID parsing or portfolio replay problems. Report deserializes orders and runs PortfolioLooper before compiling template placeholders.
Verified artifact
The tested workflow creates lean/demo-generated-data/sma-report.html, approximately 610 KB with 15 embedded charts, strategy metadata, and SEK display values.