Skip to main content

Documentation Index

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

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

Measure, Interval, and Memory are the three adapters that support soft-delete semantics. Instead of physically removing documents, their remove*Data methods set a removed: true flag on the document. All subsequent reads for that key return null, and list operations skip soft-deleted entries entirely. This pattern ensures that deleted data is recoverable for debugging and that concurrent readers never observe a partially-deleted state. Each of these adapters is also bucket-based: a bucket or bucketName constructor argument namespaces all keys within the adapter instance, allowing the same key to coexist across different strategy contexts.

Soft-Delete Semantics

write(key, data)   → removed: false, payload: data
remove(key)        → removed: true  (document stays in collection)
read(key)          → returns null if removed: true
list()             → skips entries where removed: true
Soft-deleted entries remain in MongoDB and can be recovered by querying the collection directly with { removed: true }. They are never returned through the adapter API.

Measure Adapter

The Measure adapter is designed for caching expensive external lookups such as LLM completions or API responses. Each cache entry is stored under a (bucket, key) pair. Reads return null for soft-deleted entries.

Constructor

class implements IPersistMeasureInstance {
  constructor(readonly bucket: string) {}
}
bucket
string
required
A namespace for this set of measure entries, e.g. "llm-cache" or "price-feed".

readMeasureData

Fetches the measure payload for a key. Returns null if the entry does not exist or has been soft-deleted.
async readMeasureData(key: string): Promise<MeasureData | null> {
  const row = await ioc.measureDbService.findByKey(this.bucket, key);
  if (!row || row.removed) return null;
  return row.payload;
}
key
string
required
The cache key within this bucket.
Returns: MeasureData | null

writeMeasureData

Upserts a measure payload for a key. The _when parameter is accepted for interface compatibility but is not stored.
async writeMeasureData(data: MeasureData, key: string, _when: Date): Promise<void> {
  await ioc.measureDbService.upsert(this.bucket, key, data);
}
data
MeasureData
required
The payload to store.
key
string
required
The cache key within this bucket.
_when
Date
required
Accepted for interface compatibility; not persisted.

removeMeasureData

Soft-deletes a measure entry by setting removed: true.
async removeMeasureData(key: string): Promise<void> {
  await ioc.measureDbService.softRemove(this.bucket, key);
}
key
string
required
The key to soft-delete within this bucket.

listMeasureData

Yields all non-removed keys in this bucket as an AsyncGenerator<string>.
async *listMeasureData(): AsyncGenerator<string> {
  const keys = await ioc.measureDbService.listKeys(this.bucket);
  for (const key of keys) yield key;
}
Returns: AsyncGenerator<string> — yields each active (non-removed) key in the bucket.

Interval Adapter

The Interval adapter stores once-per-interval markers — used to ensure that a strategy action (e.g., sending an alert or making an API call) happens at most once per bar or time window. It stores a when: Date alongside the payload for interval boundary checking.

Constructor

class implements IPersistIntervalInstance {
  constructor(readonly bucket: string) {}
}
bucket
string
required
A namespace for this set of interval entries.

readIntervalData

Fetches the interval payload for a key. Returns null if not found or soft-deleted.
async readIntervalData(key: string): Promise<IntervalData | null> {
  const row = await ioc.intervalDbService.findByKey(this.bucket, key);
  if (!row || row.removed) return null;
  return row.payload;
}
key
string
required
The interval key within this bucket.
Returns: IntervalData | null

writeIntervalData

Upserts an interval payload for a key, storing when alongside the document.
async writeIntervalData(data: IntervalData, key: string, when: Date): Promise<void> {
  await ioc.intervalDbService.upsert(this.bucket, key, data, when);
}
data
IntervalData
required
The payload to store.
key
string
required
The interval key within this bucket.
when
Date
required
The bar time at which this entry was written. Stored for interval boundary checks.

removeIntervalData

Soft-deletes an interval entry.
async removeIntervalData(key: string): Promise<void> {
  await ioc.intervalDbService.softRemove(this.bucket, key);
}
key
string
required
The key to soft-delete within this bucket.

listIntervalData

Yields all non-removed keys in this bucket.
async *listIntervalData(): AsyncGenerator<string> {
  const keys = await ioc.intervalDbService.listKeys(this.bucket);
  for (const key of keys) yield key;
}
Returns: AsyncGenerator<string> — yields each active key in the bucket.

Memory Adapter

The Memory adapter provides per-signal named memory slots, used by LLM-driven or stateful strategies to persist arbitrary data across bars. It has the richest API of the three, adding hasMemoryData for efficient existence checks, a dispose() no-op for lifecycle compatibility, and a list method that yields both keys and payloads.

Constructor

class implements IPersistMemoryInstance {
  constructor(
    readonly signalId: string,
    readonly bucketName: string,
  ) {}
}
signalId
string
required
The unique signal ID that owns this memory bucket.
bucketName
string
required
A namespace within the signal’s memory, e.g. "context" or "history".

readMemoryData

Fetches a memory entry by memoryId. Returns null if not found or soft-deleted.
async readMemoryData(memoryId: string): Promise<MemoryData | null> {
  const row = await ioc.memoryDbService.findByMemoryId(
    this.signalId, this.bucketName, memoryId,
  );
  if (!row || row.removed) return null;
  return row.payload;
}
memoryId
string
required
The identifier for this memory slot within the bucket.
Returns: MemoryData | null

hasMemoryData

Returns true if a non-removed entry exists for memoryId. More efficient than readMemoryData when only existence needs to be checked.
async hasMemoryData(memoryId: string): Promise<boolean> {
  return await ioc.memoryDbService.hasMemoryEntry(
    this.signalId, this.bucketName, memoryId,
  );
}
memoryId
string
required
The identifier for the memory slot to check.
Returns: boolean

writeMemoryData

Upserts a memory payload for a memoryId, storing when alongside the document.
async writeMemoryData(data: MemoryData, memoryId: string, when: Date): Promise<void> {
  await ioc.memoryDbService.upsert(
    this.signalId, this.bucketName, memoryId, data, when,
  );
}
data
MemoryData
required
The payload to store.
memoryId
string
required
The memory slot identifier.
when
Date
required
The bar time at which this entry was written.

removeMemoryData

Soft-deletes a memory entry.
async removeMemoryData(memoryId: string): Promise<void> {
  await ioc.memoryDbService.softRemove(
    this.signalId, this.bucketName, memoryId,
  );
}
memoryId
string
required
The memory slot to soft-delete.

listMemoryData

Yields all non-removed memory entries as { memoryId, data } pairs.
async *listMemoryData(): AsyncGenerator<{ memoryId: string; data: MemoryData }> {
  const rows = await ioc.memoryDbService.listEntries(
    this.signalId, this.bucketName,
  );
  for (const row of rows) yield { memoryId: row.memoryId, data: row.payload };
}
Returns: AsyncGenerator<{ memoryId: string; data: MemoryData }> — yields each active entry with its ID and payload.

dispose

A no-op lifecycle method required by the IPersistMemoryInstance interface.
dispose(): void { void 0; }

Collection Summary

AdapterCollectionContext KeySoft DeleteExtra Methods
Measuremeasure-items(bucket, entryKey)YeslistMeasureData
Intervalinterval-items(bucket, entryKey)YeslistIntervalData
Memorymemory-items(signalId, bucketName, memoryId)YeshasMemoryData, listMemoryData, dispose
Use hasMemoryData instead of readMemoryData followed by a null check when you only need to know whether a memory slot exists. It avoids deserializing the full payload.

Build docs developers (and LLMs) love