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.

addExchangeSchema connects Backtest Kit to a market data source. The exchange adapter is the single point of contact for all price data consumed by strategies: VWAP calculation, candle history, order book snapshots, and aggregated trade streams. Once registered, the exchange is referenced by name in every Backtest.run, Live.run, and Walker.run context. The adapter can wrap any data provider—CCXT, a proprietary REST API, or a local database.

Function Signature

addExchangeSchema(exchangeSchema: IExchangeSchema): void

Parameters

exchangeName
string
required
A unique string identifier for this exchange. Used as the routing key in execution contexts. Duplicate names throw at registration.
getCandles
async (symbol, interval, since, limit, backtest) => IPublicCandleData[]
required
The primary data-fetching function. Backtest Kit calls it with exact parameters derived from the execution context timestamp.Adapter contract:
  • since is always aligned to an interval boundary (e.g., 00:15:00 for 15m).
  • The first returned candle’s timestamp must equal since.
  • The adapter must return exactly limit candles.
  • Sequential timestamps: since + i * stepMs for i = 0 .. limit-1.
Violations cause assertion errors during validation.
formatPrice
async (symbol, price, backtest) => string
Formats a raw price number to the exchange’s required precision string. Used when formatting signals for display and reports. Defaults to Bitcoin/USDT precision on Binance (2 decimal places).
formatQuantity
async (symbol, quantity, backtest) => string
Formats a raw quantity to the exchange’s lot-size precision. Defaults to Bitcoin precision (8 decimal places).
getOrderBook
async (symbol, depth, from, to, backtest) => IOrderBookData
Optional. Fetches an order book snapshot. In backtest mode the from/to window (derived from CC_ORDER_BOOK_TIME_OFFSET_MINUTES) allows serving historical snapshots. In live mode the implementation typically ignores from/to and calls the exchange’s current depth endpoint. Throws if called when not implemented.
getAggregatedTrades
async (symbol, from, to, backtest) => IAggregatedTradeData[]
Optional. Fetches aggregated trade data for the given time window. Backtest Kit aligns to to the nearest 1-minute boundary to prevent look-ahead bias. Throws if called when not implemented.
note
string
Optional developer note for documentation or introspection.
callbacks
Partial<IExchangeCallbacks>
Optional lifecycle callbacks:
  • onCandleData(symbol, interval, since, limit, data) — called after every successful getCandles fetch. Useful for logging or caching raw API responses.

ICandleData — Candle Format

timestamp
number
required
Unix timestamp in milliseconds of the candle’s open time (openTime). This is the candle boundary, not the close time.
open
number
required
Opening price at candle start.
high
number
required
Highest price during the candle period.
low
number
required
Lowest price during the candle period.
close
number
required
Closing price at candle end.
volume
number
required
Trading volume during the candle period.

Adapter Contract

The getCandles implementation must satisfy these invariants for the framework to work correctly:
  1. Timestamp alignment: since is always aligned down to the interval boundary before being passed to the adapter. The adapter must begin the response at exactly that timestamp.
  2. Exact count: The adapter must return exactly limit candles. Fewer candles will cause assertion errors; more will be silently sliced.
  3. No pending candles: The last candle in the response must be fully closed. Backtest Kit never requests the currently open candle.
  4. Sequential timestamps: Each candle in the result must have timestamp = since + i * stepMs.

Example — CCXT Binance Adapter

import ccxt from 'ccxt';
import { addExchangeSchema } from 'backtest-kit';

const binance = new ccxt.binance({ enableRateLimit: true });
await binance.loadMarkets();

addExchangeSchema({
  exchangeName: 'binance',

  getCandles: async (symbol, interval, since, limit, backtest) => {
    // CCXT fetchOHLCV accepts timestamp in milliseconds
    const ohlcv = await binance.fetchOHLCV(
      symbol,
      interval,
      since.getTime(),
      limit,
    );
    return ohlcv.map(([timestamp, open, high, low, close, volume]) => ({
      timestamp: timestamp as number,
      open:      open      as number,
      high:      high      as number,
      low:       low       as number,
      close:     close     as number,
      volume:    volume    as number,
    }));
  },

  formatPrice: async (symbol, price, backtest) => {
    return binance.priceToPrecision(symbol, price);
  },

  formatQuantity: async (symbol, quantity, backtest) => {
    return binance.amountToPrecision(symbol, quantity);
  },

  // Optional: real-time order book (backtest ignores from/to)
  getOrderBook: async (symbol, depth, from, to, backtest) => {
    if (backtest) {
      // Return a historical snapshot from your database
      return await myDb.getOrderBookSnapshot(symbol, depth, from, to);
    }
    const book = await binance.fetchOrderBook(symbol, depth);
    return {
      symbol,
      bids: book.bids.map(([price, quantity]) => ({
        price:    String(price),
        quantity: String(quantity),
      })),
      asks: book.asks.map(([price, quantity]) => ({
        price:    String(price),
        quantity: String(quantity),
      })),
    };
  },

  callbacks: {
    onCandleData: (symbol, interval, since, limit, data) => {
      console.debug(`Fetched ${data.length} ${interval} candles for ${symbol} from ${since.toISOString()}`);
    },
  },
});
In backtest mode Backtest Kit caches candle data automatically via PersistCandleAdapter. The adapter’s getCandles is only called on cache miss, so you will not exceed exchange rate limits during large backtests as long as the candle cache is warm (see cacheCandles / warmCandles).

Build docs developers (and LLMs) love