Open-source project
joaquinbejar/OrderBook-rs avatar
joaquinbejar/OrderBook-rs

OrderBook-rs: a lock-free limit order book in Rust, with a hard panic policy

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.

545 stars99 forksRustMIT

At a glance

What is it?
OrderBook-rs is an MIT-licensed Rust implementation of a limit order book built on atomics and lock-free structures, supporting a wide set of order types and per-level concurrent mutation, and it enforces a zero-tolerance policy against panics in production code. It suits a team building a matching engine or simulating market behaviour, and its 0.15 snapshot format change will bite replays.
Who is it for?
OrderBook-rs is worth evaluating if you are building a matching engine or a market simulator, because the lock-free price level design and the broad order type coverage are the parts you would otherwise write, and because the snapshot and replay machinery is what makes a recorded market reproducible. It is the wrong tool if you need a strategy framework rather than a book, and it is the wrong tool if you cannot live with a young API.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 18 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the library is, and the design goals behind it

OrderBook-rs is a high-performance, thread-safe limit order book implementation written in Rust, described as a comprehensive order matching engine designed for low-latency trading systems, with a focus on concurrent access patterns and lock-free data structures.

The four design goals are stated plainly, and they are worth reading because they tell you what the library is optimising for. Correctness means all operations maintain the integrity of the order book even under high concurrency. Performance means optimising for low latency and high throughput in both write-heavy and read-heavy workloads. Scalability means supporting millions of orders and thousands of price levels without degradation. And flexibility means being easily extendable to support additional order types and matching algorithms.

The use cases follow from those goals and they are broader than trading. The library is a core component for building trading systems and exchanges, a tool for back-testing trading strategies with realistic market dynamics, a platform for studying market microstructure and order flow, and a reference implementation for understanding modern exchange architecture. That last one is a real use, and it is the one a lot of the users of a book like this are actually there for.

The feature list gives the mechanism. The lock-free architecture is built using atomics and lock-free data structures to minimise contention and maximise throughput in high-frequency trading scenarios. Price levels are thread-safe, so each price level can be independently and concurrently modified by multiple threads without blocking. The matching algorithm handles both market and limit orders and correctly deals with complex order types and partial fills. There are built-in statistics for benchmarking and monitoring, and the design is intended to scale to millions of orders with minimal memory overhead.

The library is MIT licensed, the primary language is Rust, the default branch is main, and the recent releases are v0.15.0 from 2026-09-30, v0.14.0 from 2026-09-30 and v0.13.1 from 2026-09-18, with the last push to the repository on 2026-10-05. The crate is published on crates.io as orderbook-rs and the API documentation is on docs.rs.

The order types, and why trailing stops are held off the book

The order type coverage is the widest part of the library, and one implementation detail explains how the less usual types work.

The supported types are 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. Reserve orders are the ones worth recognising: an order that is not resting but is instead kept alive by a rule that replenishes it, so the book holds a standing intent rather than a standing order.

Trailing stops are handled specially, and the description is precise. Trailing stops, held in a structure called special_orders, are held off book, trail the last trade price and execute as market orders when the last trade crosses them.

Keeping them off the book is the right design, because a trailing stop is not a price at which anybody can trade. It is a rule that watches the last trade price, and if it were a resting order it would sit in the book as a price level that nobody could hit, which would distort the book and the depth that others see. Holding it in a separate structure means the book stays clean and the stop is evaluated against trades rather than matched against quotes.

The consequence is that trailing stops are evaluated against the last trade, not against incoming orders, and that a strategy that expects a stop to be visible in the depth will not find it. That is a design decision with a cost, and the documentation is clear enough about it that a user can plan around it.

The other types are more conventional, but their interactions are where a matching engine usually goes wrong, and the design goal of correctness under concurrency is aimed precisely at that. Post-only orders that would immediately trade are rejected rather than filled, fill-or-kill orders take what liquidity is available and cancel the rest, and partial fills are handled across all of them.

The 0.15 stop protection collar, and what it changes about replay

The 0.15.0 release adds one substantial feature, and it is worth reading in detail because it is a good example of a change that is narrow in code and wide in consequence.

The feature is a protection collar for elected stop orders. The call is OrderBook::set_stop_protection(Some(StopProtection::try_new(collar)?)), and it bounds the child an elected trailing stop executes as. The child becomes an immediate-or-cancel limit order at stop minus collar for a sell stop, and stop plus collar for a buy stop, where stop is the stop's trailed stop price at election and collar is an absolute offset in price units. The collar is described as being like CME protection points, except that the remainder is cancelled rather than rested, so a stop whose band is exhausted leaves its position unprotected. The child trades only within that band and nothing rests.

The consequences are specific. A remainder the collar cut ends as Cancelled with reason StopProtectionBand, which is a new CancelReason, and one left because the side ran out within the band keeps InsufficientLiquidity. The collar must be a multiple of the tick size, giving InvalidTickSize, and it cannot be zero, giving OrderBookError::InvalidStopProtection, where unset is None. A band that reaches or passes the representable bound has the bound as its limit, and unset keeps the 0.14 unpriced immediate-or-cancel market child. The config type exists in every build, but it only acts where trailing stops exist, and paths without a pending stop never read it.

The breaking changes are the part to plan around. The snapshot format version moves to 6, with ORDERBOOK_SNAPSHOT_FORMAT_VERSION set to 6 and reads accepting 2 to 6. The payload and its checksum are unchanged from version 5, and the bump exists so that a 0.14 reader refuses a 0.15 package instead of silently restoring stops without their collar. Version-5 packages restore with no collar, and a package below 6 that carries one is rejected.

The replay behaviour is the sharpest edge. New public fields on OrderBookSnapshotPackage and ReplayBookConfig break exhaustive struct literals. Replay must be given the source book's collar, through ReplayBookConfig::with_stop_protection, constant over the replayed range, to reproduce its elections. And a mismatch is not reported as a ReplayError::OutcomeMismatch, because snapshots_match catches it only when it changed an outcome, that is when a stop was elected and filled differently, since OrderBookSnapshot does not carry the collar. The documentation is explicit that you have to verify it by comparing the replayed book's stop_protection with the source book's, or with the snapshot package's.

The wire formats diverge too. The CancelReason enum gains StopProtectionBand at bincode index 10, so exhaustive matches need the arm, and OrderStatus::Triggered gains a limit_price field, which breaks patterns and literals that name every field. JSON written by 0.14 decodes because the field is None, but bincode Triggered payloads written by 0.14 do not decode and vice versa. Nothing in the journal or the wire codec carries an OrderStatus, since the ExecReport carries only the status code, still 5.

The build system, and a panic policy enforced as a build gate

The Makefile is conventional for a Rust project, and one target is not.

sh
all: test fmt lint build

test:
	LOGLEVEL=WARN cargo test

lint: lint-panic
	cargo clippy --all-targets --all-features -- -D warnings

The default target runs the tests, the formatter, the linter and the build, so a single make invocation is the whole gate. The clippy invocation denies warnings across all targets and all features, which is stricter than the default and catches issues in the test and benchmark code as well as the library.

The unusual part is the Production Panic Policy syntax gate, and the project treats it as a first-class rule rather than a lint suggestion. The comment in the Makefile explains that the gate covers what clippy has no lint for at all, the assert and debug_assert family, and what clippy's own test detection can wrongly exempt, a standalone cfg(test) production helper that is not a mod tests block. It also covers the saturating and wrapping operations on production state, and any production allow or expect of a denied clippy lint, which is the escape hatch a plain cargo clippy cannot see, since the attribute suppresses the lint.

The implementation is a script, scripts/check_panic_policy.py, and its design is strict in two ways. It runs the scanner's own fixture self-test first, so a broken scanner can never silently report a clean source tree, and it has zero tolerance with no allowlist ledger, so any finding fails the build.

Underneath that, the clippy configuration narrows the relevant lints: unwrap_used, expect_used, panic, indexing_slicing and string_slice are the families being restricted, and clippy.toml allows them inside test items with allow-unwrap-in-tests, allow-expect-in-tests, allow-panic-in-tests and allow-indexing-slicing-in-tests. The Cargo.toml comment explains the scope, that the policy table applies to every target of the package, the library, the integration test binaries and the bench binaries, and not to the separate examples workspace member.

The panic policy is unusual for a trading library, and the reasoning behind it is sound. A panic in a matching engine is not a stack trace, it is a process that dies in the middle of a book, and a lock-free design makes the consistency argument harder to verify by inspection, so the rule is that the code must not be able to panic at all. The repository also carries a rules/ directory, an .agents/ and a .codex/ directory, a rust-toolchain.toml, a clippy.toml, a codecov.yml, BENCH.md and BENCHMARKS.md, and a target-review/ directory.

Where OrderBook-rs is the wrong tool

The first limit is that this is a book, not a trading system. It provides matching, order types, snapshots and metrics, and the use cases include building trading systems and exchanges, but there is no strategy engine, no position or risk accounting, no market data feed, no exchange connectivity and no execution layer. A team looking for a strategy framework will find an excellent component and a lot of assembly work.

The second is the young API. The crate is at 0.15.0, the releases are recent, and 0.15.0 alone carries a snapshot format bump, two new public fields, a new enum variant and a changed struct variant. That is a project moving fast and changing shape, and every one of those changes is a migration for a consumer with persisted snapshots or exhaustive matches.

The third is the replay caveat, which is a genuine trap rather than a documentation quibble. A replay that produces the same outcomes for different reasons can look correct, because the snapshot does not carry the collar and the mismatch is not reported as an outcome mismatch. A team that relies on replay to reproduce a market has to add the explicit comparison the documentation asks for, and if they do not, the failure is silent.

The fourth is the lock-free design as a cost. Lock-free structures avoid blocking but they are harder to reason about, and the price is paid at review time rather than at run time. The trailing stop implementation, which is evaluated against the last trade rather than matched in the book, is a case in point, because it means the book and the stop logic have to be kept consistent with each other by hand, and there is a documented case where a gap of more than one collar through a stop's price always consumes the stop with zero fill and leaves the position unprotected.

And the fifth is the panic policy as a constraint on contributors. Zero tolerance with no allowlist means that a legitimate case for an expect, in a branch that is genuinely unreachable, still has to be argued for in the source rather than allowed by default. That is the right default for a matching engine and a real cost for anyone extending it, because a rejected pull request over a lint is a slower contribution loop than a codebase with a pragmatic allowlist.

Editorial conclusion

OrderBook-rs is worth evaluating if you are building a matching engine or a market simulator, because the lock-free price level design and the broad order type coverage are the parts you would otherwise write, and because the snapshot and replay machinery is what makes a recorded market reproducible. It is the wrong tool if you need a strategy framework rather than a book, and it is the wrong tool if you cannot live with a young API. Before you build on it, check three things: that you understand the snapshot format change in 0.15.0, because ORDERBOOK_SNAPSHOT_FORMAT_VERSION moved to 6 with reads accepting 2 to 6, so a 0.14 reader will refuse a 0.15 package rather than silently restoring stops without their collar, and a package below 6 that carries a collar is rejected; that you set the collar explicitly when replaying, since the snapshot itself does not carry it, the mismatch is not reported as an outcome mismatch, and you have to compare the replayed book's stop_protection with the source book's yourself; and that you read the panic policy, because the project treats any unwrap, expect, panic, unreachable, todo or unimplemented in production code as a build failure with a scanner that runs its own fixture self-test first and keeps no allowlist.

Frequently asked questions

Which order types does OrderBook-rs support?

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. Trailing stops are held off the book in a special_orders structure, trail the last trade price, and execute as market orders when the last trade crosses them.

What changed in OrderBook-rs 0.15.0?

The release adds a protection collar for elected stop orders, bounding the child an elected trailing stop executes as to an immediate-or-cancel limit order at stop minus collar for a sell stop and stop plus collar for a buy stop. It also bumps the snapshot format to version 6, with reads accepting 2 to 6, adds the stop_protection field to OrderBookSnapshotPackage and ReplayBookConfig, appends CancelReason::StopProtectionBand at bincode index 10, and adds a limit_price field to OrderStatus::Triggered.

What is the Production Panic Policy in OrderBook-rs?

It is a build gate that fails the build on any unwrap, expect, panic, unreachable, todo or unimplemented in production code, with no allowlist ledger, and it covers the assert family that clippy has no lint for as well as production allow attributes that suppress a denied clippy lint. The scanner runs its own fixture self-test first so a broken scanner cannot report a clean source tree, and the clippy.toml file allows those constructs inside test items only.

Official sources

  1. Issues
  2. joaquinbejar/OrderBook-rs on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/joaquinbejar-orderbook-rs.svg)](https://hysenlabs.com/projects/joaquinbejar-orderbook-rs)

Was this useful?