backtest-kit 9.0+ added aDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/backtest-kit/backtest-kit-redis-postgres-pgpool-docker/llms.txt
Use this file to discover all available pages before exploring further.
when: Date argument to every adapter write* method, and to read* for adapters that directly affect signal logic (Risk, Partial, Breakeven). This argument carries the logical simulation timestamp at which the write occurs — the bar timestamp being replayed during a backtest, or the wall-clock time during live/paper trading. It is stored in a when bigint column (milliseconds since Unix epoch) so the framework can enforce that no read* call returns a value that was written in the future relative to the current simulation time, eliminating look-ahead bias at the persistence layer.
Which adapters carry when?
Eight adapters write and store the when timestamp. Eight do not.
Carry when: Date
Risk, Partial, Breakeven, Recent, State, Session, Memory, IntervalThese adapters store signal-affecting state that must be temporally consistent with the simulation timeline. The
when column is declared as bigint with epochTransformer in each entity schema.No when column
Candle, Signal, Strategy, Schedule, Storage, Notification, Log, MeasureThese adapters either store immutable market data (Candle), pure bookkeeping state (Storage, Notification, Log), or domain data where temporal consistency is not enforced at the persistence layer (Signal, Strategy, Schedule). Measure is intentionally exempt — see the note below.
Schema example
TheState entity schema is representative of all eight when-carrying schemas. The when column is declared as bigint with the shared epochTransformer value transformer. The createDate and updatedDate columns use PostgreSQL timestamptz and are managed automatically by TypeORM — they are wall-clock timestamps for auditing, not simulation time.
epochTransformer
PostgreSQL’sbigint type is returned by the pg driver as a JavaScript string, because JavaScript’s Number type cannot safely represent all 64-bit integer values. A shared ValueTransformer bridges the gap: to passes the number through unchanged on write; from calls Number(value) on read to restore a plain JS number.
when-carrying schemas (State, Session, Recent, Risk, Partial, Breakeven, Interval, Memory) import and apply epochTransformer to their when column. The Candle schema applies the same transformer to its timestamp column, since candle timestamps are also stored as epoch milliseconds.
How it’s written
The DbService converts the incomingDate to epoch milliseconds via when.getTime() inside the same atomic upsert that writes the payload. The when column is included in the orUpdate list so that subsequent writes to the same context key also update the simulation timestamp:
when value written to Postgres is always when.getTime() — a plain number (milliseconds since epoch). On read, epochTransformer.from converts the pg string back to a number, so callers always receive a numeric timestamp regardless of Postgres’s internal type representation.
Candle adapter and time-ordered reconstruction
The Candle adapter does not store awhen column for look-ahead purposes, but it enforces temporal order through its readCandlesData implementation. The method reconstructs the requested window by iterating limit slots starting at sinceTimestamp with steps of INTERVAL_MINUTES[interval] * 60_000 milliseconds:
readCandlesData returns null. The backtest engine treats null as a cache miss and fetches the window from the exchange, then calls writeCandlesData to populate the missing slots. This ensures the framework never silently returns a partial window — which would itself be a form of look-ahead bias if the trailing slots were from a future bar.
Measure exemption
Measure is intentionally exempt from the
when column. The Measure adapter caches LLM and external API responses by (bucket, entryKey). These calls are made during live strategy execution, not historical simulation — the response is a function of the prompt, not of the bar timestamp. Including when would add no temporal constraint and would prevent cache sharing across backtest runs replaying the same date range. The Measure.schema.ts entity has no when column, and IMeasureDto has no when field.Soft-delete adapters and when
Both Interval and Memory carry when to record the simulation timestamp at which a key was created or last updated. The softRemove path does not update when — a tombstone records the timestamp of the last live write, not the time of removal. This preserves the original write timestamp for auditing and for the framework’s temporal consistency checks. The jsonb_set soft-delete statement updates only removed and payload.removed:
listKeys and listEntries queries filter on removed = false, so tombstoned rows are invisible to normal read paths while remaining available for auditing via direct Postgres queries.
Session uniqueness and look-ahead safety
TheSession schema includes both symbol and backtest in its unique index. Without symbol, two symbols running the same strategy on the same exchange and frame would share a single session record. After a restart, one symbol’s session restore would overwrite the other’s, corrupting the resumed state. The when column on Session records the simulation timestamp of the last writeSessionData call, enabling the framework to detect stale session restores when replaying historical data.