Skip to main content

Documentation 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.

The project supports three operating modes selected at startup. Backtest replays historical OHLCV data through the strategy logic against the MinIO candle cache, producing a full simulation of every trade. Paper mode subscribes to a live market feed and runs the strategy in real time, but executes no real orders — useful for validating a strategy before committing capital. Live mode runs the strategy on the live feed and routes order execution to the real exchange.

CLI mode

Run the compiled bundle directly with Node.js using the npm run start script. The mode is controlled by a combination of --entry (required to actually start) plus one of --backtest, --live, or --paper. The --ui ./build/index.cjs argument is consumed by the @backtest-kit/cli layer to load your compiled strategy bundle — it is not parsed by getArgs.
Replays January 2026 OHLCV data for TRXUSDT through the strategy. MinIO and Redis must be running before this command.
npm run start -- --entry --backtest --ui ./build/index.cjs

getArgs

All three entry points share the same argument parsing logic. getArgs is a singleshot-wrapped function that parses process.argv once and caches the result for the lifetime of the process:
// src/helpers/getArgs.ts
import { singleshot } from "functools-kit";
import { parseArgs } from "util";

export const getArgs = singleshot(() => {
  const { values } = parseArgs({
    args: process.argv,
    options: {
      entry: {
        type: "boolean",
        default: false,
      },
      backtest: {
        type: "boolean",
        default: false,
      },
      live: {
        type: "boolean",
        default: false,
      },
      paper: {
        type: "boolean",
        default: false,
      },
    },
    strict: false,
    allowPositionals: true,
  });
  return { values };
});
Available CLI flags parsed by getArgs:
FlagTypeDefaultDescription
--entrybooleanfalseRequired gate — without this flag, all entry points exit immediately
--backtestbooleanfalseActivate backtest mode
--livebooleanfalseActivate live trading mode
--paperbooleanfalseActivate paper trading mode
strict: false means unknown flags (such as --ui) are silently ignored by parseArgs — they are consumed by the @backtest-kit/cli layer instead.

Entry point logic

Each mode has a dedicated entry point in src/main/. All three follow the same guard pattern: check --entry, check the mode flag, wait for Redis, then hand off to the runner.
// src/main/backtest.ts
import { getArgs } from "../helpers/getArgs";
import ioc from "../lib";
import { Backtest, warmCandles, waitForReady } from "backtest-kit";
import { ExchangeName } from "../enum/ExchangeName";
import { FrameName } from "../enum/FrameName";
import { StrategyName } from "../enum/StrategyName";

const main = async () => {

  const { values } = getArgs();

  if (!values.entry) {
    return;
  }

  if (!values.backtest) {
    return;
  }

  {
    await ioc.redisService.waitForInit();
  }

  await waitForReady(true);

  await warmCandles({
    exchangeName: ExchangeName.CCXT,
    from: new Date("2026-01-01T00:00:00Z"),
    to: new Date("2026-01-31T23:59:59Z"),
    interval: "1m",
    symbol: "TRXUSDT",
  })

  Backtest.background("TRXUSDT", {
    exchangeName: ExchangeName.CCXT,
    frameName: FrameName.Jan2026Frame,
    strategyName: StrategyName.Jan2026Strategy,
  });
};

main();
Key differences between the entry points:
StepBacktestLivePaper
RunnerBacktest.background()Live.background()Live.background()
waitForReady argumenttrue (backtest mode)false (live mode)false (live mode)
warmCandles✅ Required❌ Not needed❌ Not needed
frameNameRequiredNot usedNot used
Paper mode uses Live.background() rather than a dedicated Paper runner — the distinction is that paper mode does not send real orders to the exchange. This is controlled at the exchange adapter level, not at the runner level.

warmCandles

Before starting a backtest replay, warmCandles pre-fetches all OHLCV data for the backtest window from Binance and stores it in MinIO. This one-time cache fill means the replay loop reads only from local MinIO storage — no live exchange calls are made during the replay itself, making backtests fast and deterministic.
await warmCandles({
  exchangeName: ExchangeName.CCXT,
  from: new Date("2026-01-01T00:00:00Z"),
  to: new Date("2026-01-31T23:59:59Z"),
  interval: "1m",
  symbol: "TRXUSDT",
})
warmCandles respects the PersistCandleAdapter insert-only contract: if a candle for a given (symbol, interval, timestamp) already exists in MinIO, it is skipped without a PUT — re-running warmCandles is safe and idempotent.

Docker mode

The full Docker deploy bundles the strategy runner and backtest-kit into a single container managed by the root docker-compose.yaml. The mode is selected via the MODE environment variable instead of CLI flags. Use the npm convenience scripts to build and start the full stack:
npm run start:docker
npm run stop:docker
The start:docker script builds the strategy bundle and starts the container stack with MODE=backtest, ENTRY=1, UI=1, and STRATEGY_FILE=./build/index.cjs set via cross-env. To run in a different mode, pass the MODE variable explicitly before the script or edit the command directly:
cross-env MODE=live ENTRY=1 UI=1 STRATEGY_FILE=./build/index.cjs docker-compose up -d
docker-compose logs -f
Available npm scripts from package.json:
ScriptDescription
npm run startBuild and run via the @backtest-kit/cli Node.js entrypoint
npm run start:debugBuild and run with --inspect-brk for attaching a debugger
npm run start:replBuild and start an interactive Node.js REPL with the strategy bundle loaded
npm run start:dockerBuild and start the full Docker Compose stack in backtest mode
npm run stop:dockerTear down the Docker Compose stack

Environment variable mapping

When running in Docker mode, CLI flags are replaced by environment variables that the @backtest-kit/cli container image reads:
CLI flagEnvironment variableDescription
--entryENTRY=1Required gate — enables the entry point
--backtestMODE=backtestActivate backtest mode
--liveMODE=liveActivate live trading mode
--paperMODE=paperActivate paper trading mode
--ui <path>UI=1 + STRATEGY_FILE=<path>Enable web UI and set strategy bundle path
Additional container variables:
VariableDescription
CC_MINIO_ENDPOINTMinIO host (default: host.docker.internal)
CC_MINIO_PORTMinIO S3 port (default: 9000)
CC_MINIO_ACCESSKEYMinIO access key
CC_MINIO_SECRETKEYMinIO secret key
CC_REDIS_HOSTRedis host (default: host.docker.internal)
CC_REDIS_PORTRedis port (default: 6379)
CC_REDIS_USERRedis username (default: default)
CC_REDIS_PASSWORDRedis password
SYMBOLOverride trading symbol
STRATEGYOverride strategy name
EXCHANGEOverride exchange name
FRAMEOverride frame name
TELEGRAMEnable Telegram notifications
VERBOSEEnable verbose logging
NO_CACHEDisable candle cache reads
NO_FLUSHDisable state flush on startup
The backtest-kit container exposes a healthcheck endpoint at http://localhost:60050/api/v1/health/health_check. Docker pings this endpoint every 30 seconds. If the process has not yet started the web UI (e.g., UI=1 is not set), the healthcheck will fail — set UI=1 or disable the healthcheck in docker-compose.yaml for headless runs.

Build docs developers (and LLMs) love