Systems project · Oct 2026 – present
EngineX
A deterministic C++20 limit-order matching engine with a crash-safe journal and a sequenced TCP feed.
- Role
- Sole author
- Status
- v1.0.0 released November 2026
- Stack
- C++20, CMake, GoogleTest, POSIX sockets, GitHub Actions
- Source
- The repository is private for now. Architecture and test approach are described here.
- matching-core commands
- 8.2M/s
- local benchmark
- p99.9 matching latency
- 417 ns
- local benchmark
- journal replay records
- 3.6M/s
- local benchmark, warm page cache
- TCP order-entry requests
- 85.7K/s
- 8 local clients, in-memory server (no journal sync)
The problem
A matching engine decides who trades with whom. If the same orders can produce different fills depending on thread timing, nobody can audit it, replay it, or trust a recovery after a crash.
EngineX is an educational exchange lab built around three promises: the same input always produces byte-for-byte the same state, in durable mode an acknowledged order survives a process crash, and one slow client cannot stall everyone else.
Architecture
Order path through EngineX
TCP clients send length-prefixed JSON commands to per-connection reader threads, which feed one bounded ingress queue. A single sequencer validates each command, assigns a sequence number and applies it to the per-symbol order books. Commands are written to a CRC32C-framed journal and acknowledged only after the journal is synced to disk. Acknowledgements and book updates go out through bounded per-client outbound queues. On startup the journal is replayed and checked against a SHA-256 state hash.
- TCP clients to Bounded ingress (commands)
- Bounded ingress to Sequencer (typed)
- Sequencer to Write-ahead journal (group commit)
- Sequencer to Order books (apply)
- Order books to Outbound queues (after sync)
- Write-ahead journal to Replay + verify (on startup)
- Outbound queues to TCP clients
- Validation is a pure prepare step; only commit assigns a sequence number and mutates state. A rejected command leaves no trace in the books.
- Market data subscribers receive an atomic snapshot followed by sequenced updates from an event watermark, so a reconnecting client can resynchronize without gaps.
- Version 1.0.0 adds a separate read-only path that decodes Nasdaq TotalView-ITCH 5.0 binary data and rebuilds order books from it. That path never sends anything to the simulated exchange.
Decisions and trade-offs
One sequencer instead of fine-grained locks
All state is owned by a single sequencer thread; networking threads only move bytes.
Trade-off: Matching cannot scale across cores, but ordering is total and replayable, and the matching core needs no locks.
Acknowledge only after the disk says so
An order is acknowledged after its journal frame is synced with fdatasync, using group commit to amortize the sync.
Trade-off: Durability is expensive: with 8 local clients the server handles about 85.7K requests/s in memory but about 1.4K/s with --durability sync. In exchange, under the journal's documented assumptions, an acknowledged order survives a process crash.
Idempotent request IDs
Clients attach a request ID; a retried command after a timeout or restart returns the original outcome.
Trade-off: The engine has to remember request IDs, which costs memory; in return a client can always retry safely.
How it is tested
- 151 GoogleTest cases plus property tests that run 100 seeds against an independent reference model.
- Crash-point tests fork the process at journal write boundaries, and a SIGKILL harness kills the server mid-stream; recovery must repair a torn tail and refuse a corrupted journal.
- AddressSanitizer, UndefinedBehaviorSanitizer and ThreadSanitizer builds run in GitHub Actions CI on Linux.
- The ITCH decoder was validated locally on three public Nasdaq sample days with zero decode errors.
Outcomes
- Deterministic replay is checkable: two runs over the same journal produce the same SHA-256 state hash.
- Matching follows the TradeGrid club specification and passes its shared fixtures.
Scope: EngineX is a learning project, not trading software. Benchmarks were measured on a local machine and are not production figures.