Reading the Bokeh report¶
Backtest.plot() (and TradingEnv.plot()) renders an interactive
Bokeh report combining equity, trade returns, and per-asset OHLC
panels. This page explains what each panel shows and how to interpret
it.
Saving to file¶
By default plot() calls bokeh.io.show() which opens the report in
a browser. To save a self-contained HTML for sharing or archiving:
from qtrade.utils.plot_bokeh import plot_with_bokeh
plot_with_bokeh(bt.broker, filename="report.html")
The HTML has all data inlined — no Bokeh server, no external assets. Email it, commit it, drop it in a wiki.
Single-asset layout¶
Three stacked panels with linked x-axes:
┌─────────────────────────────────────────────────┐
│ ▒▓▒ Equity vs. Buy & Hold (cumulative returns) │
│ │
├─────────────────────────────────────────────────┤
│ ▲ ▼ ▲ Trade returns (long / short) │
├─────────────────────────────────────────────────┤
│ OHLC + volume + win/lose trade boxes │
│ + buy/sell markers │
│ │
└─────────────────────────────────────────────────┘
Top: Equity panel¶
Solid blue line: portfolio equity (cumulative returns, normalized to 1.0 at the start).
Gray dotted line: Buy & Hold returns on the same scale.
Purple dot: peak equity point.
Blue dot: final equity point (legend shows the final pct).
Gray dot: final B&H point.
Red dot: max drawdown trough.
Red shaded area: the drawdown region (gap between equity and its running max).
Red horizontal segment: the longest drawdown duration.
What to look for:
Is the blue line above the gray? You’re beating Buy & Hold.
How “smooth” is the blue line vs gray? Smoother = lower volatility = better risk-adjusted return (the Sharpe story).
Is the red shaded area concentrated in one period or spread out? Concentrated = strategy has one weak regime; spread out = systemic drag.
Middle: Trade returns¶
A scatter of every closed trade plotted at its exit time:
Green up-triangles: long trades. y-axis is
(exit/entry − 1).Red down-triangles: short trades. y-axis is the equivalent for shorts.
Marker size: scaled to position size (bigger = larger trade).
Dashed horizontal at 0: break-even line.
What to look for:
Are most markers above the 0-line? That’s your win rate eyeballed.
Is there a cluster of large-magnitude losses (way below 0)? That’s where stop-losses (or lack thereof) hurt.
Are big winners and big losers symmetric around 0? Asymmetric is good — small losses + large gains is the trend-following sweet spot.
Bottom: OHLC + volume + trade boxes¶
The price action with overlays:
Black line: closing prices.
Bottom bars (faint green/red): volume (right y-axis), color-coded by close ≥/< open.
Translucent green rectangles: winning trades — left/right edges are entry/exit times, top/bottom are entry/exit prices.
Translucent red rectangles: losing trades, same convention.
Triangle markers: order fills. Up = buy; down = sell. Size scaled to order magnitude.
What to look for:
Trade boxes that span long horizontal stretches = you held through noise. Short stretches = quick in-out trades.
Buy markers at local highs / sell markers at local lows = bad timing, possibly a sign of late signal generation.
Boxes piling up densely = high turnover. Watch the
Total Commission Costmetric inshow_stats().
Multi-asset layout¶
The report adds one OHLC panel per asset, all stacked, all sharing the same x-axis:
┌─────────────────────────────────────────────────┐
│ Portfolio equity vs equal-weighted Buy & Hold │
├─────────────────────────────────────────────────┤
│ Trade returns scatter (all assets combined) │
├─────────────────────────────────────────────────┤
│ OHLC — AAPL │
├─────────────────────────────────────────────────┤
│ OHLC — MSFT │
├─────────────────────────────────────────────────┤
│ OHLC — NVDA │
└─────────────────────────────────────────────────┘
Each per-asset OHLC panel shows trades and orders filtered to that asset only, so you can see exactly when the strategy moved in each name. The equity panel up top is portfolio-level (one curve, summing across all assets).
The Buy & Hold benchmark is the equal-weighted average of each asset’s first-to-last return — a fair “naive portfolio” comparison.
Interactive features¶
Drag the x-axis on any panel to pan; scroll to zoom.
Click a legend entry to toggle that series on/off.
Hover for tooltips: dates, prices, returns, profit per trade.
Auto-rescaling: zooming the x-axis triggers a JS callback that rescales the y-axes for the visible range only (single-asset layout).
Common surprises¶
Trade-return scatter looks empty: the strategy hasn’t closed any trades yet. SL/TP not triggered + no signal exits = no closed trades.
OHLC shows a gap at the end with no buy/sell: the
close_all_positions()end-of-run sweep records exits at the last bar’s close, which can produce a flurry of markers right at the right edge.Volume is missing: your input data didn’t have a
Volumecolumn. Add one (or accept volume bars don’t show).Equity line drops sharply with no visible trade: you took a large mark-to-market loss without exiting. Check
unrealized_pnlin your strategy logic.