DDSA Solutions
Case Study6 min read·

Design a Stock Trading Platform

How to design a stock trading system for interviews: market data, order gateway, matching engine sketch, ledger, risk checks, and low-latency paths.

Trading platforms scare candidates into drawing a Wall Street exchange. Most interview prompts mean a retail broker: users place orders, you route or match, you keep a correct ledger of cash and positions. Latency matters, but correctness and idempotency matter more — same DNA as a payment system, with a live market-data firehose on the side.

Clarify with the framework: retail app vs exchange matching engine, equities only vs crypto, market hours, and whether you simulate an exchange or route to external venues. Pick retail broker + simplified matching unless they insist.

Functional requirements

  • View quotes and basic charts for symbols.
  • Place market/limit orders; cancel open orders.
  • Show portfolio: cash, positions, buying power.
  • Fill notifications and order status history.
  • Optional: watchlists, paper trading, options (mention only).

Non-functional

  • Order path: low tens of milliseconds internally; never lose or double-apply a fill.
  • Strong consistency on balances and positions — AP is wrong here.
  • Market data: high throughput, eventual display lag of hundreds of ms is often OK for retail.
  • Auditability: immutable order/fill log for compliance.
  • Idempotent order submission (client order ids).

Ledger first

If cash and share counts drift, the product is broken even if the UI is pretty. Design the ledger and risk checks before obsessing over nanosecond matching. Interviewers reward that ordering.

Capacity sketch

10M users, peak order rates in the tens of thousands/sec at the open (retail is bursty at 9:30 ET — use whatever number the interviewer gives you). Market data: thousands of symbols × quote updates — easily 1M+ msgs/sec into your fan-out tier. Separate the hot market-data plane from the transactional order plane so a quote storm cannot stall bookings.

High-level architecture

  1. API / mobile gateway — auth, rate limits, schema validation (API gateway).
  2. Market data service — ingest exchange feeds, normalize, publish to clients via WebSocket.
  3. Order gateway — validate, assign ids (Snowflake), persist intent.
  4. Risk engine — buying power, pattern-day-trader rules, notional limits.
  5. Matching / router — simplify as an in-memory book per symbol or a smart order router to venues.
  6. Ledger service — double-entry cash and positions; source of truth.
  7. Notification — fills via push.
  8. Analytics / warehouse — async copy for tax lots and statements.

Order lifecycle

  1. Client sends placeOrder with client_order_id (idempotency key).
  2. Persist NEW order; reserve buying power (hold cash or shares).
  3. Risk accept/reject; on reject release hold and return reason.
  4. Route to matching engine or external broker API.
  5. On partial/full fill: ledger posts debit/credit; update order status.
  6. Emit fill event; unlock remaining holds on cancel/complete.

Treat fills as the only thing that mutates positions. UI optimism is fine; the ledger is not optimistic. Use exactly-once-effect processing with idempotent fill ids — classic queue consumer pattern.

Data model

EntityStoreNotes
Account / balancesSQL CP primaryRow-level lock or serializable txn per account
OrdersSQL + append logStatus machine: NEW→OPEN→PARTIAL→FILLED/CANCELED
Fills / executionsAppend-only SQLImmutable; drive ledger postings
PositionsSQLDerived from fills; reconcile nightly
QuotesRedis / in-memoryEphemeral; not transactional truth
WatchlistsSQL or KVRead-heavy, weakly consistent OK

Matching engine (keep honest)

If you include matching: one single-threaded event loop per symbol (or shard of symbols) processing an input queue — determinism beats premature multi-threading. Price-time priority for limit books. Market orders consume the opposite side. Acknowledge that real exchanges are FPGA/colocated beasts; you are illustrating the state machine. For a broker-only design, replace this box with “venue adapter.”

Market data fan-out

Ingest → normalize → publish to a pub/sub fabric. Clients subscribe to symbols; gateway multiplexes WebSockets. Coalesce quotes (last N ms) so mobile clients are not crushed. Cache last trade/last quote in Redis for REST snapshots. This path should not share databases with the ledger.

Consistency and failure

  • Account updates are CP: better to reject orders than corrupt cash.
  • Use database transactions or a transactional outbox when emitting fill events.
  • Replay the order log to rebuild an in-memory book after matcher crash.
  • Circuit-break trading on a symbol if venue feed is stale — show “data delayed.”
  • Shard users for ledger hot spots; shard books by symbol for matching.

Worked example

  1. User submits limit buy 10 AAPL @ $190 with client_order_id C1.
  2. Gateway dedupes C1; risk holds $1,900 buying power.
  3. Book rests the order; later a sell hits → fill 10 @ $190.
  4. Ledger: −$1900 cash, +10 AAPL; order FILLED; push notification.
  5. Retry of C1 is a no-op thanks to idempotency key.

Interview narrative

Separate market-data plane from order/ledger plane. Walk place → risk → match/route → ledger → notify. Stress idempotency and strong consistency on money. Compare to payments (no live book) and to ticket booking (inventory holds). That story reads senior without claiming you built NASDAQ.

More in this series