Skip to main content

matchcore/orderbook/book/
limit_book.rs

1use super::PriceLevel;
2use crate::{LevelId, OrderId, Price, RestingLimitOrder, Timestamp};
3
4use slab::Slab;
5
6use std::{
7    cmp::Reverse,
8    collections::{BTreeMap, BinaryHeap, HashMap},
9};
10
11/// Limit order book that manages limit orders and price levels
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13#[derive(Debug, Clone, Default)]
14pub struct LimitBook<const LEVELS_INITIAL_CAPACITY: usize = 2048> {
15    /// Limit orders indexed by order ID for O(1) lookup
16    pub(crate) orders: HashMap<OrderId, RestingLimitOrder>,
17
18    /// Price levels, stored in a slab with O(1) indexing
19    pub(crate) levels: Slab<PriceLevel>,
20
21    /// Bid side price levels, stored in a ordered map with O(log N) ordering
22    pub(crate) bids: BTreeMap<Price, LevelId>,
23
24    /// Ask side price levels, stored in a ordered map with O(log N) ordering
25    pub(crate) asks: BTreeMap<Price, LevelId>,
26
27    /// Queue of limit order IDs to be expired, stored in a min heap of tuples of
28    /// (expires_at, order_id) with O(log N) push and pop
29    pub(crate) expiration_queue: BinaryHeap<Reverse<(Timestamp, OrderId)>>,
30}
31
32impl<const LEVELS_INITIAL_CAPACITY: usize> LimitBook<LEVELS_INITIAL_CAPACITY> {
33    /// Create a new limit order book
34    pub fn new() -> Self {
35        Self::default()
36    }
37}
38
39impl LimitBook {
40    /// Get the limit orders indexed by order ID
41    pub fn orders(&self) -> &HashMap<OrderId, RestingLimitOrder> {
42        &self.orders
43    }
44
45    /// Get the price levels
46    pub fn levels(&self) -> &Slab<PriceLevel> {
47        &self.levels
48    }
49
50    /// Get the bid side price levels
51    pub fn bids(&self) -> &BTreeMap<Price, LevelId> {
52        &self.bids
53    }
54
55    /// Get the ask side price levels
56    pub fn asks(&self) -> &BTreeMap<Price, LevelId> {
57        &self.asks
58    }
59
60    /// Get the queue of limit order IDs to be expired
61    pub fn expiration_queue(&self) -> &BinaryHeap<Reverse<(Timestamp, OrderId)>> {
62        &self.expiration_queue
63    }
64
65    pub fn get_bid_level(&self, price: Price) -> Option<&PriceLevel> {
66        self.bids
67            .get(&price)
68            .map(|level_id| &self.levels[*level_id])
69    }
70
71    pub fn get_ask_level(&self, price: Price) -> Option<&PriceLevel> {
72        self.asks
73            .get(&price)
74            .map(|level_id| &self.levels[*level_id])
75    }
76}