A production-ready, high-performance order matching engine written in C++17. Achieves 300,000 orders/second sustained throughput with sub-4 microsecond latency through careful optimization and clean architecture.
- ⚡ 300k orders/second sustained throughput (measured)
- 🎯 Sub-4μs latency per order (3.34μs average)
- ✅ Production-ready: Input validation, error handling, structured logging
- 🔒 Zero data loss: Comprehensive testing under load (3M+ orders)
- 📊 Price-Time Priority: Standard FIFO matching algorithm
- 🔢 Multiple Order Types: LIMIT, MARKET, and STOP orders
- 🚀 Lock-Free Design: Single-threaded for cache efficiency
- 💾 Memory Efficient: Pre-allocated object pools (zero malloc in hot path)
make clean
make all./matching_engine --port 8080 --no-logging# In another terminal
./load_generator --host 127.0.0.1 --port 8080 --duration 10 --rate 500000 --clients 8Expected output:
Load Generation Complete:
Total orders sent: ~3,000,000
Duration: 10.005 seconds
Throughput: ~300,000 orders/sec ✅
./tests/run_tests.shMeasured on Apple M2 Pro (3.5 GHz), macOS:
| Metric | Value |
|---|---|
| Sustained Throughput | 299,545 orders/sec |
| Average Latency | 3.34 μs per order |
| Test Duration | 10 seconds (3M orders) |
| Concurrent Clients | 8 |
| Data Loss | 0 (zero) |
| Memory Usage | ~80 MB |
| CPU Utilization | ~98% (single core) |
Per-order processing (3.34μs):
├─ TCP receive ~0.5μs
├─ Message parsing ~0.3μs
├─ Input validation ~0.2μs
├─ Order matching ~1.5μs
├─ Execution report ~0.5μs
└─ TCP send ~0.3μs
┌─────────────────────────────────────────────────────────┐
│ TCP Clients │
│ (Multiple Connections) │
└─────────────────────┬───────────────────────────────────┘
│ Binary Protocol (kqueue/epoll)
┌─────────────────────▼───────────────────────────────────┐
│ TCP Server │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Session 1 │ │ Session 2 │ │ Session N │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────┬───────────────────────────────────┘
│ Validated Order Messages
┌─────────────────────▼───────────────────────────────────┐
│ Matching Engine (Single-Threaded) │
│ ┌───────────────────────────────────────────────┐ │
│ │ Symbol Router (Hash Map) │ │
│ └───────┬───────────────────┬───────────────────┘ │
│ │ │ │
│ ┌───────▼───────┐ ┌────────▼────────┐ ┌──────────┐ │
│ │ Order Book │ │ Order Book │ │Order Book│ │
│ │ (AAPL) │ │ (GOOGL) │ │ (MSFT) │ │
│ │ │ │ │ │ │ │
│ │ Bids Asks │ │ Bids Asks │ │Bids Asks │ │
│ │ (map) (map) │ │ (map) (map) │ │(map)(map)│ │
│ └───────────────┘ └─────────────────┘ └──────────┘ │
│ │
│ Object Pool (1M pre-allocated Orders) │
│ Lock-Free Ring Buffers (Network I/O) │
└──────────────────────────────────────────────────────────┘
Key Design Decisions:
- Single-threaded: Optimized for cache locality and simplicity
- Event-driven I/O: kqueue (macOS) / epoll (Linux) for scalability
- Memory pools: Zero allocations in hot path
- Binary protocol: Minimal parsing overhead
📖 Read detailed architecture documentation →
./matching_engine [options]
--port PORT Server port (default: 8080)
--symbols SYM1,SYM2 Comma-separated symbols (default: AAPL,GOOGL,MSFT)
--pool-size SIZE Order pool size (default: 1000000)
--log-file FILE Log file path (default: matching_engine.log)
--no-logging Disable logging (for max performance)
--help, -h Show helpExample:
./matching_engine --port 8080 --symbols AAPL,TSLA,NVDA --no-logging./load_generator [options]
--host HOST Server host (default: 127.0.0.1)
--port PORT Server port (default: 8080)
--clients N Number of client threads (default: 1)
--duration SEC Duration in seconds (default: 60)
--rate OPS Target orders per second (default: 10000)
--symbol SYM Symbol to trade (default: AAPL)
--help, -h Show helpExample:
./load_generator --host 127.0.0.1 --port 8080 --duration 10 --rate 500000 --clients 8./book_visualizer [options]
--host HOST Server host (default: 127.0.0.1)
--port PORT Server port (default: 8080)
--symbol SYM Symbol to visualize (default: AAPL)
--help, -h Show helpEfficient fixed-size binary protocol over TCP for minimal overhead.
| Type | ID | Description |
|---|---|---|
| NEW_ORDER | 1 | Submit new order |
| CANCEL_ORDER | 2 | Cancel existing order |
| EXECUTION_REPORT | 3 | Order status update |
| TRADE | 4 | Trade notification |
| REJECT | 5 | Order rejection (with reason) |
┌─────────┬─────────┬────────┬──────────────┐
│ msg_type│ padding │ length │ sequence_num │
│ (1 byte)│ (1 byte)│(2 bytes)│ (4 bytes) │
└─────────┴─────────┴────────┴──────────────┘
┌──────────┬────────┬───────┬──────────┬──────┬────────────┬─────────┐
│ order_id │ symbol │ price │ quantity │ side │ order_type │ padding │
│ (8 bytes)│(8 bytes)│(8 bytes)│(4 bytes)│(1 byte)│ (1 byte) │(18 bytes)│
└──────────┴────────┴───────┴──────────┴──────┴────────────┴─────────┘
Field Details:
side: 0 = BUY, 1 = SELLorder_type: 0 = LIMIT, 1 = MARKET, 2 = STOPprice: Integer (cents), must be > 0 for LIMIT/STOPquantity: 1 to 10,000,000 shares
All orders validated before processing:
| Field | Validation |
|---|---|
| Side | Must be 0 (BUY) or 1 (SELL) |
| Order Type | Must be 0 (LIMIT), 1 (MARKET), or 2 (STOP) |
| Price | 1 cent to $10M (LIMIT/STOP only) |
| Quantity | 1 to 10M shares |
| Symbol | Non-empty, valid characters |
| Market Orders | Price must equal 0 |
Invalid orders receive REJECT messages with specific reason codes.
- ✅ Pool exhaustion: Sends REJECT message ("Pool exhausted")
- ✅ Buffer overflow: Closes connection gracefully
- ✅ Partial send: Peek-consume pattern prevents data loss
- ✅ Invalid messages: Validated before processing
- ✅ Connection drops: Cleaned up automatically
- Async logging: Non-blocking ring buffer
- Structured format: CSV for easy parsing
- Log levels: DEBUG, INFO, WARN, ERROR
- Zero hot-path I/O: All debug output removed from critical path
Enable logging:
./matching_engine --port 8080 --log-file trades.logView logs:
tail -f matching_engine.logmatching-engine/
├── Makefile # Build configuration
├── README.md # This file
├── src/
│ ├── main.cpp # Entry point
│ ├── engine/ # Core matching engine
│ │ ├── types.h # Data structures & validation constants
│ │ ├── price_level.* # Price level queue (FIFO)
│ │ ├── order_book.* # Order book implementation
│ │ └── matching_engine.* # Main engine logic
│ ├── network/ # Network layer
│ │ ├── protocol.h # Binary message definitions
│ │ ├── session.* # Connection handling
│ │ └── tcp_server.* # kqueue/epoll-based server
│ ├── memory/ # Memory management
│ │ ├── object_pool.h # Pre-allocated order pool
│ │ └── ring_buffer.h # Lock-free SPSC buffers
│ └── utils/ # Utilities
│ ├── timer.h # Performance timing
│ ├── logger.h # Async logging
│ └── config.h # Configuration
├── tests/
│ ├── unit/ # Unit tests
│ ├── integration/ # Integration tests
│ ├── benchmark/ # Performance benchmarks
│ └── run_tests.sh # Test runner
├── tools/
│ ├── load_generator.cpp # Load testing tool
│ └── book_visualizer.cpp # Order book monitor
└── docs/
├── ARCHITECTURE.md # Detailed design documentation
└── PERFORMANCE.md # Performance testing guide
Why single-threaded?
- ✅ L1/L2 cache efficiency (no cache coherency overhead)
- ✅ Deterministic latency (no thread scheduling jitter)
- ✅ Simpler code (easier to debug and maintain)
- ✅ Lock-free (no mutex contention)
Result: 300k orders/sec on a single core
Pre-allocates 1M Order objects at startup:
- O(1) allocation/deallocation
- Zero syscalls in hot path
- No heap fragmentation
- Predictable memory usage (~64MB)
SPSC (Single Producer Single Consumer) design:
- Wait-free read/write operations
- Zero-copy where possible
- Peek-consume pattern prevents data loss
Order struct is exactly 64 bytes (one cache line):
- Prevents false sharing
- Maximizes cache utilization
- Improves memory bandwidth
| Before | After | Improvement |
|---|---|---|
| 20+ std::cout in hot path | 0 debug output | 30x faster |
| std::cerr error messages | Async LOG_ERROR | Non-blocking |
| Broken partial send | Peek-consume pattern | Zero data loss |
| Silent pool exhaustion | REJECT messages | Proper error handling |
| No input validation | Comprehensive checks | Production-ready |
📊 Read performance testing guide →
Quick benchmark:
# Maximum throughput test
./load_generator --host 127.0.0.1 --port 8080 --duration 10 --rate 500000 --clients 8
# Sustained load test
./load_generator --host 127.0.0.1 --port 8080 --duration 60 --rate 250000 --clients 4- Throughput: ~300k orders/sec
- Latency: <4μs per order
- Architecture: One thread, one core
Natural partitioning by symbol:
Gateway Thread → Routes orders to symbol threads
├─ AAPL Thread → 300k orders/sec
├─ GOOGL Thread → 300k orders/sec
├─ MSFT Thread → 300k orders/sec
└─ ... → ...
Estimated: 1.5-2M orders/sec across 8 cores
Not implemented to maintain code clarity for portfolio.
| System | Throughput | Latency | Architecture |
|---|---|---|---|
| This Engine | 300k/sec | 3.3μs | Single-threaded |
| Small Exchange | 10-50k/sec | 10-50μs | Typical |
| Medium Exchange | 100-200k/sec | 5-20μs | Multi-threaded |
| Major Exchange | 500k-1M/sec | 1-10μs | Distributed |
This engine achieves professional-grade performance with clean, maintainable code.
-
📖 Architecture & Design Decisions
- Single-threaded rationale
- Memory management strategy
- Performance optimization journey
- Scalability considerations
-
- Benchmark scenarios
- Tuning parameters
- Profiling instructions
- Troubleshooting tips
- C++17 compatible compiler (GCC 9+, Clang 10+, or Apple Clang 12+)
- macOS (kqueue) or Linux (epoll)
- pthread library
# Clone the repository
git clone https://github.com/yourusername/matching-engine.git
cd matching-engine
# Build all targets
make clean
make all
# Run tests
./tests/run_tests.shBuild outputs:
matching_engine- Main serverload_generator- Load testing toolbook_visualizer- Order book visualization
Contributions welcome! This is a portfolio project demonstrating production-quality systems programming.
Areas for contribution:
- Additional order types (IOC, FOK, GTD)
- Market data feed
- Historical replay functionality
- Multi-symbol threading
- Additional test coverage
MIT License - See LICENSE file for details.
Matthias Masiero
Built as a demonstration of high-performance systems programming with modern C++.
Key learnings:
- Low-latency design patterns
- Lock-free algorithms
- Cache-friendly data structures
- Production-ready error handling
- Performance measurement & optimization
- Inspired by real-world trading systems
- Built with modern C++ best practices
- Optimized for both performance and code clarity
⭐ If you found this project interesting, please give it a star!