|
| 1 | +# Order Book Implementations |
| 2 | + |
| 3 | +This crate provides different order book data structure implementations optimized for various use cases in cryptocurrency trading systems. Each implementation provides the same interface through the `OrderBook` trait but uses different underlying data structures for optimal performance characteristics. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +- **Multiple Implementations**: BTreeSet, HashMap, AVL Tree, Red-Black Tree |
| 8 | +- **Async/Await Support**: All operations are async-compatible |
| 9 | +- **Thread Safety**: Built with Arc<RwLock<>> for safe concurrent access |
| 10 | +- **Depth Management**: Automatic trimming to configurable maximum depth |
| 11 | +- **Exchange Support**: Handle orders from multiple exchanges at same price levels |
| 12 | +- **Comprehensive Testing**: Extensive test suite covering edge cases and performance |
| 13 | + |
| 14 | +## Available Implementations |
| 15 | + |
| 16 | +### BTreeSet Implementation (`BTreeOrderBook`) |
| 17 | + |
| 18 | +**Best for**: General purpose use, sorted access patterns |
| 19 | + |
| 20 | +- **Insertion**: O(log n) - Maintains sorted order automatically |
| 21 | +- **Lookup**: O(log n) - Binary search through sorted structure |
| 22 | +- **Best Price**: O(1) - First element in sorted set |
| 23 | +- **Range Queries**: O(log n + k) - Efficient for getting top N orders |
| 24 | +- **Memory**: Moderate overhead due to tree structure |
| 25 | + |
| 26 | +```rust |
| 27 | +use orderbook_implementations::BTreeOrderBook; |
| 28 | + |
| 29 | +let mut orderbook = BTreeOrderBook::new(); |
| 30 | +``` |
| 31 | + |
| 32 | +### HashMap Implementation (`HashMapOrderBook`) |
| 33 | + |
| 34 | +**Best for**: High-frequency updates, fast lookups |
| 35 | + |
| 36 | +- **Insertion**: O(1) average - Direct hash table access |
| 37 | +- **Lookup**: O(1) average - Hash table lookup |
| 38 | +- **Best Price**: O(n) - Requires scanning sorted price list |
| 39 | +- **Range Queries**: O(n) - Must filter through price levels |
| 40 | +- **Memory**: Lower overhead, separate price sorting |
| 41 | + |
| 42 | +```rust |
| 43 | +use orderbook_implementations::HashMapOrderBook; |
| 44 | + |
| 45 | +let mut orderbook = HashMapOrderBook::new(); |
| 46 | +``` |
| 47 | + |
| 48 | +### Future Implementations |
| 49 | + |
| 50 | +- **AVL Tree**: Self-balancing binary search tree (placeholder) |
| 51 | +- **Red-Black Tree**: Alternative balanced tree implementation (placeholder) |
| 52 | + |
| 53 | +## Usage |
| 54 | + |
| 55 | +### Basic Operations |
| 56 | + |
| 57 | +```rust |
| 58 | +use orderbook_implementations::{BTreeOrderBook, OrderBook}; |
| 59 | +use aggregator_core::{Bid, Ask, Exchange}; |
| 60 | +use chrono::Utc; |
| 61 | + |
| 62 | +#[tokio::main] |
| 63 | +async fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 64 | + let mut orderbook = BTreeOrderBook::new(); |
| 65 | + |
| 66 | + // Add some bids |
| 67 | + let bids = vec![ |
| 68 | + Bid { |
| 69 | + price: 100.0, |
| 70 | + quantity: 10.0, |
| 71 | + exchange: Exchange::Binance, |
| 72 | + timestamp: Utc::now(), |
| 73 | + }, |
| 74 | + Bid { |
| 75 | + price: 99.5, |
| 76 | + quantity: 5.0, |
| 77 | + exchange: Exchange::Coinbase, |
| 78 | + timestamp: Utc::now(), |
| 79 | + }, |
| 80 | + ]; |
| 81 | + |
| 82 | + orderbook.update_bids(bids, 100).await; |
| 83 | + |
| 84 | + // Add some asks |
| 85 | + let asks = vec![ |
| 86 | + Ask { |
| 87 | + price: 101.0, |
| 88 | + quantity: 8.0, |
| 89 | + exchange: Exchange::Binance, |
| 90 | + timestamp: Utc::now(), |
| 91 | + }, |
| 92 | + ]; |
| 93 | + |
| 94 | + orderbook.update_asks(asks, 100).await; |
| 95 | + |
| 96 | + // Get best prices |
| 97 | + if let Some(best_bid) = orderbook.get_best_bid().await { |
| 98 | + println!("Best bid: {} @ {}", best_bid.quantity, best_bid.price); |
| 99 | + } |
| 100 | + |
| 101 | + if let Some(best_ask) = orderbook.get_best_ask().await { |
| 102 | + println!("Best ask: {} @ {}", best_ask.quantity, best_ask.price); |
| 103 | + } |
| 104 | + |
| 105 | + // Calculate spread |
| 106 | + if let Some(spread) = orderbook.get_spread().await { |
| 107 | + println!("Spread: {}", spread); |
| 108 | + } |
| 109 | + |
| 110 | + // Get top 5 bids and asks |
| 111 | + let top_bids = orderbook.get_best_n_bids(5).await; |
| 112 | + let top_asks = orderbook.get_best_n_asks(5).await; |
| 113 | + |
| 114 | + println!("Market depth: {} bids, {} asks", |
| 115 | + orderbook.bid_depth().await, |
| 116 | + orderbook.ask_depth().await); |
| 117 | + |
| 118 | + Ok(()) |
| 119 | +} |
| 120 | +``` |
| 121 | + |
| 122 | +### Side-Only Operations |
| 123 | + |
| 124 | +```rust |
| 125 | +use orderbook_implementations::{BTreeOrderBook, BuySide, SellSide}; |
| 126 | + |
| 127 | +#[tokio::main] |
| 128 | +async fn main() { |
| 129 | + let orderbook = BTreeOrderBook::new(); |
| 130 | + |
| 131 | + // Get side-specific views |
| 132 | + let mut bid_side = orderbook.bid_side(); |
| 133 | + let mut ask_side = orderbook.ask_side(); |
| 134 | + |
| 135 | + // Work with bids only |
| 136 | + bid_side.update_bids(bids, 100).await; |
| 137 | + let best_bid = bid_side.get_best_bid().await; |
| 138 | + |
| 139 | + // Work with asks only |
| 140 | + ask_side.update_asks(asks, 100).await; |
| 141 | + let best_ask = ask_side.get_best_ask().await; |
| 142 | +} |
| 143 | +``` |
| 144 | + |
| 145 | +### Order Updates and Removal |
| 146 | + |
| 147 | +```rust |
| 148 | +// Update existing order (same price + exchange) |
| 149 | +let updated_bid = Bid { |
| 150 | + price: 100.0, |
| 151 | + quantity: 20.0, // New quantity |
| 152 | + exchange: Exchange::Binance, |
| 153 | + timestamp: Utc::now(), |
| 154 | +}; |
| 155 | +orderbook.update_bids(vec![updated_bid], 100).await; |
| 156 | + |
| 157 | +// Remove order (set quantity to 0) |
| 158 | +let remove_bid = Bid { |
| 159 | + price: 100.0, |
| 160 | + quantity: 0.0, // Zero quantity removes the order |
| 161 | + exchange: Exchange::Binance, |
| 162 | + timestamp: Utc::now(), |
| 163 | +}; |
| 164 | +orderbook.update_bids(vec![remove_bid], 100).await; |
| 165 | +``` |
| 166 | + |
| 167 | +### Depth Management |
| 168 | + |
| 169 | +```rust |
| 170 | +// Limit to top 50 price levels |
| 171 | +let max_depth = 50; |
| 172 | +orderbook.update_bids(large_bid_list, max_depth).await; |
| 173 | +orderbook.update_asks(large_ask_list, max_depth).await; |
| 174 | + |
| 175 | +// Only the best 50 levels will be kept |
| 176 | +assert!(orderbook.bid_depth().await <= max_depth); |
| 177 | +assert!(orderbook.ask_depth().await <= max_depth); |
| 178 | +``` |
| 179 | + |
| 180 | +## Performance Considerations |
| 181 | + |
| 182 | +### Choosing an Implementation |
| 183 | + |
| 184 | +- **BTreeOrderBook**: Choose when you need sorted access and don't mind O(log n) operations |
| 185 | +- **HashMapOrderBook**: Choose when you need fastest updates and can tolerate O(n) for best price queries |
| 186 | +- **Future implementations**: Will provide specialized performance characteristics |
| 187 | + |
| 188 | +### Optimization Tips |
| 189 | + |
| 190 | +1. **Batch Updates**: Update multiple orders in a single call when possible |
| 191 | +2. **Appropriate Depth**: Set `max_depth` to limit memory usage and improve performance |
| 192 | +3. **Concurrent Access**: Use the shared Arc<RwLock<>> pattern for multiple readers |
| 193 | +4. **Avoid Frequent Clearing**: Prefer selective updates over full clears |
| 194 | + |
| 195 | +## Testing |
| 196 | + |
| 197 | +The crate includes comprehensive tests covering: |
| 198 | + |
| 199 | +- **Integration Tests**: Cross-implementation compatibility |
| 200 | +- **Unit Tests**: Implementation-specific behavior |
| 201 | +- **Edge Cases**: Extreme values, error conditions |
| 202 | +- **Performance Benchmarks**: Comparative performance analysis |
| 203 | + |
| 204 | +### Running Tests |
| 205 | + |
| 206 | +```bash |
| 207 | +# Run all tests |
| 208 | +cargo test |
| 209 | + |
| 210 | +# Run specific test suite |
| 211 | +cargo test --test integration_tests |
| 212 | +cargo test --test btree_tests |
| 213 | +cargo test --test edge_cases |
| 214 | + |
| 215 | +# Run benchmarks |
| 216 | +cargo bench |
| 217 | +``` |
| 218 | + |
| 219 | +### Test Coverage |
| 220 | + |
| 221 | +- Basic CRUD operations |
| 222 | +- Order updates and replacements |
| 223 | +- Depth limiting functionality |
| 224 | +- Multi-exchange handling |
| 225 | +- Concurrent access patterns |
| 226 | +- Edge cases (extreme values, empty states) |
| 227 | +- Performance under load |
| 228 | + |
| 229 | +## Thread Safety |
| 230 | + |
| 231 | +All implementations are designed for concurrent access: |
| 232 | + |
| 233 | +```rust |
| 234 | +use std::sync::Arc; |
| 235 | +use tokio::sync::Mutex; |
| 236 | + |
| 237 | +let orderbook = Arc::new(Mutex::new(BTreeOrderBook::new())); |
| 238 | + |
| 239 | +// Multiple tasks can safely access the orderbook |
| 240 | +let orderbook_clone = orderbook.clone(); |
| 241 | +tokio::spawn(async move { |
| 242 | + let mut ob = orderbook_clone.lock().await; |
| 243 | + ob.update_bids(bids, 100).await; |
| 244 | +}); |
| 245 | +``` |
| 246 | + |
| 247 | +## Error Handling |
| 248 | + |
| 249 | +The implementations handle various edge cases gracefully: |
| 250 | + |
| 251 | +- Empty order books return `None` for best price queries |
| 252 | +- Zero quantities automatically remove orders |
| 253 | +- Depth limiting keeps only the best N levels |
| 254 | +- Invalid inputs are handled without panicking |
| 255 | + |
| 256 | +## Contributing |
| 257 | + |
| 258 | +When adding new implementations: |
| 259 | + |
| 260 | +1. Implement the `OrderBook` trait |
| 261 | +2. Add comprehensive tests in the `tests/` directory |
| 262 | +3. Include benchmarks in `benches/` |
| 263 | +4. Update this README with performance characteristics |
| 264 | +5. Ensure thread safety with appropriate synchronization |
| 265 | + |
| 266 | +## Dependencies |
| 267 | + |
| 268 | +- `aggregator-core`: Core types (Bid, Ask, Exchange) |
| 269 | +- `tokio`: Async runtime and synchronization primitives |
| 270 | +- `async-trait`: Async trait support |
| 271 | +- `chrono`: Timestamp handling |
| 272 | +- `criterion`: Benchmarking framework (dev dependency) |
| 273 | + |
| 274 | +## License |
| 275 | + |
| 276 | +This project is licensed under the same terms as the parent aggregator project. |
0 commit comments