pub mod display;
mod test;
use std::collections::btree_map::BTreeMap;
use serde_derive::{Serialize, Deserialize};
use crate::Side;
use crate::tick::TickUnit;
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct OrderBook {
ask: BTreeMap<TickUnit, TickUnit>,
bid: BTreeMap<TickUnit, TickUnit>,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
pub struct LimitUpdate {
pub price: TickUnit,
pub size: TickUnit,
pub side: Side,
}
impl LimitUpdate {
pub fn new(price: TickUnit, size: TickUnit, side: Side) -> Self {
LimitUpdate {
price,
size,
side,
}
}
}
impl OrderBook {
pub fn new() -> Self {
OrderBook {
ask: BTreeMap::new(),
bid: BTreeMap::new(),
}
}
pub fn best_bid(&self) -> TickUnit {
self.bid().next().map(|(price, _)| *price).unwrap_or(0)
}
pub fn best_ask(&self) -> TickUnit {
self.ask().next().map(|(price, _)| *price).unwrap_or(TickUnit::max_value())
}
pub fn update(&mut self, update: LimitUpdate) {
use std::collections::btree_map::Entry;
let entry = match update.side {
Side::Bid if update.size == 0 => {
self.bid.remove(&update.price);
return;
},
Side::Ask if update.size == 0 => {
self.ask.remove(&update.price);
return;
},
Side::Bid => self.bid.entry(update.price),
Side::Ask => self.ask.entry(update.price),
};
match entry {
Entry::Occupied(mut entry) => *entry.get_mut() = update.size,
Entry::Vacant(entry) => { entry.insert(update.size); },
};
}
pub fn size_at_limit(&self, side: Side, price: TickUnit) -> TickUnit {
let size = match side {
Side::Bid => self.bid.get(&price),
Side::Ask => self.ask.get(&price),
};
size.cloned().unwrap_or(0)
}
pub fn bid(&self) -> impl Iterator<Item = (&TickUnit, &TickUnit)> {
self.bid.iter().rev()
}
pub fn ask(&self) -> impl Iterator<Item = (&TickUnit, &TickUnit)> {
self.ask.iter()
}
pub fn diff(&self, other: &OrderBook) -> impl Iterator<Item = LimitUpdate> {
use std::collections::HashMap;
let mut updates = Vec::new();
let mut compute_diff = |entries: &BTreeMap<_, _>, other_entries, side| {
let mut entries: HashMap<_, _> = entries.iter().map(|(x, y)| (*x, *y)).collect();
for (&price, &other_size) in other_entries {
let need_update = entries.remove(&price)
.map(|size| size != other_size)
.unwrap_or(true);
if need_update {
updates.push(LimitUpdate::new(price, other_size, side));
}
}
for (price, _) in entries {
updates.push(LimitUpdate::new(price, 0, side));
}
};
compute_diff(&self.bid, &other.bid, Side::Bid);
compute_diff(&self.ask, &other.ask, Side::Ask);
updates.into_iter()
}
}