2Brute2Best
πŸ”₯0
B6

Matching Buyers and Sellers Through an Order Book

Pro OnlyMediator <=> spaceship (C++20) std::flat_map (C++23)
⚑ 60-Second Architecture SummaryB6 · Mediator Pattern
Naive Bottleneck→Mediator Pattern Cure
The Naive Bottleneck: O(N^2) tightly coupled mesh of peer connections

Desks maintain direct pointers to peer desks, iterating through counterparties to discover liquidity and negotiate trades. This creates an $O(N^2)$ mesh of pointers, introduces re-entrancy deadlocks, and destroys centralized Price-Time Priority (FIFO) because a desk queries peers sequentially rather than matching the best resting price on the book.

Adding or removing a single desk requires updating pointer registries across all other N - 1 desk objects, creating an unmaintainable web of dependencies.

The Pattern Cure: Mediator Pattern

Define an object that encapsulates how a set of objects interact, promoting loose coupling by keeping objects from referring to each other explicitly.

Instead of trading desks talking directly to one another, all desks communicate exclusively with an OrderBookMediator. Desks submit orders to the mediator, and the mediator manages resting bids/asks according to price-time priority. When a trade matches, the mediator dispatches onFill events to the respective buyer and seller desks. Coupling collapses from O(N^2) to O(N).

Sprint 6 of 9 Β· Coordinating the Matching Engine Hub
Story B β€” Low-Latency Trading System β€” Progressive System Build
1. Where our codebase left off
← B5

In Sprint 5 (B5 Β· Abstract Factory), we ensured each exchange session is instantiated with compatible routing, fee, and validation components. Orders now arrive at our matching engine from diverse trading desks (Retail, Institutional, Prop, Market Maker).

2. What we are building now

We are coordinating order matching and fill notifications across multiple concurrent trading desks operating on the same liquidity pool.

3. The pain point we hit

Desks maintain direct pointers to peer desks, iterating through counterparties to discover liquidity and negotiate trades. This creates an O(N^2) mesh of pointers, introduces re-entrancy deadlocks, and destroys centralized Price-Time Priority (FIFO) because a desk queries peers sequentially rather than matching the best resting price on the book.

4. What this unlocks next
Next: B7 β†’

Using the Mediator pattern, OrderBook acts as a central hub (OrderBookMediator) that decouples all trading desks into an O(N) star topology, enforcing strict Price-Time matching and dispatching onFill callbacks. Next in Sprint 7 (B7 Β· Proxy), thousands of UI terminal widgets and algorithmic trading bots polling live market quotes overwhelm our expensive upstream exchange feed.

01

The product ticket

Ticket Β· B6TRADE-206 Β· Centralize Multi-Desk Order Matching via an OrderBook Mediator

Our institutional trading platform connects multiple independent trading desks (RetailDesk, InstitutionalDesk, PropDesk) buying and selling equities. Counterparties need to discover orders, match crossing trades, and receive instant fill confirmations.

Requirements
  • β€’

    Let multiple buyer and seller trading desks submit limit orders and receive automated fill execution callbacks (onFill).

  • β€’

    Enforce strict Price-Time Priority (FIFO): highest bid matches lowest ask, and older resting orders at the same price level fill first.

  • β€’

    Support partial fills without desks needing to hold direct references or negotiate peer-to-peer.

The next requirement that breaks naive code

New desk types (ArbitrageDesk, MarketMakerDesk) are dynamically connecting and disconnecting at runtime. With N desks, maintaining direct counterparty connections creates an O(N^2) mesh of pointers, causing deadlock risks and violating regulatory best-execution transparency.

02

Step 1 β€” The naive code & why it breaks

Every trading desk maintains a direct list of pointers to every other desk (counterparties_). When placing a buy order, the desk iterates through peers, directly interrogating their inventory.

Naive design (what not to ship) Β· naive.cpp
#include <print>
#include <string>
#include <vector>

// Naive design: Trading desks maintain direct references to every other desk.
// For N desks, this creates N * (N - 1) / 2 connections (O(N^2) mesh).
class NaiveTradingDesk {
    std::string deskId_;
    std::vector<NaiveTradingDesk*> counterparties_;

public:
    explicit NaiveTradingDesk(std::string id) : deskId_(std::move(id)) {}

    void addCounterparty(NaiveTradingDesk* other) {
        counterparties_.push_back(other);
    }

    const std::string& id() const { return deskId_; }

    // Direct peer-to-peer negotiation: Desk A interrogates Desk B directly.
    bool directMatch(const std::string& symbol, double price, int qty, const std::string& buyerId) {
        // Hardcoded matching check: Desk answers for itself without any centralized price discovery
        if (symbol == "TCS" && price >= 3500.0 && qty <= 100) {
            std::println("[DIRECT MATCH] Seller {} traded {} shares with Buyer {} at Rs.{:.2f}",
                         deskId_, qty, buyerId, price);
            return true;
        }
        return false;
    }

    void submitBuyOrder(const std::string& symbol, double price, int qty) {
        std::println("{} searching {} counterparties for best price...", deskId_, counterparties_.size());
        for (auto* peer : counterparties_) {
            if (peer->directMatch(symbol, price, qty, deskId_)) {
                return; // Matched first peer found, ignoring price-time priority of other desks!
            }
        }
        std::println("{} found no matching counterparty.", deskId_);
    }
};

int main() {
    NaiveTradingDesk deskA("Desk-Alpha");
    NaiveTradingDesk deskB("Desk-Bravo");
    NaiveTradingDesk deskC("Desk-Charlie");

    // Tangled N^2 mesh setup: Every desk must know every other desk
    deskA.addCounterparty(&deskB);
    deskA.addCounterparty(&deskC);
    deskB.addCounterparty(&deskA);
    deskB.addCounterparty(&deskC);
    deskC.addCounterparty(&deskA);
    deskC.addCounterparty(&deskB);

    deskA.submitBuyOrder("TCS", 3550.0, 50);
}
O(N^2) tightly coupled mesh of peer connections

Adding or removing a single desk requires updating pointer registries across all other N - 1 desk objects, creating an unmaintainable web of dependencies.

Loss of centralized Price-Time Priority

A desk queries peers sequentially in loop order; Desk A might match Desk C at Rs.3550 simply because Desk C appeared earlier in its peer vector, ignoring a resting ask of Rs.3500 on Desk B.

Re-entrancy loops and concurrency deadlocks

Desk A calls Desk B's negotiation method; Desk B updates its state and calls back into Desk A, causing stack overflow, double execution, or mutex deadlock.

03

Step 2 β€” The fix: Mediator Pattern

Core idea in one sentence

Define an object that encapsulates how a set of objects interact, promoting loose coupling by keeping objects from referring to each other explicitly.

Instead of trading desks talking directly to one another, all desks communicate exclusively with an OrderBookMediator. Desks submit orders to the mediator, and the mediator manages resting bids/asks according to price-time priority. When a trade matches, the mediator dispatches onFill events to the respective buyer and seller desks. Coupling collapses from O(N^2) to O(N).

Pattern roles in our story
Mediator Interface

OrderBookMediator β€” defines the contract (registerDesk, placeOrder) for registering colleagues and accepting incoming orders.

Concrete Mediator

OrderBook β€” manages resting order queues, executes price-time matching, and notifies matched desks via onFill.

Colleague Base Class

TradingDesk β€” stores a pointer to OrderBookMediator; sends orders to the mediator and receives fill callbacks.

Concrete Colleagues

InstitutionalDesk, RetailDesk β€” execute trades without any knowledge of who took the opposite side.

Brute2Best Pro Content

Unlock Full UML Diagram & C++23 Solution

The interactive UML architecture diagrams, refactored C++23 code, real-world extensions, and interview Q&A are part of Brute2Best Pro. All 7 foundation chapters are 100% free.

All 440 visual dry runs & algorithms
Interactive step-by-step playback with pointer & array state transitions
52 comprehensive LLD chapters
Interactive UML diagrams, real-world stories (Food Delivery, Trading, RPG), and practice solutions
40 C++ basics labs & hardware memory models
Vtables, byte layouts, assembly insights, and multi-threading race conditions
Production-ready C++23 source code
Modern idioms, clean contracts, time/space complexity derivations, and interview takeaways

First anchor question per pattern, Part 1 LLD & Module 1 C++ basics are 100% Free forever.

Systems Integration

Related C++ Systems & Algorithmic Foundations

Deep dive into underlying layers