Skip to main content

lobster/
orderbook.rs

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/// An order book that executes orders serially through the [`execute`] method.
12///
13/// [`execute`]: #method.execute
14#[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    /// Create an instance representing a single order book, with stats tracking
29    /// disabled, a default arena capacity of 10,000 and a default queue
30    /// capacity of 10.
31    fn default() -> Self {
32        Self::new(DEFAULT_ARENA_CAPACITY, DEFAULT_QUEUE_CAPACITY, false)
33    }
34}
35
36impl OrderBook {
37    /// Create an instance representing a single order book.
38    ///
39    /// The `arena_capacity` parameter represents the number of orders that will
40    /// be pre-allocated.
41    ///
42    /// The `queue_capacity` parameter represents the capacity of each vector
43    /// storing orders at the same price point.
44    ///
45    /// The `track_stats` parameter indicates whether to enable volume and
46    /// trades tracking (see [`last_trade`] and [`traded_volume`]).
47    ///
48    /// [`last_trade`]: #method.last_trade
49    /// [`traded_volume`]: #method.traded_volume
50    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    /// Return the lowest ask price, if present.
81    #[inline(always)]
82    pub fn min_ask(&self) -> Option<u64> {
83        self.min_ask
84    }
85
86    /// Return the highest bid price, if present.
87    #[inline(always)]
88    pub fn max_bid(&self) -> Option<u64> {
89        self.max_bid
90    }
91
92    /// Return the difference of the lowest ask and highest bid, if both are
93    /// present.
94    #[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    /// Return the last trade recorded while stats tracking was active as a
103    /// [`Trade`] object, if present.
104    ///
105    /// [`Trade`]: struct.Trade.html
106    #[inline(always)]
107    pub fn last_trade(&self) -> Option<Trade> {
108        self.last_trade
109    }
110
111    /// Return the total traded volume for all the trades that occurred while
112    /// the stats tracking was active.
113    #[inline(always)]
114    pub fn traded_volume(&self) -> u64 {
115        self.traded_volume
116    }
117
118    /// Return the order book depth as a [`BookDepth`] struct, up to the
119    /// specified level. Bids and offers at the same price level are merged in a
120    /// single [`BookLevel`] struct.
121    ///
122    /// [`BookDepth`]: struct.BookDepth.html
123    /// [`BookLevel`]: struct.BookLevel.html
124    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    /// Toggle the stats tracking on or off, depending on the `track` parameter.
158    pub fn track_stats(&mut self, track: bool) {
159        self.track_stats = track;
160    }
161
162    /// Execute an order, returning immediately an event indicating the result.
163    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                // If we are here, fills is not empty, so it's safe to unwrap it
177                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                // If we are here, fills is not empty, so it's safe to unwrap it
196                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    // In general, floating point values cannot be compared for equality. That's
551    // why we don't derive PartialEq in lobster::models, but we do it here for
552    // our tests in some very specific cases.
553    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}