All persistent data in this project is stored as JSON objects in a single MinIO bucket namedDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/theonetrade/backtest-kit-minio-s3-docker/llms.txt
Use this file to discover all available pages before exploring further.
backtest-kit. There are no tables, no schemas, and no migrations — each entity type occupies a logical folder under that bucket, and every record is a self-contained JSON file addressed by a deterministic key. MinioService lazily creates the bucket the first time an adapter touches it, so there is no manual setup step.
Bucket Layout
The physical layout inside thebacktest-kit bucket mirrors the adapter table:
BaseStorage: Constructor and Prefix Parsing
BaseStorage is a factory-generated class that maps a human-readable name like "backtest-kit/candle-items" to a physical bucket name and a transparent key prefix:
BaseStorage.ts
BaseStorage prepend rootPrefix to every key before calling the MinIO client, so callers always work with short entity-relative keys:
BaseStorage Public API
Every data service inherits the following methods fromBaseStorage. All network I/O goes through the MinIO Node.js SDK (minio package).
set(key, value): Promise<void>
Serialises value to UTF-8 JSON and writes it as a single MinIO object. The Content-Type header is set to application/json.
BaseStorage.ts
get<T>(key): Promise<T | null>
Downloads and JSON-parses the object at key. Returns null for NoSuchKey / NotFound errors; re-throws all other errors. Stream chunks are collected via createAwaiter from functools-kit — the method awaits the stream’s end event before parsing.
BaseStorage.ts
has(key): Promise<boolean>
Issues a statObject (HEAD) call — downloads no body. Returns false for not-found errors.
BaseStorage.ts
delete(key): Promise<void>
Physically removes the object from MinIO. Used by soft-delete entities (Measure, Interval, Memory) to keep listKeys clean.
BaseStorage.ts
clear(prefix?): Promise<void>
Deletes all objects whose keys start with prefix (default: all objects under rootPrefix). Batches deletions in groups of 1 000 so memory stays O(batch), not O(bucket).
BaseStorage.ts
keys(prefix?, limit?): AsyncIterableIterator<string>
Streams object names from MinIO’s listObjectsV2 (recursive), stripping the rootPrefix so callers receive entity-relative keys. Stops early when limit is reached.
BaseStorage.ts
values(prefix?, limit?): AsyncIterableIterator<unknown>
Yields the parsed JSON body of each object returned by keys. Skips objects whose body is null (deleted between list and get).
iterate(prefix?, limit?): AsyncIterableIterator<readonly [string, unknown]>
Yields [key, value] tuples — useful for bulk migration or inspection.
toArray(prefix?): Promise<[string, unknown][]>
Eagerly materialises iterate into an array. Use with a scoped prefix to avoid pulling an entire bucket into memory.
size(prefix?): Promise<number>
Counts objects by walking keys — no body downloads.
MinioService: Lazy Bucket Creation
MinioService.getClient(bucketName) is a memoised async function: the first call for a given bucket name checks whether it exists and creates it if not; subsequent calls return the same client immediately without any network round trip.
MinioService.ts
backtest-kit is created automatically. Subsequent process restarts skip the makeBucket call entirely because the bucket already exists — the bucketExists check handles the idempotency.
Candle Object Key Format
CandleDataService (which extends BaseStorage("backtest-kit/candle-items")) constructs its object keys from four fields:
CandleDataService.ts
(symbol, interval, timestamp) triple you always get the same key, with no UUID generation or sequence counters.
Candle Insert-Only Semantics
Candles are immutable market data.CandleDataService.create never overwrites an existing object — it uses has() (a zero-body statObject) to check existence before calling set():
CandleDataService.ts
- No re-downloads — a warm candle cache costs only 1 HEAD per candle, not 1 GET.
- No overwrites — if two strategy instances race to write the same candle, both produce identical data, so whichever PUT lands first is the canonical copy.
The MinIO web console is available at port 9001 (configured in
docker/minio/docker-compose.yaml). You can browse buckets, inspect object metadata, and manually purge entries from the console UI during development. The S3 API itself is served on port 9000.