Skip to content

Design a stock brokerage system

TL;DR

  • You build the broker, not the exchange: accounts with cash and holdings, orders that reserve before they trade, and settlement driven by execution reports from a venue you do not control.
  • Three decisions carry the interview: reserve funds or shares atomically before the order leaves the building, settle every fill idempotently on its fill id, and never hold the account lock across the call to the exchange.
  • Observer drives the price feed into resting limit orders and alerts; the order lifecycle is an explicit transition table; Unit of Work makes cash, holding, order and trade commit together.

Problem statement

"Design the backend of a retail brokerage. Users have an account with cash and a portfolio, keep watchlists, and place market and limit orders to buy and sell. Orders are validated against available funds and holdings, sent to an exchange, and may come back filled, partially filled or not at all. Trades update cash and holdings; users see order history and get price alerts. Focus on the classes, the order lifecycle, and what happens when the exchange sends the same execution report twice."

Requirements

Functional

  • Accounts holding cash and a Portfolio of Holding rows (quantity plus average cost).
  • A market data feed of quotes; watchlists that follow it; price alerts that fire once when a threshold is crossed.
  • Market and limit orders, buy and sell, validated against available cash and available shares.
  • An order lifecycle: new, submitted, partially filled, filled, cancelled, rejected — with only legal transitions allowed.
  • Fills arrive from the exchange as execution reports; each one becomes a Trade that updates cash and holdings.
  • Cancel an open order and get the unused reservation back.
  • Order and trade history per account.

Non-functional and constraints

  • Money is common.Money (integer cents). Decimal would also be defensible; a float is not.
  • Reserving funds must be atomic: 20 concurrent orders against a balance that covers five must accept exactly five.
  • Execution reports are at-least-once. Settlement must be effectively-once: the same fill id may arrive many times and must move the account once.
  • No network call happens while an account lock is held.
  • In-memory, single process; the exchange is behind a Protocol so a real venue drops in.

Out of scope: the matching engine itself (that is the exchange), margin and leverage, options, tax lots, market hours and halts, regulatory reporting.

Clarifying questions and assumptions

Question to ask Assumption taken here
Are we the broker or the exchange? The broker. We reserve, submit, and settle what comes back. The venue is a Protocol with submit and cancel.
Do market orders reserve cash, and at what price? Yes, at the last print plus 5% headroom, because the price moves between reservation and fill. A limit order reserves exactly limit x quantity.
Can an order fill in pieces? Yes. Each slice releases its share of the reservation; the remainder is released when the order reaches a terminal state.
Can the exchange send the same fill twice? Assume yes. Fill.fill_id is the idempotency key and the account stores the trade it produced.
What if a fill arrives after we cancelled? It is refused. A production broker treats the venue as the authority and reconciles; say so, then show the guard.
Decimal or integer cents? Integer cents. Share counts are ints, prices are cents, and price * quantity is exact — no quantisation rules to argue about.
Do we simulate the whole book? No. SimulatedExchange rests orders and fills them when a tick makes them marketable, with a knob for partial fills.

Core entities and relationships

  • Account — cash, reserved_cash and a Portfolio. available_cash() is cash - reserved_cash, and it is the only number order validation looks at.
  • Portfolio and Holding — quantity, reserved (claimed by open sell orders) and weighted average_cost. available() mirrors available_cash().
  • Order (base) with MarketOrder and LimitOrder, built by OrderFactory. The subclasses answer exactly three questions: would you trade at this price, at what price, and what price sizes the reservation.
  • OrderStatus plus the ORDER_TRANSITIONS table — the state machine, enforced by Order.transition_to.
  • Quote, Fill, Trade — all frozen. Fill is what the venue says happened; Trade is what the account actually booked.
  • MarketDataFeed — the subject. SimulatedExchange, AlertService and Watchlist are its observers; RestingOrder is the venue's own copy of a working order.
  • BrokerageStore holds one AccountState and one lock per account; AccountUnitOfWork is the transaction boundary; OrderService is the facade and the only writer.

Multiplicities: account 1 -> 1 portfolio, portfolio 1 -> * holdings, account 1 -> * orders, order 1 -> * trades, feed 1 -> * listeners.

Class diagram

The domain: an account, its holdings, and the two kinds of order.

classDiagram
    class Account {
        +id: str
        +cash: Money
        +reserved_cash: Money
        +available_cash() Money
        +reserve_cash(amount)
        +release_cash(amount)
        +debit(amount)
        +credit(amount)
    }
    class Portfolio {
        +holdings: Dict~str,Holding~
        +holding(symbol) Holding
        +value(prices) Money
    }
    class Holding {
        +symbol: str
        +quantity: int
        +reserved: int
        +average_cost: Money
        +available() int
        +add(quantity, price)
        +remove(quantity)
    }
    class Stock {
        +symbol: str
        +name: str
    }
    class Quote {
        +symbol: str
        +price: Money
        +at: float
    }
    class Fill {
        +fill_id: str
        +order_id: str
        +quantity: int
        +price: Money
    }
    class Trade {
        +id: str
        +symbol: str
        +quantity: int
        +price: Money
        +notional: Money
    }
    class Order {
        +id: str
        +side: OrderSide
        +quantity: int
        +filled_quantity: int
        +unit_reserve: Money
        +status: OrderStatus
        +remaining() int
        +is_marketable(quote) bool
        +execution_price(quote) Money
        +reference_price(quote) Money
        +transition_to(status)
        +apply_fill(quantity, price)
    }
    class MarketOrder
    class LimitOrder {
        +limit_price: Money
    }
    class OrderFactory {
        +create(order_type, ...) Order
    }
    class Watchlist {
        +symbols: set
        +on_quote(quote)
        +render() str
    }
    class PriceAlert {
        +threshold: Money
        +matches(quote) bool
        +trigger(at)
    }
    Account "1" *-- "1" Portfolio
    Portfolio "1" *-- "many" Holding
    Order <|-- MarketOrder
    Order <|-- LimitOrder
    OrderFactory ..> Order : creates
    Order "1" --> "many" Trade : settles into
    Fill ..> Trade : becomes
    Holding --> Stock
    Watchlist ..> Quote
    PriceAlert ..> Quote

The services: the feed and its observers, the venue, and the transaction boundary.

classDiagram
    class QuoteListener {
        <<interface>>
        +on_quote(quote)
    }
    class MarketDataFeed {
        -_lock: Lock
        +subscribe(symbol, listener)
        +subscribe_all(listener)
        +publish(quote)
        +last(symbol) Quote
    }
    class AlertService {
        +register(alert) PriceAlert
        +on_quote(quote)
        +triggered() List~PriceAlert~
    }
    class ExchangeGateway {
        <<interface>>
        +submit(order) str
        +cancel(exchange_order_id) bool
    }
    class SimulatedExchange {
        -_book: Dict~str,RestingOrder~
        +connect(on_fill)
        +submit(order) str
        +cancel(exchange_order_id) bool
        +on_quote(quote)
    }
    class RestingOrder {
        +exchange_order_id: str
        +remaining: int
    }
    class OrderService {
        +place_order(...) Order
        +cancel_order(account_id, order_id) Order
        +on_fill(fill) Trade
        +open_orders(account_id) List~Order~
    }
    class BrokerageStore {
        +account_lock(account_id) Lock
        +snapshot(account_id) AccountState
        +publish(state)
        +account_for_order(order_id) str
    }
    class AccountState {
        +account: Account
        +orders: Dict~str,Order~
        +trades_by_fill: Dict~str,Trade~
        +copy() AccountState
    }
    class UnitOfWork {
        <<interface>>
        +commit()
        +rollback()
    }
    class AccountUnitOfWork {
        +state: AccountState
        +commit()
        +rollback()
    }
    class TradeListener {
        <<interface>>
        +on_trade(trade)
    }
    class TradeLog
    class OrderCommand {
        <<interface>>
        +execute() Order
        +undo() Order
    }
    class PlaceOrderCommand
    QuoteListener <|.. SimulatedExchange
    QuoteListener <|.. AlertService
    MarketDataFeed --> "many" QuoteListener : notifies
    ExchangeGateway <|.. SimulatedExchange
    SimulatedExchange "1" o-- "many" RestingOrder
    OrderService --> ExchangeGateway
    OrderService --> MarketDataFeed
    OrderService --> AccountUnitOfWork
    OrderService --> "many" TradeListener : notifies
    UnitOfWork <|.. AccountUnitOfWork
    AccountUnitOfWork --> BrokerageStore
    AccountUnitOfWork --> AccountState
    TradeListener <|.. TradeLog
    OrderCommand <|.. PlaceOrderCommand

Design patterns applied

Pattern Where Why it earns its place
Observer MarketDataFeed -> SimulatedExchange, AlertService, Watchlist One tick drives three unrelated reactions. Adding trailing stops or a chart service is a new listener, and the feed never learns their names.
State (transition table) OrderStatus + ORDER_TRANSITIONS + Order.transition_to Six states, one table, every illegal move rejected in one place. Six State classes would be ceremony; say that and show the parametrized test.
Template Method / polymorphism Order.is_marketable, execution_price, reference_price The service never asks "is this a limit order?". Adding stop-loss is a third subclass and one registry branch.
Factory Method OrderFactory.create Turns ("limit", 395.00) from the API into the right class, and rejects a market order carrying a limit price.
Unit of Work AccountUnitOfWork A settled fill touches cash, reservation, holding, order status and the trade row. All five commit together or none do.
Adapter behind a Protocol ExchangeGateway / SimulatedExchange The venue is someone else's system. Tests inject a simulator with a partial-fill knob; production injects FIX or REST.
Command PlaceOrderCommand Placement and cancellation are one request-object pair, which is what an order-entry queue or a "cancel my last order" button needs.
Facade OrderService The app calls four methods. Reservation, transaction, venue and notification are all behind them.

What was deliberately not used: a Singleton feed or store. Both are created in main and injected, so tests build a dozen independent brokerages. Also no Memento for order history — the trade rows already are the history, and duplicating them into snapshots would create two truths.

Key flows

A limit buy from reservation to settlement. Note where the account lock is not held.

sequenceDiagram
    autonumber
    actor U as User
    participant S as OrderService
    participant W as AccountUnitOfWork
    participant A as Account
    participant X as SimulatedExchange
    participant F as MarketDataFeed
    U->>S: place_order(acc-1, MSFT, BUY, 30, LIMIT 395.00)
    S->>W: open (snapshot under the account lock)
    S->>A: reserve_cash(30 x 395.00)
    A-->>S: ok, available_cash reduced
    S->>W: store order NEW, commit
    Note over S,X: the account lock is released before any network call
    S->>X: submit(order)
    X-->>S: exchange_order_id
    S->>W: acknowledge, NEW to SUBMITTED
    F-)X: on_quote(MSFT 394.00)
    X-)S: on_fill(fill_id, 20 shares at 394.00)
    S->>W: open, check fill_id not seen
    S->>A: release_cash(20 x 395.00), debit(20 x 394.00), holding.add(20)
    S->>W: order to PARTIALLY_FILLED, store trade by fill_id, commit
    S-)U: on_trade notification

Order lifecycle. The transition table is the code; this diagram is the picture of it.

stateDiagram-v2
    [*] --> NEW : validated, funds or shares reserved
    NEW --> SUBMITTED : venue acknowledged
    NEW --> REJECTED : venue refused
    NEW --> CANCELLED : pulled before acknowledgement
    SUBMITTED --> PARTIALLY_FILLED : first slice executes
    SUBMITTED --> FILLED : executed in one go
    SUBMITTED --> CANCELLED : client cancels
    SUBMITTED --> REJECTED : venue rejects late
    PARTIALLY_FILLED --> PARTIALLY_FILLED : another slice
    PARTIALLY_FILLED --> FILLED : last slice
    PARTIALLY_FILLED --> CANCELLED : client cancels the rest
    FILLED --> [*]
    CANCELLED --> [*]
    REJECTED --> [*]

Implementation

Write the vocabulary first, then the account, then the order hierarchy, then the feed, and only then the service that ties them together.

The enums include the transition table. Putting it next to OrderStatus is deliberate: the legal moves are part of the vocabulary, not scattered through the service.

code/lld/stock_brokerage/models.py — enums and transitions
class OrderSide(StrEnum):
    BUY = "buy"
    SELL = "sell"


class OrderType(StrEnum):
    MARKET = "market"  # execute at whatever the feed says now
    LIMIT = "limit"  # execute only at the limit price or better


class OrderStatus(StrEnum):
    NEW = "new"  # validated, funds or shares reserved, not yet acknowledged
    SUBMITTED = "submitted"  # the exchange acknowledged it and it rests on the book
    PARTIALLY_FILLED = "partially_filled"  # some shares traded, the rest still resting
    FILLED = "filled"  # fully executed
    CANCELLED = "cancelled"  # pulled by the client, reservation released
    REJECTED = "rejected"  # the exchange refused it, reservation released


class AlertDirection(StrEnum):
    ABOVE = "above"
    BELOW = "below"


TERMINAL_STATUSES = frozenset({OrderStatus.FILLED, OrderStatus.CANCELLED, OrderStatus.REJECTED})

ORDER_TRANSITIONS: Mapping[OrderStatus, frozenset[OrderStatus]] = {
    OrderStatus.NEW: frozenset({OrderStatus.SUBMITTED, OrderStatus.CANCELLED, OrderStatus.REJECTED}),
    OrderStatus.SUBMITTED: frozenset(
        {OrderStatus.PARTIALLY_FILLED, OrderStatus.FILLED, OrderStatus.CANCELLED, OrderStatus.REJECTED}
    ),
    OrderStatus.PARTIALLY_FILLED: frozenset(
        {OrderStatus.PARTIALLY_FILLED, OrderStatus.FILLED, OrderStatus.CANCELLED}
    ),
    OrderStatus.FILLED: frozenset(),
    OrderStatus.CANCELLED: frozenset(),
    OrderStatus.REJECTED: frozenset(),
}
code/lld/stock_brokerage/models.py — errors
class InsufficientFundsError(ConflictError):
    """Available cash (balance minus reservations) cannot cover the order."""


class InsufficientHoldingsError(ConflictError):
    """The account does not hold enough unreserved shares to sell."""


class OrderStateError(InvalidStateError):
    """The order is not in a state that allows this transition."""


class UnknownEntityError(NotFoundError):
    """No such account, order or symbol."""

Quote, Fill and Trade are frozen. Fill is the venue's claim; Trade is what your ledger booked. Keeping them as separate types is what makes the idempotency check obvious later.

code/lld/stock_brokerage/models.py — market values
@dataclass(frozen=True, slots=True)
class Stock:
    symbol: str
    name: str


@dataclass(frozen=True, slots=True)
class Quote:
    """One price tick from the feed. Immutable, so a listener cannot rewrite history."""

    symbol: str
    price: Money
    at: float


@dataclass(frozen=True, slots=True)
class Fill:
    """An execution report from the exchange. ``fill_id`` is the idempotency key."""

    fill_id: str
    order_id: str
    quantity: int
    price: Money
    at: float


@dataclass(frozen=True, slots=True)
class Trade:
    """The settled result of one fill: what actually moved in the account."""

    id: str
    order_id: str
    account_id: str
    symbol: str
    side: OrderSide
    quantity: int
    price: Money
    notional: Money
    at: float

The account is where "available" is defined. Every validation in the system reduces to available_cash() or Holding.available(), which is why a reservation is enough to make concurrent orders safe.

code/lld/stock_brokerage/models.py — account and portfolio
@dataclass(slots=True)
class Holding:
    """Shares of one symbol. ``reserved`` is what open sell orders have claimed."""

    symbol: str
    quantity: int = 0
    reserved: int = 0
    average_cost: Money = Money(0)

    def available(self) -> int:
        return self.quantity - self.reserved

    def reserve(self, quantity: int) -> None:
        if quantity > self.available():
            raise InsufficientHoldingsError(
                f"{self.symbol}: {self.available()} shares available, {quantity} requested"
            )
        self.reserved += quantity

    def release(self, quantity: int) -> None:
        self.reserved = max(0, self.reserved - quantity)

    def add(self, quantity: int, price: Money) -> None:
        """Weighted average cost; the rounding here is for display, never for cash."""
        total = self.average_cost * self.quantity + price * quantity
        self.quantity += quantity
        self.average_cost = Money(total.cents // self.quantity, price.currency)

    def remove(self, quantity: int) -> None:
        if quantity > self.quantity:
            raise InsufficientHoldingsError(f"{self.symbol}: cannot remove {quantity} of {self.quantity}")
        self.quantity -= quantity
        self.reserved = max(0, self.reserved - quantity)
        if self.quantity == 0:
            self.average_cost = Money(0, self.average_cost.currency)

    def copy(self) -> Holding:
        return Holding(self.symbol, self.quantity, self.reserved, self.average_cost)


@dataclass(slots=True)
class Portfolio:
    account_id: str
    holdings: dict[str, Holding] = field(default_factory=dict)

    def holding(self, symbol: str) -> Holding:
        return self.holdings.setdefault(symbol, Holding(symbol))

    def value(self, prices: Mapping[str, Money]) -> Money:
        total = Money(0)
        for symbol, holding in self.holdings.items():
            if symbol in prices:
                total = total + prices[symbol] * holding.quantity
        return total

    def copy(self) -> Portfolio:
        return Portfolio(self.account_id, {s: h.copy() for s, h in self.holdings.items()})


@dataclass(slots=True)
class Account:
    """Cash plus a portfolio. ``reserved_cash`` is what open buy orders have claimed."""

    id: str
    owner_id: str
    cash: Money
    portfolio: Portfolio
    reserved_cash: Money = Money(0)

    @classmethod
    def open(cls, account_id: str, owner_id: str, cash: Money) -> Account:
        return cls(account_id, owner_id, cash, Portfolio(account_id))

    def available_cash(self) -> Money:
        return self.cash - self.reserved_cash

    def reserve_cash(self, amount: Money) -> None:
        if amount > self.available_cash():
            raise InsufficientFundsError(f"{self.available_cash()} available, {amount} requested")
        self.reserved_cash = self.reserved_cash + amount

    def release_cash(self, amount: Money) -> None:
        self.reserved_cash = Money(max(0, (self.reserved_cash - amount).cents), amount.currency)

    def debit(self, amount: Money) -> None:
        if amount > self.cash:
            raise InsufficientFundsError(f"balance {self.cash} cannot cover {amount}")
        self.cash = self.cash - amount

    def credit(self, amount: Money) -> None:
        self.cash = self.cash + amount

    def copy(self) -> Account:
        return Account(self.id, self.owner_id, self.cash, self.portfolio.copy(), self.reserved_cash)

Watchlists and alerts are listeners with three lines of logic each — the whole point of Observer is that they cost this little.

code/lld/stock_brokerage/models.py — watchlist and alerts
@dataclass(slots=True)
class Watchlist:
    """A named set of symbols that caches the last price it heard. Observer of the feed."""

    id: str
    owner_id: str
    symbols: set[str] = field(default_factory=set)
    last_price: dict[str, Money] = field(default_factory=dict)

    def add(self, symbol: str) -> None:
        self.symbols.add(symbol)

    def on_quote(self, quote: Quote) -> None:
        if quote.symbol in self.symbols:
            self.last_price[quote.symbol] = quote.price

    def render(self) -> str:
        return ", ".join(f"{s} {self.last_price[s]}" for s in sorted(self.symbols) if s in self.last_price)


@dataclass(slots=True)
class PriceAlert:
    """Fires once when the price crosses the threshold, then stays triggered."""

    id: str
    owner_id: str
    symbol: str
    direction: AlertDirection
    threshold: Money
    triggered_at: float | None = None

    def matches(self, quote: Quote) -> bool:
        if self.triggered_at is not None or quote.symbol != self.symbol:
            return False
        if self.direction is AlertDirection.ABOVE:
            return quote.price >= self.threshold
        return quote.price <= self.threshold

    def trigger(self, at: float) -> None:
        if self.triggered_at is not None:
            raise ValidationError(f"alert {self.id} already fired")
        self.triggered_at = at

The order hierarchy carries unit_reserve, the cash held per share. Releasing a partial fill is then a multiplication, never a division, so no cent is ever stranded.

code/lld/stock_brokerage/orders.py
@dataclass(slots=True, kw_only=True)
class Order:
    """An intention to trade, plus everything needed to unwind its reservation.

    ``unit_reserve`` is the cash reserved per share for a buy; releasing a
    partial fill is then ``unit_reserve * filled_shares``, which is exact in
    cents and needs no division.
    """

    id: str
    account_id: str
    symbol: str
    side: OrderSide
    quantity: int
    created_at: float
    status: OrderStatus = OrderStatus.NEW
    filled_quantity: int = 0
    filled_notional: Money = Money(0)
    unit_reserve: Money = Money(0)
    exchange_order_id: str | None = None

    order_type: ClassVar[OrderType]

    def __post_init__(self) -> None:
        if self.quantity <= 0:
            raise ValidationError("order quantity must be positive")

    def remaining(self) -> int:
        return self.quantity - self.filled_quantity

    def is_open(self) -> bool:
        return self.status in (OrderStatus.NEW, OrderStatus.SUBMITTED, OrderStatus.PARTIALLY_FILLED)

    def is_marketable(self, quote: Quote) -> bool:
        raise NotImplementedError

    def execution_price(self, quote: Quote) -> Money:
        raise NotImplementedError

    def reference_price(self, quote: Quote) -> Money:
        """The price used to size the cash reservation before anything trades."""
        raise NotImplementedError

    def average_price(self) -> Money:
        if self.filled_quantity == 0:
            return Money(0, self.filled_notional.currency)
        cents = self.filled_notional.cents
        return Money((cents + self.filled_quantity // 2) // self.filled_quantity, self.filled_notional.currency)

    def transition_to(self, status: OrderStatus) -> None:
        if status not in ORDER_TRANSITIONS[self.status]:
            raise OrderStateError(f"order {self.id}: {self.status} cannot become {status}")
        self.status = status

    def apply_fill(self, quantity: int, price: Money) -> None:
        """Book shares against the order and move it to PARTIALLY_FILLED or FILLED."""
        if quantity <= 0 or quantity > self.remaining():
            raise ValidationError(f"order {self.id}: cannot fill {quantity} of {self.remaining()} remaining")
        self.filled_quantity += quantity
        self.filled_notional = self.filled_notional + price * quantity
        self.transition_to(OrderStatus.FILLED if self.remaining() == 0 else OrderStatus.PARTIALLY_FILLED)

    def copy(self) -> Order:
        return type(self)(**{f.name: getattr(self, f.name) for f in fields(self)})


# 5% headroom: a market buy reserves slightly more than the last print, because
# the price can move between the reservation and the fill.
MARKET_RESERVE_BASIS_POINTS = 10_500


@dataclass(slots=True, kw_only=True)
class MarketOrder(Order):
    """Trades at whatever the feed prints next. Always marketable."""

    order_type: ClassVar[OrderType] = OrderType.MARKET

    def is_marketable(self, quote: Quote) -> bool:
        return True

    def execution_price(self, quote: Quote) -> Money:
        return quote.price

    def reference_price(self, quote: Quote) -> Money:
        return Money(quote.price.cents * MARKET_RESERVE_BASIS_POINTS // 10_000, quote.price.currency)


@dataclass(slots=True, kw_only=True)
class LimitOrder(Order):
    """Trades only at the limit or better, so the reservation is exact."""

    order_type: ClassVar[OrderType] = OrderType.LIMIT
    limit_price: Money

    def __post_init__(self) -> None:
        # Named base call, not ``super()``: ``slots=True`` rebuilds the class object
        # and the zero-argument ``super()`` cell would still point at the old one.
        Order.__post_init__(self)
        if self.limit_price.cents <= 0:
            raise ValidationError("limit price must be positive")

    def is_marketable(self, quote: Quote) -> bool:
        if self.side is OrderSide.BUY:
            return quote.price <= self.limit_price
        return quote.price >= self.limit_price

    def execution_price(self, quote: Quote) -> Money:
        if self.side is OrderSide.BUY:
            return min(quote.price, self.limit_price)
        return max(quote.price, self.limit_price)

    def reference_price(self, quote: Quote) -> Money:
        return self.limit_price


class OrderFactory:
    """Factory Method: the API sends ``"limit"`` plus a price, the registry picks the class."""

    @staticmethod
    def create(
        order_type: OrderType | str,
        *,
        order_id: str,
        account_id: str,
        symbol: str,
        side: OrderSide,
        quantity: int,
        created_at: float,
        limit_price: Money | None = None,
    ) -> Order:
        kind = OrderType(order_type)
        common = {
            "id": order_id,
            "account_id": account_id,
            "symbol": symbol,
            "side": side,
            "quantity": quantity,
            "created_at": created_at,
        }
        if kind is OrderType.MARKET:
            if limit_price is not None:
                raise ValidationError("a market order cannot carry a limit price")
            return MarketOrder(**common)
        if limit_price is None:
            raise ValidationError("a limit order needs a limit price")
        return LimitOrder(**common, limit_price=limit_price)

The feed fans out under a lock it does not hold while calling listeners; the venue keeps its own remaining counter because the broker replaces its Order object on every commit.

code/lld/stock_brokerage/market.py — feed
class QuoteListener(Protocol):
    """Observer interface: anything that reacts to a price tick."""

    def on_quote(self, quote: Quote) -> None: ...


class MarketDataFeed:
    """Fans a tick out to every listener for that symbol, then to the wildcards.

    ``_lock`` guards the subscription map and the last-price cache only.
    Listeners are called *outside* it: a slow alert must not stall the feed, and
    a listener that publishes back into the feed must not deadlock.
    """

    def __init__(self) -> None:
        self._lock = threading.Lock()
        self._by_symbol: dict[str, list[QuoteListener]] = {}
        self._all: list[QuoteListener] = []
        self._last: dict[str, Quote] = {}

    def subscribe(self, symbol: str, listener: QuoteListener) -> None:
        with self._lock:
            self._by_symbol.setdefault(symbol, []).append(listener)

    def subscribe_all(self, listener: QuoteListener) -> None:
        with self._lock:
            self._all.append(listener)

    def publish(self, quote: Quote) -> None:
        with self._lock:
            self._last[quote.symbol] = quote
            listeners = [*self._by_symbol.get(quote.symbol, ()), *self._all]
        for listener in listeners:
            listener.on_quote(quote)

    def last(self, symbol: str) -> Quote:
        with self._lock:
            try:
                return self._last[symbol]
            except KeyError:
                raise UnknownEntityError(f"no price yet for {symbol}") from None
code/lld/stock_brokerage/market.py — exchange gateway
class ExchangeGateway(Protocol):
    """The venue, as the broker sees it. Everything below this line is someone else's system."""

    def submit(self, order: Order) -> str: ...

    def cancel(self, exchange_order_id: str) -> bool: ...


@dataclass(slots=True)
class RestingOrder:
    """The venue's own copy of an order. It owns the remaining quantity, not the broker."""

    exchange_order_id: str
    order: Order
    remaining: int


class SimulatedExchange:
    """A stand-in venue: it rests orders and fills them when a tick makes them marketable.

    The venue keeps its own ``remaining`` counter -- the broker's ``Order`` object
    is replaced on every commit, so reading its state from here would be a bug.
    ``max_fill_quantity`` caps how many shares one tick can execute, which is how
    the tests and the demo reproduce partial fills deterministically. Fills are
    pushed to ``on_fill``: the broker's inbound execution report, in effect.
    """

    def __init__(
        self,
        on_fill: Callable[[Fill], None] | None = None,
        clock: Clock | None = None,
        ids: IdGenerator | None = None,
        max_fill_quantity: int | None = None,
    ) -> None:
        self._on_fill = on_fill
        self._clock = clock or SystemClock()
        self._ids = ids or SequentialIdGenerator("F")
        self._max_fill = max_fill_quantity
        self._lock = threading.Lock()
        self._book: dict[str, RestingOrder] = {}

    def connect(self, on_fill: Callable[[Fill], None]) -> None:
        """Wire the broker's execution-report handler once both objects exist."""
        self._on_fill = on_fill

    def submit(self, order: Order) -> str:
        exchange_order_id = self._ids.next_id()
        with self._lock:
            self._book[exchange_order_id] = RestingOrder(exchange_order_id, order, order.remaining())
        return exchange_order_id

    def cancel(self, exchange_order_id: str) -> bool:
        with self._lock:
            return self._book.pop(exchange_order_id, None) is not None

    def on_quote(self, quote: Quote) -> None:
        """Fill one slice of every resting order this tick makes marketable, in submission order."""
        with self._lock:
            exchange_order_ids = list(self._book)
        for exchange_order_id in exchange_order_ids:
            fill = self._slice(exchange_order_id, quote)
            if fill is not None and self._on_fill is not None:
                self._on_fill(fill)  # outside the lock: the broker calls back into us

    def _slice(self, exchange_order_id: str, quote: Quote) -> Fill | None:
        with self._lock:
            resting = self._book.get(exchange_order_id)
            if resting is None or resting.order.symbol != quote.symbol:
                return None
            if not resting.order.is_marketable(quote) or resting.remaining <= 0:
                return None
            quantity = resting.remaining if self._max_fill is None else min(resting.remaining, self._max_fill)
            resting.remaining -= quantity
            if resting.remaining == 0:
                self._book.pop(exchange_order_id, None)
            price = resting.order.execution_price(quote)
            return Fill(self._ids.next_id(), resting.order.id, quantity, price, self._clock.now())

    def resting(self) -> Iterable[str]:
        with self._lock:
            return list(self._book)

The store hands out snapshots and takes back whole states; the Unit of Work is the five-things-at-once boundary.

code/lld/stock_brokerage/store.py — unit of work
class UnitOfWork(Protocol):
    """One transaction boundary over one account. ``state`` is the working copy."""

    state: AccountState

    def commit(self) -> None: ...

    def rollback(self) -> None: ...


class AccountUnitOfWork:
    """Cash, reservation, holding, order status and the trade row commit together.

    A settled fill touches five things. If the process died between the debit
    and the holding update, the account would have paid for shares it does not
    own -- so all five happen on a private copy that ``commit`` publishes in one
    assignment, and any exception leaves the stored state untouched.
    """

    def __init__(self, store: BrokerageStore, account_id: str) -> None:
        self._store = store
        self._account_id = account_id
        self._committed = False
        self.state = store.snapshot(account_id)

    def __enter__(self) -> Self:
        return self

    def __exit__(
        self,
        exc_type: type[BaseException] | None,
        exc: BaseException | None,
        tb: TracebackType | None,
    ) -> None:
        if not self._committed:
            self.rollback()

    def commit(self) -> None:
        self._store.publish(self.state)
        self._committed = True

    def rollback(self) -> None:
        self.state = self._store.snapshot(self._account_id)

place_order and on_fill are the two methods to write on the whiteboard. Read the docstrings: the lock is released before the venue call, and the fill id short-circuits a redelivery before anything moves.

code/lld/stock_brokerage/services.py — order service
class OrderService:
    """Place, cancel and settle. Every method that moves money takes the account lock."""

    def __init__(
        self,
        store: BrokerageStore,
        feed: MarketDataFeed,
        exchange: ExchangeGateway,
        clock: Clock | None = None,
        ids: IdGenerator | None = None,
        listeners: Iterable[TradeListener] = (),
    ) -> None:
        self._store = store
        self._feed = feed
        self._exchange = exchange
        self._clock = clock or SystemClock()
        self._ids = ids or SequentialIdGenerator("O")
        self._listeners = list(listeners)

    def place_order(
        self,
        account_id: str,
        symbol: str,
        side: OrderSide,
        quantity: int,
        order_type: OrderType | str = OrderType.MARKET,
        limit_price: Money | None = None,
    ) -> Order:
        """Reserve funds or shares, persist, then hand the order to the venue.

        The exchange call happens *after* the transaction commits and *outside*
        the account lock: never hold a lock across a network call. The cost is
        that a fill can arrive before the acknowledgement lands, which
        ``_acknowledge`` handles by leaving an already-progressed order alone.
        """
        self._store.stock(symbol)
        quote = self._feed.last(symbol)
        with self._store.account_lock(account_id):
            with AccountUnitOfWork(self._store, account_id) as uow:
                order = OrderFactory.create(
                    order_type,
                    order_id=self._ids.next_id(),
                    account_id=account_id,
                    symbol=symbol,
                    side=side,
                    quantity=quantity,
                    created_at=self._clock.now(),
                    limit_price=limit_price,
                )
                self._reserve(uow.state, order, quote_price=order.reference_price(quote))
                uow.state.orders[order.id] = order
                uow.commit()
        self._store.index_order(order.id, account_id)
        try:
            exchange_order_id = self._exchange.submit(order)
        except Exception:
            self._finish(account_id, order.id, OrderStatus.REJECTED)
            raise
        return self._acknowledge(account_id, order.id, exchange_order_id)

    def cancel_order(self, account_id: str, order_id: str) -> Order:
        """Release whatever is still reserved, then pull the order off the book."""
        order = self._finish(account_id, order_id, OrderStatus.CANCELLED)
        if order.exchange_order_id is not None:
            self._exchange.cancel(order.exchange_order_id)
        return order

    def on_fill(self, fill: Fill) -> Trade:
        """Settle one execution report. Idempotent: a repeated fill id returns the first trade."""
        account_id = self._store.account_for_order(fill.order_id)
        with self._store.account_lock(account_id):
            with AccountUnitOfWork(self._store, account_id) as uow:
                seen = uow.state.trades_by_fill.get(fill.fill_id)
                if seen is not None:
                    return seen  # duplicate delivery: no second debit, no second trade
                order = uow.state.orders[fill.order_id]
                if order.status in TERMINAL_STATUSES:
                    raise OrderStateError(f"order {order.id} is {order.status}; fill {fill.fill_id} arrived too late")
                trade = self._settle(uow.state, order, fill)
                uow.state.trades.append(trade)
                uow.state.trades_by_fill[fill.fill_id] = trade
                uow.commit()
        for listener in self._listeners:
            listener.on_trade(trade)  # outside the lock
        return trade

    # -- queries ---------------------------------------------------------------------
    def account(self, account_id: str) -> Account:
        return self._store.snapshot(account_id).account

    def order(self, account_id: str, order_id: str) -> Order:
        try:
            return self._store.snapshot(account_id).orders[order_id]
        except KeyError:
            raise UnknownEntityError(f"unknown order {order_id}") from None

    def trades(self, account_id: str) -> list[Trade]:
        return self._store.snapshot(account_id).trades

    def open_orders(self, account_id: str) -> list[Order]:
        return [o for o in self._store.snapshot(account_id).orders.values() if o.is_open()]

    # -- internals -------------------------------------------------------------------
    @staticmethod
    def _reserve(state: AccountState, order: Order, quote_price: Money) -> None:
        """Buy: hold cash at the reference price. Sell: hold the shares themselves."""
        if order.side is OrderSide.BUY:
            order.unit_reserve = quote_price
            state.account.reserve_cash(quote_price * order.quantity)
        else:
            state.account.portfolio.holding(order.symbol).reserve(order.quantity)

    def _settle(self, state: AccountState, order: Order, fill: Fill) -> Trade:
        notional = fill.price * fill.quantity
        holding = state.account.portfolio.holding(order.symbol)
        if order.side is OrderSide.BUY:
            state.account.release_cash(order.unit_reserve * fill.quantity)
            state.account.debit(notional)
            holding.add(fill.quantity, fill.price)
        else:
            holding.remove(fill.quantity)
            state.account.credit(notional)
        order.apply_fill(fill.quantity, fill.price)
        if order.status is OrderStatus.FILLED:
            self._release_remainder(state, order)
        return Trade(
            id=self._ids.next_id(),
            order_id=order.id,
            account_id=order.account_id,
            symbol=order.symbol,
            side=order.side,
            quantity=fill.quantity,
            price=fill.price,
            notional=notional,
            at=fill.at,
        )

    @staticmethod
    def _release_remainder(state: AccountState, order: Order) -> None:
        """Give back what the unfilled part of the order was still holding."""
        if order.side is OrderSide.BUY:
            state.account.release_cash(order.unit_reserve * order.remaining())
        else:
            state.account.portfolio.holding(order.symbol).release(order.remaining())

    def _acknowledge(self, account_id: str, order_id: str, exchange_order_id: str) -> Order:
        with self._store.account_lock(account_id):
            with AccountUnitOfWork(self._store, account_id) as uow:
                order = uow.state.orders[order_id]
                order.exchange_order_id = exchange_order_id
                if order.status is OrderStatus.NEW:
                    order.transition_to(OrderStatus.SUBMITTED)  # a fill may already have moved it on
                uow.commit()
                return order

    def _finish(self, account_id: str, order_id: str, status: OrderStatus) -> Order:
        with self._store.account_lock(account_id):
            with AccountUnitOfWork(self._store, account_id) as uow:
                order = uow.state.orders.get(order_id)
                if order is None:
                    raise UnknownEntityError(f"unknown order {order_id}")
                if not order.is_open():
                    raise OrderStateError(f"order {order_id} is already {order.status}")
                self._release_remainder(uow.state, order)
                order.transition_to(status)
                uow.commit()
                return order

The demo runs a full session: a market buy, a limit buy that fills in two slices, a redelivered report, a sell that trips an alert, and a cancellation.

code/lld/stock_brokerage/demo.py
"""One session: a market buy, a limit buy that fills in two slices, a duplicate report, a sell."""

from common import FakeClock, Money, SequentialIdGenerator
from lld.stock_brokerage.market import AlertService, MarketDataFeed, SimulatedExchange
from lld.stock_brokerage.models import (
    Account,
    AlertDirection,
    Fill,
    OrderSide,
    OrderType,
    PriceAlert,
    Quote,
    Stock,
    Watchlist,
)
from lld.stock_brokerage.services import OrderService
from lld.stock_brokerage.store import BrokerageStore


def tick(feed: MarketDataFeed, clock: FakeClock, symbol: str, price: str) -> None:
    clock.advance(60)
    feed.publish(Quote(symbol, Money.of(price), clock.now()))


def main() -> None:
    clock = FakeClock(start=1_700_000_000)
    store = BrokerageStore()
    store.list_stock(Stock("AAPL", "Apple"))
    store.list_stock(Stock("MSFT", "Microsoft"))
    store.open_account(Account.open("acc-1", "ada", Money.of("50000.00")))

    feed = MarketDataFeed()
    exchange = SimulatedExchange(clock=clock, ids=SequentialIdGenerator("F"), max_fill_quantity=20)
    service = OrderService(store, feed, exchange, clock=clock, ids=SequentialIdGenerator("O"))
    fills: list[Fill] = []

    def settle(fill: Fill) -> None:
        fills.append(fill)
        service.on_fill(fill)

    exchange.connect(settle)
    alerts = AlertService(clock=clock)
    alerts.register(PriceAlert("al-1", "ada", "AAPL", AlertDirection.ABOVE, Money.of("190.00")))
    watchlist = Watchlist("wl-1", "ada", {"AAPL", "MSFT"})
    for listener in (exchange, alerts, watchlist):
        feed.subscribe_all(listener)

    tick(feed, clock, "AAPL", "185.00")
    tick(feed, clock, "MSFT", "400.00")
    buy = service.place_order("acc-1", "AAPL", OrderSide.BUY, 20, OrderType.MARKET)
    print(f"{buy.id} market BUY 20 AAPL -> {buy.status}, reserved {service.account('acc-1').reserved_cash}")
    tick(feed, clock, "AAPL", "186.50")
    account = service.account("acc-1")
    print(f"filled at {service.order('acc-1', buy.id).average_price()}, cash {account.cash}, reserved {account.reserved_cash}")

    limit = service.place_order("acc-1", "MSFT", OrderSide.BUY, 30, OrderType.LIMIT, Money.of("395.00"))
    print(f"{limit.id} limit BUY 30 MSFT at 395.00 -> {limit.status}, reserved {service.account('acc-1').reserved_cash}")
    tick(feed, clock, "MSFT", "398.00")
    print(f"tick 398.00: still {service.order('acc-1', limit.id).status}, 0 shares")
    tick(feed, clock, "MSFT", "394.00")
    partial = service.order("acc-1", limit.id)
    print(f"tick 394.00: {partial.status} {partial.filled_quantity}/{partial.quantity}, cash {service.account('acc-1').cash}")
    service.on_fill(fills[-1])
    print(f"duplicate report {fills[-1].fill_id} replayed: cash still {service.account('acc-1').cash}")
    tick(feed, clock, "MSFT", "393.00")
    done = service.order("acc-1", limit.id)
    print(f"tick 393.00: {done.status} at average {done.average_price()}, cash {service.account('acc-1').cash}")

    sell = service.place_order("acc-1", "AAPL", OrderSide.SELL, 10, OrderType.LIMIT, Money.of("190.00"))
    tick(feed, clock, "AAPL", "191.00")
    print(f"{sell.id} limit SELL 10 AAPL at 190.00 -> {service.order('acc-1', sell.id).status} at 191.00")
    print(f"alerts fired: {[a.id for a in alerts.triggered()]}")

    stale = service.place_order("acc-1", "AAPL", OrderSide.BUY, 5, OrderType.LIMIT, Money.of("150.00"))
    print(f"{stale.id} rests off-market, reserving {service.account('acc-1').reserved_cash}")
    service.cancel_order("acc-1", stale.id)
    account = service.account("acc-1")
    print(f"cancelled: reserved back to {account.reserved_cash}, cash {account.cash}")
    prices = {"AAPL": Money.of("191.00"), "MSFT": Money.of("393.00")}
    print(f"portfolio {account.portfolio.value(prices)} across {len(service.trades('acc-1'))} trades")
    print(f"watchlist: {watchlist.render()}")


if __name__ == "__main__":
    main()

Running python -m lld.stock_brokerage.demo prints:

O-1 market BUY 20 AAPL -> submitted, reserved 3885.00 USD
filled at 186.50 USD, cash 46270.00 USD, reserved 0.00 USD
O-3 limit BUY 30 MSFT at 395.00 -> submitted, reserved 11850.00 USD
tick 398.00: still submitted, 0 shares
tick 394.00: partially_filled 20/30, cash 38390.00 USD
duplicate report F-4 replayed: cash still 38390.00 USD
tick 393.00: filled at average 393.67 USD, cash 34460.00 USD
O-6 limit SELL 10 AAPL at 190.00 -> filled at 191.00
alerts fired: ['al-1']
O-8 rests off-market, reserving 750.00 USD
cancelled: reserved back to 0.00 USD, cash 36370.00 USD
portfolio 13700.00 USD across 4 trades
watchlist: AAPL 191.00 USD, MSFT 393.00 USD

Trace the reservation: 20 shares at the last print of 185.00 plus 5% is 194.25 x 20 = 3885.00; the fill at 186.50 costs 3730.00, and the difference goes straight back to available cash.

Concurrency and edge cases

Which lock protects what.

  1. BrokerageStore.account_lock(account_id) guards cash, reservations, holdings, order status and the trade index of one account. Two accounts trading the same symbol never contend, which is the granularity you want: contention follows users, not symbols.
  2. BrokerageStore._registry_lock guards the account, symbol and order-to-account dictionaries, and is held for a lookup only.
  3. MarketDataFeed._lock guards the subscription map, and SimulatedExchange._lock guards the book. Both are released before any callback fires.

Lock ordering. The only nesting is account lock then registry lock, always in that direction, and nothing else nests. That is why there is no deadlock to reason about: locks are leaves or a single two-level chain.

Why the venue call is outside the lock. An uncontended mutex costs about 17 ns and a same-datacenter round trip about 500 µs (see the latency cheatsheet); the network call is roughly 500 000 / 17, near 30 000 times more expensive. Holding an account lock across it would serialise a user's entire session behind one slow venue. The price you pay is that a fill can arrive before the acknowledgement commits, so _acknowledge only moves NEW -> SUBMITTED if the order is still NEW.

Idempotent settlement. AccountState.trades_by_fill maps fill id to the trade it produced. on_fill checks it first, inside the transaction, and returns the stored trade on a repeat. That is effectively-once delivery in three lines: at-least-once transport plus an idempotent consumer.

Partial fills. Every slice releases unit_reserve x slice_quantity and debits the actual traded notional. When the order reaches a terminal state, _release_remainder gives back what the unfilled part was still holding. The arithmetic is exact because unit_reserve is a per-share Money and quantities are ints.

Common mistake

Checking the balance and then debiting it at fill time, with nothing in between. Two orders both pass the check, both get sent, and both come back filled — and now the account is overdrawn by a real amount of real money. Reserve at placement, release on settlement or cancellation, and validate against available_cash(), never cash.

Other edge cases handled: a market order carrying a limit price (rejected by the factory); a sell of shares an open sell order has already claimed; a fill larger than the remaining quantity; cancelling a filled or already cancelled order; a fill arriving after a cancel (refused, with a note that the venue is really the authority); an alert that would fire on every tick above its threshold (it fires once); an order for an unlisted symbol or one with no price yet.

Extensibility and follow-ups

  • Stop and stop-limit orders: a third Order subclass whose is_marketable compares against a trigger, plus one branch in OrderFactory. Nothing in OrderService changes — name that seam when asked.
  • Time in force (day, good-till-cancelled, immediate-or-cancel): a policy object consulted by the venue adapter at the end of each session; IOC becomes "cancel the remainder after the first slice".
  • A real venue: implement ExchangeGateway over FIX or a REST API and turn on_fill into a webhook handler. The idempotency key is already the venue's execution id, so redelivery is free.
  • Margin: available_cash() becomes cash + buying_power - reserved, computed by a MarginPolicy. The reservation machinery does not change, which is the point of having it in one method.
  • The matching engine: when the interviewer asks "now build the exchange", you are into Design a stock exchange — price-time priority, sequenced order books, deterministic replay.
  • Audit and compliance: trades already carry account, order, price and time. Add an append-only event stream fed by TradeListener, and reconstruct any account by replay.

Interview tip

Say "reserve, submit, settle, release" out loud before you write any code, and draw the four boxes. Interviewers grade this problem mostly on whether reservations exist at all; candidates who only debit on fill lose the round in the first ten minutes regardless of how good the class diagram is.

Tests

tests/test_stock_brokerage.py has 13 cases. The three to walk an interviewer through are partial fills, the duplicate execution report, and the concurrency test that proves reservations are atomic:

code/lld/stock_brokerage/tests/test_stock_brokerage.py — partial fills
def test_partial_fills_accumulate_and_cancelling_releases_the_remainder(clock: FakeClock) -> None:
    service, feed, _, _ = build(clock, max_fill=4)
    quote(feed, clock, "100.00")
    order = service.place_order("acc-1", "AAPL", OrderSide.BUY, 10, OrderType.LIMIT, Money.of("100.00"))
    assert service.account("acc-1").reserved_cash == Money.of("1000.00")  # 10 x the limit

    quote(feed, clock, "99.00")  # one slice of 4 shares
    resting = service.order("acc-1", order.id)
    assert resting.status is OrderStatus.PARTIALLY_FILLED and resting.filled_quantity == 4
    assert service.account("acc-1").reserved_cash == Money.of("600.00")  # 6 shares still held

    cancelled = service.cancel_order("acc-1", order.id)
    assert cancelled.status is OrderStatus.CANCELLED
    account = service.account("acc-1")
    assert account.reserved_cash == Money(0)
    assert account.cash == Money.of("9604.00")  # 10000 - 4 x 99.00
    assert account.portfolio.holding("AAPL").quantity == 4
code/lld/stock_brokerage/tests/test_stock_brokerage.py — idempotent settlement
def test_a_duplicate_execution_report_settles_exactly_once(clock: FakeClock) -> None:
    service, feed, exchange, _ = build(clock)
    seen: list[Fill] = []

    def record_and_settle(fill: Fill) -> None:
        seen.append(fill)
        service.on_fill(fill)

    exchange.connect(record_and_settle)
    quote(feed, clock, "100.00")
    service.place_order("acc-1", "AAPL", OrderSide.BUY, 10, OrderType.MARKET)
    quote(feed, clock, "100.00")

    first = service.trades("acc-1")[0]
    cash_after_first = service.account("acc-1").cash
    replayed = service.on_fill(seen[-1])  # the venue redelivers the same report

    assert replayed is first  # the stored trade comes back, nothing new is booked
    assert service.account("acc-1").cash == cash_after_first
    assert len(service.trades("acc-1")) == 1
    assert service.account("acc-1").portfolio.holding("AAPL").quantity == 10
code/lld/stock_brokerage/tests/test_stock_brokerage.py — concurrency
def test_concurrent_orders_never_reserve_more_cash_than_the_account_holds(clock: FakeClock) -> None:
    service, feed, _, _ = build(clock, cash="5000.00")
    quote(feed, clock, "100.00")  # limit far below market, so nothing fills

    def place(i: int) -> bool:
        try:
            service.place_order("acc-1", "AAPL", OrderSide.BUY, 10, OrderType.LIMIT, Money.of("100.00"))
        except InsufficientFundsError:
            return False
        return True

    with ThreadPoolExecutor(max_workers=10) as pool:
        accepted = list(pool.map(place, range(20)))

    account = service.account("acc-1")
    assert accepted.count(True) == 5  # 5 x 10 shares x 100.00 = the whole balance
    assert account.reserved_cash == Money.of("5000.00")
    assert account.available_cash() == Money(0)
    assert len(service.open_orders("acc-1")) == 5

The rest cover: a market buy reserving with headroom and settling at the traded price; orders beyond the available balance or holding never reaching the venue; a limit order resting through a non-crossing tick and then filling at the better price; the transition table refusing four illegal moves via parametrize; a fill delivered after a cancel; alerts firing once while the watchlist keeps following the feed; and PlaceOrderCommand undoing itself. Run them with uv run pytest code/lld/stock_brokerage -q.

45-minute pacing

Minutes What to do What to say or write
0-5 Clarify Broker or exchange? Order types? Partial fills? Duplicate execution reports? Out of scope: matching engine, margin, options.
5-10 Entities Account, Portfolio, Holding, Order, Fill, Trade, Quote. Say "available cash equals cash minus reserved" while drawing the account.
10-16 Lifecycle Draw the six-state diagram and the transition table before any other code. It anchors the rest of the discussion.
16-32 Code Account.reserve_cash, the Order subclasses, place_order (reserve, commit, submit, acknowledge), then on_fill with the fill-id check.
32-39 Concurrency The per-account lock, why the venue call sits outside it, and the 20-orders-five-succeed test.
39-45 Extensions Stop orders as a subclass, time in force, a real gateway, and the hand-off to the exchange design.