Strategy logic lives inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/theonetrade/backtest-kit-minio-s3-docker/llms.txt
Use this file to discover all available pages before exploring further.
src/logic/strategy/ and is registered with addStrategySchema() from backtest-kit. The persistence layer is entirely transparent to strategy code — strategies read and write state through the same backtest-kit API regardless of whether MinIO, Redis, or the default file system is used as the backing store. The only contract the strategy must satisfy is the addStrategySchema interface.
Define the strategy function
Implement a
getSignal function that receives (symbol, when, currentPrice) and returns a position object or null.Register with addStrategySchema
Call
addStrategySchema({ strategyName, getSignal }) at module load time. The strategyName string must match the value in your StrategyName enum.Add lifecycle listeners
Attach
listenActivePing handlers to manage open positions — trailing takes, peak staleness checks, or any time-driven exit logic. Attach a listenError handler for error observability.Strategy registration
addStrategySchema accepts an object with two required fields: strategyName (a plain string) and getSignal (an async function). The function is called on every candle tick for every symbol the runner is watching.
Strategy naming
ThestrategyName string in addStrategySchema must exactly match the enum value used when starting a runner. The StrategyName enum is the single source of truth:
"jan_2026_strategy" appears in both addStrategySchema and in Backtest.background() / Live.background() calls. A mismatch causes backtest-kit to silently skip the strategy.
getSignal
getSignal is the core of every strategy. It is called with three arguments on each 1-minute candle close:
| Parameter | Type | Description |
|---|---|---|
symbol | string | The trading pair being evaluated (e.g., "TRXUSDT") |
when | Date | The candle close timestamp, aligned to the frame interval |
currentPrice | number | The close price of the current candle |
null to do nothing. The position descriptor must include at least position ("long" or "short"), percentStopLoss, minuteEstimatedTime, and optionally note.
Position.moonbag() is a helper from backtest-kit that calculates percentStopLoss and percentTakeProfit levels from a simple percentage-based stop-loss distance. It returns the correct levels for both long and short positions so you don’t need to invert the math manually.Signal entry files
Trade signals are loaded fromassets/entry.jsonl — a newline-delimited JSON file where each line is one SignalEntryModel object. This pattern decouples signal generation (e.g., Telegram alerts, LLM analysis) from strategy execution.
assets/entry.jsonl:
SIGNALS is loaded synchronously at module import time with readFileSync, then each line is parsed as JSON:
getActiveSignal matches signals by symbol and by minute-aligned publishedAt timestamp:
alignToInterval snaps the publishedAt timestamp to the nearest 1-minute boundary, matching the when argument that backtest-kit supplies to getSignal. This ensures a signal fires on exactly the candle corresponding to when it was published.
listenActivePing
listenActivePing registers a callback that fires on every candle tick for each currently open position. Multiple listeners can be registered — they run sequentially in registration order. Each listener receives { symbol, data } where data is the current position context.
The strategy registers two independent ping listeners:
Listener 1 — Trailing take-profit
Closes the position when the price has fallen back from the peak profit by more than TRAILING_TAKE percent:
| Function | Description |
|---|---|
getPositionPnlPercent(symbol) | Current unrealised PnL as a percentage |
getPositionHighestPnlPercentage(symbol) | Highest PnL percentage ever reached by this position |
getPositionHighestProfitDistancePnlPercentage(symbol) | Distance from the peak profit back to the current price, as a percentage |
getPositionHighestProfitMinutes(symbol) | Minutes elapsed since the position last reached its highest PnL |
commitClosePending(symbol, note) | Schedules the position for close on the next tick |
listenError
Attach a global error listener to capture any unhandled errors thrown inside strategy callbacks. This is required for production observability:errorData and getErrorMessage are utilities from functools-kit that serialise error objects to plain data for structured logging.
Exporting via src/logic/index.ts
All frame and strategy files must be imported fromsrc/logic/index.ts. This single file is the entry point that the runner loads via the --ui flag: