Skip to main content

Documentation Index

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

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

The Backtest and Live facades expose the same interface — only the execution engine differs. Backtest replays historical candles from a registered addFrameSchema, while Live runs an infinite loop with real-time ticks from new Date(). This symmetry means identical strategy code runs in both modes without modification. Both facades support two consumption patterns: event-driven background execution (for production bots and long-running processes) and async iterator pull-based execution (for research, scripting, and testing).

Backtest

Backtest.background(symbol, context)

Starts a backtest in the background. Returns a stop function immediately. Results are delivered through the event listener system (listenSignalBacktest, listenDoneBacktest, etc.) rather than being returned directly. Multiple symbols can be backtested in parallel by calling background multiple times.
import { Backtest, listenSignalBacktest, listenDoneBacktest } from 'backtest-kit';

const stop = Backtest.background('BTCUSDT', {
  strategyName: 'my-strategy',
  exchangeName: 'binance',
  frameName: 'dec-2025-1m',
});

listenSignalBacktest((event) => {
  console.log(event.action, event.symbol);
});

listenDoneBacktest(async (event) => {
  await Backtest.dump(event.symbol, event.strategyName);
  console.log('Backtest complete');
});

// Optionally stop early:
// stop();
symbol
string
required
Trading pair symbol (e.g. 'BTCUSDT', 'ETH/USD'). The value is passed verbatim to all getCandles and getSignal calls.
context.strategyName
string
required
Name of a strategy registered via addStrategySchema.
context.exchangeName
string
required
Name of an exchange registered via addExchangeSchema.
context.frameName
string
required
Name of a frame registered via addFrameSchema. Defines the date range and tick interval.
Returns: () => void — calling the returned function stops the backtest. The engine waits for the current tick to finish before halting; in-flight positions are not forcibly closed.

Backtest.run(symbol, context)

Runs a backtest as an AsyncIterableIterator. Each yield delivers a IStrategyTickResultClosed — the result of one closed trade. Use this API for scripting, testing, or pulling results programmatically. Early termination is supported via break.
import { Backtest } from 'backtest-kit';

for await (const result of Backtest.run('BTCUSDT', {
  strategyName: 'my-strategy',
  exchangeName: 'binance',
  frameName: 'dec-2025-1m',
})) {
  console.log(result.action, result.pnl, result.closeReason);
  // Break early to stop the backtest:
  // if (result.pnl < -10) break;
}
symbol
string
required
Trading pair symbol.
context.strategyName
string
required
Strategy name.
context.exchangeName
string
required
Exchange name.
context.frameName
string
required
Frame name.
Returns: AsyncIterableIterator<IStrategyTickResultClosed> — yields only on closed signals, not on idle or active ticks. This makes iteration memory-efficient for large datasets.

Backtest.dump(symbol, strategyName, path?)

Saves the accumulated backtest report to a Markdown file. The report includes a table of all closed signals with PnL, entry/exit prices, close reasons, and summary statistics (win rate, Sharpe ratio, total PnL).
await Backtest.dump('BTCUSDT', 'my-strategy');
// Writes to: ./dump/backtest/BTCUSDT_my-strategy_...backtest-<timestamp>.md
symbol
string
required
Trading pair symbol.
strategyName
string
required
Strategy name.
path
string
Optional custom output directory. Defaults to ./dump/backtest/.

Backtest.getReport(strategyName)

Returns the full Markdown report as a string without writing to disk.
const markdown = await Backtest.getReport('my-strategy');
console.log(markdown);
Returns: Promise<string> — Markdown-formatted report for all symbols that ran with this strategy.

Backtest.getData(strategyName)

Returns the structured statistics object for the strategy. Useful for programmatic analysis, ranking strategies, or feeding results into an optimizer.
const stats = await Backtest.getData('my-strategy');
console.log(stats.winRate, stats.sharpeRatio, stats.totalPnl);
Returns: Promise<BacktestStatisticsModel> — includes winRate, totalPnl, sharpeRatio, sortinoRatio, maxDrawdown, avgPnl, totalTrades, closedSignals, and more.

Backtest.clear(strategyName?)

Clears accumulated report data. Call this between successive backtests to prevent data from different runs from being mixed in the same report.
// Clear a specific strategy's data:
await Backtest.clear('my-strategy');

// Clear all accumulated backtest data:
await Backtest.clear();
strategyName
string
If provided, clears only this strategy’s data. If omitted, clears all strategies.

Backtest.list()

Returns a list of all currently active background backtest runs.
const runs = Backtest.list();
// [{ symbol: 'BTCUSDT', strategyName: 'my-strategy', status: 'running' }, ...]

Backtest.stop(symbol, strategyName)

Stops a specific active background run. Equivalent to calling the stop function returned by Backtest.background().
Backtest.stop('BTCUSDT', 'my-strategy');

Live

The Live facade has the same interface as Backtest, with two key differences: there is no frameName (live trading has no historical window), and run() is infinite — it never completes unless stopped explicitly.

Live.background(symbol, context)

Starts live trading in the background. On startup, ClientStrategy.waitForInit() loads the last persisted signal state from disk, enabling crash recovery — if the process restarts, monitoring resumes from the saved state.
import { Live, listenSignalLive } from 'backtest-kit';

const stop = Live.background('BTCUSDT', {
  strategyName: 'my-strategy',
  exchangeName: 'binance',
});

listenSignalLive((event) => {
  if (event.action === 'closed') {
    console.log('Trade closed', event.pnl, event.closeReason);
  }
});
symbol
string
required
Trading pair symbol.
context.strategyName
string
required
Strategy name.
context.exchangeName
string
required
Exchange name. No frameName — live mode uses real-time data.
Returns: () => void — calling the returned function signals graceful shutdown. The engine waits for any active position to close before stopping, preventing orphaned positions.

Live.run(symbol, context)

Runs live trading as an AsyncIterableIterator. Yields IStrategyTickResult events (opened and closed; idle and active ticks are skipped). The generator never exhausts — use break to stop.
for await (const event of Live.run('BTCUSDT', {
  strategyName: 'my-strategy',
  exchangeName: 'binance',
})) {
  if (event.action === 'opened') {
    console.log('Position opened at', event.priceOpen);
  }
  if (event.action === 'closed') {
    console.log('Position closed, PnL:', event.pnl);
  }
}
Returns: AsyncIterableIterator<IStrategyTickResult>

Live.dump(), Live.getReport(), Live.getData(), Live.clear()

Identical to the Backtest counterparts. Live.getReport() produces a table of all events including idle, opened, active, and closed, with win rate and average PnL statistics.

Walker

Walker runs A/B comparisons across multiple strategies against the same exchange and frame. It executes each strategy sequentially, collects statistics, and ranks them by a chosen metric (Sharpe ratio, total PnL, win rate, etc.).

Walker.background(symbol, config)

Starts a Walker A/B comparison in the background for a given symbol. The walker schema (registered via addWalkerSchema) defines which strategies to compare, the exchange and frame to use, and the metric to rank by.
import { Walker, addWalkerSchema } from 'backtest-kit';

addWalkerSchema({
  walkerName: 'strategy-comparison',
  exchangeName: 'binance',
  frameName: 'dec-2025-1m',
  strategies: ['strategy-a', 'strategy-b', 'strategy-c'],
  metric: 'sharpeRatio', // rank by this field from BacktestStatisticsModel
});

Walker.background('BTCUSDT', {
  walkerName: 'strategy-comparison',
});
symbol
string
required
Trading pair symbol to run all strategies against (e.g. 'BTCUSDT').
config.walkerName
string
required
Name of a walker schema registered via addWalkerSchema. The schema contains the strategy list, exchange name, frame name, and comparison metric.

Walker.getReport(), Walker.getData()

Returns a sorted comparison table (Markdown or structured data) showing each strategy’s metric value and rank.

IStrategyTickResult Discriminated Union

Every signal event — whether from Backtest.run(), Live.run(), or an event listener — is typed as one of four variants. Use event.action as the discriminant to narrow the type in TypeScript.
type IStrategyTickResult =
  | {
      action: 'idle';
      symbol: string;
      strategyName: string;
      exchangeName: string;
      frameName: string;
      currentPrice: number;
      backtest: boolean;
      createdAt: number;
    }
  | {
      action: 'opened';
      symbol: string;
      strategyName: string;
      exchangeName: string;
      frameName: string;
      signal: ISignalRow;
      currentPrice: number;
      backtest: boolean;
      createdAt: number;
    }
  | {
      action: 'active';
      symbol: string;
      strategyName: string;
      exchangeName: string;
      frameName: string;
      signal: ISignalRow;
      percentTp: number;   // progress toward take-profit (0–100)
      percentSl: number;   // progress toward stop-loss (0–100)
      pnl: number;         // current unrealized PnL %
      currentPrice: number;
      backtest: boolean;
      createdAt: number;
    }
  | {
      action: 'closed';
      symbol: string;
      strategyName: string;
      exchangeName: string;
      frameName: string;
      signal: ISignalRow;
      priceClosed: number;
      closeReason: 'take_profit' | 'stop_loss' | 'time_expired' | 'close_pending';
      pnl: number;         // realized PnL % (net of fees and slippage)
      closeTimestamp: number;
      backtest: boolean;
      createdAt: number;
    };
Backtest.run() only yields closed events. Live.run() yields opened and closed events. The full set of variants is delivered through event listeners.

Build docs developers (and LLMs) love