Mode A is the monorepo’s flagship execution path: a single Node.js process that backtests all nine symbols inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/theonetrade/backtest-monorepo-parallel/llms.txt
Use this file to discover all available pages before exploring further.
CC_SYMBOL_LIST concurrently, sharing one MongoDB connection pool and one Redis client, with no IPC, no subprocess forks, and no per-symbol startup overhead. The result is a measured aggregate replay speed of ~6 326× real-time — 297 strategy events across 9 symbols in 2.9 seconds on commodity developer hardware — achievable because every Backtest.background() call is non-blocking and the hot loop is pure CPU plus local I/O against a pre-warmed cache.
The Mode A Command
Flag Reference
| Flag | Parsed by | Purpose |
|---|---|---|
--backtest | getArgs() | Activates the second guard in backtest.ts — without it the file is a no-op |
--entry | getArgs() | Activates the first guard — distinguishes Mode A from Mode B |
--cache | getArgs() | Triggers CACHE_CANDLES_FN before the runners start, pre-populating MongoDB with OHLCV candles |
--ui | @backtest-kit/cli | Starts the @backtest-kit/ui web interface on :60050 — forwarded to the CLI runner, not parsed by getArgs() |
The
--entry flag is the single switch that separates Mode A from Mode B. Without --entry, backtest.ts returns on its very first guard and the @backtest-kit/cli single-strategy runner takes over.Source: packages/main/src/main/backtest.ts
The full entry-point file is concise by design. Every concern — schema validation, caching, and symbol iteration — is expressed in fewer than 60 lines:
CC_SYMBOL_LIST — Default Symbols and Customisation
The symbol list is parsed from the CC_SYMBOL_LIST environment variable at startup. If the variable is not set, the module falls back to a hard-coded comma-separated default:
Execution Flow
Guards evaluated
getArgs() parses process.argv once (memoised via singleshot). If either --entry or --backtest is absent, main() returns immediately and the process continues with the @backtest-kit/cli runner.waitForReady(true)
waitForReady(true) blocks until all registered schemas (strategy, exchange, frame) have finished initialising their DI bindings and MongoDB connections. The true argument signals that backtest-specific schemas — including the frame/time-window schema — must be present.Schema validation
listStrategySchema(), listExchangeSchema(), and listFrameSchema() each return the first registered schema of their type. If any is missing, main() throws with a descriptive error rather than silently producing empty results.Optional cache pre-warm
If
--cache is set, CACHE_CANDLES_FN() runs sequentially over every symbol in CC_SYMBOL_LIST, calling cacheCandles() with the exchange name, start date, end date, and 1m interval. This is an awaited loop — it completes fully before any runner starts.Why Single-Process?
Running all nine symbols in one process rather than spawning nine child processes delivers three concrete advantages:No IPC overhead
All contexts share the same heap and event loop. Results, intermediate state, and log output never need to be serialised and sent across a process boundary.
Shared Mongo pool
A single
mongoose connection pool handles all concurrent writes. No per-symbol connection setup, no port exhaustion, no ECONNREFUSED under high parallelism.Shared Redis pool
BaseMap lookups from all nine symbol contexts hit the same ioredis client. Cache entries from one symbol context can be reused by another if they share the same key.waitForReady(true) Explained
waitForReady is a backtest-kit utility that waits for the framework’s internal DI container to signal readiness. Passing true means the call also waits for the frame schema to be registered — which happens when the strategy file is evaluated by @backtest-kit/cli. Without this await, listStrategySchema() would return an empty array because the strategy file may not have finished executing its top-level addStrategySchema() call.
Measured Performance
Benchmarked on a HP Victus 15-FA1022CI (Intel Core i5-13420H, 16 GB DDR4-3200, NVMe SSD) with Mongo + Redis running locally viadocker-compose:
| Metric | Value |
|---|---|
| Wall-clock span (first → last event) | 2 893 ms (~2.9 s) |
| Total events captured | 297 |
| Symbols running in parallel | 9 |
| Historical time advanced per symbol | 34 minutes of 1m candles |
| Per-symbol replay speed | ≈ 703× real-time |
| Aggregate replay speed (9 symbols) | ≈ 6 326× real-time |
| Event throughput | ≈ 103 events/sec |
| Frame coverage | 2026-04-01 → 2026-04-27 (27 days × 38 880 candles/symbol × 9 = ~350 000 candle ticks) |