C++, Multithreading, WebSockets, CMake
Asynchronous limit order book (LOB) matching engine with lock-free ingress/publish queues, lock-free memory pool allocation for order nodes, and a WebSocket API for real-time Level 2 market data.
- Single-writer matching core for deterministic FIFO price-time priority.
- Lock-free MPSC command queue for concurrent producer threads.
- Lock-free object pool for order-node allocation/reuse to reduce heap churn and latency spikes.
- Dedicated matcher + publisher threads for asynchronous market data fan-out.
- Native WebSocket server with RFC6455 handshake, text frames, ping/pong, and broadcast.
- Bench harness to measure p50/p95/p99 execution latencies.
include/lom/
lockfree_mpsc_queue.hpp
matching_engine.hpp
order_book.hpp
order_pool.hpp
types.hpp
websocket_server.hpp
src/
core/order_book.cpp
engine/matching_engine.cpp
net/websocket_server.cpp
util/base64.cpp
util/sha1.cpp
main.cpp
benchmark.cpp
tests/
order_book_tests.cpp
examples/
ws_client.html
cmake -S . -B build
cmake --build build --config Releasecmake -S . -B build -G "Visual Studio 17 2022" -A x64
cmake --build build --config Release
ctest --test-dir build -C Release --output-on-failurecmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
ctest --test-dir build --output-on-failurePerformance on 300,000 order commands:
Active resting orders: 64,546
Latency p50: 0.00 µs (sub-microsecond)
Latency p95: 0.00 µs (sub-microsecond)
Latency p99: 0.00 µs (sub-microsecond)
Latency max: 3,054 µs (~3 ms)
Run the benchmark:
./build/lom_benchmark./build/lom_engineWebSocket endpoint:
ws://127.0.0.1:9002
{
"type": "new_order",
"request_id": "client-req-001",
"order_id": 1001,
"user_id": 42,
"side": "buy",
"price_ticks": 10050,
"quantity": 25,
"client_ts_ns": 0
}{
"type": "cancel_order",
"request_id": "client-req-002",
"order_id": 1001,
"user_id": 42,
"client_ts_ns": 0
}ackfor accepted/rejected command ingestion. Includes:schema_versionrequest_id(if provided by client)reason_code+reasonwhen rejected
l2payload after accepted book updates:schema_versionsequencets_nsbids:[price_ticks, total_qty, order_count]asks:[price_ticks, total_qty, order_count]trades: array of matched fills
{
"schema_version": 1,
"type": "ack",
"event": "new_order",
"status": "accepted",
"request_id": "client-req-001",
"ts_ns": 1720000000000
}{
"schema_version": 1,
"type": "l2",
"sequence": 1024,
"ts_ns": 1720000000000,
"bids": [[10050, 45, 3]],
"asks": [[10060, 20, 1]],
"trades": [
{
"taker_order_id": 2002,
"maker_order_id": 1999,
"buy_user_id": 77,
"sell_user_id": 51,
"price_ticks": 10060,
"quantity": 5,
"match_ts_ns": 1720000000000
}
]
}Gateway validation rejects orders before enqueue if:
order_id == 0user_id == 0quantity == 0orquantity > 250000price_ticksoutside[1, 2000000]
- Producer threads enqueue commands through a lock-free MPSC queue.
- Matcher thread is the single writer to the limit order book for deterministic matching.
- Publisher thread fans out acknowledgements and
l2snapshots to websocket clients. - Memory pool recycles order nodes to minimize heap-driven latency spikes.
At shutdown, the engine prints:
- submit accepted/rejected totals
- commands processed/accepted/rejected
- total trades and matched quantity
- total market data events emitted
- Roadmap:
docs/ROADMAP.md - Issue backlog:
docs/ISSUES_BACKLOG.md
ctest --test-dir build --output-on-failure./build/lom_benchmarkOpen examples/ws_client.html, connect to ws://127.0.0.1:9002, and submit orders.