1use rustc_hash::FxHashMap;
9
10use crate::{Order, OrderId, Price, PriceLevels, Quantity, Side, TimeInForce, Timestamp, TradeId};
11
12#[cfg(test)]
14use crate::OrderStatus;
15
16#[derive(Clone, Debug)]
21pub struct OrderBook {
22 bids: PriceLevels,
24 asks: PriceLevels,
26 pub(crate) orders: FxHashMap<OrderId, Order>,
28 next_order_id: u64,
30 next_trade_id: u64,
32 next_timestamp: u64,
34}
35
36impl OrderBook {
37 pub fn new() -> Self {
39 Self {
40 bids: PriceLevels::new(Side::Buy),
41 asks: PriceLevels::new(Side::Sell),
42 orders: FxHashMap::default(),
43 next_order_id: 1,
44 next_trade_id: 1,
45 next_timestamp: 1,
46 }
47 }
48
49 pub fn next_order_id(&mut self) -> OrderId {
53 let id = OrderId(self.next_order_id);
54 self.next_order_id += 1;
55 id
56 }
57
58 pub fn next_trade_id(&mut self) -> TradeId {
60 let id = TradeId(self.next_trade_id);
61 self.next_trade_id += 1;
62 id
63 }
64
65 pub fn next_timestamp(&mut self) -> Timestamp {
67 let ts = self.next_timestamp;
68 self.next_timestamp += 1;
69 ts
70 }
71
72 pub fn peek_next_order_id(&self) -> OrderId {
74 OrderId(self.next_order_id)
75 }
76
77 pub fn get_order(&self, order_id: OrderId) -> Option<&Order> {
81 self.orders.get(&order_id)
82 }
83
84 pub fn get_order_mut(&mut self, order_id: OrderId) -> Option<&mut Order> {
86 self.orders.get_mut(&order_id)
87 }
88
89 pub fn contains_order(&self, order_id: OrderId) -> bool {
91 self.orders.contains_key(&order_id)
92 }
93
94 pub fn order_count(&self) -> usize {
96 self.orders.len()
97 }
98
99 pub fn active_order_count(&self) -> usize {
101 self.orders.values().filter(|o| o.is_active()).count()
102 }
103
104 pub fn bids(&self) -> &PriceLevels {
108 &self.bids
109 }
110
111 pub fn asks(&self) -> &PriceLevels {
113 &self.asks
114 }
115
116 pub fn bids_mut(&mut self) -> &mut PriceLevels {
118 &mut self.bids
119 }
120
121 pub fn asks_mut(&mut self) -> &mut PriceLevels {
123 &mut self.asks
124 }
125
126 pub fn side(&self, side: Side) -> &PriceLevels {
128 match side {
129 Side::Buy => &self.bids,
130 Side::Sell => &self.asks,
131 }
132 }
133
134 pub fn side_mut(&mut self, side: Side) -> &mut PriceLevels {
136 match side {
137 Side::Buy => &mut self.bids,
138 Side::Sell => &mut self.asks,
139 }
140 }
141
142 pub fn opposite_side(&self, side: Side) -> &PriceLevels {
144 self.side(side.opposite())
145 }
146
147 pub fn opposite_side_mut(&mut self, side: Side) -> &mut PriceLevels {
149 self.side_mut(side.opposite())
150 }
151
152 pub fn best_bid(&self) -> Option<Price> {
156 self.bids.best_price()
157 }
158
159 pub fn best_ask(&self) -> Option<Price> {
161 self.asks.best_price()
162 }
163
164 pub fn best_bid_ask(&self) -> (Option<Price>, Option<Price>) {
166 (self.best_bid(), self.best_ask())
167 }
168
169 pub fn spread(&self) -> Option<i64> {
171 match (self.best_bid(), self.best_ask()) {
172 (Some(bid), Some(ask)) => Some(ask.0 - bid.0),
173 _ => None,
174 }
175 }
176
177 pub fn is_crossed(&self) -> bool {
180 match (self.best_bid(), self.best_ask()) {
181 (Some(bid), Some(ask)) => bid >= ask,
182 _ => false,
183 }
184 }
185
186 pub fn add_order(&mut self, mut order: Order) {
198 assert!(
199 !self.orders.contains_key(&order.id),
200 "order {} already exists",
201 order.id
202 );
203
204 let side = order.side;
205 let price = order.price;
206 let quantity = order.remaining_quantity;
207 let order_id = order.id;
208
209 let index = self.side_mut(side).insert_order(price, order_id, quantity);
211 order.position_in_level = index;
212
213 self.orders.insert(order_id, order);
215 }
216
217 pub fn cancel_order(&mut self, order_id: OrderId) -> Option<Quantity> {
222 let order = self.orders.get_mut(&order_id)?;
223
224 if !order.is_active() {
225 return None;
226 }
227
228 let side = order.side;
229 let price = order.price;
230 let remaining = order.remaining_quantity;
231 let index = order.position_in_level;
232
233 order.cancel();
235
236 self.side_mut(side).mark_tombstone(price, index, remaining);
238
239 Some(remaining)
240 }
241
242 pub fn create_order(
251 &mut self,
252 side: Side,
253 price: Price,
254 quantity: Quantity,
255 time_in_force: TimeInForce,
256 ) -> Order {
257 let id = self.next_order_id();
258 let timestamp = self.next_timestamp();
259 Order::new(id, side, price, quantity, timestamp, time_in_force)
260 }
261
262 pub fn clear_history(&mut self) -> usize {
270 let before = self.orders.len();
271 self.orders.retain(|_, order| order.is_active());
272 before - self.orders.len()
273 }
274
275 pub fn compact(&mut self) {
277 self.bids.compact();
278 self.asks.compact();
279 }
280}
281
282impl Default for OrderBook {
283 fn default() -> Self {
284 Self::new()
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use super::*;
291
292 #[test]
293 fn new_book_is_empty() {
294 let book = OrderBook::new();
295
296 assert_eq!(book.order_count(), 0);
297 assert_eq!(book.active_order_count(), 0);
298 assert_eq!(book.best_bid(), None);
299 assert_eq!(book.best_ask(), None);
300 assert_eq!(book.spread(), None);
301 assert!(!book.is_crossed());
302 }
303
304 #[test]
305 fn id_generation_is_monotonic() {
306 let mut book = OrderBook::new();
307
308 assert_eq!(book.next_order_id(), OrderId(1));
309 assert_eq!(book.next_order_id(), OrderId(2));
310 assert_eq!(book.next_order_id(), OrderId(3));
311
312 assert_eq!(book.next_trade_id(), TradeId(1));
313 assert_eq!(book.next_trade_id(), TradeId(2));
314
315 assert_eq!(book.next_timestamp(), 1);
316 assert_eq!(book.next_timestamp(), 2);
317 }
318
319 #[test]
320 fn peek_order_id_does_not_consume() {
321 let mut book = OrderBook::new();
322
323 assert_eq!(book.peek_next_order_id(), OrderId(1));
324 assert_eq!(book.peek_next_order_id(), OrderId(1));
325 assert_eq!(book.next_order_id(), OrderId(1));
326 assert_eq!(book.peek_next_order_id(), OrderId(2));
327 }
328
329 #[test]
330 fn add_and_get_order() {
331 let mut book = OrderBook::new();
332
333 let order = book.create_order(Side::Buy, Price(100_00), 100, TimeInForce::GTC);
334 let order_id = order.id;
335 book.add_order(order);
336
337 assert!(book.contains_order(order_id));
338 assert_eq!(book.order_count(), 1);
339 assert_eq!(book.active_order_count(), 1);
340
341 let retrieved = book.get_order(order_id).unwrap();
342 assert_eq!(retrieved.id, order_id);
343 assert_eq!(retrieved.price, Price(100_00));
344 assert_eq!(retrieved.remaining_quantity, 100);
345 }
346
347 #[test]
348 fn add_order_updates_best_prices() {
349 let mut book = OrderBook::new();
350
351 let bid = book.create_order(Side::Buy, Price(100_00), 100, TimeInForce::GTC);
353 book.add_order(bid);
354 assert_eq!(book.best_bid(), Some(Price(100_00)));
355 assert_eq!(book.best_ask(), None);
356
357 let ask = book.create_order(Side::Sell, Price(101_00), 100, TimeInForce::GTC);
359 book.add_order(ask);
360 assert_eq!(book.best_bid(), Some(Price(100_00)));
361 assert_eq!(book.best_ask(), Some(Price(101_00)));
362 }
363
364 #[test]
365 fn spread_calculation() {
366 let mut book = OrderBook::new();
367
368 assert_eq!(book.spread(), None);
370
371 let bid = book.create_order(Side::Buy, Price(100_00), 100, TimeInForce::GTC);
372 book.add_order(bid);
373 assert_eq!(book.spread(), None);
374
375 let ask = book.create_order(Side::Sell, Price(101_50), 100, TimeInForce::GTC);
376 book.add_order(ask);
377 assert_eq!(book.spread(), Some(150)); }
379
380 #[test]
381 fn cancel_order() {
382 let mut book = OrderBook::new();
383
384 let order = book.create_order(Side::Buy, Price(100_00), 100, TimeInForce::GTC);
385 let order_id = order.id;
386 book.add_order(order);
387
388 assert_eq!(book.active_order_count(), 1);
389 assert_eq!(book.best_bid(), Some(Price(100_00)));
390
391 let cancelled = book.cancel_order(order_id);
393 assert_eq!(cancelled, Some(100));
394
395 assert_eq!(book.order_count(), 1);
397 assert_eq!(book.active_order_count(), 0);
398 assert_eq!(
399 book.get_order(order_id).unwrap().status,
400 OrderStatus::Cancelled
401 );
402
403 assert_eq!(book.best_bid(), None);
405 }
406
407 #[test]
408 fn cancel_nonexistent_order() {
409 let mut book = OrderBook::new();
410 assert_eq!(book.cancel_order(OrderId(999)), None);
411 }
412
413 #[test]
414 fn cancel_already_cancelled() {
415 let mut book = OrderBook::new();
416
417 let order = book.create_order(Side::Buy, Price(100_00), 100, TimeInForce::GTC);
418 let order_id = order.id;
419 book.add_order(order);
420
421 book.cancel_order(order_id);
422 assert_eq!(book.cancel_order(order_id), None); }
424
425 #[test]
426 fn multiple_orders_same_price() {
427 let mut book = OrderBook::new();
428
429 let o1 = book.create_order(Side::Buy, Price(100_00), 100, TimeInForce::GTC);
430 let o2 = book.create_order(Side::Buy, Price(100_00), 200, TimeInForce::GTC);
431 let o3 = book.create_order(Side::Buy, Price(100_00), 150, TimeInForce::GTC);
432
433 book.add_order(o1);
434 book.add_order(o2);
435 book.add_order(o3);
436
437 assert_eq!(book.active_order_count(), 3);
438 assert_eq!(book.bids().level_count(), 1);
439 assert_eq!(book.bids().total_quantity(), 450);
440 }
441
442 #[test]
443 fn multiple_price_levels() {
444 let mut book = OrderBook::new();
445
446 let o1 = book.create_order(Side::Buy, Price(100_00), 100, TimeInForce::GTC);
447 let o2 = book.create_order(Side::Buy, Price(99_00), 200, TimeInForce::GTC);
448 let o3 = book.create_order(Side::Sell, Price(101_00), 150, TimeInForce::GTC);
449 let o4 = book.create_order(Side::Sell, Price(102_00), 175, TimeInForce::GTC);
450
451 book.add_order(o1);
452 book.add_order(o2);
453 book.add_order(o3);
454 book.add_order(o4);
455
456 assert_eq!(book.bids().level_count(), 2);
457 assert_eq!(book.asks().level_count(), 2);
458 assert_eq!(book.best_bid(), Some(Price(100_00)));
459 assert_eq!(book.best_ask(), Some(Price(101_00)));
460 }
461
462 #[test]
463 fn is_crossed() {
464 let mut book = OrderBook::new();
465
466 assert!(!book.is_crossed());
468
469 let bid = book.create_order(Side::Buy, Price(100_00), 100, TimeInForce::GTC);
471 let ask = book.create_order(Side::Sell, Price(101_00), 100, TimeInForce::GTC);
472 book.add_order(bid);
473 book.add_order(ask);
474 assert!(!book.is_crossed());
475
476 let high_bid = book.create_order(Side::Buy, Price(102_00), 100, TimeInForce::GTC);
478 book.add_order(high_bid);
479 assert!(book.is_crossed());
480 }
481
482 #[test]
483 fn opposite_side() {
484 let mut book = OrderBook::new();
485
486 let bid = book.create_order(Side::Buy, Price(100_00), 100, TimeInForce::GTC);
487 let ask = book.create_order(Side::Sell, Price(101_00), 100, TimeInForce::GTC);
488 book.add_order(bid);
489 book.add_order(ask);
490
491 assert_eq!(
493 book.opposite_side(Side::Buy).best_price(),
494 Some(Price(101_00))
495 );
496 assert_eq!(
498 book.opposite_side(Side::Sell).best_price(),
499 Some(Price(100_00))
500 );
501 }
502
503 #[test]
504 #[should_panic(expected = "already exists")]
505 fn add_duplicate_order_panics() {
506 let mut book = OrderBook::new();
507
508 let order = book.create_order(Side::Buy, Price(100_00), 100, TimeInForce::GTC);
509 let order_clone = order.clone();
510
511 book.add_order(order);
512 book.add_order(order_clone); }
514
515 #[test]
516 fn get_order_mut() {
517 let mut book = OrderBook::new();
518
519 let order = book.create_order(Side::Buy, Price(100_00), 100, TimeInForce::GTC);
520 let order_id = order.id;
521 book.add_order(order);
522
523 {
525 let order = book.get_order_mut(order_id).unwrap();
526 order.fill(30);
527 }
528
529 let order = book.get_order(order_id).unwrap();
531 assert_eq!(order.remaining_quantity, 70);
532 assert_eq!(order.filled_quantity, 30);
533 }
534
535 #[test]
536 fn clear_history_removes_inactive_orders() {
537 let mut book = OrderBook::new();
538
539 let o1 = book.create_order(Side::Buy, Price(100_00), 100, TimeInForce::GTC);
541 let o2 = book.create_order(Side::Buy, Price(99_00), 100, TimeInForce::GTC);
542 let o3 = book.create_order(Side::Sell, Price(101_00), 100, TimeInForce::GTC);
543 let o1_id = o1.id;
544 let o2_id = o2.id;
545 let o3_id = o3.id;
546
547 book.add_order(o1);
548 book.add_order(o2);
549 book.add_order(o3);
550
551 assert_eq!(book.order_count(), 3);
552
553 book.cancel_order(o1_id);
555 assert_eq!(book.order_count(), 3);
556 assert_eq!(book.active_order_count(), 2);
557
558 let removed = book.clear_history();
560 assert_eq!(removed, 1);
561 assert_eq!(book.order_count(), 2);
562 assert_eq!(book.active_order_count(), 2);
563
564 assert!(book.get_order(o1_id).is_none());
566 assert!(book.get_order(o2_id).is_some());
568 assert!(book.get_order(o3_id).is_some());
569 }
570}