A reproducible C++20 market-making simulator — from ticks to trades to PnL.
ToyQuant replays market data through the complete trading loop — feed, order book, strategy, matching, execution reports, and backtest metrics — so you can observe every decision a market maker makes, tick by tick.
It is a toy project for learning and experimentation, not a production trading system. APIs, scenarios, and strategy behavior may change between versions.
$ ./out/build/linux-debug/toy_quant csv data/scenarios/sample_ticks.csv 0 optimized
[TICK] EURUSD ts:1625097601900 price:1.1859 size:100 side:S | Top Bid: 1.1855@150 | Top Ask: 1.1851@50
...
[SUMMARY] submitted_orders=24 submitted_quantity=1302 cancel_requests=9
trade_reports=11 fill_rate=0.318 cancel_rate=0.375
net_position=-414 inventory_exposure=414 working_orders=6The same input and parameters produce deterministic runtime CSV output for this simulator.
CSV scenario ──╮
├─► Feed ──► Order Book ──► Strategy ──► Matching Engine ──► orders.csv
UDP stream ────╯ top of book naive / price–time trades.csv
optimized priority │
▼
backtest_main ──► PnL · equity · max drawdown
- Two feed modes — replay CSV scenarios or stream ticks over UDP.
- Two market-making strategies —
naiveandoptimizedbehind a common interface. - Price–time priority matching with self-trade prevention and partial fills.
- Stateful execution reports — position and working orders update from trade, cancel, and fill events.
- Deterministic backtests — realized/unrealized PnL and a reusable drawdown calculation.
- Small toolchain — CMake, a C++20 compiler, and Python 3 for the optional scenario and report tools.
Requirements: CMake 3.16+, a C++20-capable compiler, and Python 3.
cmake --preset linux-debug
cmake --build --preset linux-debug
ctest --preset linux-debugRun a CSV scenario (flat, trending, shock, and random markets ship in data/scenarios):
./out/build/linux-debug/toy_quant csv data/scenarios/flat_ticks.csv 0 optimizedStream ticks over UDP (and send a scenario from another terminal):
./out/build/linux-debug/toy_quant udp 9000 naive
python3 tools/udp_sender.py --port 9000Replay a backtest from generated order and trade records:
./out/build/linux-debug/backtest_main \
data/scenarios/sample_ticks.csv \
data/runtime/orders.csv \
data/runtime/trades.csv \
0 0 backtest logs/backtest.logGenerate your own scenarios with a fixed seed for reproducible runs:
python3 tools/gen_ticks.py all --count 1000 --seed 42 --output-dir data/scenariosEach toy_quant run creates or truncates:
data/runtime/orders.csv— every order the strategy submitted.data/runtime/trades.csv— every execution report the engine returned.
Both runtime files include a # source_ticks=... metadata line. Pass the same Tick file to backtest_main; when metadata is present, the backtest rejects a mismatched file. Older runtime files without metadata remain readable.
The default backtest log is logs/backtest.log.
Generate a static report with the market price, strategy quotes, executions, net inventory, and run summary:
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python tools/plot_report.py \
--ticks data/scenarios/synthetic_ticks.csv \
--orders data/runtime/orders.csv \
--trades data/runtime/trades.csv \
--output reports/synthetic_ticks_optimized.pngThe generated PNG is designed for quick inspection and README screenshots. Runtime CSV files are overwritten by the next simulation, so generate or copy the report before starting another run.
ToyQuant deliberately excludes real exchange connectivity, FIX, a risk gateway, persistence and recovery, nanosecond-latency claims, and full L2 market reconstruction. Keeping these out of scope is what keeps the core loop small enough to read in one sitting.
| Document | Contents |
|---|---|
| User Guide | CLI reference, scenarios, experiments, data contracts, and troubleshooting |
| Architecture | Data flow, module responsibilities, matching rules, order lifecycle |
| Data Files | Tick CSV format, runtime outputs, typical workflow |
Bug reports, documentation improvements, and focused tests are welcome. Please open an issue before proposing new features.
This project is for educational purposes only. It does not provide investment advice and must not be used for live trading.
