1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
use rust_decimal::Decimal;
use serde::Deserialize;

use std::borrow::BorrowMut;
use std::collections::BTreeMap;
use std::ops::Neg;

use crate::misc::DateTimeUTC;
use crate::utils::{WrapIterator, WrappedIterator};

/// Alias for price type.
pub type Price = Decimal;

/// Alias for stock/contract amount type.
pub type Quantity = Decimal;

/// Represents raw trade.
#[derive(Clone, Deserialize)]
pub struct Trade {
    pub price: Price,
    pub quantity: Quantity,
    /// The trade ID officially marked by the exchange.
    pub trade_id: String,
    /// Received timestamp of the trade
    pub timestamp: DateTimeUTC,
    /// Is buyer maker of this trade?
    pub is_buyer_maker: Option<bool>,
}

/// Represents single change on an orderbook.
pub enum DirectOrderbookChange {
    /// Set `= quantity` at given `price` level.
    Set { price: Price, quantity: Quantity },
    /// Set `+= quantity` at given `price` level.
    Delta { price: Price, quantity: Quantity },
}

/// Represents any orderbook change.
pub enum OrderbookChange {
    DirectChange(Vec<DirectOrderbookChange>),
    Snapshot(Box<dyn Orderbook>),
}

impl DirectOrderbookChange {
    /// Get price target level.
    fn get_price_level(&self) -> Price {
        match self {
            Self::Set {
                price,
                quantity: _q,
            } => *price,
            Self::Delta {
                price,
                quantity: _q,
            } => *price,
        }
    }

    /// Apply current change into given `quantity`.
    fn apply(&self, quantity: &mut Quantity) -> () {
        match self {
            Self::Set {
                price: _p,
                quantity: q,
            } => {
                *quantity = *q;
            }
            Self::Delta {
                price: _p,
                quantity: q,
            } => {
                *quantity += q;
            }
        }
    }
}

impl Neg for DirectOrderbookChange {
    type Output = Self;

    fn neg(self) -> Self::Output {
        match self {
            Self::Set { price, quantity } => Self::Set {
                price,
                quantity: -quantity,
            },
            Self::Delta { price, quantity } => Self::Delta {
                price,
                quantity: -quantity,
            },
        }
    }
}

/// Type alias for orderbook iterators.
type OrderbookIterator<'s> = WrappedIterator<'s, (&'s Price, &'s Quantity)>;

/// Trait for orderbook.
/// The reason why I made a trait for this is because
/// there can be several different structs of an Orderbook.
///
/// Following list contains variations on level;
/// - L1: Best ask/bid
/// - L2: Aggregated asks/bids
/// - L3: Non-aggregated asks/bids (Currently not supported)
///
/// And also an orderbook can be unsized or have fixed size.
pub trait Orderbook {
    /// Return an iterator that yields asks from the best to the worst.
    fn iter_ask<'s>(&'s self) -> OrderbookIterator<'s>;
    /// Return an iterator that yields bids from the best to the worst.
    fn iter_bid<'s>(&'s self) -> OrderbookIterator<'s>;

    /// Apply change on current orderbook.
    /// This method does not guarantee that the modified state is valid.
    fn apply_change(&mut self, change: &DirectOrderbookChange, is_ask: bool) -> ();

    /// Return first ask price, first ask quantity, and iterator of remaining ask levels.
    /// If there is no ask, return `Price::MIN` as price and `Quantity::ZERO` as quantity.
    /// You can safely drop iterator if there is no needs.
    fn best_ask<'s>(&'s self) -> (&'s Price, &'s Quantity, OrderbookIterator<'s>) {
        let mut iter_ask = self.iter_ask();
        let (price, quantity) = iter_ask.next().unwrap_or((&Price::MIN, &Quantity::ZERO));
        (price, quantity, iter_ask)
    }

    /// Return first bid price, first bid quantity, and iterator of remaining bid levels.
    /// If there is no bid, return `Price::MAX` as price and `Quantity::ZERO` as quantity.
    /// You can safely drop iterator if there is no needs.
    fn best_bid<'s>(&'s self) -> (&'s Price, &'s Quantity, OrderbookIterator<'s>) {
        let mut iter_bid = self.iter_bid();
        let (price, quantity) = iter_bid.next().unwrap_or((&Price::MAX, &Quantity::ZERO));
        (price, quantity, iter_bid)
    }

    /// Validate if current state of this orderbook is valid.
    fn validate(&self) -> bool {
        let (mut prev_ask_p, prev_ask_q, mut iter_ask) = self.best_ask();
        let (mut prev_bid_p, prev_bid_q, mut iter_bid) = self.best_bid();
        if (prev_ask_p != &Price::MIN && prev_bid_p != &Price::MIN && prev_ask_p < prev_bid_p)
            || (prev_ask_p != &Price::MIN && prev_ask_q.is_zero())
            || (prev_bid_p != &Price::MAX && prev_bid_q.is_zero())
        {
            // 1. Both ask and bid are not empty, but price is reversed
            // 2. Ask is not empty but ask quantity is zero
            // 3. Bid is not empty but bid quantity is zero
            return false;
        }

        while let Some((worse_ask_p, worse_ask_q)) = iter_ask.next() {
            // Ask prices should be in increasing order
            if prev_ask_p > worse_ask_p || worse_ask_q.is_zero() {
                return false;
            }
            prev_ask_p = worse_ask_p;
        }
        while let Some((worse_bid_p, worse_bid_q)) = iter_bid.next() {
            // Bid prices should be in decreasing order
            if prev_bid_p < worse_bid_p || worse_bid_q.is_zero() {
                return false;
            }
            prev_bid_p = worse_bid_p;
        }
        true
    }
}

/// Represents unsized orderbook.
#[derive(Clone, Default)]
pub struct UnsizedOrderbook {
    asks: BTreeMap<Price, Quantity>,
    bids: BTreeMap<Price, Quantity>,
}

impl Orderbook for UnsizedOrderbook {
    fn iter_ask<'s>(&'s self) -> WrappedIterator<'s, (&'s Price, &'s Quantity)> {
        self.asks.iter().wrap_iter()
    }

    fn iter_bid<'s>(&'s self) -> WrappedIterator<'s, (&'s Price, &'s Quantity)> {
        self.bids.iter().wrap_iter()
    }

    fn apply_change(&mut self, change: &DirectOrderbookChange, is_ask: bool) -> () {
        let mapping = if is_ask {
            self.asks.borrow_mut()
        } else {
            self.bids.borrow_mut()
        };
        let entry = mapping.entry(change.get_price_level()).or_default();
        change.apply(entry);
    }
}