Strategy authoring¶
ONIX's Strategy Studio is the product surface for authoring a real Nautilus v2 Python
Strategy/StrategyConfig project, saving it as an immutable revision, validating it against the
installed Nautilus pin, and running it through the official BacktestNode. A sealed revision can
also be submitted to POST /v2/sandbox/start, but at this pin that route answers a typed
UNAVAILABLE/501 refusal on the core spine and Binance node — the sandbox-lifecycle admission path
exists and is wired to this same revision store, but the underlying runtime it would start is
deferred this release; see execution-runtime.md for the full account.
Strategy source is Python — the only language this surface has ever authored strategies in at this
pin.
Draft, then immutable revision¶
A strategy project has a mutable draft (a working tree of files) and zero or more immutable
revisions. A revision's id is its content hash: saving identical content twice is
idempotently the same revision, and a published revision's files are never rewritten. Draft file
writes use an atomic conditional-write precondition (MATCH_HASH on the previous content hash, or
ABSENT to create a new path) — there is no unconditional public write form, so two concurrent
editors cannot silently clobber each other's changes.
Revision identity is demand-bearing¶
A revision's identity covers not just its file bytes but its data demand — which instruments,
channels and resolutions it will subscribe to when run. This is deliberate: the same files under a
different data demand are a different revision, not the same one with different behavior hidden
inside it. A revision's demand_seal state is either SEALED (demand is part of the identity,
verified) or DEMAND_UNSEALED (a frozen, pre-demand encoding, kept forever for older revisions and
never migrated). DEMAND_UNSEALED revisions remain fully readable and can still be validated for
integrity — they simply cannot execute, because nothing records what they would subscribe to.
The admission door¶
Every path that turns a saved revision into a running child process — a backtest submission, an
optimization study trial, a promotion rerun, a holdout evaluation — passes through one function,
the studio's admission gate, which independently re-derives (never trusts a caller-supplied flag,
and never trusts the admission block a document carries about itself):
Sandbox start is designed to be a fifth caller of this same gate, but is not one at this pin.
SpineService.sandbox_start currently raises a typed deferred refusal (see
execution-runtime.md) before any spec is read, so a sandbox-start request
never reaches the admission gate below on the nodes that defer it — it is refused unconditionally,
regardless of whether the submitted revision would otherwise have passed every check. The
shared-helper design (_resolve_revision_files, documented in source as "the one door every
execution path goes through") describes the intended shape once sandbox execution is undeferred,
not the current runtime behavior of the route.
- the requested ids against what the loaded document actually claims;
- the exact file set on disk and every file's content hash, re-read fresh;
- the recorded Nautilus engine pin against what is actually installed;
- the full revision content identity, under the correct seal-state domain;
- the canonical data-demand encoding, re-canonicalized and re-digested;
- that the demand digest is the one bound into the revision's own
content_hash; - that the seal state is
SEALEDand the resulting admission verdict ispromotable.
A revision that fails any of these is refused by a stable, named code (DEMAND_UNSEALED,
DEMAND_DIGEST_MISMATCH, IDENTITY_MISMATCH, ENGINE_PIN_MISMATCH, and others) — never
best-effort executed. A prior wire form that let a caller submit an arbitrary importable
module:ClassName triple directly, bypassing the saved-revision requirement entirely, has been
removed: only an immutable {strategy_id, revision_id} pair now resolves into executable
strategy code.
Validation runs outside the market-spine process¶
POST /v2/strategies/{id}/validate runs in a dedicated child-process boundary against the
installed Nautilus pin. Editor-authored code is never imported into the market-spine process.
Validation is a diagnostics-only surface: it starts no job, subscribes to no data, and places no
order — it exists so an author can decide whether to seal a revision before anything executes.
Templates¶
Twenty scaffolded strategy templates are present in source at this pin, spanning trend, mean
reversion, breakout, market-making, multi-timeframe confirmation, and execution-shape patterns
(e.g. ema_crossover_trend, rsi_mean_reversion, donchian_atr_breakout,
bollinger_volatility_regime, mtf_trend_confirmation, htf_aligned_wick_reversal,
liquidity_sweep_reclaim, l2_imbalance_maker, pairs_spread, spot_perp_basis,
dca_recovery_bounded, range_grid_mean_reversion, signal_bracket, multi_target_breakout,
trailing_entry_exit, bracket_trailing_exec, wick_rejection_single_candle,
trade_tick_momentum, ta_scanner_momentum, minimal_market_order). A template that declares no
data demand cannot seal a revision — sealing with an empty demand would falsely assert the
revision subscribes to nothing, so it is refused by name rather than silently accepted.
A separate offline authoring path¶
Alongside the gateway/REST surface, a local workbench command-line tool exists for scaffolding a
strategy project, validating it, running an offline backtest, and proving byte-for-byte
determinism across a fresh process rerun of the same revision. It is a local, single-user
alternative front end to the same admission and validation machinery, not a second implementation
of it.
What is not part of this backend¶
Generated or LLM-authored strategy execution — code an author did not write and check in through
the flow above — is explicitly out of scope by design decision (ADR 0003), and this repository
never shipped a partial substitute for it: the decision record is explicit that "a partial sandbox
is worse than none," so no sandboxed execution runtime for arbitrary generated code was built here.
No TypeScript-based strategy compilation, execution, or isolation runtime exists anywhere in this
backend at the pin — Python, through the sealed-revision path described above, is and has been the
only strategy-authoring surface this repository implements. unverified: this documentation found
no backend-repository evidence, in either direction, of a TypeScript strategy runtime having
existed and later been retired elsewhere in the ONIX product (for example in a separate frontend
history); it can state with confidence only that no such runtime is present in, or reachable from,
this backend at this pin, and that the backend's own architecture decisions treat that capability
as deliberately unbuilt rather than removed.
Evidence and source pins for this page
Verified. Current behaviour, confirmed in source at the pinned commit.
Verified on against the following immutable sources:
backend@efa38e04:docs/contracts/strategy-studio-v2.mdbackend@efa38e04:docs/decisions/0003-python-strategy-boundary.md
Status tokens are defined on the documentation and status model page. Every pin on this site is listed under versions and source pins.