Reports

Performance metrics and HTML tearsheet generation.

Two entry points:

  • mktlib.reports.html() — generates an interactive HTML tearsheet (returns the string or writes to disk).

  • mktlib.reports.metrics() — computes the same metric set without the rendering overhead, returns a MetricsResult dataclass.

Both accept a daily returns series; sub-daily input is automatically collapsed to one geometrically-compounded value per date. The accepted input types — pl.Series, pl.DataFrame with date and return columns, or any pandas-like object with a DatetimeIndex — are documented under mktlib.reports.html().

mktlib.reports.html(returns, *, benchmark=None, trades=None, output=None, title='Strategy Tearsheet', rf=0.0, periods_per_year=252, compounded=True, extra_metrics=None, extra_charts=None, template=None, mc_config=None)[source]

Generate an interactive HTML tearsheet report.

Parameters:
  • returns (DataFrame | Series | PandasConvertible) – Daily returns as pl.Series, pl.DataFrame (with date and return columns), or pd.Series with a DatetimeIndex.

  • benchmark (DataFrame | Series | PandasConvertible | None) – Optional benchmark returns (same types as returns).

  • trades (DataFrame | None) – Optional per-trade DataFrame with columns entry_date (Date), exit_date (Date), side (Int8), pnl (Float64), and bars_held (Int64). When provided, per-trade metrics are computed and the Win/Loss card values are overridden with trade-based figures. Two extra metric cards (Trade Stats, Trade Risk-Adjusted) and two extra charts (PnL distribution, PnL over time) are added.

  • output (str | None) – File path to write the HTML to. When None, returns the HTML string.

  • title (str) – Report title shown in the header.

  • rf (float | str) – Risk-free rate (annualised, e.g. 0.05 for 5 %). Pass "auto" to fetch the 3-month T-bill average for the returns date range.

  • periods_per_year (int) – Trading days per year (default 252).

  • compounded (bool) – Whether to compute compounded returns (default True).

  • extra_metrics (dict[str, list[tuple[str, str]]] | None) – Additional metric cards: {card_title: [(label, value), ...]}. Appended to the built-in metrics grid.

  • extra_charts (dict[str, Figure] | None) – Additional charts: {name: plotly.graph_objects.Figure}. Converted to HTML divs and rendered after the built-in charts.

  • template (str | Path | None) – Custom Jinja2 template. Path loads from file, str is treated as inline Jinja2 source, None uses the built-in template.

  • mc_config (MonteCarloConfig | None)

Returns:

The HTML string when output is None, otherwise None.

Return type:

str | None

mktlib.reports.metrics(returns, *, benchmark=None, trades=None, rf=0.0, periods_per_year=252, compounded=True, mc_config=None)[source]

Compute performance metrics without generating an HTML report.

Parameters:
  • rf (float | str) – Risk-free rate (annualised). Pass "auto" to fetch the 3-month T-bill average for the returns date range.

  • trades (DataFrame | None) – Optional per-trade DataFrame (same schema as html()). When provided, MetricsResult.trade_metrics is populated.

  • mc_config (MonteCarloConfig | None) – Optional MonteCarloConfig. When mc_config.enabled, populates MetricsResult.mc_var and mc_cvar with simulation- based forward-looking risk numbers; otherwise leaves them None.

  • returns (DataFrame | Series | PandasConvertible)

  • benchmark (DataFrame | Series | PandasConvertible | None)

  • periods_per_year (int)

  • compounded (bool)

Return type:

MetricsResult

Result and Configuration

class mktlib.reports.MetricsResult(cumulative_return, cagr, mtd, ytd, one_year, sharpe, sortino, calmar, omega, romad, max_drawdown, max_drawdown_date, longest_drawdown_days, avg_drawdown, volatility, var_95, cvar_95, win_rate, payoff_ratio, profit_factor, kelly_criterion, alpha=None, beta=None, r_squared=None, information_ratio=None, trade_metrics=None, mc_var=None, mc_cvar=None)[source]

Complete metrics computation result (25 metrics).

Parameters:
cumulative_return: float
cagr: float
mtd: float
ytd: float
one_year: float
sharpe: float
sortino: float
calmar: float
omega: float
romad: float
max_drawdown: float
max_drawdown_date: str | None
longest_drawdown_days: float
avg_drawdown: float
volatility: float
var_95: float
cvar_95: float
win_rate: float
payoff_ratio: float
profit_factor: float
kelly_criterion: float
alpha: float | None
beta: float | None
r_squared: float | None
information_ratio: float | None
trade_metrics: TradeMetrics | None
mc_var: float | None
mc_cvar: float | None
class mktlib.reports.ReportConfig(rf=0.0, periods_per_year=252, compounded=True, title='Strategy Tearsheet')[source]

Configuration for report generation.

Parameters:
rf: float
periods_per_year: int
compounded: bool
title: str
class mktlib.reports.TradeMetrics(trade_win_rate, payoff_ratio, profit_factor, kelly_criterion, avg_trade_pnl, avg_bars_held, avg_duration_minutes, total_trades, avg_winner, avg_loser, largest_winner, largest_loser, max_consecutive_wins, max_consecutive_losses, trade_sharpe, trade_sortino, trades_per_year)[source]

Per-trade performance metrics computed from a trades DataFrame.

Parameters:
trade_win_rate: float
payoff_ratio: float
profit_factor: float
kelly_criterion: float
avg_trade_pnl: float
avg_bars_held: float
avg_duration_minutes: float
total_trades: int
avg_winner: float
avg_loser: float
largest_winner: float
largest_loser: float
max_consecutive_wins: int
max_consecutive_losses: int
trade_sharpe: float
trade_sortino: float
trades_per_year: float
class mktlib.reports.DrawdownInfo(max_drawdown, max_drawdown_date, longest_drawdown_days, avg_drawdown)[source]

Drawdown analysis results.

Parameters:
  • max_drawdown (float)

  • max_drawdown_date (str | None)

  • longest_drawdown_days (float)

  • avg_drawdown (float)

max_drawdown: float
max_drawdown_date: str | None
longest_drawdown_days: float
avg_drawdown: float

Forward-Looking Risk (Monte Carlo)

The MonteCarloConfig dataclass enables an opt-in Monte Carlo estimation path on top of the standard tearsheet. When enabled=True, html() and metrics() populate two new MetricsResult fields — mc_var and mc_cvar — using the simulation-based estimator from Metrics, and (in html()) render a Monte Carlo Forward Paths chart showing the spaghetti subset, α/2 / 1−α/2 percentile band, and median path anchored at the last historical equity value over forward business days.

class mktlib.reports.MonteCarloConfig(enabled=False, horizon=21, n_simulations=10000, innovations=None, df=None, seed=None, alpha=0.05, n_paths_displayed=100, exchange='XNYS')[source]

Configuration for opt-in Monte Carlo VaR / CVaR + path chart in reports.

Pass to mktlib.reports.html() / mktlib.reports.metrics() via the mc_config= kwarg. Default enabled=False preserves backwards-compatible report output exactly.

When enabled=True, the report runs three MC GBM batches under a single shared seed (one for the chart’s full simulation frame, two for the VaR / CVaR estimators). Identical seeds produce identical sample paths, so all three artefacts are mutually consistent. When seed is None the driver mints one OS-derived seed up front and threads it through all three calls.

The dataclass intentionally has no “method” knob (closed-form Gaussian vs simulation): when MC is enabled we always run paths because the spaghetti chart requires actual paths. Users who want closed-form numbers without paths should call mktlib.metrics.var(method="gaussian") directly.

Parameters:
  • enabled (bool) – Master switch; False (default) disables the entire MC code path and the report renders identically to v0.10.x.

  • horizon (int) – Forecast horizon in trading bars (default 21 ≈ 1 month at 252 ppy).

  • n_simulations (int) – Number of simulated paths (default 10 000). At default scales, Gaussian MC runs in ~10 ms / Student-t in ~15 ms.

  • innovations (Innovations | None) – mktlib.data.Innovations member or None (Gaussian default). STUDENT_T requires df; BOOTSTRAP resamples standardized empirical residuals from the input series.

  • df (float | None) – Degrees of freedom for Innovations.STUDENT_T (>2).

  • seed (int | None) – Reproducibility seed. None uses OS entropy.

  • alpha (float) – Tail probability for both the VaR / CVaR numbers and the α/2 / 1−α/2 percentile band on the path chart.

  • n_paths_displayed (int) – Number of individual MC paths to render in the spaghetti plot. Hard-capped at 500 inside the chart helper to keep the Plotly DOM responsive — pass any larger value and it is silently clipped.

  • exchange (str) – ISO MIC for the calendar used to project forward dates on the path chart’s x-axis ("XNYS" / "XLON" / "XPAR" / "XCME" / "XNAS" / "XCBO" / "XTSE" / "XETR" / "XTKS").

enabled: bool
horizon: int
n_simulations: int
innovations: Innovations | None
df: float | None
seed: int | None
alpha: float
n_paths_displayed: int
exchange: str

Three MC runs per report, one shared seed. Internally html() and metrics() run mktlib.metrics.monte_carlo_paths() for the chart frame plus two mktlib.metrics.simulate_metric() calls (VaR + CVaR), all threaded through one fixed seed so they produce identical sample paths. When mc_config.seed is None the driver mints one OS-derived seed up front and reuses it across all three calls; otherwise the user-supplied seed is honoured. At the perf-path defaults (~10–15 ms per MC batch) the triplet adds 30–45 ms total — invisible inside the typical tearsheet render.

from mktlib.data import Innovations
from mktlib.reports import html, MonteCarloConfig

# Heavy-tailed Student-t innovations, 21-bar (≈1 month) horizon
html(
    returns,
    title="Forward-Looking Tearsheet",
    output="tearsheet.html",
    mc_config=MonteCarloConfig(
        enabled=True,
        horizon=21,
        n_simulations=10_000,
        innovations=Innovations.STUDENT_T,
        df=5,
        seed=42,
        alpha=0.05,
        n_paths_displayed=100,
        exchange="XNYS",
    ),
)

The chart’s x-axis spans roughly 60 historical bars plus the forecast horizon, with forward dates generated via mktlib.scheduling.get_calendar(exchange).session_offset(...) so weekends and holidays are skipped.

Displayed-subset sampling. When n_simulations > n_paths_displayed the chart renders only a subset of paths. The subset is drawn via uniform random sampling without replacement, seeded from the MC run’s parent seed for reproducibility — this is preferred over taking the prefix simulation < n_paths_displayed because the prefix relies on the underlying RNG’s i.i.d. property over consecutive samples (mostly fine for modern PRNGs but a known MC-literature footgun re: warm-up bias). Distributional equivalence between the displayed subset and the full population is regression-tested via two-sample Kolmogorov–Smirnov.

Note

When enabled=False (the default), the mc_* fields stay None and the tearsheet renders identically to v0.10.x. The MonteCarloConfig import has zero runtime cost on [reports]-only installs — the mktlib.data dependency is loaded lazily inside the MC code path.