Backtest Lab

Fine Print

Five behaviors that are easy to miss and worth knowing before you rely on a result.

  • Manual flatten + brackets: manually flattening a bracketed position (e.g. a plain ctx.sell()) does not cancel its still-open take-profit/stop-loss — they stay resting and armed, and only cancel if one later triggers while it would increase or flip exposure rather than reduce it. Cancel them yourself (ctx.cancelAll() or a targeted cancel), or they can close a later position.
  • Portfolio expiresAfterBars counts ticks on the merged axis, not a sparse symbol's own bars — an order on a thin symbol can expire during its gaps.
  • Equity timing differs by mode: in single-symbol mode ctx.equity during onBar reflects the previous bar's close (mark-to-market runs after onBar returns); in portfolio mode it's live at the current tick's marks. Sizing helpers inherit this.
  • Everything is UTC. No exchange calendars or DST — session helpers are pure UTC math.
  • The walk-forward run-count preview is an estimate for portfolios of misaligned intraday symbols; the actual run computes exact totals.

Contract multipliers

Set Contract multiplier in Costs & capital to the money-per-point of the instrument you are testing: 1 for stocks and crypto, 50 for ES, 20 for NQ, 100 for a standard equity option, 0.5 for the Micro E-mini Dow. Fractional values are legal — the micro contracts need them.

What scales with it: P&L (realized and unrealized), cash, buying power, mark-to-market, and both position-sizing helpers. ctx.position.unrealizedPnl is money, not points — on ES one contract ten points offside reads -500. ctx.size.percentOfEquity and ctx.size.riskPerTrade divide by the money value of one unit, so they hand back a count of contracts whose notional (or whose money at risk) is the fraction of equity you asked for — see Sizing helpers.

What does not: per-order and per-contract commission, and all slippage settings — those are already charged per order, per contract, and in price terms respectively. Percentage-of-notional commission does scale, since its base is notional. Ratio metrics are unchanged by construction: pnlPct and R-multiples divide money by money, so a multiplier cancels out of both.

One multiplier applies to every symbol in a run, the same way one tick size does.

What this does not model: futures margin. Cash is debited for the full notional of a position rather than the initial margin an exchange would actually require. That is exact for options, which are fully paid, and conservative for futures — your buying power is consumed faster than a real futures account's would be.