Strategies

Stats Reference

Every performance stat the Strategy Tester reports, its exact formula, and its edge cases. All formulas are locked by engine tests.

Every number below is computed by the engine with a locked formula (pinned by tests, byte-identical across reruns) and delivered on the run result under output.strategy.stats. Percent-scaled fields end in Pct and are already multiplied by 100.

Returns

StatDefinition
netProfitSum of realized trade PnL minus all fees paid. netProfitPct is relative to initialCapital.
grossProfit / grossLossSum of winning trades' PnL and (absolute) sum of losing trades' PnL, respectively.
profitFactorgrossProfit / grossLoss. Reported as null when there are no losses (division by zero is not a number worth printing).
buyHoldReturnPct(lastClose / firstTradableClose - 1) * 100: what doing nothing would have returned over the same window. If your strategy does not beat this after costs, the market did the work, not the rules.

Trades

StatDefinition
totalTrades, winTrades, lossTradesClosed trades, and the win/loss split. winRatePct is winTrades / totalTrades * 100.
avgTrade, avgWin, avgLossMean PnL per closed trade, per winner, per loser.
payoffRatioavgWin / abs(avgLoss). null when there are no losers. Read it WITH the win rate: 40% winners at a 3.0 payoff is profitable, 70% winners at 0.3 is not.
largestWin, largestLossThe single best and worst closed trades. If largestWin dominates netProfit, one trade made the backtest.
avgBarsInTradeMean holding time in bars.
rejectedOrdersOrders the broker refused (pyramiding cap, invalid sizing, non-positive equity, NaN bars; on perps also insufficient margin and post-halt entries). Rejections are counted, never silently dropped.

Risk

StatDefinition
maxDrawdownLargest peak-to-trough equity decline over the run, in money. maxDrawdownPct is relative to the equity peak it fell from.
maxRunupMirror of drawdown: the largest trough-to-peak climb.
sharpemean(r) / sampleStd(r) * sqrt(barsPerYear), where r are per-bar equity returns over confirmed bars and barsPerYear = 31,536,000,000 / intervalMs. Zero when the return series has no variance. Annualized from YOUR chart interval, so compare Sharpe across runs at the same interval.
sortinoSame as Sharpe with downside deviation (only returns below zero) in the denominator. Punishes losing volatility, forgives winning volatility.
exposurePctBars with a nonzero position divided by all confirmed bars, times 100. A strategy in the market 4% of the time with the same net profit as one exposed 90% of the time is taking far less risk per unit of return.

Costs

StatDefinition
feesPaidTotal fees across all fills, already subtracted from equity and netProfit (funding is excluded; it has its own stats). Spot: commissionPercent of each fill's notional. Perps: exactly makerFeesPaid + takerFeesPaid (observed 1.0625991428568167 = 0.7247578990925553 + 0.3378412437642613).
makerFeesPaid / takerFeesPaidPerps fee split by fill type: maker for limit-priced fills, taker for market-crossing fills (including liquidation fills). Both 0 on spot runs, even with maker/taker rates declared (they are ignored with a diagnostic; see Slippage and Costs).
fundingPaidNet funding settled against open perps positions, signed from the strategy's side: positive means the strategy paid funding, negative means it received it (a probed long under a positive rate paid: 0.36904136169411894). 0 when funding="off" or on spot.
fundingEventsAppliedFunding settlements applied to an open position. Events with no open position do not count (38 events in the window, 36 applied to a position opened at bar 10).
fundingUnavailableCountBars on which an open perps position had no covering funding data under funding="data": a funding window not fully covered, invalid OHLC for funding, or settlement events dropped in a data gap (observed 289 for a position held from bar 10 through a 300-bar run with no funding data). The disclosure counter: no rate is ever invented.

Slippage is not a separate stat line because it is baked into every fill price; the slippage disclosure in the run details reports how it was priced.

Perps

Populated by instrument="perps" runs; spot runs report them as 0/false. Mechanics on the Perps page.

StatDefinition
liquidationCountTrades force-closed by the broker's implicit liquidation stop. Those trades carry exitReason: "liquidation" in the trades list (observed: 7 of 7 trades at leverage=25 under onLiquidation="continue"). One liquidation event can close multiple open trade records in the same net position.
liquidationHaltedtrue when onLiquidation="halt" stopped the run at the first liquidation; every subsequent entry is then rejected and counted (observed: liquidationCount: 1, rejectedOrders: 6). Always false under "continue" and on spot.
bankruptcyDeficitShortfall beyond the position's committed margin left by liquidation fills (the amount by which equity would have gone below zero before the engine floored it). 0 in every probed run: each observed liquidation loss (3.853208734751064) settled inside its committed margin (4.381648789802639).

Perps runs also add two bar-aligned output series next to the stats, committedMarginSeries and fundingPaidSeries (cumulative, ending at stats.fundingPaid); both are omitted on spot runs. See Perps output series.

Long / short splits

stats.long and stats.short carry netProfit, totalTrades, and winRatePct per direction. A "market-neutral" idea whose entire profit sits in stats.long during a bull-market window is a long-only idea with extra steps.

Simulation-quality stats

These describe how the result was produced, not how the strategy performed. They power the disclosures in the run-details popover:

StatDefinition
ambiguousFillCountIntrabar ordering decisions settled by the declared fillModel assumption rather than data. Details in fill simulation.
fineResolvedCountOrdering questions settled by walking finer-interval bars (no assumption involved).
fineFillCoveragePctWalked ordering questions over all ordering questions, times 100. null when the run posed none (zero of zero is not zero percent).
fillResolutionByLaneWalked questions per finer-data lane, e.g. { "1m": 12, "5m": 3 }.
bookSlippageFillCountFills priced from recorded order-book depth (slippageModel="bookEstimate" only).
bookSlippageUnavailableCountbookEstimate fills that fell back to the declared rate (no usable book for that bar or size).
bookSlippageAvgBpsMean applied book impact in basis points; null when nothing was book-priced.

Equity accounting, precisely

Equity on every bar i is cash plus the open position marked at close[i], minus all fees paid so far, recorded on flat bars too. Per-bar returns for Sharpe and Sortino are r_i = equity_i / equity_{i-1} - 1 over confirmed bars with positive prior equity. On the live edge, strategy scripts fully recompute on every tick; the forming bar can shift pending-order and stat values once between the initial render and the first tick, and settles when the bar confirms.