1use std::{
19 cmp::Ordering,
20 collections::{BTreeMap, HashMap},
21 fmt::{Debug, Display, Formatter},
22};
23
24use nautilus_core::UnixNanos;
25
26use crate::{
27 data::order::{BookOrder, OrderId},
28 enums::OrderSideSpecified,
29 orderbook::BookLevel,
30 types::{Price, Quantity},
31};
32
33#[derive(Clone, Copy, Debug, Eq)]
35#[cfg_attr(
36 feature = "python",
37 pyo3::pyclass(module = "posei_trader.core.nautilus_pyo3.model")
38)]
39pub struct BookPrice {
40 pub value: Price,
41 pub side: OrderSideSpecified,
42}
43
44impl BookPrice {
45 #[must_use]
47 pub fn new(value: Price, side: OrderSideSpecified) -> Self {
48 Self { value, side }
49 }
50}
51
52impl PartialOrd for BookPrice {
53 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
54 Some(self.cmp(other))
55 }
56}
57
58impl PartialEq for BookPrice {
59 fn eq(&self, other: &Self) -> bool {
60 self.value == other.value
61 }
62}
63
64impl Ord for BookPrice {
65 fn cmp(&self, other: &Self) -> Ordering {
66 match self.side {
67 OrderSideSpecified::Buy => other.value.cmp(&self.value),
68 OrderSideSpecified::Sell => self.value.cmp(&other.value),
69 }
70 }
71}
72
73impl Display for BookPrice {
74 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
75 write!(f, "{}", self.value)
76 }
77}
78
79#[derive(Clone, Debug)]
81pub(crate) struct BookLadder {
82 pub side: OrderSideSpecified,
83 pub levels: BTreeMap<BookPrice, BookLevel>,
84 pub cache: HashMap<u64, BookPrice>,
85}
86
87impl BookLadder {
88 #[must_use]
90 pub fn new(side: OrderSideSpecified) -> Self {
91 Self {
92 side,
93 levels: BTreeMap::new(),
94 cache: HashMap::new(),
95 }
96 }
97
98 #[must_use]
100 pub fn len(&self) -> usize {
101 self.levels.len()
102 }
103
104 #[must_use]
106 #[allow(dead_code)] pub fn is_empty(&self) -> bool {
108 self.levels.is_empty()
109 }
110
111 #[allow(dead_code)] pub fn add_bulk(&mut self, orders: Vec<BookOrder>) {
114 for order in orders {
115 self.add(order);
116 }
117 }
118
119 pub fn clear(&mut self) {
121 self.levels.clear();
122 self.cache.clear();
123 }
124
125 pub fn add(&mut self, order: BookOrder) {
127 let book_price = order.to_book_price();
128 self.cache.insert(order.order_id, book_price);
129
130 match self.levels.get_mut(&book_price) {
131 Some(level) => {
132 level.add(order);
133 }
134 None => {
135 let level = BookLevel::from_order(order);
136 self.levels.insert(book_price, level);
137 }
138 }
139 }
140
141 pub fn update(&mut self, order: BookOrder) {
143 let price = self.cache.get(&order.order_id).copied();
144 if let Some(price) = price {
145 if let Some(level) = self.levels.get_mut(&price) {
146 if order.price == level.price.value {
147 let level_len_before = level.len();
149 level.update(order);
150
151 if order.size.raw == 0 {
153 self.cache.remove(&order.order_id);
154 debug_assert_eq!(
155 level.len(),
156 level_len_before - 1,
157 "Level should have one less order after zero-size update"
158 );
159 } else {
160 debug_assert!(
161 self.cache.contains_key(&order.order_id),
162 "Cache should still contain order {} after update",
163 order.order_id
164 );
165 }
166
167 if level.is_empty() {
169 self.levels.remove(&price);
170 debug_assert!(
171 !self.cache.values().any(|p| *p == price),
172 "Cache should not contain removed price level {:?}",
173 price
174 );
175 }
176
177 debug_assert_eq!(
179 self.cache.len(),
180 self.levels.values().map(|level| level.len()).sum::<usize>(),
181 "Cache size should equal total orders across all levels"
182 );
183 return;
184 }
185
186 self.cache.remove(&order.order_id);
188 level.delete(&order);
189 if level.is_empty() {
190 self.levels.remove(&price);
191 debug_assert!(
192 !self.cache.values().any(|p| *p == price),
193 "Cache should not contain removed price level {:?}",
194 price
195 );
196 }
197 }
198 }
199
200 if order.size.is_positive() {
202 self.add(order);
203 }
204
205 debug_assert_eq!(
207 self.cache.len(),
208 self.levels.values().map(|level| level.len()).sum::<usize>(),
209 "Cache size should equal total orders across all levels"
210 );
211 }
212
213 pub fn delete(&mut self, order: BookOrder, sequence: u64, ts_event: UnixNanos) {
215 self.remove(order.order_id, sequence, ts_event);
216 }
217
218 pub fn remove(&mut self, order_id: OrderId, sequence: u64, ts_event: UnixNanos) {
220 if let Some(price) = self.cache.get(&order_id).copied() {
221 if let Some(level) = self.levels.get_mut(&price) {
222 if level.orders.contains_key(&order_id) {
224 let level_len_before = level.len();
225
226 self.cache.remove(&order_id);
228 level.remove_by_id(order_id, sequence, ts_event);
229
230 debug_assert_eq!(
231 level.len(),
232 level_len_before - 1,
233 "Level should have exactly one less order after removal"
234 );
235
236 if level.is_empty() {
237 self.levels.remove(&price);
238 debug_assert!(
239 !self.cache.values().any(|p| *p == price),
240 "Cache should not contain removed price level {:?}",
241 price
242 );
243 }
244 }
245 }
246 }
247
248 debug_assert_eq!(
250 self.cache.len(),
251 self.levels.values().map(|level| level.len()).sum::<usize>(),
252 "Cache size should equal total orders across all levels"
253 );
254 }
255
256 #[must_use]
258 #[allow(dead_code)] pub fn sizes(&self) -> f64 {
260 self.levels.values().map(BookLevel::size).sum()
261 }
262
263 #[must_use]
265 #[allow(dead_code)] pub fn exposures(&self) -> f64 {
267 self.levels.values().map(BookLevel::exposure).sum()
268 }
269
270 #[must_use]
272 pub fn top(&self) -> Option<&BookLevel> {
273 match self.levels.iter().next() {
274 Some((_, l)) => Option::Some(l),
275 None => Option::None,
276 }
277 }
278
279 #[must_use]
282 pub fn simulate_fills(&self, order: &BookOrder) -> Vec<(Price, Quantity)> {
283 let is_reversed = self.side == OrderSideSpecified::Buy;
284 let mut fills = Vec::new();
285 let mut cumulative_denominator = Quantity::zero(order.size.precision);
286 let target = order.size;
287
288 for level in self.levels.values() {
289 if (is_reversed && level.price.value < order.price)
290 || (!is_reversed && level.price.value > order.price)
291 {
292 break;
293 }
294
295 for book_order in level.orders.values() {
296 let current = book_order.size;
297 if cumulative_denominator + current >= target {
298 let remainder = target - cumulative_denominator;
300 if remainder.is_positive() {
301 fills.push((book_order.price, remainder));
302 }
303 return fills;
304 }
305
306 fills.push((book_order.price, current));
308 cumulative_denominator += current;
309 }
310 }
311
312 fills
313 }
314}
315
316impl Display for BookLadder {
317 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
318 writeln!(f, "{}(side={})", stringify!(BookLadder), self.side)?;
319 for (price, level) in &self.levels {
320 writeln!(f, " {} -> {} orders", price, level.len())?;
321 }
322 Ok(())
323 }
324}
325
326#[cfg(test)]
330mod tests {
331 use rstest::rstest;
332
333 use crate::{
334 data::order::BookOrder,
335 enums::{OrderSide, OrderSideSpecified},
336 orderbook::ladder::{BookLadder, BookPrice},
337 types::{Price, Quantity},
338 };
339
340 #[rstest]
341 fn test_is_empty() {
342 let ladder = BookLadder::new(OrderSideSpecified::Buy);
343 assert!(ladder.is_empty(), "A new ladder should be empty");
344 }
345
346 #[rstest]
347 fn test_is_empty_after_add() {
348 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
349 assert!(ladder.is_empty(), "Ladder should start empty");
350 let order = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(100), 1);
351 ladder.add(order);
352 assert!(
353 !ladder.is_empty(),
354 "Ladder should not be empty after adding an order"
355 );
356 }
357
358 #[rstest]
359 fn test_add_bulk_empty() {
360 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
361 ladder.add_bulk(vec![]);
362 assert!(
363 ladder.is_empty(),
364 "Adding an empty vector should leave the ladder empty"
365 );
366 }
367
368 #[rstest]
369 fn test_add_bulk_orders() {
370 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
371 let orders = vec![
372 BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 1),
373 BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(30), 2),
374 BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(50), 3),
375 ];
376 ladder.add_bulk(orders);
377 assert_eq!(ladder.len(), 1, "Ladder should have one price level");
379 let orders_in_level = ladder.top().unwrap().get_orders();
380 assert_eq!(
381 orders_in_level.len(),
382 3,
383 "Price level should contain all bulk orders"
384 );
385 }
386
387 #[rstest]
388 fn test_book_price_bid_sorting() {
389 let mut bid_prices = [
390 BookPrice::new(Price::from("2.0"), OrderSideSpecified::Buy),
391 BookPrice::new(Price::from("4.0"), OrderSideSpecified::Buy),
392 BookPrice::new(Price::from("1.0"), OrderSideSpecified::Buy),
393 BookPrice::new(Price::from("3.0"), OrderSideSpecified::Buy),
394 ];
395 bid_prices.sort();
396 assert_eq!(bid_prices[0].value, Price::from("4.0"));
397 }
398
399 #[rstest]
400 fn test_book_price_ask_sorting() {
401 let mut ask_prices = [
402 BookPrice::new(Price::from("2.0"), OrderSideSpecified::Sell),
403 BookPrice::new(Price::from("4.0"), OrderSideSpecified::Sell),
404 BookPrice::new(Price::from("1.0"), OrderSideSpecified::Sell),
405 BookPrice::new(Price::from("3.0"), OrderSideSpecified::Sell),
406 ];
407
408 ask_prices.sort();
409 assert_eq!(ask_prices[0].value, Price::from("1.0"));
410 }
411
412 #[rstest]
413 fn test_add_single_order() {
414 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
415 let order = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 0);
416
417 ladder.add(order);
418 assert_eq!(ladder.len(), 1);
419 assert_eq!(ladder.sizes(), 20.0);
420 assert_eq!(ladder.exposures(), 200.0);
421 assert_eq!(ladder.top().unwrap().price.value, Price::from("10.0"));
422 }
423
424 #[rstest]
425 fn test_add_multiple_buy_orders() {
426 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
427 let order1 = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 0);
428 let order2 = BookOrder::new(OrderSide::Buy, Price::from("9.00"), Quantity::from(30), 1);
429 let order3 = BookOrder::new(OrderSide::Buy, Price::from("9.00"), Quantity::from(50), 2);
430 let order4 = BookOrder::new(OrderSide::Buy, Price::from("8.00"), Quantity::from(200), 3);
431
432 ladder.add_bulk(vec![order1, order2, order3, order4]);
433 assert_eq!(ladder.len(), 3);
434 assert_eq!(ladder.sizes(), 300.0);
435 assert_eq!(ladder.exposures(), 2520.0);
436 assert_eq!(ladder.top().unwrap().price.value, Price::from("10.0"));
437 }
438
439 #[rstest]
440 fn test_add_multiple_sell_orders() {
441 let mut ladder = BookLadder::new(OrderSideSpecified::Sell);
442 let order1 = BookOrder::new(OrderSide::Sell, Price::from("11.00"), Quantity::from(20), 0);
443 let order2 = BookOrder::new(OrderSide::Sell, Price::from("12.00"), Quantity::from(30), 1);
444 let order3 = BookOrder::new(OrderSide::Sell, Price::from("12.00"), Quantity::from(50), 2);
445 let order4 = BookOrder::new(
446 OrderSide::Sell,
447 Price::from("13.00"),
448 Quantity::from(200),
449 0,
450 );
451
452 ladder.add_bulk(vec![order1, order2, order3, order4]);
453 assert_eq!(ladder.len(), 3);
454 assert_eq!(ladder.sizes(), 300.0);
455 assert_eq!(ladder.exposures(), 3780.0);
456 assert_eq!(ladder.top().unwrap().price.value, Price::from("11.0"));
457 }
458
459 #[rstest]
460 fn test_add_to_same_price_level() {
461 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
462 let order1 = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 1);
463 let order2 = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(30), 2);
464
465 ladder.add(order1);
466 ladder.add(order2);
467
468 assert_eq!(ladder.len(), 1);
469 assert_eq!(ladder.sizes(), 50.0);
470 assert_eq!(ladder.exposures(), 500.0);
471 }
472
473 #[rstest]
474 fn test_add_descending_buy_orders() {
475 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
476 let order1 = BookOrder::new(OrderSide::Buy, Price::from("9.00"), Quantity::from(20), 1);
477 let order2 = BookOrder::new(OrderSide::Buy, Price::from("8.00"), Quantity::from(30), 2);
478
479 ladder.add(order1);
480 ladder.add(order2);
481
482 assert_eq!(ladder.top().unwrap().price.value, Price::from("9.00"));
483 }
484
485 #[rstest]
486 fn test_add_ascending_sell_orders() {
487 let mut ladder = BookLadder::new(OrderSideSpecified::Sell);
488 let order1 = BookOrder::new(OrderSide::Sell, Price::from("8.00"), Quantity::from(20), 1);
489 let order2 = BookOrder::new(OrderSide::Sell, Price::from("9.00"), Quantity::from(30), 2);
490
491 ladder.add(order1);
492 ladder.add(order2);
493
494 assert_eq!(ladder.top().unwrap().price.value, Price::from("8.00"));
495 }
496
497 #[rstest]
498 fn test_update_buy_order_price() {
499 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
500 let order = BookOrder::new(OrderSide::Buy, Price::from("11.00"), Quantity::from(20), 1);
501
502 ladder.add(order);
503 let order = BookOrder::new(OrderSide::Buy, Price::from("11.10"), Quantity::from(20), 1);
504
505 ladder.update(order);
506 assert_eq!(ladder.len(), 1);
507 assert_eq!(ladder.sizes(), 20.0);
508 assert_eq!(ladder.exposures(), 222.0);
509 assert_eq!(ladder.top().unwrap().price.value, Price::from("11.1"));
510 }
511
512 #[rstest]
513 fn test_update_sell_order_price() {
514 let mut ladder = BookLadder::new(OrderSideSpecified::Sell);
515 let order = BookOrder::new(OrderSide::Sell, Price::from("11.00"), Quantity::from(20), 1);
516
517 ladder.add(order);
518
519 let order = BookOrder::new(OrderSide::Sell, Price::from("11.10"), Quantity::from(20), 1);
520
521 ladder.update(order);
522 assert_eq!(ladder.len(), 1);
523 assert_eq!(ladder.sizes(), 20.0);
524 assert_eq!(ladder.exposures(), 222.0);
525 assert_eq!(ladder.top().unwrap().price.value, Price::from("11.1"));
526 }
527
528 #[rstest]
529 fn test_update_buy_order_size() {
530 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
531 let order = BookOrder::new(OrderSide::Buy, Price::from("11.00"), Quantity::from(20), 1);
532
533 ladder.add(order);
534
535 let order = BookOrder::new(OrderSide::Buy, Price::from("11.00"), Quantity::from(10), 1);
536
537 ladder.update(order);
538 assert_eq!(ladder.len(), 1);
539 assert_eq!(ladder.sizes(), 10.0);
540 assert_eq!(ladder.exposures(), 110.0);
541 assert_eq!(ladder.top().unwrap().price.value, Price::from("11.0"));
542 }
543
544 #[rstest]
545 fn test_update_sell_order_size() {
546 let mut ladder = BookLadder::new(OrderSideSpecified::Sell);
547 let order = BookOrder::new(OrderSide::Sell, Price::from("11.00"), Quantity::from(20), 1);
548
549 ladder.add(order);
550
551 let order = BookOrder::new(OrderSide::Sell, Price::from("11.00"), Quantity::from(10), 1);
552
553 ladder.update(order);
554 assert_eq!(ladder.len(), 1);
555 assert_eq!(ladder.sizes(), 10.0);
556 assert_eq!(ladder.exposures(), 110.0);
557 assert_eq!(ladder.top().unwrap().price.value, Price::from("11.0"));
558 }
559
560 #[rstest]
561 fn test_delete_non_existing_order() {
562 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
563 let order = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 1);
564
565 ladder.delete(order, 0, 0.into());
566
567 assert_eq!(ladder.len(), 0);
568 }
569
570 #[rstest]
571 fn test_delete_buy_order() {
572 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
573 let order = BookOrder::new(OrderSide::Buy, Price::from("11.00"), Quantity::from(20), 1);
574
575 ladder.add(order);
576
577 let order = BookOrder::new(OrderSide::Buy, Price::from("11.00"), Quantity::from(10), 1);
578
579 ladder.delete(order, 0, 0.into());
580 assert_eq!(ladder.len(), 0);
581 assert_eq!(ladder.sizes(), 0.0);
582 assert_eq!(ladder.exposures(), 0.0);
583 assert_eq!(ladder.top(), None);
584 }
585
586 #[rstest]
587 fn test_delete_sell_order() {
588 let mut ladder = BookLadder::new(OrderSideSpecified::Sell);
589 let order = BookOrder::new(OrderSide::Sell, Price::from("10.00"), Quantity::from(10), 1);
590
591 ladder.add(order);
592
593 let order = BookOrder::new(OrderSide::Sell, Price::from("10.00"), Quantity::from(10), 1);
594
595 ladder.delete(order, 0, 0.into());
596 assert_eq!(ladder.len(), 0);
597 assert_eq!(ladder.sizes(), 0.0);
598 assert_eq!(ladder.exposures(), 0.0);
599 assert_eq!(ladder.top(), None);
600 }
601
602 #[rstest]
603 fn test_ladder_sizes_empty() {
604 let ladder = BookLadder::new(OrderSideSpecified::Buy);
605 assert_eq!(
606 ladder.sizes(),
607 0.0,
608 "An empty ladder should have total size 0.0"
609 );
610 }
611
612 #[rstest]
613 fn test_ladder_exposures_empty() {
614 let ladder = BookLadder::new(OrderSideSpecified::Buy);
615 assert_eq!(
616 ladder.exposures(),
617 0.0,
618 "An empty ladder should have total exposure 0.0"
619 );
620 }
621
622 #[rstest]
623 fn test_ladder_sizes() {
624 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
625 let order1 = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 1);
626 let order2 = BookOrder::new(OrderSide::Buy, Price::from("9.50"), Quantity::from(30), 2);
627 ladder.add(order1);
628 ladder.add(order2);
629
630 let expected_size = 20.0 + 30.0;
631 assert_eq!(
632 ladder.sizes(),
633 expected_size,
634 "Ladder total size should match the sum of order sizes"
635 );
636 }
637
638 #[rstest]
639 fn test_ladder_exposures() {
640 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
641 let order1 = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 1);
642 let order2 = BookOrder::new(OrderSide::Buy, Price::from("9.50"), Quantity::from(30), 2);
643 ladder.add(order1);
644 ladder.add(order2);
645
646 let expected_exposure = 10.00 * 20.0 + 9.50 * 30.0;
647 assert_eq!(
648 ladder.exposures(),
649 expected_exposure,
650 "Ladder total exposure should match the sum of individual exposures"
651 );
652 }
653
654 #[rstest]
655 fn test_iter_returns_fifo() {
656 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
657 let order1 = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 1);
658 let order2 = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(30), 2);
659 ladder.add(order1);
660 ladder.add(order2);
661 let orders: Vec<BookOrder> = ladder.top().unwrap().iter().copied().collect();
662 assert_eq!(
663 orders,
664 vec![order1, order2],
665 "Iterator should return orders in FIFO order"
666 );
667 }
668
669 #[rstest]
670 fn test_update_missing_order_inserts() {
671 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
672 let order = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 1);
673 ladder.update(order);
675 assert_eq!(
676 ladder.len(),
677 1,
678 "Ladder should have one level after upsert update"
679 );
680 let orders = ladder.top().unwrap().get_orders();
681 assert_eq!(
682 orders.len(),
683 1,
684 "Price level should contain the inserted order"
685 );
686 assert_eq!(orders[0], order, "The inserted order should match");
687 }
688
689 #[rstest]
690 fn test_cache_consistency_after_operations() {
691 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
692 let order1 = BookOrder::new(OrderSide::Buy, Price::from("10.00"), Quantity::from(20), 1);
693 let order2 = BookOrder::new(OrderSide::Buy, Price::from("9.00"), Quantity::from(30), 2);
694 ladder.add(order1);
695 ladder.add(order2);
696
697 for (order_id, price) in &ladder.cache {
699 let level = ladder
700 .levels
701 .get(price)
702 .expect("Every price in the cache should have a corresponding level");
703 assert!(
704 level.orders.contains_key(order_id),
705 "Order id {order_id} should be present in the level for price {price}",
706 );
707 }
708 }
709
710 #[rstest]
711 fn test_simulate_fills_with_empty_book() {
712 let ladder = BookLadder::new(OrderSideSpecified::Buy);
713 let order = BookOrder::new(OrderSide::Buy, Price::max(2), Quantity::from(500), 1);
714
715 let fills = ladder.simulate_fills(&order);
716
717 assert!(fills.is_empty());
718 }
719
720 #[rstest]
721 #[case(OrderSide::Buy, Price::max(2), OrderSideSpecified::Sell)]
722 #[case(OrderSide::Sell, Price::min(2), OrderSideSpecified::Buy)]
723 fn test_simulate_order_fills_with_no_size(
724 #[case] side: OrderSide,
725 #[case] price: Price,
726 #[case] ladder_side: OrderSideSpecified,
727 ) {
728 let ladder = BookLadder::new(ladder_side);
729 let order = BookOrder {
730 price, size: Quantity::from(500),
732 side,
733 order_id: 2,
734 };
735
736 let fills = ladder.simulate_fills(&order);
737
738 assert!(fills.is_empty());
739 }
740
741 #[rstest]
742 #[case(OrderSide::Buy, OrderSideSpecified::Sell, Price::from("60.0"))]
743 #[case(OrderSide::Sell, OrderSideSpecified::Buy, Price::from("40.0"))]
744 fn test_simulate_order_fills_buy_when_far_from_market(
745 #[case] order_side: OrderSide,
746 #[case] ladder_side: OrderSideSpecified,
747 #[case] ladder_price: Price,
748 ) {
749 let mut ladder = BookLadder::new(ladder_side);
750
751 ladder.add(BookOrder {
752 price: ladder_price,
753 size: Quantity::from(100),
754 side: ladder_side.as_order_side(),
755 order_id: 1,
756 });
757
758 let order = BookOrder {
759 price: Price::from("50.00"),
760 size: Quantity::from(500),
761 side: order_side,
762 order_id: 2,
763 };
764
765 let fills = ladder.simulate_fills(&order);
766
767 assert!(fills.is_empty());
768 }
769
770 #[rstest]
771 fn test_simulate_order_fills_sell_when_far_from_market() {
772 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
773
774 ladder.add(BookOrder {
775 price: Price::from("100.00"),
776 size: Quantity::from(100),
777 side: OrderSide::Buy,
778 order_id: 1,
779 });
780
781 let order = BookOrder {
782 price: Price::from("150.00"), size: Quantity::from(500),
784 side: OrderSide::Buy,
785 order_id: 2,
786 };
787
788 let fills = ladder.simulate_fills(&order);
789
790 assert!(fills.is_empty());
791 }
792
793 #[rstest]
794 fn test_simulate_order_fills_buy() {
795 let mut ladder = BookLadder::new(OrderSideSpecified::Sell);
796
797 ladder.add_bulk(vec![
798 BookOrder {
799 price: Price::from("100.00"),
800 size: Quantity::from(100),
801 side: OrderSide::Sell,
802 order_id: 1,
803 },
804 BookOrder {
805 price: Price::from("101.00"),
806 size: Quantity::from(200),
807 side: OrderSide::Sell,
808 order_id: 2,
809 },
810 BookOrder {
811 price: Price::from("102.00"),
812 size: Quantity::from(400),
813 side: OrderSide::Sell,
814 order_id: 3,
815 },
816 ]);
817
818 let order = BookOrder {
819 price: Price::max(2), size: Quantity::from(500),
821 side: OrderSide::Buy,
822 order_id: 4,
823 };
824
825 let fills = ladder.simulate_fills(&order);
826
827 assert_eq!(fills.len(), 3);
828
829 let (price1, size1) = fills[0];
830 assert_eq!(price1, Price::from("100.00"));
831 assert_eq!(size1, Quantity::from(100));
832
833 let (price2, size2) = fills[1];
834 assert_eq!(price2, Price::from("101.00"));
835 assert_eq!(size2, Quantity::from(200));
836
837 let (price3, size3) = fills[2];
838 assert_eq!(price3, Price::from("102.00"));
839 assert_eq!(size3, Quantity::from(200));
840 }
841
842 #[rstest]
843 fn test_simulate_order_fills_sell() {
844 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
845
846 ladder.add_bulk(vec![
847 BookOrder {
848 price: Price::from("102.00"),
849 size: Quantity::from(100),
850 side: OrderSide::Buy,
851 order_id: 1,
852 },
853 BookOrder {
854 price: Price::from("101.00"),
855 size: Quantity::from(200),
856 side: OrderSide::Buy,
857 order_id: 2,
858 },
859 BookOrder {
860 price: Price::from("100.00"),
861 size: Quantity::from(400),
862 side: OrderSide::Buy,
863 order_id: 3,
864 },
865 ]);
866
867 let order = BookOrder {
868 price: Price::min(2), size: Quantity::from(500),
870 side: OrderSide::Sell,
871 order_id: 4,
872 };
873
874 let fills = ladder.simulate_fills(&order);
875
876 assert_eq!(fills.len(), 3);
877
878 let (price1, size1) = fills[0];
879 assert_eq!(price1, Price::from("102.00"));
880 assert_eq!(size1, Quantity::from(100));
881
882 let (price2, size2) = fills[1];
883 assert_eq!(price2, Price::from("101.00"));
884 assert_eq!(size2, Quantity::from(200));
885
886 let (price3, size3) = fills[2];
887 assert_eq!(price3, Price::from("100.00"));
888 assert_eq!(size3, Quantity::from(200));
889 }
890
891 #[rstest]
892 fn test_simulate_order_fills_sell_with_size_at_limit_of_precision() {
893 let mut ladder = BookLadder::new(OrderSideSpecified::Buy);
894
895 ladder.add_bulk(vec![
896 BookOrder {
897 price: Price::from("102.00"),
898 size: Quantity::from("100.000000000"),
899 side: OrderSide::Buy,
900 order_id: 1,
901 },
902 BookOrder {
903 price: Price::from("101.00"),
904 size: Quantity::from("200.000000000"),
905 side: OrderSide::Buy,
906 order_id: 2,
907 },
908 BookOrder {
909 price: Price::from("100.00"),
910 size: Quantity::from("400.000000000"),
911 side: OrderSide::Buy,
912 order_id: 3,
913 },
914 ]);
915
916 let order = BookOrder {
917 price: Price::min(2), size: Quantity::from("699.999999999"), side: OrderSide::Sell,
920 order_id: 4,
921 };
922
923 let fills = ladder.simulate_fills(&order);
924
925 assert_eq!(fills.len(), 3);
926
927 let (price1, size1) = fills[0];
928 assert_eq!(price1, Price::from("102.00"));
929 assert_eq!(size1, Quantity::from("100.000000000"));
930
931 let (price2, size2) = fills[1];
932 assert_eq!(price2, Price::from("101.00"));
933 assert_eq!(size2, Quantity::from("200.000000000"));
934
935 let (price3, size3) = fills[2];
936 assert_eq!(price3, Price::from("100.00"));
937 assert_eq!(size3, Quantity::from("399.999999999"));
938 }
939
940 #[rstest]
941 fn test_boundary_prices() {
942 let max_price = Price::max(1);
943 let min_price = Price::min(1);
944
945 let mut ladder_buy = BookLadder::new(OrderSideSpecified::Buy);
946 let mut ladder_sell = BookLadder::new(OrderSideSpecified::Sell);
947
948 let order_buy = BookOrder::new(OrderSide::Buy, min_price, Quantity::from(1), 1);
949 let order_sell = BookOrder::new(OrderSide::Sell, max_price, Quantity::from(1), 1);
950
951 ladder_buy.add(order_buy);
952 ladder_sell.add(order_sell);
953
954 assert_eq!(ladder_buy.top().unwrap().price.value, min_price);
955 assert_eq!(ladder_sell.top().unwrap().price.value, max_price);
956 }
957}