Skip to main content
The plotting module processes raw backtest data into frozen dataclasses that matplotlib, plotly, or any charting library can consume directly. No external dependencies required.

Bollinger Bands

Rolling mean with standard deviation envelopes

Distributions

Return and PnL histograms with full statistics

Heatmaps

Monthly returns and correlation matrices

Underwater

Per-point drawdown depth for area charts

Trade Scatter

Buy/sell markers with PnL attribution

PlotBundle

One-call extraction of all plot data

Quick Start

import horizon as hz
import matplotlib.pyplot as plt

result = hz.backtest(strategy, ...)
bundle = hz.from_backtest(result)

# Equity curve
fig, ax = plt.subplots()
ax.plot(bundle.equity.timestamps, bundle.equity.equity)
ax.set_title("Normalized Equity")

# Underwater chart
fig, ax = plt.subplots()
ax.fill_between(
    bundle.underwater.timestamps,
    [-d for d in bundle.underwater.drawdown_pct],
    alpha=0.4, color="red",
)
ax.set_title("Drawdown (%)")

# Return distribution
fig, ax = plt.subplots()
ax.bar(bundle.return_hist.bin_centers, bundle.return_hist.counts)
ax.set_title(f"Returns (skew={bundle.return_hist.skew:.2f})")
plt.show()

One-Call Extraction

from_backtest

Extract all plot data from a BacktestResult in a single call.
bundle = hz.from_backtest(
    result,
    n_bins=30,
    rolling_window=30,
    include_bands=False,
    band_window=20,
    band_std=2.0,
    calibration_bins=10,
)
ParameterTypeDefaultDescription
resultBacktestResultrequiredBacktest result object
n_binsint30Bins for histograms
rolling_windowint30Window for rolling Sharpe/Sortino
include_bandsboolFalseAdd Bollinger bands to equity
band_windowint20Bollinger band window
band_stdfloat2.0Bollinger band std multiplier
calibration_binsint10Bins for calibration plot
Returns a PlotBundle containing all extracted data.

Individual Functions

bollinger_bands

bands = hz.bollinger_bands(series, window=20, num_std=2.0)
ParameterTypeDefaultDescription
serieslist[tuple[float, float]]required(timestamp, value) pairs
windowint20Rolling window size
num_stdfloat2.0Standard deviations for bands
Returns BandData with timestamps, middle, upper, lower, bandwidth.

underwater_curve

uw = hz.underwater_curve(equity_curve)
Returns UnderwaterData with per-point drawdown_pct and peak tracking.

histogram

h = hz.histogram(values, n_bins=30)
Returns HistogramData with bin_edges, bin_centers, counts, frequencies, plus mean, median, std, skew, kurtosis.

return_distribution

h = hz.return_distribution(equity_curve, n_bins=30)
Extracts period returns from equity curve, returns HistogramData.

pnl_distribution

h = hz.pnl_distribution(trades, n_bins=30)
FIFO-matches trades into round-trips, returns HistogramData of PnL values.

monthly_returns_heatmap

hm = hz.monthly_returns_heatmap(equity_curve)
Returns HeatmapData with years as rows and months (Jan-Dec) as columns.

correlation_heatmap

hm = hz.correlation_heatmap({"BTC": btc_returns, "ETH": eth_returns})
Returns HeatmapData with Pearson correlation coefficients.

rolling_stats

r = hz.rolling_stats(equity_curve, window=30)
Returns RollingStatData with sharpe and sortino as CurveData.

normalized_equity

ne = hz.normalized_equity(equity_curve, initial_capital=1000.0, include_bands=True)
Returns NormalizedEquityData with equity normalized to 1.0 and cumulative PnL.

trade_scatter

ts = hz.trade_scatter(trades)
Returns TradeScatterData with all points, buys, and sells as TradeScatterPoint tuples.

calibration_plot

cal = hz.calibration_plot(trades, outcomes, n_bins=10)
Returns CalibrationPlotData with bin_centers, actual_freq, perfect_line, ece, and brier_score. Uses Rust calibration_curve() when available, falls back to pure Python.

Output Types

TypeFields
BandDatatimestamps, middle, upper, lower, bandwidth
UnderwaterDatatimestamps, drawdown_pct, peak
HistogramDatabin_edges, bin_centers, counts, frequencies, mean, median, std, skew, kurtosis
HeatmapDatavalues, row_labels, col_labels, title
CurveDatatimestamps, values, label
NormalizedEquityDatatimestamps, equity, cumulative_pnl, bands
TradeScatterPointtimestamp, price, size, side, market_id, pnl
TradeScatterDatapoints, buys, sells
CalibrationPlotDatabin_centers, actual_freq, counts, perfect_line, ece, brier_score
RollingStatDatasharpe, sortino
PlotBundleequity, underwater, return_hist, pnl_hist, monthly_heatmap, rolling, trades, calibration
All types are frozen dataclasses with tuple fields (immutable).