quantstats-rs is a Rust library that generates QuantStats-style HTML performance tear sheets
from return time series. It aims to closely match the behaviour and visuals of the original
Python QuantStats project.
Preview of the benchmark tear sheet:

- Generate full HTML tear sheets from:
- A single strategy return series; or
- A strategy + benchmark pair.
- Metrics table (see
PerformanceMetrics), including:- CAGR, Sharpe, Sortino, Calmar
- Max / average drawdown, longest drawdown
- Gain-to-Pain and related ratios
- Charts (SVG, embedded in the HTML):
- Cumulative Returns / Cumulative Returns vs Benchmark (including log-scaled and volatility-matched variants)
- Daily Returns (Cumulative Sum)
- Rolling Volatility / Rolling Sharpe / Rolling Sortino / Rolling Beta
- Drawdown (Underwater) (average drawdown red dashed line, filled area below 0%)
- Strategy – Worst 5 Drawdown Periods
- EOY Returns / EOY Returns vs Benchmark (with red dashed mean line)
- Monthly Returns Heatmap
- Returns Distribution / Monthly Distribution
- Visual alignment with Python QuantStats:
- Matching colour scheme (strategy
#348dc1, benchmark#ff9933, etc.) - Proportional grid, labelled y-axis, bottom time axis
- Dashed zero / mean lines and filled areas (e.g. Underwater Plot)
- Matching colour scheme (strategy
src/lib.rs– public API:html,HtmlReportOptions,ReturnSeries,PerformanceMetrics.reports.rs– report assembly, metrics table rendering, and template filling.stats.rs– performance statistics and drawdown segment logic.plots.rs– all SVG chart generation.report_template.html– HTML template, roughly mirroring QuantStats’report.html.
examples/html_report.rs– strategy only; writestearsheet.html.html_with_benchmark.rs– strategy + benchmark; writestearsheet_with_benchmark.html.common.rs– shared demo data, generated fromdata/by the script.
data/– CSVs / time series used to build the example report.scripts/gen_examples_common.py– generatesexamples/common.rsfromdata/.
From the repository root:
cargo build
# Strategy-only demo report (writes `tearsheet.html`)
cargo run --example html_report
# Strategy + benchmark demo report (writes `tearsheet_with_benchmark.html`)
cargo run --example html_with_benchmark
# Tests (if present)
cargo testThe generated HTML files can be opened directly in a browser and visually compared against reports produced by the Python QuantStats library.
Add a dependency from crates.io:
[dependencies]
quantstats-rs = "0.1"Basic usage in Rust:
use chrono::NaiveDate;
use quantstats_rs::{ReturnSeries, HtmlReportOptions, html};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. Prepare dates and returns (e.g. daily returns)
let dates: Vec<NaiveDate> = /* ... */;
let values: Vec<f64> = /* ... */; // e.g. 0.01 means +1%
let strategy = ReturnSeries::new(dates, values, Some("Strategy".to_string()))?;
// 2. Configure report options
let options = HtmlReportOptions::default()
.with_title("My Strategy Tearsheet")
.with_strategy_title("My Strategy")
.with_output("tearsheet.html");
// 3. Generate HTML string and write to file (if `output` is set)
let html_string = html(&strategy, options)?;
println!("Report generated ({} bytes)", html_string.len());
Ok(())
}With a benchmark:
let strategy: ReturnSeries = /* ... */;
let benchmark: ReturnSeries = /* ... */;
let options = HtmlReportOptions::default()
.with_benchmark(&benchmark)
.with_title("Strategy vs Benchmark")
.with_strategy_title("Strategy")
.with_benchmark_title("Benchmark")
.with_output("tearsheet_with_benchmark.html");
let html_string = html(&strategy, options)?;The example binaries use examples/common.rs, which is generated from data/:
python3 scripts/gen_examples_common.pyAfter changing the data under data/, re-run the script and then rerun the examples
to regenerate tearsheet.html and tearsheet_with_benchmark.html.
This implementation uses the vendored Python QuantStats code and its HTML output as the reference. The following aspects are intentionally aligned:
- Rolling Vol / Sharpe / Sortino / Beta:
- Axis ranges, grid density, and line styles (including red dashed mean lines).
- Underwater Plot:
- Filled area below 0% in strategy colour.
- Red dashed line at the average drawdown.
- Solid underwater curve.
- Strategy – Worst 5 Drawdown Periods:
- Y-axis and grid styling.
- Label positions for the “N: Xd” drawdown annotations.
- EOY Returns vs Benchmark:
- Bar layout and colours.
- Red dashed mean line for strategy returns.
- Time axis handling:
- Bottom-aligned date labels for all time-series charts.
- Label thinning to avoid overlap (e.g. around dense months like 2025‑10 / 2025‑11).
If you notice discrepancies compared to a Python QuantStats report (especially in a specific chart such as “Rolling Sortino” or “Underwater Plot”), please open an issue or PR and mention:
- Which chart (title),
- Which part differs (axis range, grid, colours, etc.),
- Optionally, a snippet or screenshot from the Python-generated HTML.