C++ trading engine
I built a C++23 trading engine with explicit boundaries around market data and order execution. The engineering work centers on preserving state across restarts and keeping replay behavior consistent.
Independent engine. Production orders run through a gated Python REST executor. The C++ live order path remains gated.
- Independent project
- Private source
- C++ orders gated
- Problem
- Restarting a trading process meant recomputing every indicator and losing track of orders already at the exchange.
- Engineering decision
- Built a C++23 engine with a persistent indicator cache and order-journal recovery. A versioned C ABI lets strategy plugins share the same interface across replay and exchange integrations.
- Result
- Replays four hours of live market data in 15 seconds
- Measured evidence
- Decisions in about a microsecond at the 99th percentile, September 2026
- My role
- Sole engineer, independent systems project
- Source access
- Private repository
In this case study Features and engineering details
What it does
- Persistent indicators
- Memory-mapped storage saves calculation progress for the next run.
- Order recovery
- Journal replay rebuilds local order state before exchange reconciliation.
- Strategy plugins
- A versioned C ABI checks compatibility when a strategy library loads.
- Replay adapters
- An interchangeable clock and market interfaces support historical replay.
Walkthrough
Earlier simulator and charting interface. The current C++23 engine is described below. This footage does not demonstrate live execution.
Give replay and exchange integrations the same boundaries
Market data and order execution sit behind explicit interfaces, with an interchangeable clock for replay. This lets a strategy use the same interface against historical data and exchange adapters. Strategy plugins load through a versioned C ABI, which makes compatibility checks explicit at the library boundary.
Orders cross threads through a single-producer, single-consumer ring. The repository has a Kraken integration and a separate Python REST execution path. Production orders have run through the Python REST executor since July 2026, and it carries its own fail-closed consent gate, a durable intent ledger with stable references, and its own interlock tests. The C++ live order path stays behind an arming ladder and has never been armed on the production box.
Recover state after an interruption
The indicator cache stores calculation progress in memory-mapped files. On restart, it can resume from the stored input position instead of recalculating the entire history.
Order recovery replays a journal into a fresh order-management system. Reconciliation compares local orders with the exchange's state, including fills that occurred during downtime and orders the exchange no longer reports.
A missing order is not enough evidence to cancel it locally. The recovery tests check that uncertain exchange state does not invent a fill. They also check that an order filled in part and then cancelled keeps both its fill history and its final cancelled status.
Tests exercise those recovery cases and reopen persisted stores after writes. That verifies restart behavior. It does not simulate a physical power failure. Sanitizer builds check memory errors and data races.
Profile the bottleneck
In an earlier simulator, allocation on the ingestion path limited how much history a backtest could process. Linux profiling directed the work toward container sizing and ownership. Preallocating storage and moving data instead of copying it removed that bottleneck. Pooling database connections reduced repeated setup work.
The changes allowed longer backtests without the same allocation bottleneck.
Build on exchange-integration experience
The project began with open-source contributions to zenbot in 2016. Merged pull requests #28 corrected the altcoin pair graph and #34 added Poloniex USDT pairs.
Subsequent versions added a C++ feed handler with gap detection and backfilling, followed by a backtesting simulator with an order book and charting interface. That work informed the boundaries in the current engine.
Measured / September 2026
Decisions in about a microsecond at the 99th percentile
- Replay. An observed four-hour Kraken capture, 1.53 million receipts across eight assets, replayed in 15.19 seconds, about 950 times real time. The trace and the recovered account matched byte for byte across both input paths. Measured September 18, 2026.
- Decision latency. Across 263,200 recorded inputs, with the order queue, execution engine and order management in the loop, the 99th-percentile decision took 1.25 microseconds. Measured September 18, 2026 on 100 fresh hosts.
- Throughput and charting. A synthetic single-thread benchmark ingested 70.2 million events a second on a Ryzen 9 7950X on September 9. The Vulkan chart redrew a million candles at about 18,000 frames a second on an RTX 4080 on August 19.
These are replay and benchmark measurements on recorded or synthetic data. They exclude exchange network latency, and the chart figure comes from an offscreen benchmark.
Source revision 5a4f89d