Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/backtest-kit/backtest-monorepo-parallel/llms.txt

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

backtest-monorepo-parallel is a TypeScript monorepo template built on top of backtest-kit that runs multiple trading symbols in parallel within a single Node.js process. It ships a zero-config dependency-injection runtime that exposes a typed globalThis.core object to strategy files under ./content/ — no imports, no bundler hooks, and no changes to the strategy author’s code required.

Headline performance

On commodity developer hardware (HP Victus 15-FA1022CI, i5-13420H, 16 GB DDR4-3200), the template recorded 297 backtest events across 9 symbols in 2.893 seconds of wall time. That corresponds to 34 minutes of historical market data per symbol, replayed in parallel.
MetricValue
Wall-clock span2 893 ms (~2.9 s)
Total events297
Symbols in parallel9 (BTC, POL, ZEC, HYPE, XAUT, DOGE, SOL, PENGU, HBAR)
Historical time per symbol34 minutes (2 040 000 ms)
Per-symbol replay speed≈ 703× real-time
Aggregate replay speed≈ 6 326× real-time
Event throughput≈ 103 events/sec (one Node process)

Why it’s fast

Four design decisions combine to remove every major bottleneck in the hot path:

Single-process concurrency

All 9 Backtest.background(...) calls share one Node event loop, one Mongo connection pool, and one Redis pool. No IPC, no subprocess fork overhead.

Redis O(1) lookup cache

Every findByContext(...) is a hot-path Redis GET before falling back to Mongo. Strings only — no JSON parse on the cache key.

Atomic upserts

Every write is a single findOneAndUpdate({ $set }, { upsert: true, new: true }) — no read-modify-write, no application-side locks, no retry loops under concurrent symbol writes.

JIT-friendly hot path

The per-tick strategy body is ~30 lines of synchronous arithmetic plus a few awaited helpers. V8 inlines aggressively, keeping per-tick overhead minimal.

Workspace packages

The monorepo (npm workspaces) contains two packages:
@pro/core is the shared infrastructure layer. It exports an ioc object assembled from injected service instances and immediately assigns it to globalThis.core:
// packages/core/src/lib/index.ts (excerpt)
export const ioc = {
  ...baseServices,
  ...coreServices,
  ...dbServices,
  ...screenServices,
};

init();

declare global {
  var core: typeof ioc;
}

Object.assign(globalThis, { core: ioc });
Services currently registered include loggerService, scraperService, parserService, candleDbService, and cryptoYodaScreenService. Every service is wired through a symbol-keyed TYPES registry and a provide() call, so adding a new service never touches files under ./content/.
@pro/main reads the CLI flags passed to npm run start via getArgs() and conditionally imports one of four mode files: backtest.ts, live.ts, paper.ts, or session.ts. In Mode A (the --entry flag), backtest.ts reads CC_SYMBOL_LIST and calls Backtest.background(symbol, …) for each symbol concurrently. Without --entry, the bundled @backtest-kit/cli runner takes over for single-symbol Mode B runs.

Zero-import DI runtime

Strategy files placed under ./content/ can call core.candleDbService.findById(...) — or any other service — without a single import statement. This works because the root tsconfig.json maps the @pro/core module specifier to the rolled-up packages/core/types.d.ts declaration file:
// tsconfig.json (paths section)
{
  "paths": {
    "@pro/core": ["./packages/core/types.d.ts"],
    "@pro/main": ["./packages/main/types.d.ts"]
  }
}
TypeScript resolves core.* through the global augmentation (declare global { var core: typeof ioc }) baked into types.d.ts at build time. At runtime, config/loader.config.ts imports @pro/core (mapped to the CJS build via alias.config.ts), which runs the Object.assign(globalThis, { core: ioc }) side-effect before any strategy file is evaluated.

Key dependencies

PackageVersionRole
backtest-kit9.8.4Core engine; @backtest-kit/cli is the runner
@backtest-kit/cli9.8.4CLI runner that evaluates strategy files
@backtest-kit/mongo0.6.0Mongo persist adapters + waitForInit()
@backtest-kit/ui9.8.4Optional web UI on port 60050
@backtest-kit/graph9.8.4Chart/graph rendering utilities
di-factory1.0.9Class-factory helper for BaseCRUD / BaseMap
mongoose8.23.0Mongo client and schema definitions
ioredis5.6.1Redis client (used via getRedis())
functools-kit2.3.0Utility belt: singleshot, errorData, and more
agent-swarm-kit2.7.0Agent orchestration for AI-driven strategies
dayjs1.11.20Date/time manipulation

Quickstart

Clone the repo, start infrastructure, build packages, and run your first parallel backtest in minutes.

Architecture

Understand the monorepo layout, DI wiring, build pipeline, and config layer in depth.

Mode A Parallel Guide

Deep-dive into the parallel entry point, symbol list configuration, and caching strategy.

IoC Container API

Full reference for provide(), inject<T>(), init(), and the TYPES symbol registry.

Build docs developers (and LLMs) love