Skip to main content

Documentation Index

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

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

backtest-kit-redis-mongo-docker implements a two-layer persistence architecture: MongoDB serves as the durable source of truth for all trading data, while Redis acts as a high-speed O(1) identity cache that accelerates repeated context-key lookups during backtests and live runs. Every read path checks Redis first; only on a cache miss does the adapter fall back to MongoDB, after which it immediately backfills the cache so subsequent reads stay fast.

Layered Data Flow

A call from the backtest-kit core traverses three layers before returning:
backtest-kit core


 IPersist* adapter          (src/config/setup.ts)

       ├─── Redis cache check  ──► cache HIT  ──► MongoDB findById(_id)  ──► return
       │                                                                         │
       └─── cache MISS ──► MongoDB findOne (indexed filter) ──► Redis SET ──► return
On a write the path is equally direct:
writeXData(payload, when?)


 XDbService.upsert()  ──►  MongoDB findOneAndUpdate (atomic upsert)

                                     └──► XCacheService.setXId(result)  ──► Redis SET
After the upsert returns, the cache entry is updated in the same synchronous critical section, so readXData called immediately afterward always sees the freshly written value.

IoC Container

All services are wired together in src/lib/index.ts via a lightweight IoC container built on di-factory. The container is partitioned into three groups:
GroupCountPurpose
Base services3Infrastructure: logger, Mongo connection, Redis connection
Cache services15Per-domain Redis wrappers (one per domain)
DB services15Per-domain MongoDB CRUD + upsert logic
The registration happens in src/lib/core/provide.ts using provide(TYPES.xxx, () => new XService()) calls, and src/lib/index.ts exposes the resolved instances via the ioc object:
// src/lib/index.ts (abridged)
const baseServices = {
  loggerService:  inject<LoggerService>(TYPES.loggerService),
  mongoService:   inject<MongooseService>(TYPES.mongoService),
  redisService:   inject<RedisService>(TYPES.redisService),
};

const cacheServices = {
  candleCacheService:        inject<CandleCacheService>(TYPES.candleCacheService),
  signalCacheService:        inject<SignalCacheService>(TYPES.signalCacheService),
  scheduleCacheService:      inject<ScheduleCacheService>(TYPES.scheduleCacheService),
  riskCacheService:          inject<RiskCacheService>(TYPES.riskCacheService),
  partialCacheService:       inject<PartialCacheService>(TYPES.partialCacheService),
  breakevenCacheService:     inject<BreakevenCacheService>(TYPES.breakevenCacheService),
  storageCacheService:       inject<StorageCacheService>(TYPES.storageCacheService),
  notificationCacheService:  inject<NotificationCacheService>(TYPES.notificationCacheService),
  logCacheService:           inject<LogCacheService>(TYPES.logCacheService),
  measureCacheService:       inject<MeasureCacheService>(TYPES.measureCacheService),
  intervalCacheService:      inject<IntervalCacheService>(TYPES.intervalCacheService),
  memoryCacheService:        inject<MemoryCacheService>(TYPES.memoryCacheService),
  recentCacheService:        inject<RecentCacheService>(TYPES.recentCacheService),
  stateCacheService:         inject<StateCacheService>(TYPES.stateCacheService),
  sessionCacheService:       inject<SessionCacheService>(TYPES.sessionCacheService),
};

const dbServices = {
  candleDbService:        inject<CandleDbService>(TYPES.candleDbService),
  signalDbService:        inject<SignalDbService>(TYPES.signalDbService),
  scheduleDbService:      inject<ScheduleDbService>(TYPES.scheduleDbService),
  riskDbService:          inject<RiskDbService>(TYPES.riskDbService),
  partialDbService:       inject<PartialDbService>(TYPES.partialDbService),
  breakevenDbService:     inject<BreakevenDbService>(TYPES.breakevenDbService),
  storageDbService:       inject<StorageDbService>(TYPES.storageDbService),
  notificationDbService:  inject<NotificationDbService>(TYPES.notificationDbService),
  logDbService:           inject<LogDbService>(TYPES.logDbService),
  measureDbService:       inject<MeasureDbService>(TYPES.measureDbService),
  intervalDbService:      inject<IntervalDbService>(TYPES.intervalDbService),
  memoryDbService:        inject<MemoryDbService>(TYPES.memoryDbService),
  recentDbService:        inject<RecentDbService>(TYPES.recentDbService),
  stateDbService:         inject<StateDbService>(TYPES.stateDbService),
  sessionDbService:       inject<SessionDbService>(TYPES.sessionDbService),
};

export const ioc = {
  ...baseServices,
  ...cacheServices,
  ...dbServices,
};

init();

Object.assign(globalThis, { ioc });

export default ioc;
All 15 adapter registrations in src/config/setup.ts use ioc.xDbService and ioc.xCacheService directly; no adapter needs to know whether it is talking to Mongo or Redis.

Infrastructure Guard

Before any adapter method does real work on its first call, it awaits waitForInfra() — a singleshot promise that resolves only after both mongoService.waitForInit() and redisService.waitForInit() complete. Subsequent calls skip the guard at zero cost.
const waitForInfra = singleshot(async () => {
  await Promise.all([
    ioc.mongoService.waitForInit(),
    ioc.redisService.waitForInit(),
  ]);
});

Further Reading

Atomicity

How findOneAndUpdate with compound unique indexes eliminates E11000 race conditions and guarantees read-after-write consistency.

Redis Cache

The BaseMap abstraction and per-domain CacheService classes that turn compound-key lookups into O(1) Redis reads.

Look-Ahead Bias

How the indexed when: Date column lets backtest-kit’s bias filter verify that reads never see future data.

Deployment

Docker Compose setup for running MongoDB, Redis, and the adapter layer together in a single-command environment.

Build docs developers (and LLMs) love