2Brute2Best
🔥0
B5

Supporting NSE and BSE Without Mixing Components

Pro OnlyAbstract Factory
⚡ 60-Second Architecture SummaryB5 · Abstract Factory Pattern
Naive Bottleneck→Abstract Factory Pattern Cure
The Naive Bottleneck: Accidental component mismatch

Constructing components piecemeal via scattered `if (exchange == "NSE")` checks led a developer to pair an `NseOrderRouter` with a `BseFeeCalculator`. BSE's higher transaction charges were billed on NSE executions and BSE numeric scrip codes were sent to NSE's FIX gateway, resulting in exchange rejects and regulatory billing fines.

Nothing in the type system prevents an engineer or configuration script from pairing an NseOrderRouter with a BseFeeCalculator. Mismatches compile cleanly and cause silent runtime financial errors.

The Pattern Cure: Abstract Factory Pattern

Provide an interface for creating families of related or dependent objects without specifying their concrete classes, ensuring that clients always receive compatible components.

We declare abstract product interfaces (OrderRouter, FeeCalculator, SymbolValidator) and an ExchangeFactory interface with creation methods for each product. Concrete factories (NseExchangeFactory, BseExchangeFactory) implement these methods to return their matching triplet of products. The TradingSession receives an ExchangeFactory reference and instantiates its components in one atomic step — it is physically impossible to mix components across different exchange families.

Sprint 5 of 9 · Multi-Exchange Component Families (NSE vs BSE vs Crypto)
Story B — Low-Latency Trading System — Progressive System Build
1. Where our codebase left off
← B4

In Sprint 4 (B4 · Command), we wrapped order actions into auditable and reversible OrderCommand executions against our local order book. Now our brokerage is expanding beyond a single market to route orders to multiple exchange venues: NSE, BSE, and Crypto Spot.

2. What we are building now

We are building the multi-exchange session manager, supplying each trading session with its required triplet of exchange-specific components: OrderRouter (binary/FIX gateway), FeeCalculator (STT, stamp duty, transaction fees), and SymbolValidator (ticker format and scrip codes).

3. The pain point we hit

Constructing components piecemeal via scattered if (exchange == "NSE") checks led a developer to pair an NseOrderRouter with a BseFeeCalculator. BSE's higher transaction charges were billed on NSE executions and BSE numeric scrip codes were sent to NSE's FIX gateway, resulting in exchange rejects and regulatory billing fines.

4. What this unlocks next
Next: B6 →

By introducing Abstract Factory (ExchangeFactory), concrete factories (NseExchangeFactory, BseExchangeFactory) guarantee that routers, fee calculators, and symbol validators are created as an atomic, compatible family. Next in Sprint 6 (B6 · Mediator), inside our matching engine core, OrderBook, RiskEngine, PositionTracker, and multiple trading desks start calling each other directly in an N × N spaghetti web whenever a fill occurs.

01

The product ticket

Ticket · B5TRADE-205 · Multi-Exchange Connectivity (NSE & BSE) Without Component Mismatch

Our trading terminal routes orders to multiple Indian exchanges: NSE (National Stock Exchange) and BSE (Bombay Stock Exchange). Each exchange requires a matching family of three specialized components: an OrderRouter (handles binary/FIX protocol and gateway URLs), a FeeCalculator (calculates exchange transaction charges, STT, and stamp duty), and a SymbolValidator (enforces exchange-specific ticker symbology).

Requirements
  • •

    Ensure an exchange trading session always operates with a consistent, compatible family of components: an NseOrderRouter must NEVER be paired with a BseFeeCalculator or BseSymbolValidator.

  • •

    Allow adding support for new exchanges (such as MCX for commodities or international venues) without modifying core trading algorithms or order execution services.

  • •

    Decouple client order workflows from the concrete implementations of individual exchange routers, fee schedules, and symbol parsers.

The next requirement that breaks naive code

In the naive codebase, components were constructed piecemeal via scattered if (exchange == "NSE") checks across several files. A developer configuring a new desk terminal accidentally paired NseOrderRouter with BseFeeCalculator. Because BSE's higher transaction charges were billed on NSE executions and BSE numeric scrip codes were sent to the NSE gateway, orders were rejected by the exchange and traders were incorrectly billed.

02

Step 1 — The naive code & why it breaks

The naive approach constructs routers, calculators, and validators individually using string checks or enum switches scattered across multiple setup functions.

Naive design (what not to ship) · naive.cpp
#include <cstdint>
#include <format>
#include <memory>
#include <print>
#include <string>
#include <string_view>

// Naive implementation: Components are instantiated piecemeal via scattered conditionals.
// There is zero type safety or compile-time guarantee preventing an engineer from
// pairing an NSE router with a BSE fee calculator or BSE symbol validator.

class NaiveNseRouter {
public:
    std::string route(std::string_view symbol, int qty) {
        return std::format("[NSE-NEAT] Routed {} of {}", qty, symbol);
    }
};

class NaiveBseRouter {
public:
    std::string route(std::string_view symbol, int qty) {
        return std::format("[BSE-BOLT] Routed {} of {}", qty, symbol);
    }
};

class NaiveNseFeeCalc {
public:
    int64_t calculate(int64_t turnoverPaise) {
        return (turnoverPaise * 325) / 10'000'000; // NSE rate
    }
};

class NaiveBseFeeCalc {
public:
    int64_t calculate(int64_t turnoverPaise) {
        return (turnoverPaise * 375) / 10'000'000; // BSE rate
    }
};

int main() {
    std::string exchange = "NSE";
    std::string feeTier = "BSE"; // Config typo or wrong parameter flag!

    auto nseRouter = std::make_unique<NaiveNseRouter>();
    auto bseFee = std::make_unique<NaiveBseFeeCalc>(); // ACCIDENTAL MISMATCH!

    // The trading session is now running with an NSE router but charging BSE fee schedules!
    int64_t turnoverPaise = 100'000'000; // Rs. 1,000,000
    std::println("{}", nseRouter->route("RELIANCE", 100));
    std::println("Calculated Fee (Wrong Exchange Rate!): {} paise", bseFee->calculate(turnoverPaise));
}
Accidental component mismatch

Nothing in the type system prevents an engineer or configuration script from pairing an NseOrderRouter with a BseFeeCalculator. Mismatches compile cleanly and cause silent runtime financial errors.

Violates Open-Closed Principle (OCP)

Introducing a new exchange (e.g. MCX) requires hunting down and modifying every conditional block across router setup, fee billing, and symbol parsing files.

Scattered creation logic

The knowledge of which component variants belong together is scattered across various calling functions rather than centralized in one cohesive factory.

03

Step 2 — The fix: Abstract Factory Pattern

Core idea in one sentence

Provide an interface for creating families of related or dependent objects without specifying their concrete classes, ensuring that clients always receive compatible components.

We declare abstract product interfaces (OrderRouter, FeeCalculator, SymbolValidator) and an ExchangeFactory interface with creation methods for each product. Concrete factories (NseExchangeFactory, BseExchangeFactory) implement these methods to return their matching triplet of products. The TradingSession receives an ExchangeFactory reference and instantiates its components in one atomic step — it is physically impossible to mix components across different exchange families.

Pattern roles in our story
Abstract Factory

ExchangeFactory — declares createRouter(), createFeeCalculator(), createSymbolValidator(), and exchangeName().

Concrete Factories

NseExchangeFactory, BseExchangeFactory — each instantiates the coherent family of products for that specific exchange.

Abstract Products

OrderRouter, FeeCalculator, SymbolValidator — interfaces defining communication, fee calculation, and symbol validation.

Concrete Products

NseOrderRouter, NseFeeCalculator, NseSymbolValidator vs BseOrderRouter, BseFeeCalculator, BseSymbolValidator.

Client

TradingSession — initialized with an ExchangeFactory, interacting only with the abstract product interfaces.

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