Skip to main content

Documentation Index

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

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

backtest-kit-minio-s3-docker supports three running modes. Each has its own entry point in src/main/, and each is gated by CLI flags parsed by getArgs(). The mode you choose determines whether the engine simulates against historical candles, places real orders on the exchange, or simulates order execution using live prices without touching your actual account.

Mode overview

Backtest

Replays historical OHLCV data bar-by-bar over the date range defined by the selected frame. No network calls to the exchange during replay — all candle data is served from MinIO cache.

Live

Connects to a live exchange via CCXT and places real orders. Runs getSignal on each incoming price tick. Use only with tested strategies and appropriate risk settings.

Paper

Uses live prices from the exchange but simulates order fills locally. Identical code path to live mode — only order execution is virtual. Ideal for validating a strategy before committing real capital.

CLI flags

Each mode is invoked by passing flags to npm run start. The --entry flag is a mandatory safety guard; without it the process exits immediately regardless of any other flags.
npm run start -- --entry --backtest --ui ./build/index.cjs
Runs a historical simulation over the frame defined in src/main/backtest.ts. Candles are pre-fetched via warmCandles before the loop starts.

Flags parsed by getArgs()

The four flags below are the only ones explicitly declared in src/helpers/getArgs.ts. They are the flags your application code reads via values.*.
FlagDescription
--entryRequired. Must be present for any mode to execute. Acts as an accidental-run guard.
--backtestSelects historical backtest mode.
--liveSelects live trading mode.
--paperSelects paper trading mode.

Additional flags consumed by @backtest-kit/cli

The following flags are passed on the command line alongside the mode flags but are consumed by the @backtest-kit/cli runtime layer, not by getArgs(). Because parseArgs is called with strict: false, unknown flags are silently ignored by getArgs() and forwarded transparently.
FlagDescription
--uiEnables the backtest-kit web UI on port :60050. Pass the path to the compiled UI bundle (e.g. ./build/index.cjs).
--verboseEnables verbose logging throughout the runtime.
--no-cacheDisables candle caching (candles are fetched from the exchange on every read).
--no-flushDisables the flush-on-shutdown hook.
--telegramEnables Telegram notifications for signal events.

The getArgs() helper

src/helpers/getArgs.ts wraps Node’s built-in parseArgs utility and memoises the result with singleshot so command-line parsing happens exactly once:
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 };
});
Every mode entry point calls getArgs() and checks both values.entry and the mode-specific flag before doing any work. If either is missing, the function returns early with no side-effects:
const { values } = getArgs();
if (!values.entry)    return;
if (!values.backtest) return;

Backtest mode entry point

src/main/backtest.ts is the historical simulation runner. After confirming the CLI flags it:
  1. Waits for the Redis index to be ready (redisService.waitForInit()).
  2. Calls waitForReady(true) — the true argument signals backtest mode to the runtime.
  3. Pre-fetches all candles for the frame’s date range with warmCandles.
  4. Launches the simulation loop with Backtest.background().
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();

Live mode entry point

src/main/live.ts connects to the live exchange and drives getSignal on real price ticks. It uses Live.background() instead of Backtest.background(), and calls waitForReady(false) — the false argument puts the runtime into live mode. No warmCandles call is needed; candles are fetched on demand from the exchange.
import { getArgs } from "../helpers/getArgs";
import ioc from "../lib";
import { Live, waitForReady } from "backtest-kit";
import { ExchangeName } from "../enum/ExchangeName";
import { StrategyName } from "../enum/StrategyName";

const main = async () => {
  const { values } = getArgs();
  if (!values.entry) return;
  if (!values.live)  return;

  await ioc.redisService.waitForInit();
  await waitForReady(false);

  Live.background("TRXUSDT", {
    exchangeName: ExchangeName.CCXT,
    strategyName: StrategyName.Jan2026Strategy,
  });
};

main();

Paper mode entry point

src/main/paper.ts is structurally identical to live.ts — the same Live.background() call with live prices — but it gates on values.paper instead of values.live. The differentiation between a real order and a paper order is handled internally by the backtest-kit runtime based on the mode flag.
import { getArgs } from "../helpers/getArgs";
import ioc from "../lib";
import { Live, waitForReady } from "backtest-kit";
import { ExchangeName } from "../enum/ExchangeName";
import { StrategyName } from "../enum/StrategyName";

const main = async () => {
  const { values } = getArgs();
  if (!values.entry) return;
  if (!values.paper) return;

  await ioc.redisService.waitForInit();
  await waitForReady(false);

  Live.background("TRXUSDT", {
    exchangeName: ExchangeName.CCXT,
    strategyName: StrategyName.Jan2026Strategy,
  });
};

main();

Environment variables for Docker mode

When running via docker-compose, CLI flags are replaced by environment variables. The @backtest-kit/cli container reads these at startup and translates them into the equivalent flag set:
VariableEquivalent flagValues
MODE--backtest / --live / --paperbacktest | live | paper
ENTRY--entry1 to enable
STRATEGY_FILE(path arg)Path to compiled bundle, default ./build/index.cjs
SYMBOLOverride the trading symbol (e.g. TRXUSDT)
STRATEGYOverride the strategy name
EXCHANGEOverride the exchange name
FRAMEOverride the frame name
UI--ui1 to enable web UI on :60050
TELEGRAM--telegram1 to enable Telegram notifications
VERBOSE--verbose1 for verbose logging
NO_CACHE--no-cache1 to disable candle caching
NO_FLUSH--no-flush1 to disable flush on shutdown
Example full docker deploy:
MODE=backtest ENTRY=1 UI=1 STRATEGY_FILE=./build/index.cjs docker-compose up -d
docker-compose logs -f
Or use the npm convenience scripts:
npm run start:docker   # brings up all containers
npm run stop:docker    # tears them down
Live mode places real orders. Running --live (or MODE=live in Docker) will submit actual buy and sell orders to the exchange using the credentials in your environment. Always validate your strategy in paper mode first. A misconfigured stop-loss, an overly aggressive position size, or an unexpected signal file can result in real financial losses.
Web UI — passing --ui ./build/index.cjs (or setting UI=1 in Docker) starts the backtest-kit UI server on port 60050. Open http://localhost:60050 in your browser after a backtest completes to browse signal history, PnL curves, and per-bar logs. The Docker healthcheck pings http://localhost:60050/api/v1/health/health_check every 30 seconds to confirm the container is alive.

Build docs developers (and LLMs) love