Skip to main content
The backtest tools family contains a single tool — backtest_run — that runs a deterministic backtest over a stored StrategySpec and a date range. The engine is trusted, audited numpy code; the agent never provides executable code. Same inputs always produce identical outputs, down to the content hash.

backtest_run

Run a deterministic backtest over a StrategySpec and date range. Returns a run_id, the equity curve, full statistics, final portfolio weights, and a risk attestation. The run is stored as an 8-file artifact bundle (see Artifact tools).

Arguments

What it does

  1. Validates the spec against the frozen StrategySpec contract (same validation as propose_strategy).
  2. Resolves the universe to concrete symbols and fetches the required OHLCV data through the data layer, recording provenance.
  3. Locks the environment — the numpy version, data hashes, and engine version are captured in environment_lock.json so the run is reproducible.
  4. Runs the backtest engine: signal → weights → risk → execution, rebalanced at the spec’s horizon.
  5. Computes statistics and a risk attestation.
  6. Stores the full result as an 8-file artifact bundle with SHA-256 content hashes.
  7. Returns the run_id and a summary.

Return value

Statistics block

The stats object contains a comprehensive set of performance and risk metrics:
VaR and CVaR are computed from the daily return distribution using historical simulation. They are not parametric assumptions — they reflect what actually happened in the backtest window.

Example call

Example response

Determinism

Determinism is a hard guarantee, not a best-effort property. Two backtests with the same spec, range, engine version, and data hashes must produce identical output. If they don’t, it’s a bug.
Determinism is achieved through three controls:
  1. Fixed random seed. The engine seeds numpy’s RNG with a deterministic value derived from the spec content hash and range. No call to np.random uses OS entropy.
  2. Pinned numpy. The engine runs against a pinned numpy version recorded in environment_lock.json. Floating-point behavior is stable within a numpy major.minor release.
  3. Fixed data window. The OHLCV data is fetched once, hashed, and locked. The data_manifest.json artifact records every symbol, date, and content hash used. Re-running with the same manifest guarantees identical inputs.
The result is that content_hash is a function of (spec, range, engine_version, data_hashes). If all four match, the hash matches. This lets you verify reproducibility across runs, machines, and time.
  • Different data. If the upstream provider restates a bar (e.g. a split adjustment), the data hash changes and the output changes. This is correct behavior — the data_manifest.json makes it visible.
  • Different numpy version. Floating-point summation order can change between numpy versions. The environment_lock.json pins the version so this doesn’t happen silently.
  • Different engine version. A new engine release may change the order of operations. The engine version is part of the hash input, so a version change produces a different hash by design.

The risk attestation

The risk_attestation object records whether the run respected every constraint in the spec’s risk block. It is computed after the backtest, against the realized path — not just the final weights. This catches intra-run breaches (e.g. a position that briefly exceeded max_weight before a rebalance). If any constraint was breached, the corresponding *_breached flag is true and the run is flagged in the web UI. The agent should report breaches to the human before requesting paper-trading promotion.