An exchange adapter is the bridge between backtest-kit and a real (or simulated) market data source. It is registered once viaDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/theonetrade/backtest-kit-redis-postgres-pgpool-docker/llms.txt
Use this file to discover all available pages before exploring further.
addExchangeSchema and then used by every strategy that references the same exchangeName. The adapter must implement four async methods: getCandles, getOrderBook, formatPrice, and formatQuantity. This project ships a ccxt Binance spot adapter that is registered in three module files — one per running mode.
addExchangeSchema API
exchangeName
A unique string identifier. Must match the
ExchangeName enum value used in Backtest.background / Live.background and in warmCandles.getCandles
Fetches OHLCV data from the exchange. Called by
warmCandles to pre-populate the candle cache and by the live/paper runner on each tick.getOrderBook
Fetches the current order book. Throws in backtest mode (no live book available for historical data). Implement custom logic here for order-book-based strategies.
formatPrice / formatQuantity
Round a raw price or quantity to the exchange’s tick/step size using
roundTicks. Ensures orders are accepted without precision errors.The ExchangeName Enum
All three module files register the same string "ccxt-exchange", which maps to ExchangeName.CCXT:
Module Files
The exchange adapter is registered in three separate files undermodules/, one per running mode. All three are currently identical — this lets you diverge them later (e.g. use different API credentials, a mock order book, or a different ccxt exchange for paper mode) without touching shared code:
src/main/*.ts entry point before the strategy loop starts, so the schema is always registered before it is needed.
Complete ccxt Binance Adapter (modules/backtest.module.ts)
The following is the full, unmodified source of modules/backtest.module.ts. The other two module files are identical.
Method Reference
getCandles(symbol, interval, since, limit)
Fetches historical OHLCV data starting at since (a Date object). Returns an array of CandleData:
Date to epoch milliseconds with since.getTime() because fetchOHLCV expects a numeric timestamp. Results are mapped from ccxt’s raw [timestamp, open, high, low, close, volume] tuples into plain objects.
warmCandles calls getCandles in paginated batches and writes each candle to the candle-items table via the Candle persist adapter. After warm-up, getClosePrice and getCandles in strategy code read from the database rather than hitting the exchange again.getOrderBook(symbol, depth, from, to, backtest)
| Parameter | Type | Description |
|---|---|---|
symbol | string | Trading pair, e.g. "TRXUSDT" |
depth | number | Number of price levels to fetch on each side |
from | Date | Start of the requested window (informational; exchange adapters may ignore) |
to | Date | End of the requested window |
backtest | boolean | true when called during a backtest replay |
backtest guard is critical: a live order book has no meaning during historical replay, so the default adapter throws immediately. If your strategy uses order-book data in backtests, replace this with a persisted book snapshot or a synthetic book constructed from the candle spread.
formatPrice(symbol, price) and formatQuantity(symbol, quantity)
Both helpers use roundTicks from backtest-kit to snap a raw floating-point value to the exchange’s minimum increment:
exchange.priceToPrecision / exchange.amountToPrecision) handles markets where ccxt stores precision as a decimal count rather than an absolute step size.
The singleshot Pattern for Lazy Initialisation
getExchange is wrapped in singleshot from functools-kit. This is a memoised async factory: the first call creates the ccxt exchange instance and calls loadMarkets() (a network round-trip that fetches symbol metadata); every subsequent call returns the same resolved promise.
getCandles or getOrderBook call).
setConfig — Global Strategy Configuration
setConfig sets global backtest-kit configuration values. It is called at module load time, before the schema is registered:
CC_MAX_STOPLOSS_DISTANCE_PERCENT: 100 removes the default cap on stop-loss distance (which is 5% by default), allowing Position.moonbag to place stops up to 100% away from entry. Adjust this value to match your risk model.
Registering the Adapter for All Three Modes
To ensure the adapter is available regardless of which mode is started, import all three module files from your entry points. The existing structure already does this:src/main/backtest.ts imports from modules/backtest.module.ts, src/main/live.ts from modules/live.module.ts, and src/main/paper.ts from modules/paper.module.ts.
If you want a single adapter registration shared across all modes, extract it into a shared module and import it from each src/main/*.ts:
Adding a second exchange (e.g. OKX)
Adding a second exchange (e.g. OKX)
Create a new module file, add a new Then add
ExchangeName enum member, and call addExchangeSchema with the new name:ExchangeName.OKX = "okx-exchange" to the enum and reference it in your Backtest.background or Live.background call.