1#![allow(dead_code)]
18
19use std::{
22 cmp::Ordering,
23 collections::{BTreeMap, HashMap},
24 fmt::{Display, Formatter},
25};
26
27use nautilus_core::UnixNanos;
28
29use crate::{
30 data::order::{BookOrder, OrderId},
31 enums::{OrderSide, OrderSideSpecified},
32 orderbook::BookLevel,
33 types::{Price, Quantity},
34};
35
36#[derive(Clone, Copy, Debug, Eq)]
38#[cfg_attr(
39 feature = "python",
40 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model")
41)]
42pub struct BookPrice {
43 pub value: Price,
44 pub side: OrderSide,
45}
46
47impl BookPrice {
48 #[must_use]
50 pub fn new(value: Price, side: OrderSide) -> Self {
51 Self { value, side }
52 }
53}
54
55impl PartialOrd for BookPrice {
56 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
57 Some(self.cmp(other))
58 }
59}
60
61impl PartialEq for BookPrice {
62 fn eq(&self, other: &Self) -> bool {
63 self.value == other.value
64 }
65}
66
67impl Ord for BookPrice {
68 fn cmp(&self, other: &Self) -> Ordering {
69 match self.side.as_specified() {
70 OrderSideSpecified::Buy => other.value.cmp(&self.value),
71 OrderSideSpecified::Sell => self.value.cmp(&other.value),
72 }
73 }
74}
75
76impl Display for BookPrice {
77 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
78 write!(f, "{}", self.value)
79 }
80}
81
82#[derive(Clone, Debug)]
84pub(crate) struct BookLadder {
85 pub side: OrderSide,
86 pub levels: BTreeMap<BookPrice, BookLevel>,
87 pub cache: HashMap<u64, BookPrice>,
88}
89
90impl BookLadder {
91 #[must_use]
93 pub fn new(side: OrderSide) -> Self {
94 Self {
95 side,
96 levels: BTreeMap::new(),
97 cache: HashMap::new(),
98 }
99 }
100
101 #[must_use]
103 pub fn len(&self) -> usize {
104 self.levels.len()
105 }
106
107 #[must_use]
109 pub fn is_empty(&self) -> bool {
110 self.levels.is_empty()
111 }
112
113 pub fn add_bulk(&mut self, orders: Vec<BookOrder>) {
115 for order in orders {
116 self.add(order);
117 }
118 }
119
120 pub fn clear(&mut self) {
122 self.levels.clear();
123 self.cache.clear();
124 }
125
126 pub fn add(&mut self, order: BookOrder) {
128 let book_price = order.to_book_price();
129 self.cache.insert(order.order_id, book_price);
130
131 match self.levels.get_mut(&book_price) {
132 Some(level) => {
133 level.add(order);
134 }
135 None => {
136 let level = BookLevel::from_order(order);
137 self.levels.insert(book_price, level);
138 }
139 }
140 }
141
142 pub fn update(&mut self, order: BookOrder) {
144 let price = self.cache.get(&order.order_id).copied();
145 if let Some(price) = price {
146 if let Some(level) = self.levels.get_mut(&price) {
147 if order.price == level.price.value {
148 level.update(order);
150 return;
151 }
152
153 self.cache.remove(&order.order_id);
155 level.delete(&order);
156 if level.is_empty() {
157 self.levels.remove(&price);
158 }
159 }
160 }
161
162 self.add(order);
163 }
164
165 pub fn delete(&mut self, order: BookOrder, sequence: u64, ts_event: UnixNanos) {
167 self.remove(order.order_id, sequence, ts_event);
168 }
169
170 pub fn remove(&mut self, order_id: OrderId, sequence: u64, ts_event: UnixNanos) {
172 if let Some(price) = self.cache.remove(&order_id) {
173 if let Some(level) = self.levels.get_mut(&price) {
174 level.remove_by_id(order_id, sequence, ts_event);
175 if level.is_empty() {
176 self.levels.remove(&price);
177 }
178 }
179 }
180 }
181
182 #[must_use]
184 pub fn sizes(&self) -> f64 {
185 self.levels
186 .values()
187 .map(super::level::BookLevel::size)
188 .sum()
189 }
190
191 #[must_use]
193 pub fn exposures(&self) -> f64 {
194 self.levels
195 .values()
196 .map(super::level::BookLevel::exposure)
197 .sum()
198 }
199
200 #[must_use]
202 pub fn top(&self) -> Option<&BookLevel> {
203 match self.levels.iter().next() {
204 Some((_, l)) => Option::Some(l),
205 None => Option::None,
206 }
207 }
208
209 #[must_use]
212 pub fn simulate_fills(&self, order: &BookOrder) -> Vec<(Price, Quantity)> {
213 let is_reversed = self.side == OrderSide::Buy;
214 let mut fills = Vec::new();
215 let mut cumulative_denominator = Quantity::zero(order.size.precision);
216 let target = order.size;
217
218 for level in self.levels.values() {
219 if (is_reversed && level.price.value < order.price)
220 || (!is_reversed && level.price.value > order.price)
221 {
222 break;
223 }
224
225 for book_order in level.orders.values() {
226 let current = book_order.size;
227 if cumulative_denominator + current >= target {
228 let remainder = target - cumulative_denominator;
230 if remainder.is_positive() {
231 fills.push((book_order.price, remainder));
232 }
233 return fills;
234 }
235
236 fills.push((book_order.price, current));
238 cumulative_denominator += current;
239 }
240 }
241
242 fills
243 }
244}
245
246#[cfg(test)]
250mod tests {
251 use rstest::rstest;
252
253 use crate::{
254 data::order::BookOrder,
255 enums::OrderSide,
256 orderbook::ladder::{BookLadder, BookPrice},
257 types::{Price, Quantity},
258 };
259
260 #[rstest]
261 fn test_book_price_bid_sorting() {
262 let mut bid_prices = [
263 BookPrice::new(Price::from("2.0"), OrderSide::Buy),
264 BookPrice::new(Price::from("4.0"), OrderSide::Buy),
265 BookPrice::new(Price::from("1.0"), OrderSide::Buy),
266 BookPrice::new(Price::from("3.0"), OrderSide::Buy),
267 ];
268 bid_prices.sort();
269 assert_eq!(bid_prices[0].value.as_f64(), 4.0);
270 }
271
272 #[rstest]
273 fn test_book_price_ask_sorting() {
274 let mut ask_prices = [
275 BookPrice::new(Price::from("2.0"), OrderSide::Sell),
276 BookPrice::new(Price::from("4.0"), OrderSide::Sell),
277 BookPrice::new(Price::from("1.0"), OrderSide::Sell),
278 BookPrice::new(Price::from("3.0"), OrderSide::Sell),
279 ];
280
281 ask_prices.sort();
282 assert_eq!(ask_prices[0].value.as_f64(), 1.0);
283 }
284
285 #[rstest]
286 fn test_add_single_order() {
287 let mut ladder = BookLadder::new(OrderSide::Buy);
288 let order = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 0);
289
290 ladder.add(order);
291 assert_eq!(ladder.len(), 1);
292 assert_eq!(ladder.sizes(), 20.0);
293 assert_eq!(ladder.exposures(), 200.0);
294 assert_eq!(ladder.top().unwrap().price.value.as_f64(), 10.0);
295 }
296
297 #[rstest]
298 fn test_add_multiple_buy_orders() {
299 let mut ladder = BookLadder::new(OrderSide::Buy);
300 let order1 = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 0);
301 let order2 = BookOrder::new(OrderSide::Buy, Price::from("9.00"), Quantity::from(30), 1);
302 let order3 = BookOrder::new(OrderSide::Buy, Price::from("9.00"), Quantity::from(50), 2);
303 let order4 = BookOrder::new(OrderSide::Buy, Price::from("8.00"), Quantity::from(200), 3);
304
305 ladder.add_bulk(vec![order1, order2, order3, order4]);
306 assert_eq!(ladder.len(), 3);
307 assert_eq!(ladder.sizes(), 300.0);
308 assert_eq!(ladder.exposures(), 2520.0);
309 assert_eq!(ladder.top().unwrap().price.value.as_f64(), 10.0);
310 }
311
312 #[rstest]
313 fn test_add_multiple_sell_orders() {
314 let mut ladder = BookLadder::new(OrderSide::Sell);
315 let order1 = BookOrder::new(OrderSide::Sell, Price::from("11.00"), Quantity::from(20), 0);
316 let order2 = BookOrder::new(OrderSide::Sell, Price::from("12.00"), Quantity::from(30), 1);
317 let order3 = BookOrder::new(OrderSide::Sell, Price::from("12.00"), Quantity::from(50), 2);
318 let order4 = BookOrder::new(
319 OrderSide::Sell,
320 Price::from("13.00"),
321 Quantity::from(200),
322 0,
323 );
324
325 ladder.add_bulk(vec![order1, order2, order3, order4]);
326 assert_eq!(ladder.len(), 3);
327 assert_eq!(ladder.sizes(), 300.0);
328 assert_eq!(ladder.exposures(), 3780.0);
329 assert_eq!(ladder.top().unwrap().price.value.as_f64(), 11.0);
330 }
331
332 #[rstest]
333 fn test_add_to_same_price_level() {
334 let mut ladder = BookLadder::new(OrderSide::Buy);
335 let order1 = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 1);
336 let order2 = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(30), 2);
337
338 ladder.add(order1);
339 ladder.add(order2);
340
341 assert_eq!(ladder.len(), 1);
342 assert_eq!(ladder.sizes(), 50.0);
343 assert_eq!(ladder.exposures(), 500.0);
344 }
345
346 #[rstest]
347 fn test_add_descending_buy_orders() {
348 let mut ladder = BookLadder::new(OrderSide::Buy);
349 let order1 = BookOrder::new(OrderSide::Buy, Price::from("9.00"), Quantity::from(20), 1);
350 let order2 = BookOrder::new(OrderSide::Buy, Price::from("8.00"), Quantity::from(30), 2);
351
352 ladder.add(order1);
353 ladder.add(order2);
354
355 assert_eq!(ladder.top().unwrap().price.value, Price::from("9.00"));
356 }
357
358 #[rstest]
359 fn test_add_ascending_sell_orders() {
360 let mut ladder = BookLadder::new(OrderSide::Sell);
361 let order1 = BookOrder::new(OrderSide::Sell, Price::from("8.00"), Quantity::from(20), 1);
362 let order2 = BookOrder::new(OrderSide::Sell, Price::from("9.00"), Quantity::from(30), 2);
363
364 ladder.add(order1);
365 ladder.add(order2);
366
367 assert_eq!(ladder.top().unwrap().price.value, Price::from("8.00"));
368 }
369
370 #[rstest]
371 fn test_update_buy_order_price() {
372 let mut ladder = BookLadder::new(OrderSide::Buy);
373 let order = BookOrder::new(OrderSide::Buy, Price::from("11.00"), Quantity::from(20), 1);
374
375 ladder.add(order);
376 let order = BookOrder::new(OrderSide::Buy, Price::from("11.10"), Quantity::from(20), 1);
377
378 ladder.update(order);
379 assert_eq!(ladder.len(), 1);
380 assert_eq!(ladder.sizes(), 20.0);
381 assert_eq!(ladder.exposures(), 222.0);
382 assert_eq!(ladder.top().unwrap().price.value.as_f64(), 11.1);
383 }
384
385 #[rstest]
386 fn test_update_sell_order_price() {
387 let mut ladder = BookLadder::new(OrderSide::Sell);
388 let order = BookOrder::new(OrderSide::Sell, Price::from("11.00"), Quantity::from(20), 1);
389
390 ladder.add(order);
391
392 let order = BookOrder::new(OrderSide::Sell, Price::from("11.10"), Quantity::from(20), 1);
393
394 ladder.update(order);
395 assert_eq!(ladder.len(), 1);
396 assert_eq!(ladder.sizes(), 20.0);
397 assert_eq!(ladder.exposures(), 222.0);
398 assert_eq!(ladder.top().unwrap().price.value.as_f64(), 11.1);
399 }
400
401 #[rstest]
402 fn test_update_buy_order_size() {
403 let mut ladder = BookLadder::new(OrderSide::Buy);
404 let order = BookOrder::new(OrderSide::Buy, Price::from("11.00"), Quantity::from(20), 1);
405
406 ladder.add(order);
407
408 let order = BookOrder::new(OrderSide::Buy, Price::from("11.00"), Quantity::from(10), 1);
409
410 ladder.update(order);
411 assert_eq!(ladder.len(), 1);
412 assert_eq!(ladder.sizes(), 10.0);
413 assert_eq!(ladder.exposures(), 110.0);
414 assert_eq!(ladder.top().unwrap().price.value.as_f64(), 11.0);
415 }
416
417 #[rstest]
418 fn test_update_sell_order_size() {
419 let mut ladder = BookLadder::new(OrderSide::Sell);
420 let order = BookOrder::new(OrderSide::Sell, Price::from("11.00"), Quantity::from(20), 1);
421
422 ladder.add(order);
423
424 let order = BookOrder::new(OrderSide::Sell, Price::from("11.00"), Quantity::from(10), 1);
425
426 ladder.update(order);
427 assert_eq!(ladder.len(), 1);
428 assert_eq!(ladder.sizes(), 10.0);
429 assert_eq!(ladder.exposures(), 110.0);
430 assert_eq!(ladder.top().unwrap().price.value.as_f64(), 11.0);
431 }
432
433 #[rstest]
434 fn test_delete_non_existing_order() {
435 let mut ladder = BookLadder::new(OrderSide::Buy);
436 let order = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 1);
437
438 ladder.delete(order, 0, 0.into());
439
440 assert_eq!(ladder.len(), 0);
441 }
442
443 #[rstest]
444 fn test_delete_buy_order() {
445 let mut ladder = BookLadder::new(OrderSide::Buy);
446 let order = BookOrder::new(OrderSide::Buy, Price::from("11.00"), Quantity::from(20), 1);
447
448 ladder.add(order);
449
450 let order = BookOrder::new(OrderSide::Buy, Price::from("11.00"), Quantity::from(10), 1);
451
452 ladder.delete(order, 0, 0.into());
453 assert_eq!(ladder.len(), 0);
454 assert_eq!(ladder.sizes(), 0.0);
455 assert_eq!(ladder.exposures(), 0.0);
456 assert_eq!(ladder.top(), None);
457 }
458
459 #[rstest]
460 fn test_delete_sell_order() {
461 let mut ladder = BookLadder::new(OrderSide::Sell);
462 let order = BookOrder::new(OrderSide::Sell, Price::from("10.00"), Quantity::from(10), 1);
463
464 ladder.add(order);
465
466 let order = BookOrder::new(OrderSide::Sell, Price::from("10.00"), Quantity::from(10), 1);
467
468 ladder.delete(order, 0, 0.into());
469 assert_eq!(ladder.len(), 0);
470 assert_eq!(ladder.sizes(), 0.0);
471 assert_eq!(ladder.exposures(), 0.0);
472 assert_eq!(ladder.top(), None);
473 }
474
475 #[rstest]
476 fn test_simulate_fills_with_empty_book() {
477 let ladder = BookLadder::new(OrderSide::Buy);
478 let order = BookOrder::new(OrderSide::Buy, Price::max(2), Quantity::from(500), 1);
479
480 let fills = ladder.simulate_fills(&order);
481
482 assert!(fills.is_empty());
483 }
484
485 #[rstest]
486 #[case(OrderSide::Buy, Price::max(2), OrderSide::Sell)]
487 #[case(OrderSide::Sell, Price::min(2), OrderSide::Buy)]
488 fn test_simulate_order_fills_with_no_size(
489 #[case] side: OrderSide,
490 #[case] price: Price,
491 #[case] ladder_side: OrderSide,
492 ) {
493 let ladder = BookLadder::new(ladder_side);
494 let order = BookOrder {
495 price, size: Quantity::from(500),
497 side,
498 order_id: 2,
499 };
500
501 let fills = ladder.simulate_fills(&order);
502
503 assert!(fills.is_empty());
504 }
505
506 #[rstest]
507 #[case(OrderSide::Buy, OrderSide::Sell, Price::from("60.0"))]
508 #[case(OrderSide::Sell, OrderSide::Buy, Price::from("40.0"))]
509 fn test_simulate_order_fills_buy_when_far_from_market(
510 #[case] order_side: OrderSide,
511 #[case] ladder_side: OrderSide,
512 #[case] ladder_price: Price,
513 ) {
514 let mut ladder = BookLadder::new(ladder_side);
515
516 ladder.add(BookOrder {
517 price: ladder_price,
518 size: Quantity::from(100),
519 side: ladder_side,
520 order_id: 1,
521 });
522
523 let order = BookOrder {
524 price: Price::from("50.00"),
525 size: Quantity::from(500),
526 side: order_side,
527 order_id: 2,
528 };
529
530 let fills = ladder.simulate_fills(&order);
531
532 assert!(fills.is_empty());
533 }
534
535 #[rstest]
536 fn test_simulate_order_fills_sell_when_far_from_market() {
537 let mut ladder = BookLadder::new(OrderSide::Buy);
538
539 ladder.add(BookOrder {
540 price: Price::from("100.00"),
541 size: Quantity::from(100),
542 side: OrderSide::Buy,
543 order_id: 1,
544 });
545
546 let order = BookOrder {
547 price: Price::from("150.00"), size: Quantity::from(500),
549 side: OrderSide::Buy,
550 order_id: 2,
551 };
552
553 let fills = ladder.simulate_fills(&order);
554
555 assert!(fills.is_empty());
556 }
557
558 #[rstest]
559 fn test_simulate_order_fills_buy() {
560 let mut ladder = BookLadder::new(OrderSide::Sell);
561
562 ladder.add_bulk(vec![
563 BookOrder {
564 price: Price::from("100.00"),
565 size: Quantity::from(100),
566 side: OrderSide::Sell,
567 order_id: 1,
568 },
569 BookOrder {
570 price: Price::from("101.00"),
571 size: Quantity::from(200),
572 side: OrderSide::Sell,
573 order_id: 2,
574 },
575 BookOrder {
576 price: Price::from("102.00"),
577 size: Quantity::from(400),
578 side: OrderSide::Sell,
579 order_id: 3,
580 },
581 ]);
582
583 let order = BookOrder {
584 price: Price::max(2), size: Quantity::from(500),
586 side: OrderSide::Buy,
587 order_id: 4,
588 };
589
590 let fills = ladder.simulate_fills(&order);
591
592 assert_eq!(fills.len(), 3);
593
594 let (price1, size1) = fills[0];
595 assert_eq!(price1, Price::from("100.00"));
596 assert_eq!(size1, Quantity::from(100));
597
598 let (price2, size2) = fills[1];
599 assert_eq!(price2, Price::from("101.00"));
600 assert_eq!(size2, Quantity::from(200));
601
602 let (price3, size3) = fills[2];
603 assert_eq!(price3, Price::from("102.00"));
604 assert_eq!(size3, Quantity::from(200));
605 }
606
607 #[rstest]
608 fn test_simulate_order_fills_sell() {
609 let mut ladder = BookLadder::new(OrderSide::Buy);
610
611 ladder.add_bulk(vec![
612 BookOrder {
613 price: Price::from("102.00"),
614 size: Quantity::from(100),
615 side: OrderSide::Buy,
616 order_id: 1,
617 },
618 BookOrder {
619 price: Price::from("101.00"),
620 size: Quantity::from(200),
621 side: OrderSide::Buy,
622 order_id: 2,
623 },
624 BookOrder {
625 price: Price::from("100.00"),
626 size: Quantity::from(400),
627 side: OrderSide::Buy,
628 order_id: 3,
629 },
630 ]);
631
632 let order = BookOrder {
633 price: Price::min(2), size: Quantity::from(500),
635 side: OrderSide::Sell,
636 order_id: 4,
637 };
638
639 let fills = ladder.simulate_fills(&order);
640
641 assert_eq!(fills.len(), 3);
642
643 let (price1, size1) = fills[0];
644 assert_eq!(price1, Price::from("102.00"));
645 assert_eq!(size1, Quantity::from(100));
646
647 let (price2, size2) = fills[1];
648 assert_eq!(price2, Price::from("101.00"));
649 assert_eq!(size2, Quantity::from(200));
650
651 let (price3, size3) = fills[2];
652 assert_eq!(price3, Price::from("100.00"));
653 assert_eq!(size3, Quantity::from(200));
654 }
655
656 #[rstest]
657 fn test_simulate_order_fills_sell_with_size_at_limit_of_precision() {
658 let mut ladder = BookLadder::new(OrderSide::Buy);
659
660 ladder.add_bulk(vec![
661 BookOrder {
662 price: Price::from("102.00"),
663 size: Quantity::from("100.000000000"),
664 side: OrderSide::Buy,
665 order_id: 1,
666 },
667 BookOrder {
668 price: Price::from("101.00"),
669 size: Quantity::from("200.000000000"),
670 side: OrderSide::Buy,
671 order_id: 2,
672 },
673 BookOrder {
674 price: Price::from("100.00"),
675 size: Quantity::from("400.000000000"),
676 side: OrderSide::Buy,
677 order_id: 3,
678 },
679 ]);
680
681 let order = BookOrder {
682 price: Price::min(2), size: Quantity::from("699.999999999"), side: OrderSide::Sell,
685 order_id: 4,
686 };
687
688 let fills = ladder.simulate_fills(&order);
689
690 assert_eq!(fills.len(), 3);
691
692 let (price1, size1) = fills[0];
693 assert_eq!(price1, Price::from("102.00"));
694 assert_eq!(size1, Quantity::from("100.000000000"));
695
696 let (price2, size2) = fills[1];
697 assert_eq!(price2, Price::from("101.00"));
698 assert_eq!(size2, Quantity::from("200.000000000"));
699
700 let (price3, size3) = fills[2];
701 assert_eq!(price3, Price::from("100.00"));
702 assert_eq!(size3, Quantity::from("399.999999999"));
703 }
704
705 #[rstest]
706 fn test_boundary_prices() {
707 let max_price = Price::max(1);
708 let min_price = Price::min(1);
709
710 let mut ladder_buy = BookLadder::new(OrderSide::Buy);
711 let mut ladder_sell = BookLadder::new(OrderSide::Sell);
712
713 let order_buy = BookOrder::new(OrderSide::Buy, min_price, Quantity::from(1), 1);
714 let order_sell = BookOrder::new(OrderSide::Sell, max_price, Quantity::from(1), 1);
715
716 ladder_buy.add(order_buy);
717 ladder_sell.add(order_sell);
718
719 assert_eq!(ladder_buy.top().unwrap().price.value, min_price);
720 assert_eq!(ladder_sell.top().unwrap().price.value, max_price);
721 }
722}