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);
}
}