Algostream_runtime.InstanceOne live strategy, paper-traded.
No order ever reaches a venue. There is no order placement anywhere in this repository — no credentials, no request signing, no trading endpoint; the only bytes the ingestion layer ever writes to a socket are a subscribe message, a pong and a close. Fills here are simulated against live quotes by the same Backtest.Fill_engine the offline engine uses, and every P&L figure the dashboard shows is therefore hypothetical.
Strategy.S was written so that a backtest and a live runner could drive the same strategy: on_event returns Action.t list rather than submitting, so order-id assignment, the risk gate and routing stay outside it. This module is the live driver that was always intended and never built.
It deliberately reuses Market_view, Fill_engine, Cost_model and Slippage rather than growing a parallel execution path. Beyond avoiding duplicate logic, it is what makes the two drivers comparable: test/runtime/test_parity.ml feeds one strategy the same records through this module and through Backtest.Engine and asserts they agree.
An instance is driven by exactly one Domain — the runtime supervisor's drain loop — and its internal state is ordinary mutable state. Observers on other Domains read snapshot, which is an immutable record published with Atomic.set. Control operations (pause, resume, set_allocation) are safe from any Domain: they set atomics the drain loop reads.
module Data_source = Algostream_backtest.Data_sourcemodule Strategy = Algostream_strategy.Strategymodule Venue = Algostream_order_management.Venuemodule Slippage = Algostream_backtest.Slippagemodule Latency = Algostream_backtest.Latencymodule Cost_model = Algostream_backtest.Cost_modelmodule Fill_engine = Algostream_backtest.Fill_enginemodule Risk_limits = Algostream_risk_management.Risk_limitstype config = {strategy_id : string;unique within a supervisor; used in ids, blotter rows and the API
*)symbols : string list;handed to Strategy.S.create. A strategy derives its Strategy.subscriptions from these, so leaving it empty means the instance subscribes to nothing and never trades.
initial_capital : float;venue : Venue.t;slippage : Slippage.model;latency : Latency.t;cost : Cost_model.config;risk_limits : Risk_limits.t option;maker_fill : Fill_engine.maker_fill_model;stop_trigger : Fill_engine.stop_trigger_ref;bar_interval_ns : int64;cadence for the bar builders that feed Event.Bar and the pairs cointegration retest
pairs_config : Algostream_pairs.Config.t;seed : int64;seeds latency jitter only; market data is whatever actually arrives
*)max_recent_fills : int;}val create :
(module Strategy.S with type params = 'p) ->
params:'p ->
config:config ->
tBuild an instance. The strategy's subscriptions are read once here to set up bar builders and pair state, exactly as Backtest.Engine does.
val id : t -> stringval lifecycle : t -> Snapshot.lifecycleval on_record : t -> Data_source.record -> unitFeed one market record. Runs the full step: market view, matching, strategy dispatch, action handling, marking. A no-op once stopped.
While Paused the market view and fill engine still advance — resting orders continue to fill, which is what a real paused strategy experiences — but the strategy is not consulted and emits no new orders.
val pause : t -> unitval resume : t -> unitval stop : t -> unitRun on_stop, cancel every working order, and publish a final snapshot. Idempotent.
val set_allocation : t -> float -> unitCapital assigned to this instance. Advisory: it is reported and used by position sizing, not enforced by the fill engine.
val snapshot : t -> Snapshot.instanceLatest published state. Safe from any Domain.
NAV samples for charting, oldest first. Bounded ring.