Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 29 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@

# PriceLevel

A high-performance, lock-free price level implementation for limit order books in Rust. This library provides the building blocks for creating efficient trading systems with support for multiple order types and concurrent access patterns.
A high-performance price level implementation for limit order books in Rust. The `Gtc` / `Ioc` / `Day` match path is lock-free (atomics + sharded / skiplist structures); admissions and updates (cancel / resize) take the shared side of a per-level guard — normally uncontended, but they can block behind an `O(depth)` fill-or-kill match that holds the exclusive side (see below). This library provides the building blocks for creating efficient trading systems with support for multiple order types and concurrent access patterns.

## Features

- Lock-free architecture for high-throughput trading applications
- Lock-free `Gtc` / `Ioc` / `Day` match path for high-throughput trading; admissions and updates (cancel / resize) are shared-lock mutators — one normally-uncontended shared acquisition that can block behind an `O(depth)` fill-or-kill match holding the exclusive side (issue #112)
- Support for diverse order types including standard limit orders, iceberg orders, post-only, fill-or-kill, and more
- Thread-safe operations with atomic counters and lock-free data structures
- Thread-safe operations built on atomic counters and lock-free data structures (with the fill-or-kill guard noted above)
- Efficient order matching and execution logic
- Designed with domain-driven principles for financial markets
- Comprehensive test suite demonstrating concurrent usage scenarios
Expand Down Expand Up @@ -52,7 +52,7 @@

## Implementation Details

- **Thread Safety**: Uses atomic operations and lock-free data structures to ensure thread safety without mutex locks
- **Thread Safety**: Uses atomic operations and lock-free data structures. The `Gtc` / `Ioc` / `Day` match path takes no lock; admissions and updates (cancel / resize) take the shared side of a per-level guard — normally uncontended, but they can block behind an `O(depth)` fill-or-kill match that holds the exclusive side (issue #112)
- **Order Queue Management**: Specialized order queue keeping strict price-time priority via a lock-free `crossbeam-skiplist` ordered index
- **Statistics Tracking**: Each price level tracks execution statistics in real-time
- **Snapshot Capabilities**: Create point-in-time snapshots of price levels for market data distribution
Expand Down Expand Up @@ -139,7 +139,7 @@ The simulation demonstrates the library's exceptional performance capabilities:
- **High-Frequency Trading**: Over **264,000 operations per second** in realistic mixed workloads
- **Hot Spot Performance**: Up to **7.75 million operations per second** under optimal conditions
- **Write-Heavy Workloads**: Over **6.3 million operations per second** for pure write operations
- **Lock-Free Architecture**: Maintains high throughput with minimal contention overhead
- **Lock-Free Match Path**: The `Gtc` / `Ioc` / `Day` match runs lock-free with minimal contention overhead; admissions / updates take a normally-uncontended shared lock that can block behind an `O(depth)` fill-or-kill match

The performance characteristics demonstrate that the `pricelevel` library is suitable for production use in high-performance trading systems, matching engines, and other financial applications where microsecond-level performance is critical.

Expand All @@ -162,10 +162,13 @@ The performance characteristics demonstrate that the `pricelevel` library is sui
are affected; nothing else is.
- **Matching concurrency contract.** [`PriceLevel::match_order`] assumes a
single logical matcher per level at a time. Concurrent `add_order` /
`cancel` from other threads are safe, but two concurrent `match_order`
calls on the *same* level — or a `match_order` racing a `cancel` of the
resting order it is currently matching — are the caller's responsibility
to serialize.
`update_order` (including a `cancel` of the resting order the matcher is
currently consuming) from other threads are safe and linearizable — the
match and the cancel serialize on the maker's per-entry lock (issue #81),
and a fill-or-kill match additionally takes a level-exclusive guard so it
stays all-or-nothing against those mutators (issue #112). Only two
concurrent `match_order` calls on the *same* level remain the caller's
responsibility to serialize.
- **Reserve replenish amounts are now `NonZeroU64`** (issue #70). A
replenish amount of `0` is structurally invalid: it would draw an empty
visible tranche from the hidden quantity, silently leaving nothing
Expand Down Expand Up @@ -452,6 +455,23 @@ checksum error). Re-take any persisted snapshots with this release. No code
changes are required at the call sites: `snapshot_to_json()` /
`from_snapshot_json()` keep the same signatures.

### Migration Guide (snapshot format v2 → v3)

`SNAPSHOT_FORMAT_VERSION` is bumped from `2` to `3` (issue #129). Version 3
owns the optional 9th statistics field, `stats_degraded` (issue #117): a
**degraded** level — one where an execution's statistics contribution was
dropped all-or-nothing — serializes that field, and such a payload is now a
v3 package rather than a v2 package mislabelled with an extra field an old
8-field-only reader would reject.

Restore is **backward compatible**: [`PriceLevelSnapshotPackage::validate`]
accepts **both** v2 (legacy, 8-field statistics, `stats_degraded` defaults
`false`) and v3, so snapshots written by the previous release keep restoring
unchanged; only v1 is still rejected. Checksum recomputation is
version-agnostic — a non-degraded level serializes the same 8 fields under
either version, so a legacy v2 package's SHA-256 still matches. New snapshots
are written at v3. No code changes are required at the call sites.

### Migration Guide (`Trade::total_value` is now checked)

[`Trade::total_value`](crate::execution::Trade::total_value) now returns
Expand Down
5 changes: 3 additions & 2 deletions examples/src/bin/integration_snapshot_recovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ fn main() {
.snapshot_package()
.unwrap_or_else(|e| exit_err(&format!("snapshot_package: {e}")));

// Snapshot format v2 (statistics persisted, issue #63).
assert_eq_or_exit(package.version(), 2, "snapshot version");
// Snapshot format v3 (statistics persisted since v2/#63; v3 owns the
// optional `stats_degraded` field, issue #129).
assert_eq_or_exit(package.version(), 3, "snapshot version");
assert_or_exit(
!package.checksum().is_empty(),
"checksum should not be empty",
Expand Down
38 changes: 29 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

//! # PriceLevel
//!
//! A high-performance, lock-free price level implementation for limit order books in Rust. This library provides the building blocks for creating efficient trading systems with support for multiple order types and concurrent access patterns.
//! A high-performance price level implementation for limit order books in Rust. The `Gtc` / `Ioc` / `Day` match path is lock-free (atomics + sharded / skiplist structures); admissions and updates (cancel / resize) take the shared side of a per-level guard — normally uncontended, but they can block behind an `O(depth)` fill-or-kill match that holds the exclusive side (see below). This library provides the building blocks for creating efficient trading systems with support for multiple order types and concurrent access patterns.
//!
//! ## Features
//!
//! - Lock-free architecture for high-throughput trading applications
//! - Lock-free `Gtc` / `Ioc` / `Day` match path for high-throughput trading; admissions and updates (cancel / resize) are shared-lock mutators — one normally-uncontended shared acquisition that can block behind an `O(depth)` fill-or-kill match holding the exclusive side (issue #112)
//! - Support for diverse order types including standard limit orders, iceberg orders, post-only, fill-or-kill, and more
//! - Thread-safe operations with atomic counters and lock-free data structures
//! - Thread-safe operations built on atomic counters and lock-free data structures (with the fill-or-kill guard noted above)
//! - Efficient order matching and execution logic
//! - Designed with domain-driven principles for financial markets
//! - Comprehensive test suite demonstrating concurrent usage scenarios
Expand Down Expand Up @@ -44,7 +44,7 @@
//!
//! ## Implementation Details
//!
//! - **Thread Safety**: Uses atomic operations and lock-free data structures to ensure thread safety without mutex locks
//! - **Thread Safety**: Uses atomic operations and lock-free data structures. The `Gtc` / `Ioc` / `Day` match path takes no lock; admissions and updates (cancel / resize) take the shared side of a per-level guard — normally uncontended, but they can block behind an `O(depth)` fill-or-kill match that holds the exclusive side (issue #112)
//! - **Order Queue Management**: Specialized order queue keeping strict price-time priority via a lock-free `crossbeam-skiplist` ordered index
//! - **Statistics Tracking**: Each price level tracks execution statistics in real-time
//! - **Snapshot Capabilities**: Create point-in-time snapshots of price levels for market data distribution
Expand Down Expand Up @@ -131,7 +131,7 @@
//! - **High-Frequency Trading**: Over **264,000 operations per second** in realistic mixed workloads
//! - **Hot Spot Performance**: Up to **7.75 million operations per second** under optimal conditions
//! - **Write-Heavy Workloads**: Over **6.3 million operations per second** for pure write operations
//! - **Lock-Free Architecture**: Maintains high throughput with minimal contention overhead
//! - **Lock-Free Match Path**: The `Gtc` / `Ioc` / `Day` match runs lock-free with minimal contention overhead; admissions / updates take a normally-uncontended shared lock that can block behind an `O(depth)` fill-or-kill match
//!
//! The performance characteristics demonstrate that the `pricelevel` library is suitable for production use in high-performance trading systems, matching engines, and other financial applications where microsecond-level performance is critical.
//!
Expand All @@ -154,10 +154,13 @@
//! are affected; nothing else is.
//! - **Matching concurrency contract.** [`PriceLevel::match_order`] assumes a
//! single logical matcher per level at a time. Concurrent `add_order` /
//! `cancel` from other threads are safe, but two concurrent `match_order`
//! calls on the *same* level — or a `match_order` racing a `cancel` of the
//! resting order it is currently matching — are the caller's responsibility
//! to serialize.
//! `update_order` (including a `cancel` of the resting order the matcher is
//! currently consuming) from other threads are safe and linearizable — the
//! match and the cancel serialize on the maker's per-entry lock (issue #81),
//! and a fill-or-kill match additionally takes a level-exclusive guard so it
//! stays all-or-nothing against those mutators (issue #112). Only two
//! concurrent `match_order` calls on the *same* level remain the caller's
//! responsibility to serialize.
//! - **Reserve replenish amounts are now `NonZeroU64`** (issue #70). A
//! replenish amount of `0` is structurally invalid: it would draw an empty
//! visible tranche from the hidden quantity, silently leaving nothing
Expand Down Expand Up @@ -444,6 +447,23 @@
//! changes are required at the call sites: `snapshot_to_json()` /
//! `from_snapshot_json()` keep the same signatures.
//!
//! ## Migration Guide (snapshot format v2 → v3)
//!
//! `SNAPSHOT_FORMAT_VERSION` is bumped from `2` to `3` (issue #129). Version 3
//! owns the optional 9th statistics field, `stats_degraded` (issue #117): a
//! **degraded** level — one where an execution's statistics contribution was
//! dropped all-or-nothing — serializes that field, and such a payload is now a
//! v3 package rather than a v2 package mislabelled with an extra field an old
//! 8-field-only reader would reject.
//!
//! Restore is **backward compatible**: [`PriceLevelSnapshotPackage::validate`]
//! accepts **both** v2 (legacy, 8-field statistics, `stats_degraded` defaults
//! `false`) and v3, so snapshots written by the previous release keep restoring
//! unchanged; only v1 is still rejected. Checksum recomputation is
//! version-agnostic — a non-degraded level serializes the same 8 fields under
//! either version, so a legacy v2 package's SHA-256 still matches. New snapshots
//! are written at v3. No code changes are required at the call sites.
//!
//! ## Migration Guide (`Trade::total_value` is now checked)
//!
//! [`Trade::total_value`](crate::execution::Trade::total_value) now returns
Expand Down
Loading
Loading