Skip to main content

apple_quant_algorithmic/order/
client.rs

1use crate::{
2	price::{AbsolutePrice, BidAskPriceSpread, ProtoabsolutePrice},
3	backend::OrderIdGenerator, instrument::InstrumentSpec,
4	liquidity::LiquidityEstimation, volume::DirectionalIntent,
5};
6
7use super::{ClientOrderTracker, MatchableOrder};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum ClientOrder<IS: InstrumentSpec> {
11	Stop(ClientStopOrder<IS>),
12}
13
14impl<IS: InstrumentSpec> ClientOrder<IS> {
15	pub(crate) fn parent_processed(
16		&mut self,
17		bid_ask_price_spread: &BidAskPriceSpread<IS>,
18	) {
19		#[allow(irrefutable_let_patterns)]
20		let Self::Stop(
21			client_stop_order,
22		) = self else {
23			return;
24		};
25
26		client_stop_order.parent_processed(bid_ask_price_spread);
27	}
28
29	pub fn register(
30		&self,
31		order_id_generator: &mut OrderIdGenerator,
32	) -> ClientOrderTracker
33	where
34		IS: Send,
35	{
36		let local_order_id = order_id_generator.next_local_order_id();
37		ClientOrderTracker::new(local_order_id)
38	}
39}
40
41impl<IS: InstrumentSpec> MatchableOrder<IS> for ClientOrder<IS> {
42	fn is_liquidable(
43		&self,
44		liquidity_estimation: &LiquidityEstimation<IS>,
45	) -> Option<AbsolutePrice<IS>> {
46		match self {
47			Self::Stop(
48				client_stop_order,
49			) => client_stop_order.is_liquidable(liquidity_estimation),
50		}
51	}
52}
53
54impl<IS: InstrumentSpec> From<ClientStopOrder<IS>> for ClientOrder<IS> {
55	fn from(
56		value: ClientStopOrder<IS>,
57	) -> Self {
58		Self::Stop(value)
59	}
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
63pub struct ClientStopOrder<IS: InstrumentSpec> {
64	pub price: ProtoabsolutePrice<IS>,
65	pub cross_over_directional_intent: DirectionalIntent,
66}
67
68impl<IS: InstrumentSpec> ClientStopOrder<IS> {
69	pub fn new(
70		price: ProtoabsolutePrice<IS>,
71		cross_over_directional_intent: DirectionalIntent,
72	) -> Self {
73		Self {
74			price,
75			cross_over_directional_intent,
76		}
77	}
78
79	pub(crate) fn parent_processed(
80		&mut self,
81		bid_ask_price_spread: &BidAskPriceSpread<IS>,
82	) {
83		let ProtoabsolutePrice::Relative(
84			relative_price,
85		) = &self.price else {
86			return;
87		};
88
89		let absolute_price = if relative_price.is_positive() {
90			bid_ask_price_spread.ask_price + relative_price
91		} else {
92			bid_ask_price_spread.bid_price + relative_price
93		};
94
95		self.price = absolute_price.into_protoabsolute_price();
96	}
97
98	pub fn into_client_order(
99		self,
100	) -> ClientOrder<IS> {
101		self.into()
102	}
103}
104
105impl<IS: InstrumentSpec> MatchableOrder<IS> for ClientStopOrder<IS> {
106	fn is_liquidable(
107		&self,
108		liquidity_estimation: &LiquidityEstimation<IS>,
109	) -> Option<AbsolutePrice<IS>> {
110		let Some((
111			bid_price_volume_level,
112			ask_price_volume_level,
113		)) = liquidity_estimation.furthest_bid_ask() else {
114			return None;
115		};
116
117		let ProtoabsolutePrice::Absolute(
118			absolute_price,
119		) = &self.price else {
120			return None;
121		};
122
123		match self.cross_over_directional_intent {
124			DirectionalIntent::Positive => {
125				if &ask_price_volume_level.price < absolute_price {
126					return None;
127				}
128
129				Some(ask_price_volume_level.price)
130			},
131			DirectionalIntent::Negative => {
132				if &bid_price_volume_level.price > absolute_price {
133					return None;
134				}
135
136				Some(bid_price_volume_level.price)
137			},
138		}
139	}
140}