OrderBook Rs
A high-performance, thread-safe limit order book implementation written in Rust. This project provides a comprehensive order matching engine designed for low-latency trading systems, with a focus on concurrent access patterns and lock-free data structures.
Install / Use
npx skills add joaquinbejar/OrderBook-rsInstalls into whichever agent you are using.
README
High-Performance Lock-Free Order Book Engine
A high-performance, thread-safe limit order book implementation written in Rust. This project provides a comprehensive order matching engine designed for low-latency trading systems, with a focus on concurrent access patterns and lock-free data structures.
Key Features
-
Lock-Free Architecture: Built using atomics and lock-free data structures to minimize contention and maximize throughput in high-frequency trading scenarios.
-
Multiple Order Types: Support for various order types including standard limit orders, iceberg orders, post-only, fill-or-kill, immediate-or-cancel, good-till-date, trailing stop, pegged, market-to-limit, and reserve orders with custom replenishment logic.
-
Thread-Safe Price Levels: Each price level can be independently and concurrently modified by multiple threads without blocking.
-
Advanced Order Matching: Efficient matching algorithm for both market and limit orders, correctly handling complex order types and partial fills.
-
Performance Metrics: Built-in statistics tracking for benchmarking and monitoring system performance.
-
Memory Efficient: Designed to scale to millions of orders with minimal memory overhead.
Design Goals
This order book engine is built with the following design principles:
- Correctness: Ensure that all operations maintain the integrity of the order book, even under high concurrency.
- Performance: Optimize for low latency and high throughput in both write-heavy and read-heavy workloads.
- Scalability: Support for millions of orders and thousands of price levels without degradation.
- Flexibility: Easily extendable to support additional order types and matching algorithms.
Use Cases
- Trading Systems: Core component for building trading systems and exchanges
- Market Simulation: Tool for back-testing trading strategies with realistic market dynamics
- Research: Platform for studying market microstructure and order flow
- Educational: Reference implementation for understanding modern exchange architecture
What's New in Version 0.12.0
v0.12.0 — pricelevel 0.9 hardening bump; upsize demotion survives snapshot restore (#205)
pricelevel0.8.4 → 0.9.1. Major upstream hardening release: level admission validates before mutating (duplicate id, counter capacity, price/side topology), PostOnly / fill-or-kill decisions are atomic with the sweep, execution statistics are torn-read-safe, and level snapshots materialize orders in queue-consumption order. 0.9.1 fixes theMatchResultbincode round-trip (PriceLevel#135), keeping thebincodefeature's trade-event round-trip intact.- The upsize queue-priority demotion now survives a snapshot
round-trip (#205). Restoring a snapshot rebuilds each level's queue
exactly as matching would consume it, so an order demoted by a quantity
increase keeps its back-of-queue position after
restore_from_snapshot_package. Locked in by a proptest regression (tests/unit/props_quantity_update_priority.rs). Snapshots captured with pricelevel < 0.9 restore demoted orders at their old(timestamp, seq)position — re-snapshot to pin the corrected order. - Breaking (semver-minor under 0.x):
get_bt_bids/get_bt_asksnow returnResult<BTreeMap<u128, PriceLevel>, OrderBookError>(snapshot-to-level conversion is validating and fallible upstream), and the re-exported pricelevel surface changed —PriceLevel::add_orderreturnsResult,matchable_quantitytakes the taker id,PriceLevelErrorgainedDuplicateOrderId. - Atomic PostOnly / multi-level FOK (#209). PostOnly submits thread
TakerKind::PostOnlyinto every per-level match, making it structurally impossible for a post-only order to take liquidity under any interleaving; fill-or-kill submits hold a new book-level submit gate exclusively across feasibility + sweep, so multi-level all-or-nothing can no longer partially execute against concurrent cancels. Other mutating entry points take the gate's uncontended read side; the matching core stays lock-free. Full 0.11.0 → 0.12.0 HDR tail-latency comparison inBENCH.md: every scenario's median is unchanged by this release's book-level work; the one median shift (stp_sweep, from the pricelevel 0.9 hardening) is documented there with its bisection. - Atomic, observable mutation failures (#211).
UpdateQuantityis validate-first (projected tick / lot / min-max / representability / risk before touching the level), propagates upstreamPriceLevelErrors instead of returningOk(None), and updates risk counters on success; a taker whose residual cannot rest is rejected before the sweep trades; a failed racy admission cleans up any empty level it created. - Two-tranche quantity conservation (#210). An aggressive iceberg's
residual rests with exactly the unmatched total distributed across
tranches (
visible = min(display, remainder), rest hidden) instead of inflating the book, and avisible + hiddenoverflow is rejected at admission with the new typedOrderBookError::QuantityOverflowbefore any trade or mutation. Conservation (executed + resting == submitted) is property-tested. snapshots_matchcompares full maker state and FIFO (#208). The replay oracle now checks every level's order vector in queue-consumption order (ids, variants, users, quantities, timestamps, TIF, type-specific fields) and the deterministic statistics counters includingstats_degraded; only the wall-time statistics aggregates (first_arrival_time,last_execution_time,sum_waiting_time— see thesnapshots_matchdocs for why each is inherently divergent) and the capture timestamp stay excluded. Contract tightening: aggregate-equal books with reversed FIFO or different maker identity no longer certify as replay-equal.- Failure-atomic snapshot restore (#207).
restore_from_snapshotandrestore_from_snapshot_packagevalidate every level (and reject cross-level duplicate order ids withDuplicateOrderId) against off-book structures before clearing the live book, so a failed restore leaves the pre-restore state — orders, indices, config, risk, kill-switch, engine sequence — completely untouched. - Snapshot package format v3 (#206). Pricelevel 0.9 statistics can
serialize a
stats_degradedfield that 0.8 readers reject, so newly written packages are stampedORDERBOOK_SNAPSHOT_FORMAT_VERSION = 3. Reads acceptORDERBOOK_SNAPSHOT_MIN_READ_VERSION (2)..=3— legacy v2 packages still restore — while1and future versions stay rejected with the existing typed error.
What's New in Version 0.11.0
v0.11.0 — replay reproduces the trade-ID stream: namespace in ReplayBookConfig (#200)
ReplayBookConfig.trade_id_namespace: Option<Uuid>. v0.10.5 (#199) made the trade-ID namespace injectable onOrderBook, but everyReplayEngine::replay_from*entry point still built its book with a random namespace, so trade IDs produced through the shipped replay API were not reproducible. The config now carries the live book's namespace and applies it viaOrderBook::set_trade_id_namespacebefore any journal events are replayed; a*_with_configreplay under an injectedClockthen reproduces the live trade-ID stream byte-identically.ReplayBookConfig::newkeeps its six structural parameters (namespace defaults toNone) — chain the newwith_trade_id_namespace(namespace)builder to set it. Without a namespace the fresh book keeps a random one, as before.- Suffix replays with a namespace are rejected. Applying a
namespace restarts the trade-ID counter at 0, so a namespace-carrying
config with
from_sequence != 0would mint wrong or duplicate IDs; the*_with_configentry points return the new typedReplayError::NamespaceRequiresFullReplayinstead. Namespace-free suffix replay keeps working. - Breaking (semver-minor under 0.x):
ReplayBookConfiggained a public field, so exhaustive struct literals no longer compile — addtrade_id_namespace: Noneor use..Default::default(); andReplayErrorgained theNamespaceRequiresFullReplayvariant, so exhaustive matches need a new arm.ReplayBookConfig::new(...)callers are unaffected. No journal or snapshot format change, noORDERBOOK_SNAPSHOT_FORMAT_VERSIONbump.
What's New in Version 0.10.5
v0.10.5 — injectable trade-ID namespace (#199)
OrderBook::set_trade_id_namespace(&mut self, namespace: Uuid). Every constructor used to mint the trade-ID namespace internally withUuid::new_v4(), so trade IDs differed bet
Related Skills
clawhub
385.5kSearch ClawHub for skills when a requested capability is not already available; install, verify, update, uninstall, publish, or sync skills.
coding-agent
385.5kDelegate coding work to Codex, Claude Code, or OpenCode as background workers; not simple edits or read-only code lookup.
obsidian
385.5kWork with Obsidian vaults using the official obsidian CLI: read/search/create/edit notes, tasks, links, properties, plugins.
taskflow
385.5kCoordinate multi-step detached tasks as one durable TaskFlow job with owner context, state, waits, and child tasks.
