The order book and price-time priority
The central data structure of the exchange, the two-rule algorithm that runs it, and why the engine is single-threaded on purpose.
In lesson 1.2, an accepted order either executed or rested. The order book is the state that makes both outcomes precise.
It is tempting to parallelize matching across price levels or orders and reconcile the resulting fills after the workers finish. The constraint it misses is simple: For a symbol, the same ordered input must always produce the same owners, quantities, prices, and remaining liquidity: better price wins, then earlier arrival.
A central limit order book (CLOB) is two sorted lists per symbol: bids (buyers, best = highest price) and asks (sellers, best = lowest). Within one price level, orders queue in arrival order.
flowchart LR
subgraph bids["BIDS — buyers, best price on top"]
direction TB
B1["10.01 · 300 shares · 2 orders"]
B2["10.00 · 1,200 shares · 5 orders"]
B3["9.99 · 500 shares · 3 orders"]
B1 --- B2 --- B3
end
MID["spread = 0.02"]
subgraph asks["ASKS — sellers, best price on top"]
direction TB
A1["10.03 · 200 shares · 1 order"]
A2["10.04 · 800 shares · 4 orders"]
A3["10.06 · 400 shares · 2 orders"]
A1 --- A2 --- A3
end
bids ~~~ MID ~~~ asks
Matching is governed by price-time priority, two rules applied in strict order:
- Price first: a better price always trades before a worse one.
- Time second: at the same price, whoever arrived first trades first.
Into the book above arrives: buy 900 ACME, limit 10.04. The engine walks the ask side:
- Best ask is 10.03 (200 shares). 10.03 ≤ 10.04, so it matches: trade 200 @ 10.03. Note: at the seller's resting price — the resting order sets the price; the aggressor pays it.
- Next level 10.04 (800 shares across 4 orders). 10.04 ≤ 10.04, match in time order: trade 700 @ 10.04, filling the oldest orders first; the 4th order at that level fills only partially.
- Buyer's 900 shares are done. Book now shows best ask 10.04 (100 shares remaining), best bid still 10.01. One incoming order produced 5+ trades, 5+ private fill reports, and a burst of public market data.
Now the design consequence. Rule 2 — time priority — means matching is order-sensitive: process two orders in a different sequence and you get different owners of the same fill. So the matching engine for a given set of symbols is a single-threaded event loop: one input at a time, to completion, no locks, no races. This sounds like a bottleneck; it isn't. A tight in-memory loop handles hundreds of thousands to millions of events per second — and buys you determinism, which lesson 1.7 converts into the entire recovery story.
Two sell orders rest at the same price and a buy can fill only one. Concurrent workers can choose different sellers on different runs. No later reconciliation can repair the fairness violation because the scarce fill already has two possible owners.
The book = two price-sorted sides, FIFO queues within each price. Price-time priority: better price wins; ties broken by arrival. Aggressors trade at resting prices; single-threading is a feature, not a compromise.