use crate::{
aggregation::TradeTradeTimestamp,
instrument::InstrumentSpec,
price::{AskPriceVolumeLevel, BidPriceVolumeLevel},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct Levels<IS: InstrumentSpec> {
lowest_bid_level: BidPriceVolumeLevel<IS>,
highest_ask_level: AskPriceVolumeLevel<IS>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LiquidityEstimation<IS: InstrumentSpec>(Option<Levels<IS>>);
impl<IS: InstrumentSpec> LiquidityEstimation<IS> {
pub fn reset(&mut self) {
self.0 = None;
}
pub fn collect_furthest_bid_ask(
&mut self
) -> Option<(
BidPriceVolumeLevel<IS>,
AskPriceVolumeLevel<IS>,
)> {
let Levels {
highest_ask_level,
lowest_bid_level,
} = self.0.take()?;
Some((
lowest_bid_level,
highest_ask_level,
))
}
pub fn furthest_bid_ask(
&self
) -> Option<(
&BidPriceVolumeLevel<IS>,
&AskPriceVolumeLevel<IS>,
)> {
let Some(Levels {
lowest_bid_level,
highest_ask_level,
}) = &self.0
else {
return None;
};
Some((
lowest_bid_level,
highest_ask_level,
))
}
pub fn walk_trades<'a>(
&mut self,
mut trades: impl Iterator<Item = &'a TradeTradeTimestamp<IS>>,
) where
IS: 'a,
{
let Some(first_trade_trade_timestamp) = trades.next() else {
return;
};
if self.0.is_none() {
let highest_ask_level = AskPriceVolumeLevel {
price: first_trade_trade_timestamp
.trade()
.price,
directionless_volume: *first_trade_trade_timestamp
.trade()
.aggressive_volume
.as_directionless_volume(),
};
let lowest_bid_level = BidPriceVolumeLevel {
price: highest_ask_level.price,
directionless_volume: highest_ask_level.directionless_volume,
};
self.0 = Some(Levels {
highest_ask_level,
lowest_bid_level,
});
}
let levels = self.0.as_mut().unwrap();
for trade_trade_timestamp in trades {
let trade_price = &trade_trade_timestamp
.trade()
.price;
let trade_aggressive_volume = &trade_trade_timestamp
.trade()
.aggressive_volume;
if trade_price == &levels.highest_ask_level.price {
levels
.highest_ask_level
.directionless_volume += *trade_aggressive_volume.as_directionless_volume();
} else if trade_price > &levels.highest_ask_level.price {
levels.highest_ask_level.price = *trade_price;
levels
.highest_ask_level
.directionless_volume = *trade_aggressive_volume.as_directionless_volume();
}
if trade_price == &levels.lowest_bid_level.price {
levels
.lowest_bid_level
.directionless_volume += *trade_aggressive_volume.as_directionless_volume();
} else if trade_price < &levels.lowest_bid_level.price {
levels.lowest_bid_level.price = *trade_price;
levels
.lowest_bid_level
.directionless_volume = *trade_aggressive_volume.as_directionless_volume();
}
}
}
}
impl<IS: InstrumentSpec> Default for LiquidityEstimation<IS> {
fn default() -> Self {
Self(None)
}
}