- This is my first ever software project. I literally had no idea about software development and C++ in particular. I admit there is a lot of scope for improvement.
- I have learned a lot more stuff along the way(OOPS, C++). I plan to improve this project further. Kindly suggest ways for the same if something pops up in your head.
DISCLAIMER: The README.md for this project has been generated using Copilot Agent. However, all of the code is based on me trying to figure out stuff on the fly.
A wanna-be sophisticated C++ implementation of a financial exchange system featuring real-time order matching, comprehensive order type support, and order preprocessing. Built with modern C++17 features for attempt at optimal performance and type safety.
Xchange is a complete order matching engine that simulates real-world financial exchange operations. It handles multiple participants trading various symbols with support for 10 different order types, time-based order activation, and priority-based matching algorithms.
- Multi-Symbol Trading: Support for trading multiple financial instruments simultaneously
- 10 Order Types: Comprehensive support for various order types including Market, Limit, GoodTillCancel, GoodTillDate, GoodForDay, GoodAfterTime, MarketOnOpen, MarketOnClose, ImmediateOrCancel, FillOrKill, and AllOrNone
- Smart Order Preprocessing: order queue management with configurable thresholds
- Priority-Based Matching: Price-time priority for fair and efficient order execution
- Participant Management: Track multiple participants with portfolios and trade history
- Time Zone Support: Configurable time zones with trading hours validation
- Holiday Calendar: Market holiday awareness for realistic trading simulations
The system is organized into a layered architecture with clear separation of concerns:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Xchange β
β (Central Exchange - Singleton Pattern) β
β β’ Participant Management β
β β’ Symbol Registration β
β β’ Order Routing β
βββββββββββββββββββ¬ββββββββββββββββββββββββββββ¬ββββββββββββββββ
β β
βββββββββββΌββββββββββ ββββββββββΌβββββββββββββ
β Participant β β SymbolInfo β
β β’ Portfolio β β β’ OrderBook β
β β’ Orders β β β’ PreProcessors β
β β’ Trade History β β (Buy & Sell) β
βββββββββββββββββββββ ββββββββββββ¬βββββββββββ
β
ββββββββββββββββββββββββββββ΄βββββββββββββ
β β
ββββββββββββΌβββββββββββ βββββββββββΌβββββββββ
β PreProcessor β β OrderBook β
β (Per Side/Symbol) β β (Per Symbol) β
β β’ Order Queue ββββββββββββββββββ€ β’ Bid Levels β
β β’ Time Validation β β β’ Ask Levels β
β β’ Type Ranking β β β’ Matching β
ββββββββββββ¬βββββββββββ ββββββββββββ¬ββββββββ
β β
β β
ββββββββββββΌβββββββββββ βββββββββββΌβββββββββ
β Order β β Level β
β β’ Order Details ββββββββββββββββββ β’ Price Level β
β β’ Time Attributes β β β’ Order Queue β
β β’ Status β β β’ Quantity β
βββββββββββββββββββββββ ββββββββββββ¬ββββββββ
β
ββββββββββΌβββββββββ
β Trade β
β β’ Matched β
β Orders β
βββββββββββββββββββ
File: include/Xchange.hpp, src/Xchange.cpp
The main orchestrator implementing the Singleton Pattern to ensure a single exchange instance.
Responsibilities:
- Manage participants (add, remove, lookup by government ID)
- Register and retire tradable symbols
- Route orders to appropriate order books and preprocessors
- Validate trading hours and market status
- Provide system-wide configuration (order thresholds, pending duration)
Key Features:
- Singleton pattern with custom initialization parameters
- Maps government IDs to unique participant IDs
- Manages
SymbolInfoobjects for each tradable symbol - Configurable pending order thresholds and durations
- Time zone aware with trading hours validation
File: include/SymbolInfo.hpp, src/SymbolInfo.cpp
A lightweight struct that groups all components needed for trading a specific symbol.
Components:
- One
OrderBookper symbol - Two
PreProcessorinstances (one for bids, one for asks) - Symbol identifier
Purpose: Encapsulates symbol-specific trading infrastructure for clean organization.
File: include/OrderBook.hpp, src/OrderBook.cpp
The core matching engine that maintains price levels and executes trades.
Data Structure:
- Bid Levels:
std::map<Price, Level, std::greater<Price>>(highest price first) - Ask Levels:
std::map<Price, Level, std::less<Price>>(lowest price first) - Trade History: Vector of executed trades
Operations:
AddOrder(): Insert order at appropriate price levelCancelOrder(): Remove order from order bookModifyOrder(): Update existing orderMatchPotentialOrders(): Execute price-time priority matching
Matching Algorithm:
- Check if bid price β₯ ask price (crossing condition)
- Match orders at the crossing price
- Fill orders based on time priority (FIFO at each price level)
- Generate
Tradeobjects for matched orders - Update quantities and remove fully filled orders
File: include/Preprocess.hpp, src/PreProcess.cpp
order queue that validates and schedules orders before they enter the OrderBook.
Key Responsibilities:
- Buffer orders and validate activation/deactivation times
- Rank orders by type priority (Market > ImmediateOrCancel > GoodTillCancel, etc.)
- Enforce pending order thresholds to prevent queue overflow
- Check trading hours and holiday calendar
- Flush qualified orders to OrderBook based on time and count triggers
Order Type Ranking (Higher rank = Higher priority):
Market (highest priority)
FillOrKill
ImmediateOrCancel
MarketOnClose
MarketOnOpen
GoodAfterTime
GoodForDay
GoodTillDate
GoodTillCancel
AllOrNone (lowest priority)
Configuration:
MAX_PENDING_ORDERS_THRESHOLD: Trigger flush when queue exceeds this countMAX_PENDING_DURATION: Flush interval in milliseconds- Holiday calendar with Indian market holidays for 2025
- Trading hours validation (configurable per symbol)
File: include/Level.hpp, src/Level.cpp
Represents a single price point in the order book with multiple orders at that price.
Data Structure:
m_orderList: Linked list of orders (maintains time priority)m_info: Hash map for O(1) order lookupm_quantity: Aggregate quantity at this level
Operations:
AddOrder(): Append to end of order list (time priority)CancelOrder(): Remove specific orderModifyOrder(): Update order detailsremoveMatchedOrder(): Clean up after trade execution
Benefits:
- Fast aggregation of quantities at each price
- Efficient order lookup with O(1) complexity
- Maintains strict time priority within price level
File: include/Order.hpp, src/Order.cpp
Core data structure representing a single order.
Attributes:
- Symbol, side (Buy/Sell), price, quantity
- Order type (Market, Limit, GoodTillDate, etc.)
- Participant ID
- Timestamps: creation, activation, deactivation
- Order status (NotProcessed, Processing, Fulfilled, Cancelled)
- Unique Order ID (encoded with timestamp, price, and side)
Key Methods:
encodeOrderID(): Generate unique 64-bit order IDFillPartially(): Update quantity on partial fillconvertDateTimeToTimeStamp(): Parse time stringsreturnReadableTime(): Format timestamps for display
File: include/Participant.hpp, src/Participant.cpp
Represents a market participant with portfolio and order history.
Tracks:
- Portfolio: Map of symbols to net positions (amounts)
- Order composition: All orders placed by participant
- Trade history: Record of all executed trades
- Order status: Pending, processing, fulfilled, cancelled counts
Capabilities:
- Record new orders (non-cancel and cancel)
- Update portfolio on trade execution
- Calculate portfolio valuation
- Query order and trade statistics
File: include/Trade.hpp
Immutable record of a successful trade between two orders.
Contains:
- Matched bid order (buyer)
- Matched ask order (seller)
- Symbol
- Match timestamp
Purpose: Provides audit trail and trade history for participants and the exchange.
1. Participant Submits Order
β
2. Xchange.placeOrder()
β’ Validates participant exists
β’ Routes to appropriate SymbolInfo
β
3. PreProcessor.InsertIntoPreprocessing()
β’ Validates time attributes
β’ Checks market hours & holidays
β’ Adds to type-ranked queue
β
4. PreProcessor.TryFlush() [Triggered by time/count]
β’ Sorts orders by type priority
β’ Validates activation times
β’ Flushes qualified orders
β
5. OrderBook.AddOrder()
β’ Finds/creates price level
β’ Adds order to level
β
6. OrderBook.MatchPotentialOrders()
β’ Checks for crossing orders
β’ Executes trades (price-time priority)
β’ Generates Trade objects
β
7. Participant.recordTrades()
β’ Updates portfolio
β’ Records trade history
β’ Updates order status
Participant A: Buy 100 AAPL @ $150
Participant B: Sell 50 AAPL @ $149
Flow:
1. Both orders enter respective PreProcessors (Buy/Sell)
2. PreProcessor flushes orders to OrderBook
3. OrderBook detects crossing ($150 bid β₯ $149 ask)
4. Match 50 shares at $149 (ask price)
5. Create Trade object
6. Participant A: +50 AAPL, -$7,450
7. Participant B: -50 AAPL, +$7,450
8. Participant A's order: 50 shares remaining (partial fill)
9. Participant B's order: fully filled, removed from book
#pragma once: Modern header guard replacing traditional#ifndefguardsstd::chrono: Comprehensive time handling withsystem_clock::time_point(C++11)constexpr: Compile-time holiday array in PreProcessor (C++11)- Range-based loops: Used throughout for container iteration (C++11)
- C++23 Standard: Project is compiled with
-std=c++23flag for latest language features
// Shared ownership across multiple preprocessors
std::shared_ptr<OrderBook> m_orderbookPtr;
// Unique ownership in Xchange singleton
static std::unique_ptr<Xchange> m_instance;
// Type aliases for clarity
using OrderPointer = std::shared_ptr<Order>;
using LevelPointer = std::shared_ptr<Level>;
using PreProcessorPointer = std::shared_ptr<PreProcessor>;Benefits:
- Automatic memory management (no manual
delete) - Shared ownership for OrderBook across preprocessors
- Exception-safe resource management
std::map<Price, LevelPointer, std::greater<Price>> m_bids; // Max-heap behavior
std::map<Price, LevelPointer, std::less<Price>> m_asks; // Min-heap behaviorReason: Maintains sorted price levels for efficient matching
std::unordered_map<OrderID, OrderPointer> m_orderComposition;
std::unordered_map<ParticipantID, ParticipantPointer> m_participants;Reason: O(1) lookup for orders and participants by ID
std::set<OrderActionInfo> m_laterProcessOrders;Reason: Automatic sorting with custom comparator, no duplicates
OrderList m_orderList; // typedef std::list<OrderPointer>Reason: Efficient insertion/deletion while maintaining time priority
std::vector<Trade> m_trades;Reason: Fast sequential access for trade records
namespace Side {
enum Side { Buy, Sell };
}
namespace OrderType {
enum OrderType {
AllOrNone, GoodTillCancel, GoodTillDate,
GoodForDay, GoodAfterTime, MarketOnOpen,
MarketOnClose, ImmediateOrCancel,
FillOrKill, Market
};
}
namespace OrderStatus {
enum OrderStatus {
NotProcessed, Processing, Fulfilled, Cancelled
};
}Benefits: Type-safe constants with namespace isolation
// Type aliases for readability
using Price = std::int32_t;
using Quantity = std::uint64_t;
using Symbol = std::string;
using TimeStamp = std::chrono::system_clock::time_point;
using OrderID = std::uint64_t;
using ParticipantID = std::string;
using Amount = double;
using Portfolio = std::unordered_map<Symbol, Amount>;
// Template comparators in std::map
std::map<Price, Level, std::greater<Price>> bids; // Descending
std::map<Price, Level, std::less<Price>> asks; // Ascendingclass Xchange {
private:
static std::unique_ptr<Xchange> m_instance;
Xchange(...); // Private constructor
public:
Xchange(const Xchange&) = delete; // Delete copy
Xchange& operator=(const Xchange&) = delete; // Delete assignment
static Xchange& getInstance(...);
static void destroyInstance();
};Purpose: Ensure single exchange instance across the system
- Smart pointers automatically manage Order, Level, OrderBook lifetimes
- No manual memory management required
- Exception-safe cleanup
struct SymbolInfo {
Symbol m_symbol;
OrderBookPointer m_orderbook;
PreProcessorPointer m_bidprepro;
PreProcessorPointer m_askprepro;
};Purpose: Lightweight container for related components
bool Order::operator<(const Order& other) const {
return m_timestamp < other.m_timestamp; // Time priority
}
bool Order::operator==(const Order& other) const {
return m_orderID == other.m_orderID;
}Purpose: Enable natural comparison syntax and STL container compatibility
class OrderBook {
public:
static Price decodePriceFromOrderID(const OrderID orderID);
static Side::Side decodeSideFromOrderID(const OrderID orderID);
};
class PreProcessor {
private:
static std::unordered_map<OrderType::OrderType, int> m_typeRank;
static constexpr std::array<std::tuple<...>, 15> m_holidays = {...};
};Purpose: Shared state/logic across instances, utility functions
std::optional<Trade> AddOrder(Order& order);
std::optional<OrderID> placeOrder(...);
std::optional<OrderActionInfo> getOrderInfo(const OrderID& orderID);Benefits:
- Explicit handling of "no value" cases
- Avoid null pointer errors
- Clear API contracts
Price getPrice() const { return m_price; }
Symbol getSymbol() const { return m_symbol; }
const OrderTraded& getMatchedBid() const { return m_bidMatch; }Benefits:
- Compile-time guarantees that methods don't modify state
- Enables optimization
- Prevents accidental mutations
Symbol getSymbol() const { return m_symbol; }
Price getPrice() const { return m_price; }Benefits: Compiler can inline for zero-cost abstraction
xchange/
βββ include/ # Public header files
β βββ Xchange.hpp # Central exchange
β βββ OrderBook.hpp # Matching engine
β βββ Preprocess.hpp # Order preprocessing
β βββ Participant.hpp # Trader representation
β βββ Level.hpp # Price level
β βββ Order.hpp # Order object
β βββ Trade.hpp # Trade record
β βββ OrderTraded.hpp # Matched order details
β βββ SymbolInfo.hpp # Symbol container
βββ src/ # Implementation files
β βββ Xchange.cpp
β βββ OrderBook.cpp
β βββ PreProcess.cpp
β βββ Participant.cpp
β βββ Level.cpp
β βββ Order.cpp
β βββ SymbolInfo.cpp
βββ utils/ # Utilities and type definitions
β βββ enums/ # Enumerations
β β βββ Side.hpp # Buy/Sell
β β βββ OrderTypes.hpp # 10 order types
β β βββ OrderStatus.hpp # Order lifecycle states
β β βββ Actions.hpp # Add/Modify/Cancel
β βββ alias/ # Type aliases
β β βββ Fundamental.hpp # Basic types (Price, Quantity, etc.)
β β βββ OrderRel.hpp # Order-related pointers
β β βββ LevelRel.hpp # Level-related pointers
β β βββ ...
β βββ helpers/ # Helper functions
β β βββ HelperFunctions.hpp
β β βββ HelperFunctions.cpp
β βββ Constants.hpp # System constants
βββ tests/ # Test files (GTest framework)
β βββ core-xchange.tests.cpp # Xchange tests
β βββ core-part.tests.cpp # Participant tests
β βββ core-pre.tests.cpp # PreProcessor tests
β βββ actual/
β β βββ core-ob.tests.cpp # OrderBook tests
β β βββ core-lev.tests.cpp # Level tests
β βββ cases/ # Test case data files
β βββ testHandler.cpp # Test utilities
βββ makefile # Build configuration
βββ .gitignore
βββ README.md # This file
- Compiler: g++ with C++23 support (GCC 12+ or Clang 15+ recommended)
- Build System: GNU Make
- Testing: Google Test (GTest) framework
# Clean build artifacts
make clean
# Build object files
make getObjectFiles
# Build and run (uses tests/core-pre.cpp as entry point)
make fresh
# Run existing executable
make run# Run test health check
make testHealth
# Build all test binaries
make testFiles
# Run all tests
make test
# Run all tests and clean up
make testAll
# Clean test artifacts
make cleanTestsThe project uses a sophisticated Makefile with:
- Compiler:
g++ - C++ Standard:
-std=c++23 - Flags:
-Wall -Wextra -pedantic-errors(strict warnings) - Debug:
-ggdb -O0(debug symbols, no optimization) - Include Path:
-I.(root directory)
Directory Structure:
src/βobj/*.o(compiled objects)tests/*.tests.cppβtests/bin/*(test executables)
The project includes comprehensive tests organized by component:
- core-xchange.tests.cpp: Exchange operations (participants, symbols, order routing)
- core-part.tests.cpp: Participant portfolio and order tracking
- core-pre.tests.cpp: PreProcessor queue management and order validation
- core-ob.tests.cpp: OrderBook matching logic
- core-lev.tests.cpp: Level operations
The tests/cases/ directory contains structured test data for:
- PreProcessor: Order insertion, removal, modification, queue flushing
- OrderBook: Matching scenarios (no match, partial match, complete match, time priority)
// Initialize exchange with thresholds
Xchange& xchange = Xchange::getInstance(
50, // Pending order threshold
5000, // Pending duration (ms)
"America/New_York" // Time zone
);
// Add participants
ParticipantID trader1 = xchange.addParticipant("GOV_ID_12345");
ParticipantID trader2 = xchange.addParticipant("GOV_ID_67890");
// Enable symbol trading
xchange.tradeNewSymbol("AAPL");
// Place buy order
auto orderID = xchange.placeOrder(
trader1, // Participant
Actions::Add, // Action
std::nullopt, // Order ID (null for new)
"AAPL", // Symbol
Side::Buy, // Side
OrderType::GoodTillCancel, // Order type
15000, // Price ($150.00)
100, // Quantity
std::nullopt, // Activation time
std::nullopt // Deactivation time
);
// Place sell order
xchange.placeOrder(
trader2,
Actions::Add,
std::nullopt,
"AAPL",
Side::Sell,
OrderType::Market,
14900, // Price ($149.00)
50, // Quantity
std::nullopt,
std::nullopt
);
// Check trades
auto trades = xchange.getTradesExecuted("AAPL");
for (const auto& trade : trades) {
std::cout << "Trade executed: " << trade.getSymbol() << std::endl;
}
// Cleanup
Xchange::destroyInstance();- O(1) Order Lookup: Hash maps for instant order retrieval
- Sorted Price Levels:
std::mapwith custom comparators for efficient matching - Time Priority: Linked lists maintain FIFO order at each price level
- Smart Pointer Sharing: Avoid deep copies with shared ownership
- Multi-Symbol Support: Independent order books per symbol
- Configurable Thresholds: Adjust queue sizes and flush intervals
- Extensible Order Types: Easy to add new order type behaviors
- Modular Architecture: Components can be tested and optimized independently
- Time Zone Awareness: Convert between local and GMT times
- Trading Hours Validation: Prevent orders outside market hours
- Holiday Calendar: Skip non-trading days
- Order Status Tracking: Monitor order lifecycle from submission to fulfillment
- Modern C++: C++23 Standard
- Smart Pointers: std::shared_ptr, std::unique_ptr
- STL Containers: std::map, std::unordered_map, std::list
- Chrono Library: std::chrono
- Optional: std::optional
- Singleton Pattern: Ensures single instance
- RAII: Resource management through object lifetime
- Type Aliases: Improve code readability
This project demonstrates:
- Clean architecture with separation of concerns
- Extensive use of modern C++ features
- Comprehensive test coverage
- Real-world financial system modeling
MIT
Ash4dev - GitHub Profile
- Coding Jesus Orderbook Series for the idea
- LearnCPP for a beginner friendly guide to C++
- CPPReference for crisp and clear reference
- Mike Shah for the missing parts
- CppNuts for the missing parts
- Build systems "make"ing it
- GDB fixing bugs left and right
- Google Test framework for robust testing infrastructure