1use std::collections::BTreeMap;
2
3use crate::arena::OrderArena;
4use crate::models::{
5 BookDepth, BookLevel, FillMetadata, OrderEvent, OrderType, Side, Trade,
6};
7
8const DEFAULT_ARENA_CAPACITY: usize = 10_000;
9const DEFAULT_QUEUE_CAPACITY: usize = 10;
10
11#[derive(Debug)]
15pub struct OrderBook {
16 last_trade: Option<Trade>,
17 traded_volume: u64,
18 min_ask: Option<u64>,
19 max_bid: Option<u64>,
20 asks: BTreeMap<u64, Vec<usize>>,
21 bids: BTreeMap<u64, Vec<usize>>,
22 arena: OrderArena,
23 default_queue_capacity: usize,
24 track_stats: bool,
25}
26
27impl Default for OrderBook {
28 fn default() -> Self {
32 Self::new(DEFAULT_ARENA_CAPACITY, DEFAULT_QUEUE_CAPACITY, false)
33 }
34}
35
36impl OrderBook {
37 pub fn new(
51 arena_capacity: usize,
52 queue_capacity: usize,
53 track_stats: bool,
54 ) -> Self {
55 Self {
56 last_trade: None,
57 traded_volume: 0,
58 min_ask: None,
59 max_bid: None,
60 asks: BTreeMap::new(),
61 bids: BTreeMap::new(),
62 arena: OrderArena::new(arena_capacity),
63 default_queue_capacity: queue_capacity,
64 track_stats,
65 }
66 }
67
68 #[cfg(test)]
69 #[doc(hidden)]
70 pub fn _asks(&self) -> BTreeMap<u64, Vec<usize>> {
71 self.asks.clone()
72 }
73
74 #[cfg(test)]
75 #[doc(hidden)]
76 pub fn _bids(&self) -> BTreeMap<u64, Vec<usize>> {
77 self.bids.clone()
78 }
79
80 #[inline(always)]
82 pub fn min_ask(&self) -> Option<u64> {
83 self.min_ask
84 }
85
86 #[inline(always)]
88 pub fn max_bid(&self) -> Option<u64> {
89 self.max_bid
90 }
91
92 #[inline(always)]
95 pub fn spread(&self) -> Option<u64> {
96 match (self.max_bid, self.min_ask) {
97 (Some(b), Some(a)) => Some(a - b),
98 _ => None,
99 }
100 }
101
102 #[inline(always)]
107 pub fn last_trade(&self) -> Option<Trade> {
108 self.last_trade
109 }
110
111 #[inline(always)]
114 pub fn traded_volume(&self) -> u64 {
115 self.traded_volume
116 }
117
118 pub fn depth(&self, levels: usize) -> BookDepth {
125 let mut asks: Vec<BookLevel> = Vec::with_capacity(levels);
126 let mut bids: Vec<BookLevel> = Vec::with_capacity(levels);
127
128 for (ask_price, queue) in self.asks.iter() {
129 let mut qty = 0;
130 for idx in queue {
131 qty += self.arena[*idx].qty;
132 }
133 if qty > 0 {
134 asks.push(BookLevel {
135 price: *ask_price,
136 qty,
137 });
138 }
139 }
140
141 for (bid_price, queue) in self.bids.iter() {
142 let mut qty = 0;
143 for idx in queue {
144 qty += self.arena[*idx].qty;
145 }
146 if qty > 0 {
147 bids.push(BookLevel {
148 price: *bid_price,
149 qty,
150 });
151 }
152 }
153
154 BookDepth { levels, asks, bids }
155 }
156
157 pub fn track_stats(&mut self, track: bool) {
159 self.track_stats = track;
160 }
161
162 pub fn execute(&mut self, event: OrderType) -> OrderEvent {
164 let event = self._execute(event);
165 if !self.track_stats {
166 return event;
167 }
168
169 match event.clone() {
170 OrderEvent::Filled {
171 id: _,
172 filled_qty,
173 fills,
174 } => {
175 self.traded_volume += filled_qty;
176 let last_fill = fills.last().unwrap();
178 self.last_trade = Some(Trade {
179 total_qty: filled_qty,
180 avg_price: fills
181 .iter()
182 .map(|fm| fm.price * fm.qty)
183 .sum::<u64>() as f64
184 / (filled_qty as f64),
185 last_qty: last_fill.qty,
186 last_price: last_fill.price,
187 });
188 }
189 OrderEvent::PartiallyFilled {
190 id: _,
191 filled_qty,
192 fills,
193 } => {
194 self.traded_volume += filled_qty;
195 let last_fill = fills.last().unwrap();
197 self.last_trade = Some(Trade {
198 total_qty: filled_qty,
199 avg_price: fills
200 .iter()
201 .map(|fm| fm.price * fm.qty)
202 .sum::<u64>() as f64
203 / (filled_qty as f64),
204 last_qty: last_fill.qty,
205 last_price: last_fill.price,
206 });
207 }
208 _ => {}
209 }
210 event
211 }
212
213 fn _execute(&mut self, event: OrderType) -> OrderEvent {
214 match event {
215 OrderType::Market { id, side, qty } => {
216 let (fills, partial, filled_qty) = self.market(id, side, qty);
217 if fills.is_empty() {
218 OrderEvent::Unfilled { id }
219 } else {
220 match partial {
221 false => OrderEvent::Filled {
222 id,
223 filled_qty,
224 fills,
225 },
226 true => OrderEvent::PartiallyFilled {
227 id,
228 filled_qty,
229 fills,
230 },
231 }
232 }
233 }
234 OrderType::Limit {
235 id,
236 side,
237 qty,
238 price,
239 } => {
240 let (fills, partial, filled_qty) =
241 self.limit(id, side, qty, price);
242 if fills.is_empty() {
243 OrderEvent::Placed { id }
244 } else {
245 match partial {
246 false => OrderEvent::Filled {
247 id,
248 filled_qty,
249 fills,
250 },
251 true => OrderEvent::PartiallyFilled {
252 id,
253 filled_qty,
254 fills,
255 },
256 }
257 }
258 }
259 OrderType::Cancel { id } => {
260 self.cancel(id);
261 OrderEvent::Canceled { id }
262 }
263 }
264 }
265
266 fn cancel(&mut self, id: u128) -> bool {
267 if let Some((price, idx)) = self.arena.get(id) {
268 if let Some(ref mut queue) = self.asks.get_mut(&price) {
269 if let Some(i) = queue.iter().position(|i| *i == idx) {
270 queue.remove(i);
271 }
272 self.update_min_ask();
273 }
274 if let Some(ref mut queue) = self.bids.get_mut(&price) {
275 if let Some(i) = queue.iter().position(|i| *i == idx) {
276 queue.remove(i);
277 }
278 self.update_max_bid();
279 }
280 }
281 self.arena.delete(&id)
282 }
283
284 fn market(
285 &mut self,
286 id: u128,
287 side: Side,
288 qty: u64,
289 ) -> (Vec<FillMetadata>, bool, u64) {
290 let mut partial = false;
291 let remaining_qty;
292 let mut fills = Vec::new();
293
294 match side {
295 Side::Bid => {
296 remaining_qty = self.match_with_asks(id, qty, &mut fills, None);
297 if remaining_qty > 0 {
298 partial = true;
299 }
300 }
301 Side::Ask => {
302 remaining_qty = self.match_with_bids(id, qty, &mut fills, None);
303 if remaining_qty > 0 {
304 partial = true;
305 }
306 }
307 }
308
309 (fills, partial, qty - remaining_qty)
310 }
311
312 fn limit(
313 &mut self,
314 id: u128,
315 side: Side,
316 qty: u64,
317 price: u64,
318 ) -> (Vec<FillMetadata>, bool, u64) {
319 let mut partial = false;
320 let remaining_qty;
321 let mut fills: Vec<FillMetadata> = Vec::new();
322
323 match side {
324 Side::Bid => {
325 remaining_qty =
326 self.match_with_asks(id, qty, &mut fills, Some(price));
327 if remaining_qty > 0 {
328 partial = true;
329 let index = self.arena.insert(id, price, remaining_qty);
330 let queue_capacity = self.default_queue_capacity;
331 self.bids
332 .entry(price)
333 .or_insert_with(|| Vec::with_capacity(queue_capacity))
334 .push(index);
335 match self.max_bid {
336 None => {
337 self.max_bid = Some(price);
338 }
339 Some(b) if price > b => {
340 self.max_bid = Some(price);
341 }
342 _ => {}
343 };
344 }
345 }
346 Side::Ask => {
347 remaining_qty =
348 self.match_with_bids(id, qty, &mut fills, Some(price));
349 if remaining_qty > 0 {
350 partial = true;
351 let index = self.arena.insert(id, price, remaining_qty);
352 if let Some(a) = self.min_ask {
353 if price < a {
354 self.min_ask = Some(price);
355 }
356 }
357 let queue_capacity = self.default_queue_capacity;
358 self.asks
359 .entry(price)
360 .or_insert_with(|| Vec::with_capacity(queue_capacity))
361 .push(index);
362 match self.min_ask {
363 None => {
364 self.min_ask = Some(price);
365 }
366 Some(a) if price < a => {
367 self.min_ask = Some(price);
368 }
369 _ => {}
370 };
371 }
372 }
373 }
374
375 (fills, partial, qty - remaining_qty)
376 }
377
378 fn match_with_asks(
379 &mut self,
380 id: u128,
381 qty: u64,
382 fills: &mut Vec<FillMetadata>,
383 limit_price: Option<u64>,
384 ) -> u64 {
385 let mut remaining_qty = qty;
386 let mut update_bid_ask = false;
387 for (ask_price, queue) in self.asks.iter_mut() {
388 if queue.is_empty() {
389 continue;
390 }
391 if (update_bid_ask || self.min_ask.is_none()) && !queue.is_empty() {
392 self.min_ask = Some(*ask_price);
393 update_bid_ask = false;
394 }
395 if let Some(lp) = limit_price {
396 if lp < *ask_price {
397 break;
398 }
399 }
400 if remaining_qty == 0 {
401 break;
402 }
403 let filled_qty = Self::process_queue(
404 &mut self.arena,
405 queue,
406 remaining_qty,
407 id,
408 Side::Bid,
409 fills,
410 );
411 if queue.is_empty() {
412 update_bid_ask = true;
413 }
414 remaining_qty -= filled_qty;
415 }
416
417 self.update_min_ask();
418 remaining_qty
419 }
420
421 fn match_with_bids(
422 &mut self,
423 id: u128,
424 qty: u64,
425 fills: &mut Vec<FillMetadata>,
426 limit_price: Option<u64>,
427 ) -> u64 {
428 let mut remaining_qty = qty;
429 let mut update_bid_ask = false;
430 for (bid_price, queue) in self.bids.iter_mut().rev() {
431 if queue.is_empty() {
432 continue;
433 }
434 if (update_bid_ask || self.max_bid.is_none()) && !queue.is_empty() {
435 self.max_bid = Some(*bid_price);
436 update_bid_ask = false;
437 }
438 if let Some(lp) = limit_price {
439 if lp > *bid_price {
440 break;
441 }
442 }
443 if remaining_qty == 0 {
444 break;
445 }
446 let filled_qty = Self::process_queue(
447 &mut self.arena,
448 queue,
449 remaining_qty,
450 id,
451 Side::Ask,
452 fills,
453 );
454 if queue.is_empty() {
455 update_bid_ask = true;
456 }
457 remaining_qty -= filled_qty;
458 }
459
460 self.update_max_bid();
461 remaining_qty
462 }
463
464 fn update_min_ask(&mut self) {
465 let mut cur_asks = self.asks.iter().filter(|(_, q)| !q.is_empty());
466 self.min_ask = match cur_asks.next() {
467 None => None,
468 Some((p, _)) => Some(*p),
469 };
470 }
471
472 fn update_max_bid(&mut self) {
473 let mut cur_bids =
474 self.bids.iter().rev().filter(|(_, q)| !q.is_empty());
475 self.max_bid = match cur_bids.next() {
476 None => None,
477 Some((p, _)) => Some(*p),
478 };
479 }
480
481 fn process_queue(
482 arena: &mut OrderArena,
483 opposite_orders: &mut Vec<usize>,
484 remaining_qty: u64,
485 id: u128,
486 side: Side,
487 fills: &mut Vec<FillMetadata>,
488 ) -> u64 {
489 let mut qty_to_fill = remaining_qty;
490 let mut filled_qty = 0;
491 let mut filled_index = None;
492
493 for (index, head_order_idx) in opposite_orders.iter_mut().enumerate() {
494 if qty_to_fill == 0 {
495 break;
496 }
497 let head_order = &mut arena[*head_order_idx];
498 let traded_price = head_order.price;
499 let available_qty = head_order.qty;
500 if available_qty == 0 {
501 filled_index = Some(index);
502 continue;
503 }
504 let traded_quantity: u64;
505 let filled;
506
507 if qty_to_fill >= available_qty {
508 traded_quantity = available_qty;
509 qty_to_fill -= available_qty;
510 filled_index = Some(index);
511 filled = true;
512 } else {
513 traded_quantity = qty_to_fill;
514 qty_to_fill = 0;
515 filled = false;
516 }
517 head_order.qty -= traded_quantity;
518 let fill: FillMetadata;
519 fill = FillMetadata {
520 order_1: id,
521 order_2: head_order.id,
522 qty: traded_quantity,
523 price: traded_price,
524 taker_side: side,
525 total_fill: filled,
526 };
527 fills.push(fill);
528 filled_qty += traded_quantity;
529 }
530 if let Some(index) = filled_index {
531 opposite_orders.drain(0..index + 1);
532 }
533
534 filled_qty
535 }
536}
537
538#[cfg(test)]
539mod test {
540 use crate::{
541 BookDepth, BookLevel, FillMetadata, OrderBook, OrderEvent, OrderType,
542 Side, Trade,
543 };
544 use std::collections::BTreeMap;
545
546 const DEFAULT_QUEUE_SIZE: usize = 10;
547 const BID_ASK_COMBINATIONS: [(Side, Side); 2] =
548 [(Side::Bid, Side::Ask), (Side::Ask, Side::Bid)];
549
550 impl PartialEq for Trade {
554 fn eq(&self, other: &Self) -> bool {
555 self.total_qty == other.total_qty
556 && (self.avg_price - other.avg_price).abs() < 1.0e-6
557 && self.last_qty == other.last_qty
558 && self.last_price == other.last_price
559 }
560 }
561
562 fn init_ob(events: Vec<OrderType>) -> (OrderBook, Vec<OrderEvent>) {
563 let mut ob = OrderBook::default();
564 ob.track_stats(true);
565 let mut results = Vec::new();
566 for e in events {
567 results.push(ob.execute(e));
568 }
569 (ob, results)
570 }
571
572 fn init_book(orders: Vec<(u64, usize)>) -> BTreeMap<u64, Vec<usize>> {
573 let mut bk = BTreeMap::new();
574 for (p, i) in orders {
575 bk.entry(p)
576 .or_insert_with(|| Vec::with_capacity(DEFAULT_QUEUE_SIZE))
577 .push(i);
578 }
579 bk
580 }
581
582 fn init_book_holes(
583 orders: Vec<(u64, usize)>,
584 holes: Vec<u64>,
585 ) -> BTreeMap<u64, Vec<usize>> {
586 let mut bk = init_book(orders);
587 for h in holes {
588 bk.insert(h, Vec::new());
589 }
590 bk
591 }
592
593 #[test]
594 fn empty_book() {
595 let (ob, results) = init_ob(Vec::new());
596 assert_eq!(results, Vec::new());
597 assert_eq!(ob.min_ask(), None);
598 assert_eq!(ob.max_bid(), None);
599 assert_eq!(ob._asks(), BTreeMap::new());
600 assert_eq!(ob._bids(), BTreeMap::new());
601 assert_eq!(ob.spread(), None);
602 assert_eq!(ob.traded_volume(), 0);
603 assert_eq!(
604 ob.depth(2),
605 BookDepth {
606 levels: 2,
607 asks: Vec::new(),
608 bids: Vec::new()
609 }
610 );
611 assert_eq!(ob.last_trade(), None);
612 }
613
614 #[test]
615 fn one_resting_order() {
616 for (bid_ask, _) in &BID_ASK_COMBINATIONS {
617 let (ob, results) = init_ob(vec![OrderType::Limit {
618 id: 0,
619 side: *bid_ask,
620 qty: 12,
621 price: 395,
622 }]);
623 assert_eq!(results, vec![OrderEvent::Placed { id: 0 }]);
624 if *bid_ask == Side::Bid {
625 assert_eq!(ob.min_ask(), None);
626 assert_eq!(ob.max_bid(), Some(395));
627 assert_eq!(ob._asks(), BTreeMap::new());
628 assert_eq!(ob._bids(), init_book(vec![(395, 9999)]));
629 assert_eq!(ob.spread(), None);
630 assert_eq!(ob.traded_volume(), 0);
631 assert_eq!(
632 ob.depth(3),
633 BookDepth {
634 levels: 3,
635 asks: Vec::new(),
636 bids: vec![BookLevel {
637 price: 395,
638 qty: 12
639 }],
640 }
641 );
642 assert_eq!(ob.last_trade(), None);
643 } else {
644 assert_eq!(ob.min_ask(), Some(395));
645 assert_eq!(ob.max_bid(), None);
646 assert_eq!(ob._asks(), init_book(vec![(395, 9999)]));
647 assert_eq!(ob._bids(), BTreeMap::new());
648 assert_eq!(ob.spread(), None);
649 assert_eq!(ob.traded_volume(), 0);
650 assert_eq!(
651 ob.depth(4),
652 BookDepth {
653 levels: 4,
654 asks: vec![BookLevel {
655 price: 395,
656 qty: 12
657 }],
658 bids: Vec::new()
659 }
660 );
661 assert_eq!(ob.last_trade(), None);
662 }
663 }
664 }
665
666 #[test]
667 fn two_resting_orders() {
668 for (bid_ask, ask_bid) in &BID_ASK_COMBINATIONS {
669 let (ob, results) = init_ob(vec![
670 OrderType::Limit {
671 id: 0,
672 side: *bid_ask,
673 qty: 12,
674 price: 395,
675 },
676 OrderType::Limit {
677 id: 1,
678 side: *ask_bid,
679 qty: 2,
680 price: 398,
681 },
682 ]);
683 if *bid_ask == Side::Bid {
684 assert_eq!(
685 results,
686 vec![
687 OrderEvent::Placed { id: 0 },
688 OrderEvent::Placed { id: 1 }
689 ]
690 );
691 assert_eq!(ob.min_ask(), Some(398));
692 assert_eq!(ob.max_bid(), Some(395));
693 assert_eq!(ob._asks(), init_book(vec![(398, 9998)]));
694 assert_eq!(ob._bids(), init_book(vec![(395, 9999)]));
695 assert_eq!(ob.spread(), Some(3));
696 assert_eq!(ob.traded_volume(), 0);
697 assert_eq!(
698 ob.depth(4),
699 BookDepth {
700 levels: 4,
701 asks: vec![BookLevel { price: 398, qty: 2 }],
702 bids: vec![BookLevel {
703 price: 395,
704 qty: 12
705 }],
706 }
707 );
708 assert_eq!(ob.last_trade(), None);
709 } else {
710 assert_eq!(
711 results,
712 vec![
713 OrderEvent::Placed { id: 0 },
714 OrderEvent::Filled {
715 id: 1,
716 filled_qty: 2,
717 fills: vec![FillMetadata {
718 order_1: 1,
719 order_2: 0,
720 qty: 2,
721 price: 395,
722 taker_side: *ask_bid,
723 total_fill: false,
724 }],
725 }
726 ]
727 );
728 assert_eq!(ob.min_ask(), Some(395));
729 assert_eq!(ob.max_bid(), None);
730 assert_eq!(ob._asks(), init_book(vec![(395, 9999)]));
731 assert_eq!(ob._bids(), init_book(vec![]));
732 assert_eq!(ob.spread(), None);
733 assert_eq!(ob.traded_volume(), 2);
734 assert_eq!(
735 ob.depth(4),
736 BookDepth {
737 levels: 4,
738 asks: vec![BookLevel {
739 price: 395,
740 qty: 10,
741 }],
742 bids: Vec::new(),
743 }
744 );
745 assert_eq!(
746 ob.last_trade(),
747 Some(Trade {
748 total_qty: 2,
749 avg_price: 395.0,
750 last_qty: 2,
751 last_price: 395,
752 })
753 );
754 }
755 }
756 }
757
758 #[test]
759 fn two_resting_orders_merged() {
760 for (bid_ask, _) in &BID_ASK_COMBINATIONS {
761 let (ob, results) = init_ob(vec![
762 OrderType::Limit {
763 id: 0,
764 side: *bid_ask,
765 qty: 12,
766 price: 395,
767 },
768 OrderType::Limit {
769 id: 1,
770 side: *bid_ask,
771 qty: 2,
772 price: 395,
773 },
774 ]);
775 assert_eq!(
776 results,
777 vec![
778 OrderEvent::Placed { id: 0 },
779 OrderEvent::Placed { id: 1 }
780 ]
781 );
782 if *bid_ask == Side::Bid {
783 assert_eq!(ob.min_ask(), None);
784 assert_eq!(ob.max_bid(), Some(395));
785 assert_eq!(ob._asks(), BTreeMap::new());
786 assert_eq!(
787 ob._bids(),
788 init_book(vec![(395, 9999), (395, 9998)])
789 );
790 assert_eq!(ob.spread(), None);
791 assert_eq!(ob.traded_volume(), 0);
792 assert_eq!(
793 ob.depth(3),
794 BookDepth {
795 levels: 3,
796 asks: Vec::new(),
797 bids: vec![BookLevel {
798 price: 395,
799 qty: 14
800 }],
801 }
802 );
803 assert_eq!(ob.last_trade(), None);
804 } else {
805 assert_eq!(ob.min_ask(), Some(395));
806 assert_eq!(ob.max_bid(), None);
807 assert_eq!(
808 ob._asks(),
809 init_book(vec![(395, 9999), (395, 9998)])
810 );
811 assert_eq!(ob._bids(), BTreeMap::new());
812 assert_eq!(ob.spread(), None);
813 assert_eq!(ob.traded_volume(), 0);
814 assert_eq!(
815 ob.depth(3),
816 BookDepth {
817 levels: 3,
818 asks: vec![BookLevel {
819 price: 395,
820 qty: 14
821 }],
822 bids: Vec::new(),
823 }
824 );
825 assert_eq!(ob.last_trade(), None);
826 }
827 }
828 }
829
830 #[test]
831 fn two_resting_orders_stacked() {
832 for (bid_ask, _) in &BID_ASK_COMBINATIONS {
833 let (ob, results) = init_ob(vec![
834 OrderType::Limit {
835 id: 0,
836 side: *bid_ask,
837 qty: 12,
838 price: 395,
839 },
840 OrderType::Limit {
841 id: 1,
842 side: *bid_ask,
843 qty: 2,
844 price: 398,
845 },
846 ]);
847 assert_eq!(
848 results,
849 vec![
850 OrderEvent::Placed { id: 0 },
851 OrderEvent::Placed { id: 1 }
852 ]
853 );
854 if *bid_ask == Side::Bid {
855 assert_eq!(ob.min_ask(), None);
856 assert_eq!(ob.max_bid(), Some(398));
857 assert_eq!(ob._asks(), BTreeMap::new());
858 assert_eq!(
859 ob._bids(),
860 init_book(vec![(398, 9998), (395, 9999)])
861 );
862 assert_eq!(ob.spread(), None);
863 } else {
864 assert_eq!(ob.min_ask(), Some(395));
865 assert_eq!(ob.max_bid(), None);
866 assert_eq!(
867 ob._asks(),
868 init_book(vec![(398, 9998), (395, 9999)])
869 );
870 assert_eq!(ob._bids(), BTreeMap::new());
871 assert_eq!(ob.spread(), None);
872 }
873 }
874 }
875
876 #[test]
877 fn three_resting_orders_stacked() {
878 for (bid_ask, ask_bid) in &BID_ASK_COMBINATIONS {
879 let (ob, results) = init_ob(vec![
880 OrderType::Limit {
881 id: 0,
882 side: *bid_ask,
883 qty: 12,
884 price: 395,
885 },
886 OrderType::Limit {
887 id: 1,
888 side: *ask_bid,
889 qty: 2,
890 price: 399,
891 },
892 OrderType::Limit {
893 id: 2,
894 side: *bid_ask,
895 qty: 2,
896 price: 398,
897 },
898 ]);
899 if *bid_ask == Side::Bid {
900 assert_eq!(
901 results,
902 vec![
903 OrderEvent::Placed { id: 0 },
904 OrderEvent::Placed { id: 1 },
905 OrderEvent::Placed { id: 2 }
906 ]
907 );
908 assert_eq!(ob.min_ask(), Some(399));
909 assert_eq!(ob.max_bid(), Some(398));
910 assert_eq!(ob._asks(), init_book(vec![(399, 9998)]));
911 assert_eq!(
912 ob._bids(),
913 init_book(vec![(398, 9997), (395, 9999)])
914 );
915 assert_eq!(ob.spread(), Some(1));
916 } else {
917 assert_eq!(
918 results,
919 vec![
920 OrderEvent::Placed { id: 0 },
921 OrderEvent::Filled {
922 id: 1,
923 filled_qty: 2,
924 fills: vec![FillMetadata {
925 order_1: 1,
926 order_2: 0,
927 qty: 2,
928 price: 395,
929 taker_side: *ask_bid,
930 total_fill: false,
931 }],
932 },
933 OrderEvent::Placed { id: 2 }
934 ]
935 );
936 assert_eq!(ob.min_ask(), Some(395));
937 assert_eq!(ob.max_bid(), None);
938 assert_eq!(
939 ob._asks(),
940 init_book(vec![(398, 9998), (395, 9999)])
941 );
942 assert_eq!(ob._bids(), init_book(vec![]));
943 assert_eq!(ob.spread(), None);
944 }
945 }
946 }
947
948 #[test]
949 fn crossing_limit_order_partial() {
950 for (bid_ask, ask_bid) in &BID_ASK_COMBINATIONS {
951 let (mut ob, results) = init_ob(vec![
952 OrderType::Limit {
953 id: 0,
954 side: *bid_ask,
955 qty: 12,
956 price: 395,
957 },
958 OrderType::Limit {
959 id: 1,
960 side: *ask_bid,
961 qty: 2,
962 price: 399,
963 },
964 OrderType::Limit {
965 id: 2,
966 side: *bid_ask,
967 qty: 2,
968 price: 398,
969 },
970 ]);
971 let result = ob.execute(OrderType::Limit {
972 id: 3,
973 side: *ask_bid,
974 qty: 1,
975 price: 397,
976 });
977
978 if *bid_ask == Side::Bid {
979 assert_eq!(
980 results,
981 vec![
982 OrderEvent::Placed { id: 0 },
983 OrderEvent::Placed { id: 1 },
984 OrderEvent::Placed { id: 2 }
985 ]
986 );
987 assert_eq!(
988 result,
989 OrderEvent::Filled {
990 id: 3,
991 filled_qty: 1,
992 fills: vec![FillMetadata {
993 order_1: 3,
994 order_2: 2,
995 qty: 1,
996 price: 398,
997 taker_side: *ask_bid,
998 total_fill: false,
999 }]
1000 }
1001 );
1002 assert_eq!(ob.min_ask(), Some(399));
1003 assert_eq!(ob.max_bid(), Some(398));
1004 assert_eq!(ob._asks(), init_book(vec![(399, 9998)]));
1005 assert_eq!(
1006 ob._bids(),
1007 init_book(vec![(398, 9997), (395, 9999)])
1008 );
1009 assert_eq!(ob.spread(), Some(1));
1010 } else {
1011 assert_eq!(
1012 results,
1013 vec![
1014 OrderEvent::Placed { id: 0 },
1015 OrderEvent::Filled {
1016 id: 1,
1017 filled_qty: 2,
1018 fills: vec![FillMetadata {
1019 order_1: 1,
1020 order_2: 0,
1021 qty: 2,
1022 price: 395,
1023 taker_side: *ask_bid,
1024 total_fill: false,
1025 }],
1026 },
1027 OrderEvent::Placed { id: 2 }
1028 ]
1029 );
1030 assert_eq!(
1031 result,
1032 OrderEvent::Filled {
1033 id: 3,
1034 filled_qty: 1,
1035 fills: vec![FillMetadata {
1036 order_1: 3,
1037 order_2: 0,
1038 qty: 1,
1039 price: 395,
1040 taker_side: *ask_bid,
1041 total_fill: false,
1042 }]
1043 }
1044 );
1045 assert_eq!(ob.min_ask(), Some(395));
1046 assert_eq!(ob.max_bid(), None);
1047 assert_eq!(
1048 ob._asks(),
1049 init_book(vec![(398, 9998), (395, 9999)])
1050 );
1051 assert_eq!(ob._bids(), init_book(vec![]));
1052 assert_eq!(ob.spread(), None);
1053 }
1054 }
1055 }
1056
1057 #[test]
1058 fn crossing_limit_order_matching() {
1059 for (bid_ask, ask_bid) in &BID_ASK_COMBINATIONS {
1060 let (mut ob, results) = init_ob(vec![
1061 OrderType::Limit {
1062 id: 0,
1063 side: *bid_ask,
1064 qty: 12,
1065 price: 395,
1066 },
1067 OrderType::Limit {
1068 id: 1,
1069 side: *ask_bid,
1070 qty: 2,
1071 price: 399,
1072 },
1073 OrderType::Limit {
1074 id: 2,
1075 side: *bid_ask,
1076 qty: 2,
1077 price: 398,
1078 },
1079 ]);
1080 let result = ob.execute(OrderType::Limit {
1081 id: 3,
1082 side: *ask_bid,
1083 qty: 2,
1084 price: 397,
1085 });
1086
1087 if *bid_ask == Side::Bid {
1088 assert_eq!(
1089 results,
1090 vec![
1091 OrderEvent::Placed { id: 0 },
1092 OrderEvent::Placed { id: 1 },
1093 OrderEvent::Placed { id: 2 }
1094 ]
1095 );
1096 assert_eq!(
1097 result,
1098 OrderEvent::Filled {
1099 id: 3,
1100 filled_qty: 2,
1101 fills: vec![FillMetadata {
1102 order_1: 3,
1103 order_2: 2,
1104 qty: 2,
1105 price: 398,
1106 taker_side: *ask_bid,
1107 total_fill: true,
1108 }]
1109 }
1110 );
1111 assert_eq!(ob.min_ask(), Some(399));
1112 assert_eq!(ob.max_bid(), Some(395));
1113 assert_eq!(ob._asks(), init_book(vec![(399, 9998)]));
1114 assert_eq!(
1115 ob._bids(),
1116 init_book_holes(vec![(395, 9999)], vec![398])
1117 );
1118 assert_eq!(ob.spread(), Some(4));
1119 } else {
1120 assert_eq!(
1121 results,
1122 vec![
1123 OrderEvent::Placed { id: 0 },
1124 OrderEvent::Filled {
1125 id: 1,
1126 filled_qty: 2,
1127 fills: vec![FillMetadata {
1128 order_1: 1,
1129 order_2: 0,
1130 qty: 2,
1131 price: 395,
1132 taker_side: *ask_bid,
1133 total_fill: false,
1134 }],
1135 },
1136 OrderEvent::Placed { id: 2 }
1137 ]
1138 );
1139 assert_eq!(
1140 result,
1141 OrderEvent::Filled {
1142 id: 3,
1143 filled_qty: 2,
1144 fills: vec![FillMetadata {
1145 order_1: 3,
1146 order_2: 0,
1147 qty: 2,
1148 price: 395,
1149 taker_side: *ask_bid,
1150 total_fill: false,
1151 }]
1152 }
1153 );
1154 assert_eq!(ob.min_ask(), Some(395));
1155 assert_eq!(ob.max_bid(), None);
1156 assert_eq!(
1157 ob._asks(),
1158 init_book(vec![(395, 9999), (398, 9998)])
1159 );
1160 assert_eq!(ob._bids(), init_book(vec![]));
1161 assert_eq!(ob.spread(), None);
1162 }
1163 }
1164 }
1165
1166 #[test]
1167 fn crossing_limit_order_over() {
1168 for (bid_ask, ask_bid) in &BID_ASK_COMBINATIONS {
1169 let (mut ob, results) = init_ob(vec![
1170 OrderType::Limit {
1171 id: 0,
1172 side: *bid_ask,
1173 qty: 12,
1174 price: 395,
1175 },
1176 OrderType::Limit {
1177 id: 1,
1178 side: *ask_bid,
1179 qty: 2,
1180 price: 399,
1181 },
1182 OrderType::Limit {
1183 id: 2,
1184 side: *bid_ask,
1185 qty: 2,
1186 price: 398,
1187 },
1188 ]);
1189 let result = ob.execute(OrderType::Limit {
1190 id: 3,
1191 side: *ask_bid,
1192 qty: 5,
1193 price: 397,
1194 });
1195
1196 if *bid_ask == Side::Bid {
1197 assert_eq!(
1198 results,
1199 vec![
1200 OrderEvent::Placed { id: 0 },
1201 OrderEvent::Placed { id: 1 },
1202 OrderEvent::Placed { id: 2 }
1203 ]
1204 );
1205 assert_eq!(
1206 result,
1207 OrderEvent::PartiallyFilled {
1208 id: 3,
1209 filled_qty: 2,
1210 fills: vec![FillMetadata {
1211 order_1: 3,
1212 order_2: 2,
1213 qty: 2,
1214 price: 398,
1215 taker_side: *ask_bid,
1216 total_fill: true,
1217 }]
1218 }
1219 );
1220 assert_eq!(ob.min_ask(), Some(397));
1221 assert_eq!(ob.max_bid(), Some(395));
1222 assert_eq!(
1223 ob._asks(),
1224 init_book(vec![(399, 9998), (397, 9996)])
1225 );
1226 assert_eq!(
1227 ob._bids(),
1228 init_book_holes(vec![(395, 9999)], vec![398])
1229 );
1230 assert_eq!(ob.spread(), Some(2));
1231 } else {
1232 assert_eq!(
1233 results,
1234 vec![
1235 OrderEvent::Placed { id: 0 },
1236 OrderEvent::Filled {
1237 id: 1,
1238 filled_qty: 2,
1239 fills: vec![FillMetadata {
1240 order_1: 1,
1241 order_2: 0,
1242 qty: 2,
1243 price: 395,
1244 taker_side: *ask_bid,
1245 total_fill: false,
1246 }],
1247 },
1248 OrderEvent::Placed { id: 2 }
1249 ]
1250 );
1251 assert_eq!(
1252 result,
1253 OrderEvent::Filled {
1254 id: 3,
1255 filled_qty: 5,
1256 fills: vec![FillMetadata {
1257 order_1: 3,
1258 order_2: 0,
1259 qty: 5,
1260 price: 395,
1261 taker_side: *ask_bid,
1262 total_fill: false,
1263 }]
1264 }
1265 );
1266 assert_eq!(ob.min_ask(), Some(395));
1267 assert_eq!(ob.max_bid(), None);
1268 assert_eq!(
1269 ob._asks(),
1270 init_book(vec![(395, 9999), (398, 9998)])
1271 );
1272 assert_eq!(ob._bids(), init_book(vec![]));
1273 assert_eq!(ob.spread(), None);
1274 }
1275 }
1276 }
1277
1278 #[test]
1279 fn market_order_unfilled() {
1280 for (_, ask_bid) in &BID_ASK_COMBINATIONS {
1281 let (mut ob, _) = init_ob(vec![]);
1282 let result = ob.execute(OrderType::Market {
1283 id: 0,
1284 side: *ask_bid,
1285 qty: 5,
1286 });
1287
1288 assert_eq!(result, OrderEvent::Unfilled { id: 0 });
1289 }
1290 }
1291
1292 #[test]
1293 fn market_order_partially_filled() {
1294 for (bid_ask, ask_bid) in &BID_ASK_COMBINATIONS {
1295 let (mut ob, results) = init_ob(vec![
1296 OrderType::Limit {
1297 id: 0,
1298 side: *bid_ask,
1299 qty: 12,
1300 price: 395,
1301 },
1302 OrderType::Limit {
1303 id: 1,
1304 side: *ask_bid,
1305 qty: 2,
1306 price: 399,
1307 },
1308 OrderType::Limit {
1309 id: 2,
1310 side: *bid_ask,
1311 qty: 2,
1312 price: 398,
1313 },
1314 ]);
1315 let result = ob.execute(OrderType::Market {
1316 id: 3,
1317 side: *ask_bid,
1318 qty: 15,
1319 });
1320
1321 if *bid_ask == Side::Bid {
1322 assert_eq!(
1323 results,
1324 vec![
1325 OrderEvent::Placed { id: 0 },
1326 OrderEvent::Placed { id: 1 },
1327 OrderEvent::Placed { id: 2 }
1328 ]
1329 );
1330 assert_eq!(
1331 result,
1332 OrderEvent::PartiallyFilled {
1333 id: 3,
1334 filled_qty: 14,
1335 fills: vec![
1336 FillMetadata {
1337 order_1: 3,
1338 order_2: 2,
1339 qty: 2,
1340 price: 398,
1341 taker_side: *ask_bid,
1342 total_fill: true,
1343 },
1344 FillMetadata {
1345 order_1: 3,
1346 order_2: 0,
1347 qty: 12,
1348 price: 395,
1349 taker_side: *ask_bid,
1350 total_fill: true,
1351 }
1352 ]
1353 }
1354 );
1355 assert_eq!(ob.min_ask(), Some(399));
1356 assert_eq!(ob.max_bid(), None);
1357 assert_eq!(ob._asks(), init_book(vec![(399, 9998)]));
1358 assert_eq!(ob._bids(), init_book_holes(vec![], vec![395, 398]));
1359 assert_eq!(ob.spread(), None);
1360 } else {
1361 assert_eq!(
1362 results,
1363 vec![
1364 OrderEvent::Placed { id: 0 },
1365 OrderEvent::Filled {
1366 id: 1,
1367 filled_qty: 2,
1368 fills: vec![FillMetadata {
1369 order_1: 1,
1370 order_2: 0,
1371 qty: 2,
1372 price: 395,
1373 taker_side: *ask_bid,
1374 total_fill: false,
1375 }],
1376 },
1377 OrderEvent::Placed { id: 2 }
1378 ]
1379 );
1380 assert_eq!(
1381 result,
1382 OrderEvent::PartiallyFilled {
1383 id: 3,
1384 filled_qty: 12,
1385 fills: vec![
1386 FillMetadata {
1387 order_1: 3,
1388 order_2: 0,
1389 qty: 10,
1390 price: 395,
1391 taker_side: *ask_bid,
1392 total_fill: true,
1393 },
1394 FillMetadata {
1395 order_1: 3,
1396 order_2: 2,
1397 qty: 2,
1398 price: 398,
1399 taker_side: *ask_bid,
1400 total_fill: true,
1401 }
1402 ]
1403 }
1404 );
1405 assert_eq!(ob.min_ask(), None);
1406 assert_eq!(ob.max_bid(), None);
1407 assert_eq!(ob._asks(), init_book_holes(vec![], vec![395, 398]));
1408 assert_eq!(ob._bids(), init_book(vec![]));
1409 assert_eq!(ob.spread(), None);
1410 }
1411 }
1412 }
1413
1414 #[test]
1415 fn market_order_filled() {
1416 for (bid_ask, ask_bid) in &BID_ASK_COMBINATIONS {
1417 let (mut ob, results) = init_ob(vec![
1418 OrderType::Limit {
1419 id: 0,
1420 side: *bid_ask,
1421 qty: 12,
1422 price: 395,
1423 },
1424 OrderType::Limit {
1425 id: 1,
1426 side: *ask_bid,
1427 qty: 2,
1428 price: 399,
1429 },
1430 OrderType::Limit {
1431 id: 2,
1432 side: *bid_ask,
1433 qty: 2,
1434 price: 398,
1435 },
1436 ]);
1437 let result = ob.execute(OrderType::Market {
1438 id: 3,
1439 side: *ask_bid,
1440 qty: 7,
1441 });
1442
1443 if *bid_ask == Side::Bid {
1444 assert_eq!(
1445 results,
1446 vec![
1447 OrderEvent::Placed { id: 0 },
1448 OrderEvent::Placed { id: 1 },
1449 OrderEvent::Placed { id: 2 }
1450 ]
1451 );
1452 assert_eq!(
1453 result,
1454 OrderEvent::Filled {
1455 id: 3,
1456 filled_qty: 7,
1457 fills: vec![
1458 FillMetadata {
1459 order_1: 3,
1460 order_2: 2,
1461 qty: 2,
1462 price: 398,
1463 taker_side: *ask_bid,
1464 total_fill: true,
1465 },
1466 FillMetadata {
1467 order_1: 3,
1468 order_2: 0,
1469 qty: 5,
1470 price: 395,
1471 taker_side: *ask_bid,
1472 total_fill: false,
1473 }
1474 ]
1475 }
1476 );
1477 assert_eq!(ob.min_ask(), Some(399));
1478 assert_eq!(ob.max_bid(), Some(395));
1479 assert_eq!(ob._asks(), init_book(vec![(399, 9998)]));
1480 assert_eq!(
1481 ob._bids(),
1482 init_book_holes(vec![(395, 9999)], vec![398])
1483 );
1484 assert_eq!(ob.spread(), Some(4));
1485 } else {
1486 assert_eq!(
1487 results,
1488 vec![
1489 OrderEvent::Placed { id: 0 },
1490 OrderEvent::Filled {
1491 id: 1,
1492 filled_qty: 2,
1493 fills: vec![FillMetadata {
1494 order_1: 1,
1495 order_2: 0,
1496 qty: 2,
1497 price: 395,
1498 taker_side: *ask_bid,
1499 total_fill: false,
1500 }],
1501 },
1502 OrderEvent::Placed { id: 2 }
1503 ]
1504 );
1505 assert_eq!(
1506 result,
1507 OrderEvent::Filled {
1508 id: 3,
1509 filled_qty: 7,
1510 fills: vec![FillMetadata {
1511 order_1: 3,
1512 order_2: 0,
1513 qty: 7,
1514 price: 395,
1515 taker_side: *ask_bid,
1516 total_fill: false,
1517 }]
1518 }
1519 );
1520 assert_eq!(ob.min_ask(), Some(395));
1521 assert_eq!(ob.max_bid(), None);
1522 assert_eq!(
1523 ob._asks(),
1524 init_book(vec![(395, 9999), (398, 9998)])
1525 );
1526 assert_eq!(ob._bids(), init_book(vec![]));
1527 assert_eq!(ob.spread(), None);
1528 }
1529 }
1530 }
1531
1532 #[test]
1533 fn cancel_non_existing_order() {
1534 let (mut ob, _) = init_ob(vec![]);
1535 let result = ob.execute(OrderType::Cancel { id: 0 });
1536 assert_eq!(result, OrderEvent::Canceled { id: 0 });
1537 assert_eq!(ob.min_ask(), None);
1538 assert_eq!(ob.max_bid(), None);
1539 assert_eq!(ob._asks(), BTreeMap::new());
1540 assert_eq!(ob._bids(), BTreeMap::new());
1541 assert_eq!(ob.spread(), None);
1542 }
1543
1544 #[test]
1545 fn cancel_resting_order() {
1546 for (bid_ask, _) in &BID_ASK_COMBINATIONS {
1547 let (mut ob, results) = init_ob(vec![OrderType::Limit {
1548 id: 0,
1549 side: *bid_ask,
1550 qty: 12,
1551 price: 395,
1552 }]);
1553 let result = ob.execute(OrderType::Cancel { id: 0 });
1554 assert_eq!(results, vec![OrderEvent::Placed { id: 0 }]);
1555 assert_eq!(result, OrderEvent::Canceled { id: 0 });
1556 assert_eq!(ob.min_ask(), None);
1557 assert_eq!(ob.max_bid(), None);
1558 if *bid_ask == Side::Bid {
1559 assert_eq!(ob._asks(), BTreeMap::new());
1560 assert_eq!(ob._bids(), init_book_holes(vec![], vec![395]));
1561 } else {
1562 assert_eq!(ob._asks(), init_book_holes(vec![], vec![395]));
1563 assert_eq!(ob._bids(), BTreeMap::new());
1564 }
1565 assert_eq!(ob.spread(), None);
1566 }
1567 }
1568
1569 #[test]
1570 fn cancel_resting_order_of_many() {
1571 for (bid_ask, ask_bid) in &BID_ASK_COMBINATIONS {
1572 let (mut ob, results) = init_ob(vec![
1573 OrderType::Limit {
1574 id: 0,
1575 side: *bid_ask,
1576 qty: 12,
1577 price: 395,
1578 },
1579 OrderType::Limit {
1580 id: 1,
1581 side: *ask_bid,
1582 qty: 2,
1583 price: 399,
1584 },
1585 OrderType::Limit {
1586 id: 2,
1587 side: *bid_ask,
1588 qty: 2,
1589 price: 398,
1590 },
1591 ]);
1592 let result = ob.execute(OrderType::Cancel { id: 0 });
1593 if *bid_ask == Side::Bid {
1594 assert_eq!(
1595 results,
1596 vec![
1597 OrderEvent::Placed { id: 0 },
1598 OrderEvent::Placed { id: 1 },
1599 OrderEvent::Placed { id: 2 }
1600 ]
1601 );
1602 assert_eq!(result, OrderEvent::Canceled { id: 0 });
1603 assert_eq!(ob.min_ask(), Some(399));
1604 assert_eq!(ob.max_bid(), Some(398));
1605 assert_eq!(ob._asks(), init_book(vec![(399, 9998)]));
1606 assert_eq!(
1607 ob._bids(),
1608 init_book_holes(vec![(398, 9997)], vec![395])
1609 );
1610 assert_eq!(ob.spread(), Some(1));
1611 } else {
1612 assert_eq!(
1613 results,
1614 vec![
1615 OrderEvent::Placed { id: 0 },
1616 OrderEvent::Filled {
1617 id: 1,
1618 filled_qty: 2,
1619 fills: vec![FillMetadata {
1620 order_1: 1,
1621 order_2: 0,
1622 qty: 2,
1623 price: 395,
1624 taker_side: *ask_bid,
1625 total_fill: false,
1626 }],
1627 },
1628 OrderEvent::Placed { id: 2 }
1629 ]
1630 );
1631 assert_eq!(result, OrderEvent::Canceled { id: 0 });
1632 assert_eq!(ob.min_ask(), Some(398));
1633 assert_eq!(ob.max_bid(), None);
1634 assert_eq!(
1635 ob._asks(),
1636 init_book_holes(vec![(398, 9998)], vec![395])
1637 );
1638 assert_eq!(ob._bids(), init_book(vec![]));
1639 assert_eq!(ob.spread(), None);
1640 }
1641 }
1642 }
1643}