DEV Community

Cover image for Design a stock trading app: the system design interview walkthrough
Gowtham Potureddi
Gowtham Potureddi

Posted on

Design a stock trading app: the system design interview walkthrough

Design a stock trading app: the system design interview walkthrough

The request to design a stock trading app sounds like one line — watch prices, buy and sell — and that one line hides the whole interview. Picture it for a hobby portfolio tracker and a polling loop is enough; picture it for Robinhood, streaming a live price to millions of screens the instant the market moves while thousands of buy orders hit the same symbol and every cent of every account must stay exactly right, and it becomes two systems pulling in opposite directions. This is one of the most revealing stock trading system design prompts — the Robinhood-style question — because it forces the one split that fintech lives or dies on: fast real-time market data on one side, and a strongly consistent transactional trading path on the other, and they must never be the same system.

The round turns on one structural insight, and it has two parts. First, separate market data from trading: streaming quotes to millions is a read-heavy fan-out that can tolerate being milliseconds stale, while placing an order and moving money must be strongly consistent and exactly-once — so they live in separate systems. Second — the part that catches people — Robinhood is a brokerage, not an exchange. It does not run the matching engine; the order book and matching live at an external exchange, and the app's job is to validate an order, reserve the money, submit it to that exchange, and reconcile the fills that come back asynchronously. Get those two reframes and the rest of the system design interview is deciding how the quote stream fans out without melting, how an order moves through its lifecycle against an external matcher, and how buying power stays correct when two orders race for the same cash. This walkthrough follows the path a strong candidate draws on the whiteboard — requirements, estimate, API and data model, high-level design, then the deep dives — naming the follow-up the interviewer uses at each step to tell a memorised answer from real understanding.

Title card for a system design interview walkthrough on designing a stock trading app like Robinhood, showing two systems kept apart — a real-time market-data feed fanning a live price out to many client screens on one side, and a strongly consistent order-and-ledger path routing an order to an external exchange on the other — on a dark citrus-and-lavender background.

How the stock trading round is actually run

A stock trading round runs about 45 minutes on a shared canvas — you draw the boxes and arrows while you talk, and the interviewer interrupts. It is a favourite because the one-line problem opens onto deep water fast: the moment you draw "see prices, place orders," the question becomes how does a live quote reach a million screens at once and where does the order actually get matched, and every answer after that compounds from those two. The clock is a touch tighter than the hour-long rounds, so you have to spend your minutes on the feed, the order lifecycle and money correctness, not on the watchlist UI.

The interviewer rarely lets "they buy a stock" stand. "A million users are watching the same symbol as the price ticks every few milliseconds, and thousands of them fire a buy at once — what must never break, and where does the actual matching happen?" That pair — fan-out under load and who owns the order book — is what a copied answer can never rehearse, and what this round is really testing.

The rounds here are modelled on how the loop runs, not scraped from any candidate's recall. What matters for prep is the shape: a blank canvas, a tighter clock, and a follow-up after every decision you make.

The five-step framework for any HLD round

Every high-level design answer fits the same spine. Say it out loud at the start so the interviewer knows you have a plan, then walk it:

  1. Clarify requirements — functional and non-functional, and what you are explicitly not building.
  2. Estimate — concurrent market-data subscribers and tick rate versus order rate, to justify every later choice.
  3. High-level design — the boxes and arrows: the clients, the market-data path, and the trading core, and the external exchange beyond it.
  4. Deep dive — the two or three decisions that actually decide this system.
  5. Follow-ups — bottlenecks, failure modes, and what you would change at ten times the scale.

What the debrief measures

The score is not "right or wrong design." A good HLD debrief reads on four dimensions, and every move below maps to one: problem solving (did you split a fan-out market-data path from a strongly consistent trading path, and spot that Robinhood routes to an external exchange), communication (did you say why quotes can be lossy but money must be exactly-once, in a single sentence), technical execution (pub-sub plus websocket fan-out per symbol, an order state machine reconciled from async fills, a ledger with atomic buying-power reservation), and time management (did you spend your 45 minutes on the feed, the order lifecycle and funds, not on charts). Reading a walkthrough teaches the design; it does not teach you to deliver it on the clock while someone pushes back.

Step 1 — Requirements: what a stock trading platform must do

Spend the first few minutes here. Jumping to boxes before you have scoped the problem is the fastest way to design the wrong system.

Type Requirement
Functional A user watches live prices for the symbols they follow; places and cancels market and limit orders to buy and sell; sees their cash and share balances update as orders fill; views order history.
Functional (optional) Options, crypto, charts and analytics, watchlists, recurring investments — call these out, then scope most of them for later.
Non-functional Market data is real-time and low-latency and can tolerate being milliseconds stale; orders and balances are strongly consistent and exactly-once — money is never double-spent and an order is never lost or placed twice; high availability during market hours; scale to millions of concurrent users.

The sentence that earns points: "There are two systems here — a read-heavy market-data fan-out that can be a touch stale, and a strongly consistent trading path, and Robinhood is a brokerage that routes orders to an external exchange rather than matching them itself." Say that and you have framed the entire design before drawing a box.

Step 2 — Capacity estimation (back of the envelope)

Estimation here is about proving one thing: market data and trading have completely different volumes and completely different consistency needs, and the design must treat them as two systems.

Quantity Assumption Result
Concurrent subscribers millions of users watching symbols during market hours millions of long-lived websockets and a huge read fan-out — the scaling problem for market data
Quote / trade ticks popular symbols tick many times per second a high-rate stream that must fan out to every subscriber of that symbol, not be stored per-read
Order rate far fewer orders than quote views a modest write rate — but every order must be exactly-once and strongly consistent
Account writes balance and position changes on reserve and fill low-rate, high-stakes writes against a ledger that must never be wrong

Two conclusions fall out, and you should say both out loud. First, market data is the high-volume, low-stakes axis — the hard part is fanning one symbol's ticks out to a million sockets, and a dropped tick is harmless because the next one is milliseconds away. Second, trading is the low-volume, high-stakes axis — the order and money rate is modest, so it can afford strong consistency and exactly-once handling, which it absolutely needs. You have now pointed the interview at the two real deep dives — the fan-out and the order/ledger path — before anyone asked.

Step 3 — API and data model

The API is deliberately small: a client subscribes to a live feed, places and cancels orders, and reads its portfolio.

Operation Shape
subscribe(symbols) opens a websocket and streams quote/trade updates for the requested symbols.
get_quote(symbol) returns the latest price for a one-off read.
place_order(symbol, side, type, qty, limit_price, idempotency_key) submits a buy/sell, market or limit; the idempotency_key makes a retried or double-clicked order safe.
cancel_order(order_id) requests cancellation of a working order.
get_portfolio() returns cash, positions and open orders.

The data model is thin. The account ledger and the order are the source of truth for money and state; market data is a derived stream, not a stored table:

Entity Notes
instrument symbol, name, latest price (cached from the feed) — reference data.
order order_id, account_id, symbol, side, type, qty, limit_price, state (pending / submitted / filled / partially-filled / cancelled / rejected), idempotency_key.
position (account_id, symbol, quantity) — shares held, updated on fills.
ledger_entry double-entry rows that move cash and reserved buying power — the authoritative record of money.

Step 4 — High-level design: the market-data path and the trading core

Now the boxes. The clients talk through an API gateway to two clearly separated halves, plus the external exchange beyond them:

  • Market-data service: ingests the exchange / market-data feed, and fans each symbol's quote and trade updates out to every subscribed client over websockets, through a pub-sub layer — the read path.
  • Order service: owns the order state machine; it validates an order, asks the account service to reserve funds, submits the order synchronously to the external exchange, and reconciles the fills that come back asynchronously, moving the order through its states and updating positions.
  • Account / ledger service: holds balances and positions as a double-entry ledger, strongly consistent, and performs the atomic buying-power reservation — the authoritative record of money.
  • External exchange: the matching engine and order book live here, outside the brokerage; Robinhood submits orders to it and receives fills, it does not match orders itself.
  • Path separation: the market-data fan-out and the transactional trading core are separate systems, so a surge of quote traffic never contends with account writes, and the slow exchange round-trip never blocks the quote stream.

Say explicitly that this is a fan-out read path and an exactly-once write path kept apart, with the matching engine external. Naming that split unprompted — quotes stream off a pub-sub fan-out, orders route to an exchange and settle against a strongly consistent ledger — is a signal the interviewer is listening for.

A stock trading architecture diagram showing client apps talking through an API gateway to two separated paths: a market-data service that ingests an external exchange feed and fans quotes out through a pub-sub layer and websockets to subscribed clients, and a transactional trading core where an order service validates and routes orders to the external exchange and reconciles async fills while an account and ledger service holds strongly consistent balances, with the exchange matching engine drawn as an external box.

Deep dive: real-time market data at fan-out scale

This is the first decision that actually decides the round. The follow-up is always about volume: a million people watch the same symbol as it ticks every few milliseconds — how does everyone see it without melting the system?

The mistake is to treat a quote like a database read — a million clients polling get_quote for the same symbol would hammer any store. The shape that works is fan-out over pub-sub. The market-data service ingests the exchange feed once, and for each symbol it publishes updates to a topic; every client that subscribed to that symbol holds a websocket, and the pub-sub layer pushes each new tick out to all of them. One incoming tick becomes a million outbound pushes, and crucially none of it touches the transactional database:

Feed element How it is served
Ingest one connection to the exchange/market-data feed per symbol stream — the system reads the firehose once.
Publish the service publishes each symbol's updates to a per-symbol pub-sub topic.
Subscribe a client opens a websocket and subscribes to the symbols on its screen — nothing more.
Fan-out the pub-sub layer pushes each tick to every subscriber of that topic, scaling horizontally with connection servers.
Freshness updates may be milliseconds stale and a dropped tick is simply replaced by the next — acceptable for a live quote.

The reason this works is that a quote is disposable: you only ever care about the latest price, so there is no value in durably storing every tick per reader, and a lost update is corrected a few milliseconds later. That lets the whole path be an in-memory, horizontally scalable fan-out — add connection servers to carry more websockets — entirely separate from the order and ledger systems. Saying plainly that market data is lossy-tolerant and must never share a database with the money path is the sentence that separates a real answer from a hand-wave.

"A million people watch the same symbol as it ticks every few milliseconds — how does everyone see it?" Not by polling a database — the market-data service ingests the feed once and publishes each symbol to a pub-sub topic, and every client holds a websocket subscribed to its symbols, so one tick fans out to all subscribers. Updates can be milliseconds stale and a dropped tick is replaced by the next, so the whole path is an in-memory fan-out that never touches the transactional store.

A real-time market-data fan-out diagram showing an external exchange feed streaming per-symbol quote and trade ticks into a market-data service that publishes each symbol to a pub-sub topic, which fans the updates out over long-lived websockets to the many clients subscribed to that symbol, with a note that updates can be milliseconds stale and a dropped tick is replaced by the next.

System Design
HLD · Payments & marketplaces · 45 min
Design a stock trading app out loud, with follow-ups

Practise on Zynter →

Deep dive: the order lifecycle — placing and matching orders

This is the decision the whole round is really about, and the one that separates people who know the domain from people who memorised a diagram. The follow-up is blunt: where does the actual matching happen — do you build the order book?

The answer is no — and saying so is the point. Robinhood is a brokerage, not an exchange. The matching engine and order book live at an external exchange; the app's order service does not match buyers to sellers. What it owns is the order as a state machine and the job of driving it against that external matcher:

Order state Transition / trigger
pending order service validates the order and reserves buying power; the durable record is created.
submitted the order is sent synchronously to the external exchange for matching.
partially-filled some shares fill; a fill event arrives asynchronously on the trade feed and positions update.
filled the order fully fills; reserved funds settle and the position is final — terminal.
cancelled the user cancels a working order (for a limit order resting on the book); reserved funds release — terminal.
rejected validation or the exchange rejects it (bad symbol, insufficient buying power, market closed); funds release — terminal.

The flow to narrate: validate and reserve funds, submit to the exchange, then reconcile the asynchronous fills that come back on the trade feed, moving the order through its states and updating positions as they land. A market order submits for immediate execution at the best available price; a limit order can rest on the exchange's book until the price is met or it is cancelled, which is exactly why cancellation is a first-class state. Note out loud that if the interviewer instead wants you to build the matching engine and order book — price-time priority, matching bids and asks — that is the separate "design a stock exchange" question; the Robinhood round is the brokerage that routes to it. Knowing which problem you are being asked is itself a signal.

"Where does the actual matching happen — do you build the order book?" No — Robinhood is a brokerage, so the matching engine and order book are at the external exchange. My order service validates the order, reserves buying power, submits it to the exchange, and reconciles the fills that come back asynchronously on the trade feed, driving the order through pending → submitted → filled or partially-filled, cancelled or rejected. Building the matching engine itself is the separate "design a stock exchange" problem.

An order lifecycle and ledger diagram showing an order moving through a state machine from pending to submitted to the external exchange to filled, partially-filled, cancelled or rejected, with the order service first atomically reserving buying power on a double-entry ledger so concurrent orders cannot overdraw the same cash, an idempotency key making a retried order place once, and reconciliation of async fills from the exchange settling the reserved funds.

System Design
HLD · Payments & marketplaces · 45 min
Defend the order lifecycle and brokerage-vs-exchange split out loud

Practise on Zynter →

Deep dive: buying power, the ledger and consistency

Routing orders decides who matches them; this decides that the money is never wrong — and it is where a trading system quietly breaks if you treat balances like an ordinary row. The follow-up is the race: a user fires two buys that each use most of their cash at the same instant — how do you stop both filling?

The rule that must survive every failure is that an account can never spend buying power it does not have. The mistake is to read the balance, decide there is enough, and write the order as a separate step — two concurrent orders can both read "enough" before either commits. The fix is to make check-and-reserve a single atomic operation on a strongly consistent ledger:

  • Reserve, don't just check: on place_order, atomically verify and reserve the required buying power (for a buy) or shares (for a sell) in one transaction, so the funds are set aside before the order is submitted. The second racing order now sees the reduced buying power and is rejected.
  • Double-entry ledger: model money as ledger entries, not a mutable balance field — every reservation, settlement and release is a recorded movement, so the account is auditable and always reconciles.
  • Exactly-once with an idempotency key: the client sends an idempotency_key; a retried or double-clicked place_order collapses to one order, never two — essential when the request might be retried after a timeout.
  • Settle on fill, release on cancel/reject: when a fill arrives, settle the reserved funds into the position; when an order is cancelled or rejected, release the reservation back to buying power. Nothing is ever lost or stuck.

The point to state plainly: strong consistency lives exactly here, on the reserve step, because that is where double-spending would happen. Market data gets speed and fan-out; the ledger gets a transaction and exactly-once semantics; keeping them in separate systems is what lets each have the guarantee it needs without paying for the other's.

"A user fires two buys that each use most of their cash at the same instant — how do you stop both filling?" I never read-then-write the balance. Placing an order atomically reserves buying power on a strongly consistent double-entry ledger in one transaction, so the first reserves the cash and the second sees insufficient buying power and is rejected. An idempotency key means a retried order is placed once, and reserved funds settle on fill or release on cancel — so the account can never overdraw.

The follow-ups that decide the stock trading round

Scan the probes from each deep dive and they rhyme. Master these five and you are ready for a version of the question that is not drawn exactly like this one.

  • "How does a live quote reach a million screens at once?" → The market-data service ingests the feed once and publishes each symbol to a pub-sub topic; every client holds a websocket subscribed to its symbols, so one tick fans out to all subscribers, milliseconds-stale and lossy-tolerant, never touching the transactional store. (technical execution)
  • "Where does the order actually get matched — do you build the order book?" → No: Robinhood is a brokerage, so the matching engine and order book are at an external exchange; the order service validates, reserves funds, submits, and reconciles async fills. Building the matcher is the separate "design a stock exchange" problem. (problem solving)
  • "How do you stop two orders double-spending the same cash?" → Atomically reserve buying power on a strongly consistent double-entry ledger at placement, so the second racing order sees insufficient funds and is rejected; an idempotency key makes a retried order place once. (technical execution)
  • "Why separate market data from the trading path?" → Quotes are high-volume and lossy-tolerant, money is low-volume and must be exactly-once, so a fan-out stream and a strongly consistent ledger live in separate systems — neither surge nor slow exchange round-trip threatens the other. (communication)
  • "What's the difference between a market and a limit order here?" → A market order submits for immediate execution at the best price; a limit order can rest on the exchange's book until its price is met or the user cancels it, which is why cancel and partially-filled are first-class order states. (problem solving)

Each maps to a debrief dimension. Reading this list teaches you the answers; it does not teach you to deliver them while someone interrupts — that only comes from saying them out loud.

How to prepare: a one-week plan

You do not need fifty systems. You need this one cold and the framework automatic, so the next "design X" is just new nouns in the same five steps.

  • Days 1–2: Learn the five-step framework until it is reflex. Do the stock trading app end to end on paper — requirements, estimate, API, data model, and the market-data-path/trading-core boxes.
  • Days 3–4: Drill the market-data fan-out: ingest once, publish per symbol, websocket subscribers, and why a stale or dropped tick is fine. Say each tradeoff in one sentence.
  • Days 5–6: Own the order lifecycle and the ledger — the brokerage-versus-exchange split, the order state machine reconciled from async fills, and the atomic buying-power reservation with an idempotency key. Answer each of the five follow-ups out loud.
  • Day 7: A full timed 45-minute round, narrating the whole way, with someone (or something) interrupting. This is the rep that counts.

This post is the deep walkthrough behind one row of the broader Top 25 system design interview questions — once the stock trading app is automatic, the same spine carries the rest of the list.

Frequently asked questions

How do I design a stock trading app step by step?

Follow the five-step HLD framework. Clarify requirements (watch live prices; place and cancel market and limit orders; see cash and share balances; order history); estimate to show the split — millions of concurrent market-data subscribers and a high tick rate against a modest but exactly-once order rate; define the small API (subscribe, get_quote, place_order with an idempotency key, cancel_order, get_portfolio) with a thin instrument/order/position/ledger model; draw the design (clients through a gateway to a market-data service that fans quotes out over pub-sub and websockets, and a trading core — an order service that routes to an external exchange plus a strongly consistent account/ledger service); then deep-dive the decisions that matter — market-data fan-out, the order lifecycle, and buying power on the ledger. Finish on the follow-ups about matching and double-spending.

How does a stock trading app stream real-time market data to millions?

By fanning out over pub-sub, not by serving quotes from a database. The market-data service ingests the exchange feed once and publishes each symbol's updates to a per-symbol topic; every client opens a websocket and subscribes to the symbols on its screen, and the pub-sub layer pushes each new tick to every subscriber of that topic, so one incoming tick becomes many outbound pushes. Updates can be milliseconds stale and a dropped tick is simply replaced by the next, so the whole path is an in-memory, horizontally scalable fan-out — add connection servers to carry more websockets — kept entirely separate from the order and ledger systems that must be strongly consistent.

Where are orders matched — does the app build the order book?

No. Robinhood is a brokerage, not an exchange, so the matching engine and order book live at an external exchange. The app's order service validates the order, reserves buying power, submits the order synchronously to the exchange, and reconciles the fills that arrive asynchronously on the trade feed, driving the order through its state machine. Building the matching engine itself — matching bids and asks by price-time priority on an order book — is the separate "design a stock exchange" question; recognising which of the two you are being asked, and saying so, is part of what the round tests.

What is the difference between a market order and a limit order?

A market order asks to buy or sell immediately at the best available price, so it submits to the exchange and typically fills right away. A limit order sets a price boundary — buy at or below, sell at or above — so it may not fill immediately; it can rest on the exchange's order book until the market reaches its price or the user cancels it. That is why an order lifecycle needs partially-filled and cancelled as first-class states: a limit order can fill in pieces over time, and a working order must be cancellable. The brokerage tracks that state machine and reconciles fills; the exchange does the matching.

How does a trading app keep buying power consistent and avoid double-spending?

By making check-and-reserve a single atomic operation on a strongly consistent ledger rather than a read followed by a separate write. When an order is placed, the account service verifies and reserves the required buying power (for a buy) or shares (for a sell) in one transaction, so a second concurrent order sees the reduced balance and is rejected. Money is modelled as a double-entry ledger so every reservation, settlement and release is an auditable movement, and a client-supplied idempotency key ensures a retried or double-clicked order is placed exactly once. Reserved funds settle on fill and release on cancel or rejection, so an account can never overdraw or lose track of cash.

How do I practise a system design interview out loud?

Reading a walkthrough is not the same as defending a design while someone interrupts. On Zynter, the HLD track runs live voice rounds modelled on how real system design loops run — you talk through a shared design on the canvas, and a voice interviewer pushes with the follow-ups above one at a time, then gives you a debrief on problem solving, communication, technical execution, and time management. The score is a practice signal, not a hiring decision.

Practise it on Zynter

You can read every order state. The round is won on the fan-out and keeping the money exactly-once.

Pick the Stock Trading round, draw the market-data-path and trading-core design on the canvas, and defend it out loud to a voice interviewer that keeps asking "how does a live quote reach a million screens?" and "where does the order actually get matched?" — then read the debrief. Zynter.ai is on-demand mock interviews modelled on real company loops, with 150+ rounds across 20 companies including the HLD system design track (Sep 2026).

Practise the Stock Trading round →
Browse all interview tracks

Top comments (0)