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