Skip to main content

Documentation Index

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

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

Storage, Notification, and Log are the three audit-trail adapters. Rather than storing a single value per unique context key, each of these adapters manages a growing list of records — closed signal entries, event notifications, and strategy log lines — and exposes bulk read and write methods. Unlike the signal-lifecycle adapters, none of these three carries a when column; they are not subject to look-ahead-bias filtering.

Storage Adapter

The Storage adapter is the signal journal. It records every signal that has been closed or opened, segregated by execution mode (backtest: true vs. live/paper). Its read* method returns all records for the current mode; its write* method upserts each item in the array individually using an atomic INSERT … ON CONFLICT … DO UPDATE RETURNING *.

Context Key and Table

FieldTypeRole
backtestbooleanExecution mode flag — true in backtest, false in live/paper
signalIdstringUnique signal identifier — one row per signal
Table: storage-items — unique index storage_items_uq on (backtest, signalId)

Registration

PersistStorageAdapter.usePersistStorageAdapter(class implements IPersistStorageInstance {
  constructor(readonly backtest: boolean) {}

  async waitForInit(initial: boolean) {
    if (!initial) return;
    await waitForInfra();
  }

  async readStorageData(): Promise<StorageData> {
    const rows = await ioc.storageDbService.listByMode(this.backtest);
    return rows.map((row) => row.payload);
  }

  async writeStorageData(signals: StorageData): Promise<void> {
    for (const signal of signals) {
      await ioc.storageDbService.upsert(this.backtest, signal.id, signal);
    }
  }
});

Table Schema

const StorageModel = new EntitySchema<IStorageRow>({
  name: "storage-items",
  columns: {
    id:        { type: "uuid", primary: true, generated: "uuid" },
    backtest:  { type: "boolean" },
    signalId:  { type: String },
    payload:   { type: "jsonb" },
    createDate: { type: "timestamptz", createDate: true },
    updatedDate: { type: "timestamptz", updateDate: true },
  },
  indices: [
    { name: "storage_items_uq", columns: ["backtest", "signalId"], unique: true },
  ],
});

Column Reference

id
uuid
required
Auto-generated UUID primary key.
backtest
boolean
required
Execution mode flag. Rows from a backtest run are isolated from live/paper rows. Part of the unique index.
signalId
string
required
The signal’s own identifier, taken from signal.id in writeStorageData. Part of the unique index.
payload
IStorageSignalRow (jsonb)
required
Full signal entry. IStorageSignalRow is the type exported by backtest-kit containing all closed-signal fields.
createDate
timestamptz
required
Set by TypeORM on first insert.
updatedDate
timestamptz
required
Updated by TypeORM on every write.

Methods

Calls storageDbService.listByMode(backtest) which issues a SELECT … WHERE backtest = $1 query. Returns the mapped payload array in insertion order.
Iterates the array and calls storageDbService.upsert(backtest, signal.id, signal) for each item. Each call is a single atomic INSERT … ON CONFLICT (backtest, signalId) DO UPDATE SET payload = EXCLUDED.payload RETURNING *. If a signal already exists (e.g., on a restart), its payload is updated in place.

Notification Adapter

The Notification adapter stores event notifications fired during strategy execution. It shares the same mode-segregation pattern as Storage (backtest: boolean), but the second key field is notificationId rather than signalId. The read path reverses the DB result to restore original write order (oldest entry at index 0).

Context Key and Table

FieldTypeRole
backtestbooleanExecution mode flag
notificationIdstringUnique notification identifier
Table: notification-items — unique index notification_items_uq on (backtest, notificationId)

Registration

PersistNotificationAdapter.usePersistNotificationAdapter(class implements IPersistNotificationInstance {
  constructor(readonly backtest: boolean) {}

  async waitForInit(initial: boolean) {
    if (!initial) return;
    await waitForInfra();
  }

  async readNotificationData(): Promise<NotificationData> {
    const rows = await ioc.notificationDbService.listByMode(this.backtest);
    return rows.map((row) => row.payload).reverse();
  }

  async writeNotificationData(notifications: NotificationData): Promise<void> {
    for (const notification of notifications) {
      await ioc.notificationDbService.upsert(this.backtest, notification.id, notification);
    }
  }
});

Table Schema

const NotificationModel = new EntitySchema<INotificationRow>({
  name: "notification-items",
  columns: {
    id:             { type: "uuid", primary: true, generated: "uuid" },
    backtest:       { type: "boolean" },
    notificationId: { type: String },
    payload:        { type: "jsonb" },
    createDate:     { type: "timestamptz", createDate: true },
    updatedDate:    { type: "timestamptz", updateDate: true },
  },
  indices: [
    { name: "notification_items_uq", columns: ["backtest", "notificationId"], unique: true },
  ],
});
readNotificationData() calls .reverse() on the mapped payload array. NotificationDbService.listByMode returns rows in createDate DESC order (newest first); .reverse() converts that to ascending insertion order so index 0 holds the oldest entry, matching the write-order expected by backtest-kit.

Column Reference

backtest
boolean
required
Execution mode flag. Part of the unique index.
notificationId
string
required
The notification’s own identifier, taken from notification.id in writeNotificationData. Part of the unique index.
payload
NotificationModel (jsonb)
required
Full notification object. The type is NotificationModel imported from backtest-kit (re-exported under that name to avoid a name collision with the TypeORM EntitySchema variable).

Log Adapter

The Log adapter records strategy log entries — structured output lines produced by strategy code via backtest-kit’s logging API. Unlike Storage and Notification, the Log adapter has no backtest mode flag; all entries share a single table partitioned only by entryId. The read path also reverses the list.

Context Key and Table

FieldTypeRole
entryIdstringUnique log entry identifier
Table: log-items — unique index log_items_uq on (entryId)

Registration

PersistLogAdapter.usePersistLogAdapter(class implements IPersistLogInstance {
  // No constructor arguments — no context key beyond entryId

  async waitForInit(initial: boolean) {
    if (!initial) return;
    await waitForInfra();
  }

  async readLogData(): Promise<LogData> {
    const rows = await ioc.logDbService.listAll();
    return rows.map((row) => row.payload).reverse();
  }

  async writeLogData(entries: LogData): Promise<void> {
    for (const entry of entries) {
      await ioc.logDbService.upsert(entry.id, entry);
    }
  }
});

Table Schema

const LogModel = new EntitySchema<ILogRow>({
  name: "log-items",
  columns: {
    id:         { type: "uuid", primary: true, generated: "uuid" },
    entryId:    { type: String },
    payload:    { type: "jsonb" },
    createDate: { type: "timestamptz", createDate: true },
    updatedDate: { type: "timestamptz", updateDate: true },
  },
  indices: [
    { name: "log_items_uq", columns: ["entryId"], unique: true },
  ],
});

Column Reference

entryId
string
required
The log entry’s own identifier, taken from entry.id in writeLogData. Forms the sole unique index.
payload
ILogEntry (jsonb)
required
Full log entry object. ILogEntry is the type exported by backtest-kit.
createDate
timestamptz
required
Set by TypeORM on first insert.
updatedDate
timestamptz
required
Updated by TypeORM on every write.

Methods

Calls logDbService.listAll(), which queries all log entries ordered by createDate DESC (newest first). .reverse() then converts the result to ascending insertion order — oldest entry at index 0 — matching the write-order expected by backtest-kit.
Iterates the array and calls logDbService.upsert(entry.id, entry) for each entry. Each call is an atomic INSERT … ON CONFLICT (entryId) DO UPDATE SET payload = EXCLUDED.payload RETURNING *. Existing entries are updated in place; new entries are inserted.

Comparison: Storage vs. Notification vs. Log

  • Context constructor field: backtest: boolean
  • Per-item key column: signalId
  • Table: storage-items
  • Payload type: IStorageSignalRow
  • Read ordering: insertion order (not reversed)
  • Mode-isolated: yes (WHERE backtest = $1)
The Log adapter has no constructor arguments, meaning backtest-kit creates a single shared instance for the entire process. All strategy log entries land in the same log-items table regardless of symbol, strategy name, or exchange.

Build docs developers (and LLMs) love