use crate::{
price::{AbsolutePrice, BidAskPriceSpread, ProtoabsolutePrice},
backend::OrderIdGenerator, instrument::InstrumentSpec,
liquidity::LiquidityEstimation, volume::DirectionalIntent,
};
use super::{ClientOrderTracker, MatchableOrder};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ClientOrder<IS: InstrumentSpec> {
Stop(ClientStopOrder<IS>),
}
impl<IS: InstrumentSpec> ClientOrder<IS> {
pub(crate) fn parent_processed(
&mut self,
bid_ask_price_spread: &BidAskPriceSpread<IS>,
) {
#[allow(irrefutable_let_patterns)]
let Self::Stop(
client_stop_order,
) = self else {
return;
};
client_stop_order.parent_processed(bid_ask_price_spread);
}
pub fn register(
&self,
order_id_generator: &mut OrderIdGenerator,
) -> ClientOrderTracker
where
IS: Send,
{
let local_order_id = order_id_generator.next_local_order_id();
ClientOrderTracker::new(local_order_id)
}
}
impl<IS: InstrumentSpec> MatchableOrder<IS> for ClientOrder<IS> {
fn is_liquidable(
&self,
liquidity_estimation: &LiquidityEstimation<IS>,
) -> Option<AbsolutePrice<IS>> {
match self {
Self::Stop(
client_stop_order,
) => client_stop_order.is_liquidable(liquidity_estimation),
}
}
}
impl<IS: InstrumentSpec> From<ClientStopOrder<IS>> for ClientOrder<IS> {
fn from(
value: ClientStopOrder<IS>,
) -> Self {
Self::Stop(value)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ClientStopOrder<IS: InstrumentSpec> {
pub price: ProtoabsolutePrice<IS>,
pub cross_over_directional_intent: DirectionalIntent,
}
impl<IS: InstrumentSpec> ClientStopOrder<IS> {
pub fn new(
price: ProtoabsolutePrice<IS>,
cross_over_directional_intent: DirectionalIntent,
) -> Self {
Self {
price,
cross_over_directional_intent,
}
}
pub(crate) fn parent_processed(
&mut self,
bid_ask_price_spread: &BidAskPriceSpread<IS>,
) {
let ProtoabsolutePrice::Relative(
relative_price,
) = &self.price else {
return;
};
let absolute_price = if relative_price.is_positive() {
bid_ask_price_spread.ask_price + relative_price
} else {
bid_ask_price_spread.bid_price + relative_price
};
self.price = absolute_price.into_protoabsolute_price();
}
pub fn into_client_order(
self,
) -> ClientOrder<IS> {
self.into()
}
}
impl<IS: InstrumentSpec> MatchableOrder<IS> for ClientStopOrder<IS> {
fn is_liquidable(
&self,
liquidity_estimation: &LiquidityEstimation<IS>,
) -> Option<AbsolutePrice<IS>> {
let Some((
bid_price_volume_level,
ask_price_volume_level,
)) = liquidity_estimation.furthest_bid_ask() else {
return None;
};
let ProtoabsolutePrice::Absolute(
absolute_price,
) = &self.price else {
return None;
};
match self.cross_over_directional_intent {
DirectionalIntent::Positive => {
if &ask_price_volume_level.price < absolute_price {
return None;
}
Some(ask_price_volume_level.price)
},
DirectionalIntent::Negative => {
if &bid_price_volume_level.price > absolute_price {
return None;
}
Some(bid_price_volume_level.price)
},
}
}
}