Every backtest run produces a bundle of 8 artifacts. Together they form a complete, reproducible record of the run: what was computed, what the result was, what data and environment were used, and how to view it. Each file is content-hashed with SHA-256 for tamper detection and reproducibility verification.
The 8-file bundle
| # | File | Format | Purpose |
|---|
| 1 | summary.json | JSON | One-line overview: run id, spec ref, result hash, status. |
| 2 | metrics.json | JSON | Full stats block (sharpe, sortino, cagr, vol, maxDD, …). |
| 3 | equity_curve.json | JSON | Daily equity values + dates. |
| 4 | positions.json | JSON | Per-bar per-name weights and exposures. |
| 5 | data_manifest.json | JSON | Price panel provenance: source, symbols, date range, panel hash. |
| 6 | environment_lock.json | JSON | Pinned deps: numpy version, kernel version, seed. |
| 7 | run_trace.json | JSON | The full trace event stream for the run. |
| 8 | report.html | HTML | Human-readable rendered report (charts + tables). |
summary.json
{
"run_id": "run_abc123",
"spec_id": "spec_xyz",
"spec_version": 3,
"status": "succeeded",
"result_hash": "sha256:9f2c...",
"created_at": "2025-01-15T12:00:00Z"
}
metrics.json
The full stats block from the backtest kernel. See Backtest system for the field reference.
equity_curve.json
{
"dates": ["2024-01-02", "2024-01-03"],
"equity": [1.0, 1.0023]
}
positions.json
Per-bar weights keyed by date, then by symbol. Used by the web UI to render position charts.
data_manifest.json
{
"source": "polygon",
"symbols": ["NVDA", "AMD", "INTC"],
"start": "2023-01-03",
"end": "2024-12-31",
"panel_hash": "sha256:1a2b..."
}
environment_lock.json
{
"numpy_version": "1.26.4",
"kernel_version": "doomberg-backtest==0.4.2",
"seed": 42,
"python_version": "3.11.7"
}
run_trace.json
The complete ordered list of TraceEvent records for the run. See Trace events.
report.html
A self-contained HTML file with embedded charts (equity curve, drawdown, positions) and the metrics table. Openable in any browser; no external dependencies.
Content hashing
Every artifact file is hashed with SHA-256 over its exact byte content. The hashes are recorded in summary.json (and in the run record). This gives you two guarantees:
- Tamper detection. If a file is modified after the run, its hash no longer matches.
- Reproducibility verification. Re-run the same spec; if the new
result_hash matches the old one, the run is bit-identical.
The result_hash in summary.json is a hash over the metrics.json + equity_curve.json + positions.json hashes. It’s the single fingerprint of the run’s numeric output.
Storage backends
Ithaca supports two artifact storage backends, selected by environment:
| Backend | When used | Location |
|---|
memory:// | Development / local | In-process dict; lost on restart. |
file:// | Production | DOOMBERG_ARTIFACT_DIR on disk. |
Set DOOMBERG_ARTIFACT_DIR in production to a persistent, backed-up volume. Artifacts are written as individual files under <dir>/<run_id>/<filename>.
The backend is chosen at startup; runs do not pick their own backend.
REST API
| Method | Path | Description |
|---|
GET | /api/artifacts | List artifact bundles for the tenant (optional ?run_id=). |
GET | /api/artifacts/{id} | Fetch a single artifact bundle (all 8 files). |
Example: list artifacts
GET /api/artifacts?run_id=run_abc123
Authorization: Bearer dmbg_prod_...
{
"artifacts": [
{ "run_id": "run_abc123", "files": ["summary.json", "metrics.json", "..."], "result_hash": "sha256:9f2c..." }
]
}
Example: fetch a bundle
GET /api/artifacts/run_abc123
Authorization: Bearer dmbg_prod_...
Returns a JSON object with each file’s content and hash. The report.html is returned as a string; the rest are parsed JSON.