2Brute2Best
πŸ”₯0
B7

Caching & Permission-Gating Paid Market Data

Pro OnlyProxy
⚑ 60-Second Architecture SummaryB7 · Proxy Pattern
Naive Bottleneck→Proxy Pattern Cure
The Naive Bottleneck: Skyrocketing vendor API costs and redundant latency

Every terminal screen and trading bot connects directly to `RemoteMarketDataFeed`. Rapid quote polling racks up astronomical β‚Ή0.50-per-query vendor fees and adds 50–80 ms of network latency per call. Furthermore, ad-hoc `if (tier == "PRO")` checks copy-pasted across callers leak premium Level-2 depth to unauthorized basic accounts.

Every single quote refresh across dozens of open widgets fires a direct HTTP request to the remote exchange feed, wasting money and adding 50ms latency per click.

The Pattern Cure: Proxy Pattern

Provide a surrogate or placeholder for another object to control access to it, presenting the exact same interface to clients.

We create MarketDataProxy, which implements the exact same MarketDataFeed interface as RemoteMarketDataFeed. The proxy holds a std::unique_ptr<MarketDataFeed> pointing to the real feed. When getQuote() is called, the proxy checks its internal timestamped cache: if fresh, it returns immediately; if expired, it fetches from the real feed and updates cache. When getLevel2Depth() is called, the proxy validates userTier_ == UserTier::Pro before delegating. Downstream code depends only on the abstract MarketDataFeed interface.

Sprint 7 of 9 Β· Caching & Rate-Limiting the Market Data Feed
Story B β€” Low-Latency Trading System β€” Progressive System Build
1. Where our codebase left off
← B6

In Sprint 6 (B6 Β· Mediator), we centralized order matching into an OrderBookMediator maintaining Price-Time Priority across all trading desks. To make informed trading decisions, these desks and trader terminals require real-time market data quotes and Level-2 order-book depth.

2. What we are building now

We are integrating MarketDataFeed, which supplies live ticker quotes (getQuote) and Level-2 market depth (getLevel2Depth) to UI widgets and execution algorithms.

3. The pain point we hit

Every terminal screen and trading bot connects directly to RemoteMarketDataFeed. Rapid quote polling racks up astronomical β‚Ή0.50-per-query vendor fees and adds 50–80 ms of network latency per call. Furthermore, ad-hoc if (tier == "PRO") checks copy-pasted across callers leak premium Level-2 depth to unauthorized basic accounts.

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

By inserting a Proxy (MarketDataProxy) implementing the exact same MarketDataFeed interface, we achieve transparent TTL quote caching (Caching Proxy) and enforce subscription authorization (Protection Proxy) with zero client code modifications. Next in Sprint 8 (B8 Β· Template Method), our institutional desk needs to execute large parent orders via TWAP and VWAP algorithms, but duplicated execution workflows risk skipping critical pre-trade compliance checks.

01

The product ticket

Ticket Β· B7TRADE-207 Β· Protect and Cache Paid Market Data with a Proxy

Our trading terminal consumes live market quotes and Level-2 order-book depth from an external partner (RemoteMarketDataFeed). Every query incurs network latency (50–80 ms) and costs β‚Ή0.50 per request in vendor API fees.

Requirements
  • β€’

    Provide real-time ticker quotes (getQuote) and Level-2 market depth (getLevel2Depth) through a uniform MarketDataFeed interface.

  • β€’

    Implement a Caching Proxy with a configurable Time-To-Live (TTL) so repetitive quote requests return instant in-memory responses without hitting the paid remote gateway.

  • β€’

    Implement a Protection Proxy that gates Level-2 order-book depth: only users with a Pro subscription may view depth, while Basic users receive an access exception.

The next requirement that breaks naive code

Downstream consumers (the web trading UI, quantitative execution algos, backtesting tools) must not know whether they are communicating with the real network feed, an in-memory cache, or an access-control validator. The interface contract must be identical.

02

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

Client desks instantiate RemoteMarketDataFeed directly. In every calling method, developers write ad-hoc permission checks (if (tier == "PRO")) and make duplicate network calls for identical quotes.

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

struct Quote {
    std::string symbol;
    double bid;
    double ask;
};

struct MarketDepth {
    std::string symbol;
    std::vector<double> bidPrices;
    std::vector<double> askPrices;
};

// Naive: Direct remote feed without caching or access protection.
class RemoteMarketDataFeed {
    int paidApiCalls_{0};

public:
    Quote fetchQuote(const std::string& symbol) {
        ++paidApiCalls_;
        // Simulates expensive network latency and β‚Ή0.50 vendor charge per call
        std::println("[REMOTE FEED] Fetching paid quote for {} (Total API calls: {}, Incurred fee: Rs.{:.2f})",
                     symbol, paidApiCalls_, paidApiCalls_ * 0.50);
        return Quote{symbol, 2450.0, 2451.5};
    }

    MarketDepth fetchLevel2Depth(const std::string& symbol) {
        ++paidApiCalls_;
        std::println("[REMOTE FEED] Fetching Level-2 depth for {} (Total API calls: {})",
                     symbol, paidApiCalls_);
        return MarketDepth{symbol, {2450.0, 2449.5, 2449.0}, {2451.5, 2452.0, 2452.5}};
    }

    int totalCalls() const noexcept { return paidApiCalls_; }
};

// Callers directly call the remote feed, duplicating access checks and failing to cache
class NaiveClientDesk {
    RemoteMarketDataFeed& feed_;
    std::string userTier_; // "BASIC" or "PRO"

public:
    NaiveClientDesk(RemoteMarketDataFeed& feed, std::string tier)
        : feed_(feed), userTier_(std::move(tier)) {}

    void renderScreen(const std::string& symbol) {
        // Repeated calls hit the network every single time!
        auto q1 = feed_.fetchQuote(symbol);
        auto q2 = feed_.fetchQuote(symbol); // Duplicate network call

        // Ad-hoc permission check scattered in caller code: easy to forget or bypass!
        if (userTier_ == "PRO") {
            auto depth = feed_.fetchLevel2Depth(symbol);
            std::println("Rendered Level-2 depth with {} bid levels.", depth.bidPrices.size());
        } else {
            std::println("Level-2 depth skipped for basic user.");
        }
    }
};

int main() {
    RemoteMarketDataFeed feed;
    NaiveClientDesk desk(feed, "BASIC");

    desk.renderScreen("RELIANCE");
    desk.renderScreen("RELIANCE");
    return 0;
}
Skyrocketing vendor API costs and redundant latency

Every single quote refresh across dozens of open widgets fires a direct HTTP request to the remote exchange feed, wasting money and adding 50ms latency per click.

Scattered, bypassable security checks

Permission checks are copy-pasted across terminal screens and API endpoints. If an engineer misses an if (tier == "PRO") check in a new widget, non-paying users leak expensive Level-2 market depth.

Tight coupling to concrete remote infrastructure

Callers directly construct and depend on RemoteMarketDataFeed. Unit testing trading algorithms offline without an active, billable vendor network connection becomes impossible.

03

Step 2 β€” The fix: Proxy Pattern

Core idea in one sentence

Provide a surrogate or placeholder for another object to control access to it, presenting the exact same interface to clients.

We create MarketDataProxy, which implements the exact same MarketDataFeed interface as RemoteMarketDataFeed. The proxy holds a std::unique_ptr<MarketDataFeed> pointing to the real feed. When getQuote() is called, the proxy checks its internal timestamped cache: if fresh, it returns immediately; if expired, it fetches from the real feed and updates cache. When getLevel2Depth() is called, the proxy validates userTier_ == UserTier::Pro before delegating. Downstream code depends only on the abstract MarketDataFeed interface.

Pattern roles in our story
Subject Interface

MarketDataFeed β€” declares virtual Quote getQuote(...) = 0 and virtual MarketDepth getLevel2Depth(...) = 0.

RealSubject

RemoteMarketDataFeed β€” connects to the external exchange partner, incurring latency and per-call vendor fees.

Proxy

MarketDataProxy β€” wraps the real feed, manages TTL-based quote caching (Caching Proxy), and validates subscription tiers (Protection Proxy).

Client

TradingTerminal β€” interacts strictly with MarketDataFeed& without knowing whether caching or access control is active.

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