Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/theonetrade/backtest-kit/llms.txt

Use this file to discover all available pages before exploring further.

Backtest Kit exposes a rich set of event listeners built on reactive Subject-based emitters. Every listener wraps its callback in a queued function, which guarantees sequential async execution — if a callback returns a Promise, the next invocation waits for it to resolve before starting. All listeners return an unsubscribe function that tears down the subscription when called.

Signal Events

listenSignal

Subscribe to all signal events from both backtest and live modes.
listenSignal(fn: (event: IStrategyTickResult) => void): () => void
IStrategyTickResult is a discriminated union: { action: "idle" | "scheduled" | "waiting" | "opened" | "active" | "closed" | "cancelled"; ... }. Use event.action to branch.

listenSignalOnce

Subscribe to the first signal event matching a filter predicate, then automatically unsubscribe.
listenSignalOnce(
  filterFn: (event: IStrategyTickResult) => boolean,
  fn: (event: IStrategyTickResult) => void
): () => void
Returns an unsubscribe function to cancel the one-shot listener before it fires.

listenSignalBacktest

Subscribe to signal events from Backtest.background() / Backtest.run() only.
listenSignalBacktest(fn: (event: IStrategyTickResult) => void): () => void

listenSignalBacktestOnce

One-shot filtered subscription to backtest signal events.
listenSignalBacktestOnce(
  filterFn: (event: IStrategyTickResult) => boolean,
  fn: (event: IStrategyTickResult) => void
): () => void

listenSignalLive

Subscribe to signal events from Live.background() / Live.run() only.
listenSignalLive(fn: (event: IStrategyTickResult) => void): () => void

listenSignalLiveOnce

One-shot filtered subscription to live signal events.
listenSignalLiveOnce(
  filterFn: (event: IStrategyTickResult) => boolean,
  fn: (event: IStrategyTickResult) => void
): () => void

Completion Events

listenDoneBacktest

Fires when a Backtest.background() execution completes for a symbol-strategy pair.
listenDoneBacktest(fn: (event: DoneContract) => void): () => void
DoneContract contains { symbol, strategyName, exchangeName, frameName, backtest }.

listenDoneLive

Fires when a Live.background() execution completes.
listenDoneLive(fn: (event: DoneContract) => void): () => void

listenDoneWalker

Fires when a Walker.background() execution completes.
listenDoneWalker(fn: (event: DoneContract) => void): () => void

listenDoneLiveOnce / listenDoneBacktestOnce / listenDoneWalkerOnce

One-shot filtered variants for completion events.
listenDoneBacktestOnce(
  filterFn: (event: DoneContract) => boolean,
  fn: (event: DoneContract) => void
): () => void

listenDoneLiveOnce(
  filterFn: (event: DoneContract) => boolean,
  fn: (event: DoneContract) => void
): () => void

listenDoneWalkerOnce(
  filterFn: (event: DoneContract) => boolean,
  fn: (event: DoneContract) => void
): () => void

Progress

listenBacktestProgress

Receive progress updates during Backtest.background() execution.
listenBacktestProgress(fn: (event: ProgressBacktestContract) => void): () => void
ProgressBacktestContract contains { symbol, strategyName, exchangeName, totalFrames, processedFrames, progress } where progress is 0.0–1.0.

listenWalkerProgress

Receive progress updates during Walker.background() execution, emitted after each strategy completes.
listenWalkerProgress(fn: (event: ProgressWalkerContract) => void): () => void
ProgressWalkerContract contains { walkerName, exchangeName, frameName, symbol, totalStrategies, processedStrategies, progress } where progress is 0.0–1.0.

listenPerformance

Subscribe to execution timing metrics for profiling and bottleneck detection.
listenPerformance(fn: (event: PerformanceContract) => void): () => void
PerformanceContract includes { metricType, duration, strategyName, exchangeName, frameName, symbol, backtest }. metricType is one of "backtest_total" | "backtest_timeframe" | "backtest_signal" | "live_tick".

Risk & Error Events

listenRisk

Fires only when a signal is rejected by the risk management system. Does not fire for allowed signals.
listenRisk(fn: (event: RiskContract) => void): () => void
RiskContract includes { symbol, strategyName, currentPrice, activePositionCount, rejectionNote, rejectionId, backtest }.

listenRiskOnce

One-shot filtered risk rejection listener.
listenRiskOnce(
  filterFn: (event: RiskContract) => boolean,
  fn: (event: RiskContract) => void
): () => void

listenError

Subscribe to recoverable execution errors. Execution continues after these errors.
listenError(fn: (error: Error) => void): () => void

Position Milestone Events

listenPartialProfit (listenPartialProfitAvailable)

Fires once per profit milestone (10%, 20%, …, 100%) per signal. Deduplicated with a Set — each level fires at most once per signal.
listenPartialProfitAvailable(fn: (event: PartialProfitContract) => void): () => void
PartialProfitContract includes { symbol, strategyName, data, currentPrice, level, backtest, timestamp } where level is one of 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | 100.

listenPartialLoss (listenPartialLossAvailable)

Fires once per loss milestone per signal.
listenPartialLossAvailable(fn: (event: PartialLossContract) => void): () => void

listenBreakeven (listenBreakevenAvailable)

Fires once per signal when the price moves far enough to cover transaction costs and the stop-loss can be moved to entry.
listenBreakevenAvailable(fn: (event: BreakevenContract) => void): () => void

Ping Events

listenSchedulePing

Fires every minute while a scheduled signal (limit entry) is waiting for activation.
listenSchedulePing(fn: (event: SchedulePingContract) => void): () => void

listenActivePing

Fires every minute while a pending signal (active position) is being monitored.
listenActivePing(fn: (event: ActivePingContract) => void): () => void

listenIdlePing

Fires every tick when no signal is pending or scheduled.
listenIdlePing(fn: (event: IdlePingContract) => void): () => void

listenIdlePingOnce

One-shot filtered subscription to idle ping events.
listenIdlePingOnce(
  filterFn: (event: IdlePingContract) => boolean,
  fn: (event: IdlePingContract) => void
): () => void

Lifecycle Events

listenBeforeStart

Fires exactly once per run() invocation, immediately before the first candle or tick is processed. Useful for run-scoped initialization: opening log files, resetting accumulators, sending a “run started” notification.
listenBeforeStart(fn: (event: BeforeStartContract) => void): () => void
BeforeStartContract includes { symbol, strategyName, exchangeName, frameName, backtest, currentPrice, when, timestamp }. In backtest mode when is the planned frame start date; in live mode it is the current wall-clock time aligned to the minute.

listenBeforeStartOnce

One-shot filtered subscription to before-start events.
listenBeforeStartOnce(
  filterFn: (event: BeforeStartContract) => boolean,
  fn: (event: BeforeStartContract) => void
): () => void

listenAfterEnd

Fires exactly once per run() invocation after the strategy iterator finishes — whether by reaching the end of the frame, being stopped via stopStrategy, throwing an error, or external cancellation. Always paired with a preceding listenBeforeStart event. Useful for teardown: flushing buffers, closing files, computing final aggregates.
listenAfterEnd(fn: (event: AfterEndContract) => void): () => void
AfterEndContract includes { symbol, strategyName, exchangeName, frameName, backtest, currentPrice, when, timestamp }. In backtest mode when is the cursor position of the last processed candle.

listenAfterEndOnce

One-shot filtered subscription to after-end events.
listenAfterEndOnce(
  filterFn: (event: AfterEndContract) => boolean,
  fn: (event: AfterEndContract) => void
): () => void

Example: Report Generation Pattern

import {
  Backtest,
  listenSignalBacktest,
  listenDoneBacktest,
} from 'backtest-kit';

const config = {
  strategyName: 'my-strategy',
  exchangeName: 'binance',
  frameName: '1d-test',
};

// Collect every closed trade
const closed: IStrategyTickResultClosed[] = [];

const unsubSignal = listenSignalBacktest((event) => {
  if (event.action === 'closed') {
    closed.push(event);
    console.log(`[${event.symbol}] Closed: ${event.pnl.pnlPercentage.toFixed(2)}%`);
  }
});

listenDoneBacktest(async (event) => {
  console.log(`Backtest complete for ${event.symbol}`);
  console.log(`Total closed signals: ${closed.length}`);
  // Generate markdown report
  await Backtest.dump(event.symbol, config);
  unsubSignal();
});

Backtest.background('BTCUSDT', config);
Backtest.background('ETHUSDT', config);

Build docs developers (and LLMs) love