This runbook documents the operational procedures for running the live execution
stack backed by execution.live_loop.LiveExecutionLoop. It is intended for
operators who are responsible for starting, monitoring, and shutting down live
trading sessions.
- Infrastructure readiness – confirm that market data feeds, network routes, and authentication secrets are available for every configured exchange connector.
- Risk controls – verify that the
RiskManagerlimits reflect the latest risk committee directives and that the kill-switch has been reset after the previous trading session (useGET /admin/kill-switchfollowed byDELETE /admin/kill-switchif required). - State directory – ensure the state directory configured in
LiveLoopConfig.state_diris writable and backed up. Historical OMS state files are required for warm restarts and forensic analysis. - Metrics and logging – confirm that the Prometheus collector and log aggregation pipelines are running to capture structured events emitted by the live loop.
Cold starts are used when deploying a new strategy instance or when the prior state is intentionally discarded.
- Initialise the loop
from execution.live_loop import LiveExecutionLoop, LiveLoopConfig from execution.risk import RiskLimits, RiskManager config = LiveLoopConfig(state_dir="/var/lib/geosync/live") risk = RiskManager(RiskLimits(...)) loop = LiveExecutionLoop({"binance": binance_connector}, risk, config=config) loop.start(cold_start=True)
- Hydrate OMS from disk – the cold start path reloads persisted OMS state and clears transient in-memory queues. Any outstanding open orders will be re-registered for fill tracking.
- Submit orders – use
loop.submit_order(venue, order, correlation_id)to enqueue new orders. The background submission thread handles placement and retries. - Monitor metrics – dashboards should display the
live_loop.*structured logs, order placement metrics, and per-venue heartbeat gauges.
Warm starts resume trading after a controlled shutdown or short outage.
- Instantiate with persisted state – reuse the existing state directory
and connectors when constructing
LiveExecutionLoop. - Start in warm mode – call
loop.start(cold_start=False). The live loop will:- Load persisted OMS state including queued and outstanding orders.
- Fetch
open_orders()from each connector to reconcile venue state. - Re-enqueue orders that were persisted but missing on the venue.
- Adopt orphaned venue orders into the OMS to maintain risk accounting.
- Validate reconciliation – check logs for
live_loop.requeue_orderandlive_loop.adopt_orderevents to confirm that discrepancies were addressed. - Resume trading – orders can be submitted immediately after the warm start completes.
- Structured logs – the loop emits JSON-friendly logs such as
live_loop.order_processed,live_loop.register_fill, andlive_loop.heartbeat_retry. Forward these to the incident dashboard. - Metrics – Prometheus counters and gauges are updated via
core.utils.metricsfor order placements, acknowledgements, fills, and positions. Ensure dashboards alert on stalled submissions or missing heartbeats. - Lifecycle hooks – subscribe to
on_kill_switch,on_reconnect, andon_position_snapshotto integrate with alerting or downstream systems.
- Use
GET /healthbefore enabling traffic to the inference API or live loop. A200response with"status": "ready"indicates that the risk manager, cache, rate limiters, and declared dependencies are within SLO. Any503response requires intervention before proceeding. - The
risk_managercomponent reports the kill-switch state. Whenstatus="failed"orhealthy=false, the kill-switch is engaged and the detailed reason is surfaced in thedetailfield. Reset the kill-switch via the admin API before resuming trading. - Dependency probes are emitted as
dependency:<name>components. Failures are reported withstatus="failed"and a descriptive message (for example,connection refused). Investigate upstream services (Kafka, Postgres, market data feeds) before retrying. client_rate_limiterandadmin_rate_limitercomponents expose utilisation metrics and saturated keys. Repeated saturation should trigger incident handling to avoid throttling critical traffic.- The
inference_cachecomponent reports occupancy of the TTL cache. Adegradedstatus indicates the cache is full and requests will skip the fast path until entries expire; purge or expand the cache capacity if this state persists.
- Connector disconnects – heartbeat failures trigger exponential backoff
retries and emit
on_reconnectevents. Investigate repeated retries and be prepared to fail over if the venue remains unreachable. - Order discrepancies – warm start reconciliation produces warnings when orders are re-queued or adopted. Operators should confirm that downstream systems (P&L, hedging) reflect the corrected state.
- Kill-switch activation – when the risk kill-switch triggers, the live loop
stops all background tasks, emits
on_kill_switch, and requires manual intervention before restarting. Investigate the root cause, consult the kill-switch failover runbook if the PostgreSQL state store is impaired, confirm the current status withGET /admin/kill-switch, and only resume onceDELETE /admin/kill-switchrecords a successful reset event.
- Call
loop.shutdown()to stop background workers and disconnect connectors. - Confirm that no orders remain queued and that OMS state files were persisted.
- Archive logs and metrics for the session as part of the post-trade review.
The live execution loop now implements production-hardening features to ensure resilient order lifecycle management:
- Idempotent submissions – every order submission carries an idempotency key
(derived from
correlation_idor a deterministic hash). Retries are deduplicated so only one placement reaches the venue. - Order ledger – append-only JSONL at
<state_dir>/order_ledger.jsonlrecordssubmit/ack/fill/cancel/rejectevents with monotonically increasing offsets and timestamps. - OMS snapshots – periodic snapshots at
<state_dir>/oms_snapshots/*.jsonincludeledger_offset, OMS state, risk limits, and a checksum for integrity verification. - Recovery – on warm start, the loop restores the last snapshot, replays the ledger from the last offset, reconnects with jittered backoff, and adopts any venue-open orders not present in the OMS.
Order submissions automatically generate idempotency keys:
- If a
correlation_idis provided, the key iscorr:{correlation_id}. - Otherwise, a deterministic hash is computed from order attributes (symbol, side, quantity, price) bucketed by minute.
Duplicate submissions with the same idempotency key within the same venue will be deduplicated at the connector level, ensuring no duplicate orders reach the exchange.
The order ledger (order_ledger.jsonl) is an append-only journal capturing every
order lifecycle event:
{
"sequence": 42,
"event": "submit",
"timestamp": "2025-11-03T13:45:00Z",
"order_id": "abc123",
"correlation_id": "corr:my-order",
"metadata": {...},
"digest": "sha256:..."
}- Sequence numbers are monotonically increasing and used to replay events after a snapshot.
- Digests form a hash chain for integrity verification during replay.
OMS snapshots are persisted periodically (default: every 30 seconds, configurable
via LiveLoopConfig.snapshot_interval) using atomic temp-write-then-rename to
avoid partial files:
{
"mode": "live",
"ts": 1730642700.123,
"ledger_offset": 42,
"oms": {
"ledger_offset": 42,
"venues": {
"binance": {
"order-123": {
"status": "ack",
"last_update": 1730642695.0,
"order": {...}
}
}
},
"checksum": "sha256:..."
},
"checksum": "sha256:..."
}- Snapshots are stored at
<state_dir>/oms_snapshots/oms_snapshot_{timestamp}.json. - The last 5 snapshots (newest timestamps) are retained deterministically; older snapshots are pruned with debug logs on cleanup failure.
When starting the live loop with cold_start=False, the recovery sequence is:
- Restore last snapshot – load the most recent
oms_snapshot_*.jsonfile and reconstruct the OMS state. - Replay ledger delta – iterate through
order_ledger.jsonlfrom the last snapshot offset to the current ledger tail, applying all events. - Reconnect with backoff – connectors reconnect using exponential backoff
with full jitter (capped by
LiveLoopConfig.max_backoff). - Adopt stray orders – query each venue for open orders via
connector.open_orders()and adopt any orders not present in the OMS. These "stray" orders may have been placed in a previous session or by another process. - Resume normal operation – resubscribe to WebSocket streams, reseed positions, and begin processing new order submissions.
The recovery procedure targets the following operational SLOs:
- Reconciliation time – complete recovery (snapshot restore + ledger replay + stray adoption) within ≤ 2 seconds on standard hardware.
- Zero orphan orders – all venue-open orders are adopted into the OMS or explicitly cancelled by policy (configurable). No orders should be "lost" between sessions.
- 48-hour staging soak – run a staging environment for 48 hours without duplicate submissions or missed fills, validated via idempotency keys and reconciliation logs.
Check ledger health:
# Verify ledger integrity
python -m execution.order_ledger verify <state_dir>/order_ledger.jsonlInspect OMS snapshot:
# View latest snapshot
cat <state_dir>/oms_snapshots/oms_snapshot_*.json | tail -1 | jq .Force snapshot creation:
# From Python REPL or admin script
loop._persist_oms_snapshot_if_needed()Snapshot not restoring:
- Check that
<state_dir>/oms_snapshots/contains valid JSON files. - Verify checksum integrity by comparing computed hash with stored checksum.
- Review logs for
live_loop.snapshot_restore_failedevents.
Stray orders not adopted:
- Confirm
cold_start=Falsewas used on restart. - Check
live_loop.adopt_orderslog events for adoption count. - Verify
connector.open_orders()returns the expected orders.
Duplicate order placements:
- Ensure
correlation_idis provided and consistent across retries. - Check
IdempotentSubmittercache via logs or metrics. - Review ledger for duplicate
submitevents with sameidempotency_key.
Reconnection storms:
- Verify
max_backoffis set appropriately (default 60s). - Check for upstream connectivity issues or API rate limits.
- Review
live_loop.heartbeat_retryevents for backoff delays.
- Execution engineering on-call – primary contact for connector incidents.
- Risk management – escalation path for kill-switch or limit breaches.
- Operations – responsible for scheduling and communication during planned maintenance windows.
Keep this runbook up to date alongside changes to execution/live_loop.py and
related operational tooling.