Building a Multi-Broker Order Management System
Anurag Singh Kushwah·Mar 05, 2024·13 min read
The order management system is where software failures become financial losses. It sits between every strategy and every broker, and it has to stay correct while brokers time out, reject orders for undocumented reasons, and occasionally report the same fill twice. This is what four years of running one in production taught me.
One state machine, strictly enforced
Every order lives in an explicit state machine: NEW → VALIDATED → ROUTED → ACKED → PARTIAL → FILLED, with rejection and cancellation branches at each stage. Transitions are validated — an out-of-order broker callback gets logged and quarantined instead of corrupting state. Most OMS bugs I've seen come from representing order state as a string column someone mutates freely.
Risk checks live in the OMS, not the strategy
Strategies are creative; the OMS is paranoid. Before routing, every order passes a synchronous gate: position limits, notional caps, price-band sanity, rate limits, duplicate detection, and a global kill switch. Strategies cannot bypass it because there is no other path to a broker. When a strategy misbehaves — and one eventually will — this gate is the difference between an alert and a very bad day.
Broker adapters: the ugly, essential layer
Each broker gets an adapter that translates the internal order schema to its API and normalizes its callbacks. The hard-won rules:
- Treat broker order state as authoritative — reconcile against it, never assume.
- Make every operation idempotent; duplicate callbacks are a certainty, not an edge case.
- Timeouts are not failures — an unacked order may still be live. Query before retrying, or you'll double-fill.
- Rate-limit per broker in the adapter, so one venue's throttling never blocks another.
Reconciliation is the safety net
A background loop continuously compares internal state against broker-reported orders and positions. Any divergence freezes the affected strategy and pages me. It runs at startup too — recovering from a crash means rebuilding truth from the brokers, not trusting a possibly stale local database.
Throughput comes last
People ask about latency first, but correctness, observability, and recovery dominate the real work. My OMS comfortably handles retail-scale flow on a single node with async I/O. Only after the state machine, risk gate, and reconciliation were boring did optimizing the hot path make sense.