Crypto Exchange Trade Engine
The trading core of a crypto exchange: an in-memory matching engine and market-data stack written in C++. It held the live order book for every market, matched incoming orders against it, and published book changes and trades to clients in real time. The two requirements that shaped every decision were predictable tail latency under load, and a book that could always be rebuilt exactly from its own history.
- Language
- C++
- Matching
- Limit order book, price-time priority
- Order types
- Limit, market, immediate-or-cancel, fill-or-kill
- Concurrency
- Single-threaded matching behind one sequencer
- Durability
- Journaled event stream, replayed on start
- Market data
- WebSocket snapshot, incremental diffs and trade tape, sequence-numbered
- Risk
- Pre-trade balance and limit checks, price bands, self-trade prevention
A deterministic core
The engine is event-sourced. A single sequencer assigns every input its place in one ordered stream and journals it, and the matching engine is a pure function of that stream. The same inputs always produce the same book. That property carried most of the operational weight: production sessions could be replayed in tests to reproduce a bug exactly, and recovery after a restart was replaying the journal to rebuild the in-memory state before accepting new orders.
Order book
Each market has a limit order book with strict price-time priority, and each price level holds a FIFO queue of resting orders. Order types decide what happens to an unfilled remainder: a limit order rests on the book, market and immediate-or-cancel orders cancel it, and fill-or-kill orders are rejected unless they fill completely. Price levels are stored in flat, cache-friendly arrays rather than pointer-linked trees, so matching cost stays flat as the book gets deeper.
Latency
Matching runs on one thread with nothing else on it. The hot path does no heap allocation and takes no locks: orders come from a preallocated pool and are reused, and networking and journaling run on their own threads, exchanging work with the matching thread over bounded queues. Keeping one thread in charge of the book removes contention entirely, and the bounded queues turn overload into back-pressure instead of unbounded latency. The target was tight, predictable tail latency, not a good average.
Market data
Clients subscribe over WebSocket and receive a full snapshot of the book, then incremental diffs and a trade tape. Every message carries a sequence number. A client that sees a gap drops its local book and re-syncs from a fresh snapshot, so a lost message or a reconnect can never leave it trading on a stale book.
Risk and audit
Every order passes pre-trade checks before it reaches the book: available balance and limit validation, a price band that rejects orders too far from the market, and self-trade prevention so an account never matches against its own resting order. Because every event is sequenced and journaled, reconciliation and audit read the same log the engine replays, so there is one source of truth for what happened and in what order.