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