Home › Blog › Design a Stock Exchange

Design a Stock Exchange: Order Matching System Walkthrough

A step-by-step interview walkthrough of an exchange: the order book, price-time matching, the sequencer, risk checks, market data, and how the whole thing survives a crash.

To design a stock exchange, put a single-threaded, in-memory matching engine behind a sequencer that stamps every inbound order with a sequence number, so every state change comes from one ordered, replayable log. The engine keeps an order book per symbol and fills orders by price-time priority, gateways run risk checks before orders reach it, and a market data publisher multicasts every book change and trade. Durability and failover come from journaling that sequenced input and replaying it on standby replicas.

The rest of this guide walks through it the way you would in a 45-minute round, including the data structure and trade-offs interviewers push on.

Step 1: Pin down the requirements

Scope the problem in the first five minutes, or auctions and clearing will eat the session:

Then state the non-functional requirements:

A quick estimate. Suppose the interviewer gives you 1 billion orders a day. Over NYSE’s core session of 9:30 a.m. to 4:00 p.m. ET (23,400 seconds), that is roughly 43,000 orders per second on average, with peaks around the open and close. Raw throughput is not the hard part: Martin Fowler’s write-up of the LMAX trading platform describes one business-logic thread handling about 6 million orders per second on commodity hardware. Latency, fairness and correctness are.

Step 2: Draw the high-level architecture

Keep the latency-critical path short and push everything else onto the output stream:

Brokers / trading firms  (FIX or binary order entry)
        |
  [Order gateways]   auth, validation, throttling, stateless risk checks
        |
  [Sequencer]        assigns sequence numbers, journals, replicates
        |
  [Matching engine]  order books in memory, one thread per partition
        |
  [Sequenced output stream]
     |                 |                 |
 [Execution reports] [Market data]    [Post-trade: reporting,
  back via gateways   (UDP multicast)  clearing feed, audit]
ComponentJobCritical path?
Order gatewayBroker sessions, authentication, parsing, per-session throttles, stateless checksYes
Risk checksBuying power, position and size limits, price collars, kill switchYes
SequencerOne global sequence number per inbound message; journal and replicateYes
Matching engineOwns the books; emits acknowledgments, fills and cancelsYes
Market data publisherPublic feeds: top of book, depth, tradesYes, for fairness
Post-tradeDrop copies, trade reporting, clearing feed, audit trailNo

Brokers typically connect over FIX, a tag=value messaging standard dating to 1992, or a leaner binary protocol. The gateway converts either into one compact internal format.

Step 3: The order book and price-time priority

Each symbol has a book with two sides: bids sorted highest price first, asks lowest price first. Under price-time priority, a better price always fills first, and at the same price the earliest order fills first. Some markets use pro-rata matching instead, splitting a fill across all orders at a price level in proportion to their size. Mention it, then build price-time unless told otherwise.

The data structure interviewers expect has three parts:

  1. Price levels per side in a sorted map (a balanced tree) keyed by price, with a cached pointer to the best level. Because prices move in fixed ticks, an array indexed by tick is a faster option that costs more memory.
  2. A FIFO queue per level, usually a doubly linked list of orders plus the level’s total quantity.
  3. An order index: a hash map from order ID to its list node, so cancels never scan the book.
OperationCostHow
Add at an existing priceO(1)Append to that level’s tail
Add at a new priceO(log P), or O(1) with a tick arrayInsert a new level
CancelO(1)Hash lookup, then unlink
Best bid or askO(1)Cached pointer
Each fillO(1)Take from the head of the best level

P is the number of active price levels on that side.

Walk through one match. The ask side holds order A for 100 shares at $10.01, then B for 200 at $10.01, then C for 300 at $10.02. A buy limit order for 250 at $10.02 arrives. It takes 100 from A and 150 from B, both at $10.01, and stops. B keeps its place at the front of the queue with 50 left; C is untouched. In typical continuous trading the trade prints at the resting order’s price, so the buyer pays $10.01, not its $10.02 limit.

match(incoming):
  opposite = book.side_opposite(incoming)
  while incoming.qty > 0 and opposite.best_crosses(incoming.price):
    level   = opposite.best_level()
    resting = level.head()
    fill    = min(incoming.qty, resting.qty)
    emit Trade(price = level.price, qty = fill, ...)
    incoming.qty -= fill
    resting.qty  -= fill
    if resting.qty == 0: level.pop_head(); index.remove(resting.id)
    if level.empty():    opposite.remove(level)
  if incoming.qty > 0:
    if incoming.type == LIMIT: rest_on_book(incoming)   # joins tail of its level
    else: emit Cancelled(incoming)                      # market / IOC remainder

Two details worth saying unprompted. Store prices as integer ticks, never floating point; Nasdaq’s TotalView-ITCH feed sends prices as integers with an implied four decimal places. And state your amendment rule: on many venues, a replace that changes the price or raises the size loses queue position.

Step 4: The sequencer, and why the engine has one thread

Every message that can change state passes through the sequencer and receives the next number in a single, gap-free sequence. The engine processes messages strictly in that order, and its outputs carry sequence numbers too. That one decision buys fairness (first in really is first processed), determinism (replaying the log rebuilds the same books and trades) and simple recovery and audit.

In his Jane Street tech talk “How to Build an Exchange,” Brian Nigito describes the same principle: one global, totally ordered stream, and only messages in that stream may change state or be shown to clients.

The engine itself runs on one thread. Fowler’s LMAX article explains why: the team’s first prototype spent more time managing queues between threads than running business logic, and locks trigger context switches that evict data from CPU caches. A single writer over in-memory state avoids both.

To scale, partition by symbol. Matching in one stock never touches another, so each partition gets its own sequencer and engine. Name the cost: anything that spans symbols, such as a firm-wide risk limit, now needs coordination across partitions. Nigito notes that his team chose not to split by symbol for exactly that reason, to keep cross-instrument risk limits atomic.

Step 5: Low-latency design choices

You do not need to be a performance engineer for this round, but know which levers exist.

Step 6: Risk checks before the book

For context, the SEC’s market access rule (Rule 15c3-5, adopted in 2010) requires US broker-dealers with market access to have pre-trade controls that block orders exceeding pre-set credit or capital thresholds or that appear erroneous. Reserving funds on accept and settling on fill mirrors the authorize-then-capture flow in our payment system design walkthrough.

Step 7: Market data distribution

Every engine output becomes public data. The usual tiers (names vary by vendor):

TierContentsTypical consumer
Top of book (often “Level 1”)Best bid, best ask, last tradeRetail apps, dashboards
Depth by price (often “Level 2”)Total quantity at each priceActive traders
Order by order (full depth)Every add, execution, cancel and replaceMarket makers, book rebuilders

Nasdaq TotalView-ITCH is a real example of the full-depth tier: a binary feed of sequenced, order-level messages with nanosecond timestamps, offered over MoldUDP64 (UDP) or SoupBinTCP. Design points to make:

Step 8: Persistence, replay and fault tolerance

This is event sourcing: the sequenced input log is the source of truth, and the order books are derived state.

The sequenced, append-only log is the same building block as a partitioned message queue, so our distributed message queue walkthrough is useful background.

Running the 45-minute interview

MinutesCover
0–5Scope, order types, rough numbers, latency and fairness goals
5–15Architecture diagram and the critical path
15–25Order book structure, complexity, one worked match
25–35Sequencer, single thread, partitioning by symbol
35–45Market data, failure and recovery, trade-offs

Have a one-line answer ready for follow-ups like these:

Contention on one hot item is also the core problem in designing Ticketmaster, and the building blocks every design round draws on are in our 14 core system design concepts. Then rehearse out loud on a timer: a free AI mock interview in CoPilot Interview can include system design questions, reads each aloud and scores your spoken answer.

Rehearse your exchange design out loud

Paste a job description and your résumé, pick system design in the question mix, and an AI interviewer will ask, listen and score each answer. The free plan gives you 15 minutes a day with no credit card.

Try a free AI mock interview

FAQ

What is price-time priority in a matching engine?

A better price fills first, and at the same price the earliest order fills first, which is why it is also called FIFO matching. Some markets use pro-rata instead, splitting fills at a price level by order size.

What data structure should I use for an order book?

Two sorted collections of price levels (bids highest first, asks lowest first), each level holding a FIFO queue of orders, plus a hash map from order ID to its node so cancels take constant time.

Why is the matching engine usually single-threaded?

One thread reading one sequenced stream needs no locks, keeps CPU caches warm and gives the same result on every replay. Martin Fowler's write-up of LMAX describes one such thread processing about 6 million orders per second on commodity hardware.

How does a stock exchange recover from a crash?

The sequenced input log is the source of truth. A new engine loads the latest snapshot and replays the journal after it, while hot standbys that consumed the same stream can take over with identical books.

Do I need to know FIX or ITCH for a system design interview?

No, but naming them shows you know real venues. FIX is the long-standing tag=value standard for order messages, and Nasdaq TotalView-ITCH is a binary, order-by-order market data feed. Spend your time on the design.