Skip to main content
A StrategySpec is a declarative, JSON-serializable description of a trading strategy. Agents author specs; the Ithaca backtest engine executes them. No agent-authored code is ever run — the spec is matched against a frozen, closed schema and dispatched to trusted numpy kernels.

Design principles

The schema is closed: additionalProperties: false on every object. Unknown fields are rejected at validation time, not silently dropped. This prevents agents from smuggling arbitrary keys into the engine.
  • Declarative, not imperative. The agent describes what to trade, not how to compute it.
  • Closed schema. Every field is enumerated. No extension points, no freeform blobs.
  • Server-stamped identity. id, version, and tenant_id are assigned by the server. If an agent supplies them, they are ignored.
  • Deterministic. A seed field makes every backtest reproducible to the bit.

Top-level fields

Server-stamped fields (ignored if supplied)

These fields are never accepted from the agent. The server assigns them on persist:
If an agent sends "id": "..." or "tenant_id": "...", the server silently discards them. This prevents an agent from impersonating another tenant or overwriting an existing strategy.

universe

strategy

Strategy id reference

Rolling-window momentum. params: lookback (days, int), skip (days, int, default 0).
Moving-average crossover. params: fast (days), slow (days).
Z-score reversion to rolling mean. params: lookback (days), entry_z (float), exit_z (float).
Cross-sectional return ranking. params: lookback (days), top_n (int).

construction

risk

execution

resources

Validation flow

1

Parse

The request body is parsed as JSON. Malformed JSON is rejected with 400.
2

Schema validate

The JSON is validated against the frozen StrategySpec schema. Unknown fields, type mismatches, and missing required fields return 422 with a field-level error list.
3

Strip server fields

id, version, and tenant_id are removed from the payload if present.
4

Semantic validate

Cross-field rules are checked (e.g. fast < slow for ma_cross, max_name_pct <= max_gross).
5

Stamp + persist

The server assigns id, version, tenant_id and writes the immutable spec row.

Complete example

The seed field is what makes a backtest reproducible. The same spec + the same price panel + the same seed always produces the same result hash. Change the seed and you get a different Monte Carlo path (where applicable).