Stock exchange

How does an exchange order millions of bids fairly in microseconds?

About 30 minutes · open lesson · System design

Who bought the first twenty crates?

Every morning a farmers’ co-operative near Nashik sells its surplus tomatoes to the partner kitchens. It used to be a phone call. Now it is an auction in the app: farmers offer crates at a price, kitchens bid, and a match happens when a bid meets an offer.

The auction runs on two servers, one in Pune and one in Nashik, so that kitchens in both cities get a quick answer. Each server matches the orders it receives, then copies its trades to the other.

At 6:00 one morning the bell rings. A farmer offers 30 crates at ₹410. A kitchen in Pune and a kitchen in Nashik each bid ₹410 for 20 crates, one millisecond apart.

The Pune kitchen’s screen says it bought the first twenty. The Nashik kitchen’s screen says the same. Both have paid the co-operative.

Neither server crashed. Work out what each one saw before reading on. The Pune bid reached the Pune server first and the Nashik bid reached the Nashik server first, so each server matched a different bid against the same crates. By 6:01 the two servers disagreed about the trades of three traders, and the copies they sent each other made it worse: each copy was a trade the other server had never made, against crates it had already sold.

A stock exchange matches millions of orders a second and never gives the same share to two people. What does it do that these two servers did not? Think of a ration shop that hands out numbered tokens from one machine: whoever holds token 1 is served first. If the shop had two machines, each printing its own token 1, two customers would both believe they were first.

Number first, then match

Matching is the easy part. The hard part is agreeing on which order came first when orders arrive at different machines at different times. Lesson 3.3 showed that copies that accept writes on their own can disagree; here the disagreement is about order itself.

Order book and price-time priority
The list of buy orders (bids) and sell orders (asks) still waiting. A new order trades with the best price on the other side first; among orders at the same price, the older one goes first.
For example: Two bids at ₹410 and one at ₹415: an offer at ₹400 fills the ₹415 bid, then the older ₹410 bid. The trade happens at the price of the order that was waiting.

The design follows from one rule: number first, then match. A sequencer gives each order the next number. The matching engine is a pure function of that numbered list: same list in, same trades and same book out. That makes it a replicated state machine: feed the same list to a second machine and it holds the same book, ready to take over. It is the idea behind the replicated log in lesson 3.4, and behind event sourcing in lesson 6.6.

Where should the sequencer be?

One sequencer settles which order came first. Where it runs decides whose orders wait longer to reach it.

A sequencer per city is sound: it partitions the auction by lot, and each partition still has one sequencer (lesson 3.2). Real exchanges partition by instrument the same way. For one co-operative with a few hundred orders a morning, the cross-city wait is invisible, and one list is simpler to run, audit and replay.

What to remember

  1. Fairness and agreement come from one sequence: number every order before matching, and match by price, then by sequence number.
  2. A matching engine that is a pure function of the numbered input is a replicated state machine: replicas fed the same journal hold the same book.
  3. With one ordered input, the matching engine needs no locks: it runs on one thread, in memory, and the input is written to a journal as a stream.
  4. A sequencer makes every machine agree on the order, but it is fair only between traders the same distance away. Scale it by partitioning (one sequencer per instrument or lot).

Number every order once, before matching, and let every machine apply the same numbered list.

In the real world

The auction in the lab has ten orders and two order types. A real exchange adds cancels and amendments, market and immediate-or-cancel orders, auctions at the open and close, risk checks before an order reaches the book, and market data published from the same sequence so everyone sees trades in one order.

The sequencer itself must not be a single point of failure: its journal is replicated before an order is acknowledged, which is consensus again, and a standby takes over from the journal. The core stays what you built: one list, numbered once, applied the same way everywhere.

Open the interactive lesson

The interactive lesson adds the predictions with their answers, the labs, and graded practice with spaced review.