bourse_book/
orderbook.rs

1//! Order book implementation
2//!
3//! # Examples
4//!
5//! ```
6//! use bourse_book;
7//! use bourse_book::{types, OrderBook};
8//!
9//! let mut book: OrderBook  = OrderBook::new(0, 1, true);
10//! let order_id = book.create_order(
11//!     types::Side::Bid, 50, 101, Some(50)
12//! ).unwrap();
13//! book.place_order(order_id);
14//! let (bid, ask) = book.bid_ask();
15//! book.cancel_order(order_id);
16//! ```
17//!
18use serde::{Deserialize, Serialize};
19use std::cmp::min;
20use std::fmt;
21use std::path::Path;
22
23use super::side::{get_ask_key, get_bid_key, AskSide, BidSide, SideFunctionality};
24use super::types::{
25    Event, Level1Data, Level2Data, Nanos, Order, OrderCount, OrderId, OrderKey, Price, Side,
26    Status, Trade, TraderId, Vol,
27};
28
29/// Order data combined with key
30///
31/// Orders are linked with a key
32/// used to track keys in a price-time
33/// priority map used for order matching.
34#[derive(Copy, Clone, Serialize, Deserialize)]
35pub struct OrderEntry {
36    /// Order data
37    order: Order,
38    /// Key associated with order
39    key: OrderKey,
40}
41
42/// Order book with order and trade history
43///
44/// # Examples
45///
46/// ```
47/// use bourse_book;
48/// use bourse_book::{types, OrderBook};
49///
50/// let mut book: OrderBook = OrderBook::new(0, 1, true);
51/// let order_id = book.create_order(
52///     types::Side::Bid, 50, 101, Some(50)
53/// ).unwrap();
54/// book.place_order(order_id);
55/// let (bid, ask) = book.bid_ask();
56/// book.cancel_order(order_id);
57/// ```
58///
59#[derive(Serialize, Deserialize)]
60#[serde(try_from = "OrderBookState<N>")]
61pub struct OrderBook<const N: usize = 10> {
62    /// Simulated time, intended to represent
63    /// nano-seconds, but arbitrary units can
64    /// be used without effecting functionality
65    t: Nanos,
66    // Market tick size
67    tick_size: Price,
68    /// Cumulative trade volume
69    trade_vol: Vol,
70    /// Ask side of the book data structure
71    #[serde(skip_serializing)]
72    ask_side: AskSide,
73    /// Bid side of the book data structure
74    #[serde(skip_serializing)]
75    bid_side: BidSide,
76    /// Orders created on the market, once
77    /// created orders persist in this vector
78    /// with their state updated in-place
79    orders: Vec<OrderEntry>,
80    /// History of trades
81    trades: Vec<Trade>,
82    /// Flag if `true` placed orders will be
83    /// matched, if `false` no trades will be
84    /// executed (but orders can still be
85    /// placed and modified)
86    trading: bool,
87}
88
89/// Order rejection errors
90///
91/// Errors raised when error creation fails.
92#[derive(Debug, Clone)]
93pub enum OrderError {
94    /// Price not a multiple of market tick-size
95    PriceError { price: Price, tick_size: Price },
96}
97
98impl fmt::Display for OrderError {
99    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100        match self {
101            OrderError::PriceError { price, tick_size } => write!(
102                f,
103                "Price {} was not a multiple of tick-size {}",
104                price, tick_size
105            ),
106        }
107    }
108}
109
110impl<const N: usize> OrderBook<N> {
111    /// Initialise a new orderbook
112    ///
113    /// Creates a new order empty order book (
114    /// i.e. one with 0 volume and 0-MAX_PRICE
115    /// prices)
116    ///
117    /// # Arguments
118    ///
119    /// - `start_time` - Simulated time to assign to the
120    ///   order book
121    /// - `tick_size` - Tick size
122    /// - `trading` - Flag to indicate if trades will be
123    ///   executed
124    pub fn new(start_time: Nanos, tick_size: Price, trading: bool) -> Self {
125        Self {
126            t: start_time,
127            tick_size,
128            trade_vol: 0,
129            ask_side: AskSide::new(),
130            bid_side: BidSide::new(),
131            orders: Vec::new(),
132            trades: Vec::new(),
133            trading,
134        }
135    }
136
137    /// Get the order book time
138    pub fn get_time(&self) -> Nanos {
139        self.t
140    }
141
142    /// Manually set the time of the orderbook
143    ///
144    /// - `t` - Time to set
145    pub fn set_time(&mut self, t: Nanos) {
146        self.t = t;
147    }
148
149    /// Enable trade execution
150    pub fn enable_trading(&mut self) {
151        self.trading = true;
152    }
153
154    /// Disable trade execution
155    ///
156    /// > **_NOTE:_** Currently there is not
157    ///   a un-crossing algorithm implemented
158    pub fn disable_trading(&mut self) {
159        self.trading = false;
160    }
161
162    /// Get the current cumulative trade_volume
163    pub fn get_trade_vol(&self) -> Vol {
164        self.trade_vol
165    }
166
167    /// Reset cumulative trade vol to 0
168    pub fn reset_trade_vol(&mut self) {
169        self.trade_vol = 0;
170    }
171
172    /// Get the current total ask volume
173    pub fn ask_vol(&self) -> Vol {
174        self.ask_side.vol()
175    }
176
177    /// Get the current touch ask volume
178    pub fn ask_best_vol(&self) -> Vol {
179        self.ask_side.best_vol()
180    }
181
182    /// Get the current touch ask volume and order count
183    pub fn ask_best_vol_and_orders(&self) -> (Vol, OrderCount) {
184        self.ask_side.best_vol_and_orders()
185    }
186
187    /// Get volumes and number of orders at N price levels
188    ///
189    /// Returns an array of tuples containing the volume and
190    /// number of orders at each price level from the touch.
191    pub fn ask_levels(&self) -> [(Vol, OrderCount); N] {
192        let start = self.bid_ask().1;
193        core::array::from_fn(|i| {
194            self.ask_side.vol_and_orders_at_price(
195                start.wrapping_add(Price::try_from(i).unwrap() * self.tick_size),
196            )
197        })
198    }
199
200    /// Get the current total bid volume
201    pub fn bid_vol(&self) -> Vol {
202        self.bid_side.vol()
203    }
204
205    /// Get current touch bid volume
206    pub fn bid_best_vol(&self) -> Vol {
207        self.bid_side.best_vol()
208    }
209
210    /// Get the current touch bid volume and order count
211    pub fn bid_best_vol_and_orders(&self) -> (Vol, OrderCount) {
212        self.bid_side.best_vol_and_orders()
213    }
214
215    /// Get volumes and number of orders at N price levels
216    ///
217    /// Returns an array of tuples containing the volume and
218    /// number of orders at each price level from the touch.
219    pub fn bid_levels(&self) -> [(Vol, OrderCount); N] {
220        let start = self.bid_ask().0;
221        core::array::from_fn(|i| {
222            self.bid_side.vol_and_orders_at_price(
223                start.wrapping_sub(Price::try_from(i).unwrap() * self.tick_size),
224            )
225        })
226    }
227
228    /// Get current bid-ask price
229    pub fn bid_ask(&self) -> (Price, Price) {
230        (self.bid_side.best_price(), self.ask_side.best_price())
231    }
232
233    /// Get current mid-price (as a float)
234    pub fn mid_price(&self) -> f64 {
235        let (bid, ask) = self.bid_ask();
236        let spread = ask - bid;
237        f64::from(bid) + 0.5 * f64::from(spread)
238    }
239
240    /// Get current level 1 market data
241    ///
242    /// Returns level 1 data which includes
243    ///
244    /// - Best bid and ask prices
245    /// - Total bid and ask side volumes
246    /// - Bid and ask volumes at the touch
247    /// - Number of bid and ask orders at the touch
248    ///
249    pub fn level_1_data(&self) -> Level1Data {
250        let (bid_price, ask_price) = self.bid_ask();
251        let (bid_touch_vol, bid_touch_orders) = self.bid_best_vol_and_orders();
252        let (ask_touch_vol, ask_touch_orders) = self.ask_best_vol_and_orders();
253        Level1Data {
254            bid_price,
255            ask_price,
256            bid_vol: self.bid_vol(),
257            ask_vol: self.ask_vol(),
258            bid_touch_vol,
259            ask_touch_vol,
260            bid_touch_orders,
261            ask_touch_orders,
262        }
263    }
264
265    /// Get current level 2 market data
266    ///
267    /// In this case level 2 data contains
268    /// additional order information at a fixed number
269    /// of ticks from the best price
270    ///
271    /// - Best bid and ask prices
272    /// - Total bid and ask volumes
273    /// - Volume and number of orders at N levels (ticks)
274    ///   above/below the bid ask (where N is 10 by default)
275    ///
276    pub fn level_2_data(&self) -> Level2Data<N> {
277        let (bid_price, ask_price) = self.bid_ask();
278        Level2Data {
279            bid_price,
280            ask_price,
281            bid_vol: self.bid_vol(),
282            ask_vol: self.ask_vol(),
283            bid_price_levels: self.bid_levels(),
284            ask_price_levels: self.ask_levels(),
285        }
286    }
287
288    /// Get the next order-id in the sequence
289    fn current_order_id(&self) -> OrderId {
290        self.orders.len()
291    }
292
293    /// Get a reference to the order data stored at the id
294    ///
295    /// # Arguments
296    ///
297    /// - `order_id` - Id of the order
298    ///
299    pub fn order(&self, order_id: OrderId) -> &Order {
300        &self.orders[order_id].order
301    }
302
303    /// Create a new order
304    ///
305    /// Create a new order in the order list, but
306    /// this order is not automatically placed on
307    /// the market. Returns the id of the newly
308    /// created order.
309    ///
310    /// # Arguments
311    ///
312    /// - `side` - Order side
313    /// - `vol` - Order volume
314    /// - `trader_id` - Id of the trader placing the order
315    /// - `price` -  Price of the order, if `None` the
316    ///   order is treated as a market order
317    ///
318    pub fn create_order(
319        &mut self,
320        side: Side,
321        vol: Vol,
322        trader_id: TraderId,
323        price: Option<Price>,
324    ) -> Result<OrderId, OrderError> {
325        let order_id = self.current_order_id();
326
327        let order = match (side, price) {
328            (Side::Bid, Some(p)) => {
329                if p % self.tick_size != 0 {
330                    return Err(OrderError::PriceError {
331                        price: p,
332                        tick_size: self.tick_size,
333                    });
334                }
335                Order::buy_limit(self.t, vol, p, trader_id, order_id)
336            }
337            (Side::Bid, None) => Order::buy_market(self.t, vol, trader_id, order_id),
338            (Side::Ask, Some(p)) => {
339                if p % self.tick_size != 0 {
340                    return Err(OrderError::PriceError {
341                        price: p,
342                        tick_size: self.tick_size,
343                    });
344                }
345                Order::sell_limit(self.t, vol, p, trader_id, order_id)
346            }
347            (Side::Ask, None) => Order::sell_market(self.t, vol, trader_id, order_id),
348        };
349
350        let key = match side {
351            Side::Bid => get_bid_key(0, order.price),
352            Side::Ask => get_ask_key(0, order.price),
353        };
354
355        self.orders.push(OrderEntry { order, key });
356
357        Ok(order_id)
358    }
359
360    /// Convenience function to create and immediately place an order
361    ///
362    /// Create a new order in the order list and place it on the market.
363    /// Returns the id of the newly created order.
364    ///
365    /// # Arguments
366    ///
367    /// - `side` - Order side
368    /// - `vol` - Order volume
369    /// - `trader_id` - Id of the trader placing the order
370    /// - `price` -  Price of the order, if `None` the
371    ///   order is treated as a market order
372    ///
373    pub fn create_and_place_order(
374        &mut self,
375        side: Side,
376        vol: Vol,
377        trader_id: TraderId,
378        price: Option<Price>,
379    ) -> Result<OrderId, OrderError> {
380        let order_id = self.create_order(side, vol, trader_id, price)?;
381        self.place_order(order_id);
382        Ok(order_id)
383    }
384
385    /// Match an aggressive buy order
386    ///
387    /// # Arguments
388    ///
389    /// - `order_entry` - Aggressive order details
390    ///
391    fn match_bid(&mut self, order_entry: &mut OrderEntry) {
392        while (order_entry.order.vol > 0) & (order_entry.order.price >= self.ask_side.best_price())
393        {
394            let next_order_id = self.ask_side.best_order_idx();
395            match next_order_id {
396                Some(id) => {
397                    let match_order = &mut self.orders.get_mut(id).unwrap();
398                    let trade_vol = match_orders(
399                        self.t,
400                        &mut order_entry.order,
401                        &mut match_order.order,
402                        &mut self.trades,
403                    );
404                    self.trade_vol += trade_vol;
405                    if match_order.order.status == Status::Filled {
406                        self.ask_side.remove_order(match_order.key, trade_vol);
407                    } else {
408                        self.ask_side.remove_vol(match_order.key.1, trade_vol);
409                    }
410                }
411                None => {
412                    break;
413                }
414            }
415        }
416    }
417
418    /// Match an aggressive sell order
419    ///
420    /// # Arguments
421    ///
422    /// - `order_entry` - Aggressive order details
423    ///
424    fn match_ask(&mut self, order_entry: &mut OrderEntry) {
425        while (order_entry.order.vol > 0) & (order_entry.order.price <= self.bid_side.best_price())
426        {
427            let next_order_id = self.bid_side.best_order_idx();
428            match next_order_id {
429                Some(id) => {
430                    let match_order = &mut self.orders.get_mut(id).unwrap();
431                    let trade_vol = match_orders(
432                        self.t,
433                        &mut order_entry.order,
434                        &mut match_order.order,
435                        &mut self.trades,
436                    );
437                    self.trade_vol += trade_vol;
438                    if match_order.order.status == Status::Filled {
439                        self.bid_side.remove_order(match_order.key, trade_vol);
440                    } else {
441                        self.bid_side.remove_vol(match_order.key.1, trade_vol);
442                    }
443                }
444                None => {
445                    break;
446                }
447            }
448        }
449    }
450
451    /// Place a buy limit order on the market
452    ///
453    /// # Arguments
454    ///
455    /// - `order_entry` - Order details
456    ///
457    fn place_bid_limit(&mut self, order_entry: &mut OrderEntry) {
458        if self.trading {
459            self.match_bid(order_entry);
460        }
461        if order_entry.order.status != Status::Filled {
462            let key: OrderKey = (Side::Bid, order_entry.key.1, self.t);
463            order_entry.key = key;
464            self.bid_side
465                .insert_order(key, order_entry.order.order_id, order_entry.order.vol)
466        }
467    }
468
469    /// Place a buy market order on the market
470    ///
471    /// Note that market orders that cannot be completely filled
472    /// (for example due to a lack of opposite volume) are not
473    /// then placed passively on the book
474    ///
475    /// # Arguments
476    ///
477    /// - `order_entry` - Order details
478    ///
479    fn place_bid_market(&mut self, order_entry: &mut OrderEntry) {
480        match self.trading {
481            true => {
482                self.match_bid(order_entry);
483                if order_entry.order.status != Status::Filled {
484                    order_entry.order.status = Status::Cancelled;
485                    order_entry.order.end_time = self.t;
486                }
487            }
488            false => {
489                order_entry.order.status = Status::Rejected;
490                order_entry.order.end_time = self.t;
491            }
492        }
493    }
494
495    /// Place a sell limit order on the market
496    ///
497    /// # Arguments
498    ///
499    /// - `order_entry` - O
500    fn place_ask_limit(&mut self, order_entry: &mut OrderEntry) {
501        if self.trading {
502            self.match_ask(order_entry);
503        }
504        if order_entry.order.status != Status::Filled {
505            let key: OrderKey = (Side::Ask, order_entry.key.1, self.t);
506            order_entry.key = key;
507            self.ask_side
508                .insert_order(key, order_entry.order.order_id, order_entry.order.vol)
509        }
510    }
511
512    /// Place a sell market order on the market
513    ///
514    /// Note that market orders that cannot be completely filled
515    /// (for example due to a lack of opposite volume) are not
516    /// then placed passively on the book
517    ///
518    /// # Arguments
519    ///
520    /// - `order_entry` - Order details
521    ///
522    fn place_ask_market(&mut self, order_entry: &mut OrderEntry) {
523        match self.trading {
524            true => {
525                self.match_ask(order_entry);
526                if order_entry.order.status != Status::Filled {
527                    order_entry.order.status = Status::Cancelled;
528                    order_entry.order.end_time = self.t;
529                }
530            }
531            false => {
532                order_entry.order.status = Status::Rejected;
533                order_entry.order.end_time = self.t;
534            }
535        }
536    }
537
538    /// Place an order on the market
539    ///
540    /// Place an order that has been created on the market
541    ///
542    /// # Arguments
543    ///
544    /// - `order_id` - Id of the order to place
545    pub fn place_order(&mut self, order_id: OrderId) {
546        let mut order_entry = self.orders[order_id];
547
548        if order_entry.order.status != Status::New {
549            return;
550        }
551
552        order_entry.order.status = Status::Active;
553        order_entry.order.arr_time = self.t;
554
555        match order_entry.order.side {
556            Side::Bid => {
557                if order_entry.order.price == Price::MAX {
558                    self.place_bid_market(&mut order_entry)
559                } else {
560                    self.place_bid_limit(&mut order_entry)
561                }
562            }
563            Side::Ask => {
564                if order_entry.order.price == 0 {
565                    self.place_ask_market(&mut order_entry)
566                } else {
567                    self.place_ask_limit(&mut order_entry)
568                }
569            }
570        }
571
572        self.orders[order_id] = order_entry;
573    }
574
575    /// Cancel an order
576    ///
577    /// Attempts to cancel an order, if the order is
578    /// already filled or rejected then no change is made
579    ///
580    /// # Arguments
581    ///
582    /// - `order_id` - Id of the order to cancel
583    ///
584    pub fn cancel_order(&mut self, order_id: OrderId) {
585        let cancelled_order = self.orders.get_mut(order_id);
586
587        match cancelled_order {
588            Some(order_entry) => {
589                if order_entry.order.status == Status::Active {
590                    order_entry.order.status = Status::Cancelled;
591                    order_entry.order.end_time = self.t;
592                    match order_entry.key.0 {
593                        Side::Bid => {
594                            self.bid_side
595                                .remove_order(order_entry.key, order_entry.order.vol);
596                        }
597                        Side::Ask => {
598                            self.ask_side
599                                .remove_order(order_entry.key, order_entry.order.vol);
600                        }
601                    }
602                }
603            }
604            None => panic!("No order with id {} exists", order_id),
605        }
606    }
607
608    /// Reduce order volume
609    ///
610    /// Reduces the volume of an order in-place
611    ///
612    /// # Arguments
613    ///
614    /// - `order_entry` - Order data
615    /// - `reduce_vol` - Amount to reduce the available
616    ///   volume of the order by
617    ///
618    fn reduce_order_vol(&mut self, order_entry: &mut OrderEntry, reduce_vol: Vol) {
619        match order_entry.key.0 {
620            Side::Bid => {
621                order_entry.order.vol -= reduce_vol;
622                self.bid_side.remove_vol(order_entry.key.1, reduce_vol)
623            }
624            Side::Ask => {
625                order_entry.order.vol -= reduce_vol;
626                self.ask_side.remove_vol(order_entry.key.1, reduce_vol)
627            }
628        }
629    }
630
631    /// Replace an order
632    ///
633    /// Replaces an order with new price and volume
634    ///
635    /// # Arguments
636    ///
637    /// - `order_entry` - order data
638    /// - `new_price` - New price of the order
639    /// - `new_vol` - New volume of the order
640    ///
641    fn replace_order(&mut self, order_entry: &mut OrderEntry, new_price: Price, new_vol: Vol) {
642        match order_entry.key.0 {
643            Side::Bid => self
644                .bid_side
645                .remove_order(order_entry.key, order_entry.order.vol),
646            Side::Ask => self
647                .ask_side
648                .remove_order(order_entry.key, order_entry.order.vol),
649        }
650
651        order_entry.order.vol = new_vol;
652        order_entry.order.price = new_price;
653
654        if self.trading {
655            match order_entry.key.0 {
656                Side::Bid => self.match_bid(order_entry),
657                Side::Ask => self.match_ask(order_entry),
658            }
659        }
660
661        if order_entry.order.status != Status::Filled {
662            match order_entry.key.0 {
663                crate::types::Side::Bid => {
664                    let key: OrderKey = get_bid_key(self.t, new_price);
665                    order_entry.key = key;
666
667                    self.bid_side.insert_order(
668                        key,
669                        order_entry.order.order_id,
670                        order_entry.order.vol,
671                    );
672                }
673                crate::types::Side::Ask => {
674                    let key: OrderKey = get_ask_key(self.t, new_price);
675                    order_entry.key = key;
676
677                    self.ask_side.insert_order(
678                        key,
679                        order_entry.order.order_id,
680                        order_entry.order.vol,
681                    );
682                }
683            }
684        }
685    }
686
687    /// Modify the price and/or volume of an order
688    ///
689    /// If only the volume is *reduced*, then the order
690    /// maintains its price-time priority. Otherwise the
691    /// order is replaced. The modified order
692    /// maintains the same id.
693    ///
694    /// If the price/vol are None then the original
695    /// price/vol are kept.
696    ///
697    /// # Arguments
698    ///
699    /// - `order_id` - Id of the order to modify
700    /// - `new_price` - New price of the order, `None``
701    ///   keeps the same price
702    /// - `new_vol` - New volume of the order, `None``
703    ///   keeps the same volume
704    ///
705    pub fn modify_order(
706        &mut self,
707        order_id: OrderId,
708        new_price: Option<Price>,
709        new_vol: Option<Price>,
710    ) {
711        let mut order_entry = self.orders[order_id];
712
713        if order_entry.order.status == Status::Active {
714            match (new_price, new_vol) {
715                (None, None) => (),
716                (None, Some(v)) => {
717                    if v < order_entry.order.vol {
718                        let reduce_vol = order_entry.order.vol - v;
719                        self.reduce_order_vol(&mut order_entry, reduce_vol);
720                    } else {
721                        let p = order_entry.order.price;
722                        self.replace_order(&mut order_entry, p, v)
723                    }
724                }
725                (Some(p), None) => {
726                    let v = order_entry.order.vol;
727                    self.replace_order(&mut order_entry, p, v);
728                }
729                (Some(p), Some(v)) => self.replace_order(&mut order_entry, p, v),
730            }
731        }
732
733        self.orders[order_id] = order_entry;
734    }
735
736    /// Process an [Event] order instruction
737    ///
738    /// Processes an order instruction to place, cancel
739    /// or modify an order
740    ///
741    /// # Arguments
742    ///
743    /// - `event` - Order instruction
744    pub fn process_event(&mut self, event: Event) {
745        match event {
746            Event::New { order_id } => self.place_order(order_id),
747            Event::Cancellation { order_id } => self.cancel_order(order_id),
748            Event::Modify {
749                order_id,
750                new_price,
751                new_vol,
752            } => self.modify_order(order_id, new_price, new_vol),
753        }
754    }
755
756    /// Reference to list of created orders
757    pub fn get_orders(&self) -> Vec<&Order> {
758        self.orders.iter().map(|x| &x.order).collect()
759    }
760
761    /// Reference to trade records
762    pub fn get_trades(&self) -> &Vec<Trade> {
763        &self.trades
764    }
765
766    /// Save a snapshot of the order-book to JSON
767    ///
768    /// # Argument
769    ///
770    /// - `path` - Path to write snapshot JSON to
771    /// - `pretty` - If `True` JSON will be pretty printed
772    ///
773    pub fn save_json<P: AsRef<Path>>(&self, path: P, pretty: bool) -> std::io::Result<()> {
774        let file = std::fs::File::create(path)?;
775        let file = std::io::BufWriter::new(file);
776        match pretty {
777            true => serde_json::to_writer_pretty(file, self)?,
778            false => serde_json::to_writer(file, self)?,
779        }
780        Ok(())
781    }
782
783    /// Load an order-book from a JSON snapshot
784    ///
785    /// # Argument
786    ///
787    /// - `path` - Path to read snapshot JSON from
788    ///
789    pub fn load_json<P: AsRef<Path>>(path: P) -> std::io::Result<Self> {
790        let file = std::fs::File::open(path)?;
791        let file = std::io::BufReader::new(file);
792        let order_book: Self = serde_json::from_reader(file)?;
793        Ok(order_book)
794    }
795}
796
797/// Match two orders and record the trade
798///
799/// # Arguments
800///
801/// - `agg_order` - Aggressive order data
802/// - `pass_order` - Passive order data
803/// - `trades` - Trade records
804///
805fn match_orders(
806    t: Nanos,
807    agg_order: &mut Order,
808    pass_order: &mut Order,
809    trades: &mut Vec<Trade>,
810) -> Vol {
811    let trade_vol = min(agg_order.vol, pass_order.vol);
812    agg_order.vol -= trade_vol;
813    pass_order.vol -= trade_vol;
814    trades.push(Trade {
815        t,
816        side: pass_order.side,
817        price: pass_order.price,
818        vol: trade_vol,
819        active_order_id: agg_order.order_id,
820        passive_order_id: pass_order.order_id,
821    });
822    if pass_order.vol == 0 {
823        pass_order.end_time = t;
824        pass_order.status = Status::Filled;
825    };
826    if agg_order.vol == 0 {
827        agg_order.end_time = t;
828        agg_order.status = Status::Filled;
829    };
830
831    trade_vol
832}
833
834/// Dummy order book to enable deserialization
835#[derive(Deserialize)]
836struct OrderBookState<const N: usize = 10> {
837    t: Nanos,
838    tick_size: Price,
839    trade_vol: Vol,
840    orders: Vec<OrderEntry>,
841    trades: Vec<Trade>,
842    trading: bool,
843}
844
845struct OrderBookConversionErrror;
846
847impl fmt::Display for OrderBookConversionErrror {
848    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
849        write!(f, "Failed to convert OrderBookState to an OrderBook")
850    }
851}
852
853impl<const N: usize> std::convert::TryFrom<OrderBookState<N>> for OrderBook<{ N }> {
854    type Error = OrderBookConversionErrror;
855
856    fn try_from(state: OrderBookState<N>) -> Result<Self, Self::Error> {
857        let mut bid_side = BidSide::default();
858        let mut ask_side = AskSide::default();
859
860        for OrderEntry { order, key } in state.orders.iter() {
861            if order.status == Status::Active {
862                match order.side {
863                    Side::Bid => bid_side.insert_order(*key, order.order_id, order.vol),
864                    Side::Ask => ask_side.insert_order(*key, order.order_id, order.vol),
865                }
866            }
867        }
868
869        Ok(Self {
870            t: state.t,
871            tick_size: state.tick_size,
872            trade_vol: state.trade_vol,
873            ask_side,
874            bid_side,
875            orders: state.orders,
876            trades: state.trades,
877            trading: state.trading,
878        })
879    }
880}
881
882#[cfg(test)]
883mod tests {
884
885    use super::*;
886
887    #[test]
888    fn test_init() {
889        let book: OrderBook = OrderBook::new(0, 1, true);
890
891        assert!(book.bid_vol() == 0);
892        assert!(book.ask_vol() == 0);
893        assert!(book.bid_best_vol() == 0);
894        assert!(book.bid_best_vol_and_orders() == (0, 0));
895        assert!(book.bid_best_vol() == 0);
896        assert!(book.ask_best_vol_and_orders() == (0, 0));
897        assert!(book.bid_ask() == (0, Price::MAX))
898    }
899
900    #[test]
901    fn test_insert_order() {
902        let mut book: OrderBook = OrderBook::new(0, 1, true);
903
904        book.create_and_place_order(Side::Ask, 10, 0, Some(100))
905            .unwrap();
906        book.create_and_place_order(Side::Bid, 10, 0, Some(50))
907            .unwrap();
908
909        assert!(book.bid_ask() == (50, 100));
910        assert!(book.ask_vol() == 10);
911        assert!(book.bid_vol() == 10);
912        assert!(book.bid_best_vol() == 10);
913        assert!(book.bid_best_vol_and_orders() == (10, 1));
914        assert!(book.ask_best_vol() == 10);
915        assert!(book.ask_best_vol_and_orders() == (10, 1));
916
917        book.create_and_place_order(Side::Ask, 10, 0, Some(90))
918            .unwrap();
919        book.create_and_place_order(Side::Bid, 10, 0, Some(60))
920            .unwrap();
921
922        assert!(book.bid_ask() == (60, 90));
923        assert!(book.ask_vol() == 20);
924        assert!(book.bid_vol() == 20);
925        assert!(book.bid_best_vol() == 10);
926        assert!(book.bid_best_vol_and_orders() == (10, 1));
927        assert!(book.ask_best_vol() == 10);
928        assert!(book.ask_best_vol_and_orders() == (10, 1));
929
930        book.create_and_place_order(Side::Ask, 10, 0, Some(110))
931            .unwrap();
932        book.create_and_place_order(Side::Bid, 10, 0, Some(40))
933            .unwrap();
934
935        assert!(book.bid_ask() == (60, 90));
936        assert!(book.ask_vol() == 30);
937        assert!(book.bid_vol() == 30);
938        assert!(book.bid_best_vol() == 10);
939        assert!(book.bid_best_vol_and_orders() == (10, 1));
940        assert!(book.ask_best_vol() == 10);
941        assert!(book.ask_best_vol_and_orders() == (10, 1));
942    }
943
944    #[test]
945    fn test_level_data() {
946        let mut book = OrderBook::<4>::new(0, 2, true);
947
948        let bid_levels = book.bid_levels();
949
950        assert!(bid_levels.len() == 4);
951        assert!(bid_levels == [(0, 0), (0, 0), (0, 0), (0, 0)]);
952
953        let ask_levels = book.ask_levels();
954
955        assert!(ask_levels.len() == 4);
956        assert!(ask_levels == [(0, 0), (0, 0), (0, 0), (0, 0)]);
957
958        book.create_and_place_order(Side::Bid, 10, 0, Some(100))
959            .unwrap();
960        book.create_and_place_order(Side::Bid, 10, 0, Some(100))
961            .unwrap();
962        book.create_and_place_order(Side::Bid, 12, 0, Some(98))
963            .unwrap();
964        book.create_and_place_order(Side::Bid, 14, 0, Some(94))
965            .unwrap();
966
967        book.create_and_place_order(Side::Ask, 11, 0, Some(102))
968            .unwrap();
969        book.create_and_place_order(Side::Ask, 11, 0, Some(102))
970            .unwrap();
971        book.create_and_place_order(Side::Ask, 13, 0, Some(104))
972            .unwrap();
973        book.create_and_place_order(Side::Ask, 15, 0, Some(108))
974            .unwrap();
975
976        let bid_levels = book.bid_levels();
977
978        assert!(bid_levels.len() == 4);
979        assert!(bid_levels == [(20, 2), (12, 1), (0, 0), (14, 1)]);
980
981        let ask_levels = book.ask_levels();
982
983        assert!(ask_levels.len() == 4);
984        assert!(ask_levels == [(22, 2), (13, 1), (0, 0), (15, 1)]);
985
986        assert!(matches!(
987            book.level_1_data(),
988            Level1Data {
989                bid_price: 100,
990                ask_price: 102,
991                bid_vol: 46,
992                ask_vol: 50,
993                bid_touch_vol: 20,
994                ask_touch_vol: 22,
995                bid_touch_orders: 2,
996                ask_touch_orders: 2,
997            }
998        ));
999
1000        assert!(matches!(
1001            book.level_2_data(),
1002            Level2Data {
1003                bid_price: 100,
1004                ask_price: 102,
1005                bid_vol: 46,
1006                ask_vol: 50,
1007                bid_price_levels: [(20, 2), (12, 1), (0, 0), (14, 1)],
1008                ask_price_levels: [(22, 2), (13, 1), (0, 0), (15, 1)],
1009            }
1010        ));
1011    }
1012
1013    #[test]
1014    fn test_cancel_order() {
1015        let mut book: OrderBook = OrderBook::new(0, 1, true);
1016
1017        book.create_and_place_order(Side::Ask, 10, 0, Some(100))
1018            .unwrap();
1019        book.create_and_place_order(Side::Bid, 10, 0, Some(50))
1020            .unwrap();
1021        book.create_and_place_order(Side::Ask, 10, 0, Some(90))
1022            .unwrap();
1023        book.create_and_place_order(Side::Bid, 10, 0, Some(60))
1024            .unwrap();
1025
1026        assert!(book.bid_ask() == (60, 90));
1027        assert!(book.ask_vol() == 20);
1028        assert!(book.bid_vol() == 20);
1029        assert!(book.bid_best_vol() == 10);
1030        assert!(book.ask_best_vol() == 10);
1031        assert!(book.bid_best_vol_and_orders() == (10, 1));
1032        assert!(book.ask_best_vol_and_orders() == (10, 1));
1033
1034        book.cancel_order(0);
1035        book.cancel_order(3);
1036
1037        assert!(book.bid_ask() == (50, 90));
1038        assert!(book.ask_vol() == 10);
1039        assert!(book.bid_vol() == 10);
1040        assert!(book.bid_best_vol() == 10);
1041        assert!(book.ask_best_vol() == 10);
1042        assert!(book.bid_best_vol_and_orders() == (10, 1));
1043        assert!(book.ask_best_vol_and_orders() == (10, 1));
1044
1045        book.cancel_order(1);
1046        book.cancel_order(2);
1047
1048        assert!(book.bid_ask() == (0, Price::MAX));
1049        assert!(book.ask_vol() == 0);
1050        assert!(book.bid_vol() == 0);
1051        assert!(book.bid_best_vol() == 0);
1052        assert!(book.ask_best_vol() == 0);
1053        assert!(book.bid_best_vol_and_orders() == (0, 0));
1054        assert!(book.ask_best_vol_and_orders() == (0, 0));
1055
1056        assert!(matches!(book.orders[0].order.status, Status::Cancelled));
1057        assert!(matches!(book.orders[1].order.status, Status::Cancelled));
1058        assert!(matches!(book.orders[2].order.status, Status::Cancelled));
1059        assert!(matches!(book.orders[3].order.status, Status::Cancelled));
1060    }
1061
1062    #[test]
1063    fn test_mod_order_vol() {
1064        let mut book: OrderBook = OrderBook::new(0, 1, true);
1065
1066        book.create_and_place_order(Side::Ask, 10, 0, Some(100))
1067            .unwrap();
1068        book.create_and_place_order(Side::Bid, 10, 0, Some(50))
1069            .unwrap();
1070
1071        book.modify_order(0, None, Some(8));
1072        book.modify_order(1, None, Some(5));
1073
1074        assert!(book.ask_vol() == 8);
1075        assert!(book.ask_best_vol() == 8);
1076        assert!(book.ask_best_vol_and_orders() == (8, 1));
1077        assert!(book.bid_vol() == 5);
1078        assert!(book.bid_best_vol() == 5);
1079        assert!(book.bid_best_vol_and_orders() == (5, 1));
1080
1081        assert!(book.orders[0].order.vol == 8);
1082        assert!(book.orders[1].order.vol == 5);
1083    }
1084
1085    #[test]
1086    fn test_modify_order() {
1087        let mut book: OrderBook = OrderBook::new(0, 1, true);
1088
1089        book.create_and_place_order(Side::Ask, 10, 0, Some(100))
1090            .unwrap();
1091        book.create_and_place_order(Side::Bid, 10, 0, Some(50))
1092            .unwrap();
1093
1094        assert!(book.bid_ask() == (50, 100));
1095
1096        book.modify_order(0, Some(110), Some(15));
1097        book.modify_order(1, Some(60), Some(20));
1098
1099        assert!(book.ask_vol() == 15);
1100        assert!(book.ask_best_vol() == 15);
1101        assert!(book.bid_vol() == 20);
1102        assert!(book.bid_best_vol() == 20);
1103        assert!(book.bid_ask() == (60, 110));
1104    }
1105
1106    #[test]
1107    fn test_modify_order_crossing() {
1108        let mut book: OrderBook = OrderBook::new(0, 1, true);
1109
1110        book.create_and_place_order(Side::Ask, 10, 0, Some(100))
1111            .unwrap();
1112        book.create_and_place_order(Side::Bid, 10, 0, Some(50))
1113            .unwrap();
1114
1115        assert!(book.bid_ask() == (50, 100));
1116
1117        book.modify_order(1, Some(100), Some(20));
1118
1119        assert!(book.ask_vol() == 0);
1120        assert!(book.ask_best_vol() == 0);
1121        assert!(book.ask_best_vol_and_orders() == (0, 0));
1122        assert!(book.bid_vol() == 10);
1123        assert!(book.bid_best_vol() == 10);
1124        assert!(book.bid_best_vol_and_orders() == (10, 1));
1125        assert!(book.bid_ask() == (100, Price::MAX));
1126
1127        assert!(book.trades.len() == 1);
1128        assert!(book.trades[0].price == 100);
1129        assert!(book.trades[0].vol == 10);
1130    }
1131
1132    #[test]
1133    fn test_trades() {
1134        let mut book: OrderBook = OrderBook::new(0, 1, true);
1135
1136        book.create_order(Side::Ask, 101, 101, Some(20)).unwrap();
1137        book.create_order(Side::Ask, 101, 101, Some(18)).unwrap();
1138        book.create_order(Side::Bid, 202, 101, Some(12)).unwrap();
1139        book.create_order(Side::Bid, 202, 101, Some(14)).unwrap();
1140
1141        book.place_order(0);
1142        book.set_time(1);
1143        book.place_order(1);
1144        book.set_time(2);
1145        book.place_order(2);
1146        book.set_time(3);
1147        book.place_order(3);
1148        book.set_time(4);
1149
1150        book.create_order(Side::Bid, 102, 101, None).unwrap();
1151        book.place_order(4);
1152
1153        assert!(book.ask_vol() == 100);
1154        assert!(book.bid_ask() == (14, 20));
1155
1156        assert!(book.trades.len() == 2);
1157        assert!(book.trades[0].price == 18);
1158        assert!(book.trades[0].vol == 101);
1159        assert!(book.trades[1].price == 20);
1160        assert!(book.trades[1].vol == 1);
1161        assert!(book.get_trade_vol() == 102);
1162
1163        book.create_order(Side::Ask, 204, 101, Some(14)).unwrap();
1164        book.place_order(5);
1165
1166        assert!(book.bid_vol() == 202);
1167        assert!(book.ask_vol() == 102);
1168        assert!(book.bid_best_vol_and_orders() == (202, 1));
1169        assert!(book.ask_best_vol_and_orders() == (2, 1));
1170        assert!(book.bid_ask() == (12, 14));
1171
1172        assert!(book.trades.len() == 3);
1173        assert!(book.trades[2].price == 14);
1174        assert!(book.trades[2].vol == 202);
1175        assert!(book.get_trade_vol() == 304);
1176    }
1177
1178    #[test]
1179    fn test_market_order_no_trading() {
1180        let mut book: OrderBook = OrderBook::new(0, 1, false);
1181
1182        book.create_and_place_order(Side::Bid, 101, 101, None)
1183            .unwrap();
1184
1185        assert!(book.bid_ask() == (0, Price::MAX));
1186        assert!(book.bid_vol() == 0);
1187        assert!(book.ask_vol() == 0);
1188        assert!(book.orders[0].order.status == Status::Rejected);
1189    }
1190
1191    #[test]
1192    fn test_unfilled_market_order() {
1193        let mut book: OrderBook = OrderBook::new(0, 1, true);
1194
1195        book.create_and_place_order(Side::Ask, 10, 101, Some(50))
1196            .unwrap();
1197        book.create_and_place_order(Side::Bid, 20, 101, None)
1198            .unwrap();
1199
1200        assert!(book.bid_ask() == (0, Price::MAX));
1201        assert!(book.bid_vol() == 0);
1202        assert!(book.ask_vol() == 0);
1203        assert!(book.orders[1].order.status == Status::Cancelled);
1204    }
1205
1206    #[test]
1207    fn test_incorrect_price_err() {
1208        let mut book: OrderBook = OrderBook::new(0, 2, true);
1209
1210        let res = book.create_order(Side::Ask, 100, 101, Some(51));
1211
1212        assert!(res.is_err_and(|e| matches!(
1213            e,
1214            OrderError::PriceError {
1215                price: 51,
1216                tick_size: 2
1217            }
1218        )));
1219    }
1220
1221    #[test]
1222    fn test_no_double_place() {
1223        let mut book: OrderBook = OrderBook::new(0, 2, true);
1224
1225        let id = book.create_order(Side::Ask, 100, 101, Some(50)).unwrap();
1226
1227        book.place_order(id);
1228
1229        assert!(book.bid_ask() == (0, 50));
1230        assert!(book.ask_best_vol_and_orders() == (100, 1));
1231
1232        book.place_order(id);
1233
1234        assert!(book.bid_ask() == (0, 50));
1235        assert!(book.ask_best_vol_and_orders() == (100, 1));
1236    }
1237
1238    #[test]
1239    fn test_serialisation() {
1240        use rand::{seq::SliceRandom, Rng};
1241        use rand_xoshiro::rand_core::SeedableRng;
1242        use rand_xoshiro::Xoroshiro128Plus;
1243
1244        let mut book: OrderBook = OrderBook::new(0, 1, true);
1245
1246        let mut rng = Xoroshiro128Plus::seed_from_u64(101);
1247
1248        for i in (0..200).into_iter() {
1249            let side = [Side::Bid, Side::Ask].choose(&mut rng).unwrap();
1250            let price = rng.gen_range(20..40);
1251            let vol = rng.gen_range(5..20);
1252            book.create_and_place_order(*side, vol, 0, Some(price))
1253                .unwrap();
1254            book.set_time(i);
1255        }
1256
1257        let book_snapshot = serde_json::to_string(&book).unwrap();
1258        let loaded_book = serde_json::from_str::<OrderBook>(book_snapshot.as_str()).unwrap();
1259
1260        assert!(book.trading == loaded_book.trading);
1261        assert!(book.trade_vol == loaded_book.trade_vol);
1262
1263        assert!(book.bid_ask() == loaded_book.bid_ask());
1264
1265        assert!(book.bid_best_vol_and_orders() == loaded_book.bid_best_vol_and_orders());
1266        assert!(book.bid_vol() == loaded_book.bid_vol());
1267
1268        assert!(book.ask_best_vol_and_orders() == loaded_book.ask_best_vol_and_orders());
1269        assert!(book.bid_vol() == loaded_book.bid_vol());
1270
1271        assert!(book.current_order_id() == loaded_book.current_order_id());
1272
1273        assert!(book.bid_side.best_order_idx() == loaded_book.bid_side.best_order_idx());
1274        assert!(book.ask_side.best_order_idx() == loaded_book.ask_side.best_order_idx());
1275    }
1276}