Skip to main content

apple_quant_algorithmic/order/
remote.rs

1#[cfg(feature = "log-trace-order-manager")]
2use apple_quant_core::log::trace;
3
4use crate::{
5	price::{AbsolutePrice, BidAskPriceSpread, ProtoabsolutePrice},
6	volume::{
7		AggressiveVolume, AggressorSide, DirectionalIntentVolume, DirectionlessVolume,
8		RestingSide, RestingVolume,
9	},
10	backend::OrderIdGenerator, instrument::InstrumentSpec, liquidity::LiquidityEstimation,
11};
12
13use super::{
14	DesiredVolumeOrder, DesiredVolumeOrderError, MatchableOrder,
15	OrderExecutionExpectation, RemoteOrderTracker,
16};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub enum RemoteOrder<IS: InstrumentSpec> {
20	Market(MarketOrder<IS>),
21	Limit(LimitOrder<IS>),
22}
23
24impl<IS: InstrumentSpec> RemoteOrder<IS> {
25	pub(crate) fn parent_processed(
26		&mut self,
27		bid_ask_price_spread: &BidAskPriceSpread<IS>,
28	) {
29		let Self::Limit(
30			limit_order,
31		) = self else {
32			return;
33		};
34
35		limit_order.parent_processed(bid_ask_price_spread);
36	}
37
38	pub fn as_order_execution_expectation(
39		&self,
40	) -> OrderExecutionExpectation {
41		match self {
42			Self::Market(_) => OrderExecutionExpectation::Immediate,
43			Self::Limit(
44				limit_order,
45			) => limit_order.order_execution_expectation,
46		}
47	}
48
49	pub fn register(
50		&self,
51		order_id_generator: &mut OrderIdGenerator,
52	) -> Result<RemoteOrderTracker, DesiredVolumeOrderError>
53	where
54		IS: Send,
55	{
56		let local_order_id = order_id_generator.next_local_order_id();
57
58		#[cfg(feature = "log-trace-order-manager")]
59		trace!("Registering order `{self:?}` with `{local_order_id:?}`");
60
61		let directional_intent_volume = self.desired_directional_intent_volume()?;
62		let order_execution_expectation = self.as_order_execution_expectation();
63
64		Ok(RemoteOrderTracker::new(local_order_id))
65	}
66}
67
68impl<IS: InstrumentSpec> DesiredVolumeOrder<IS> for RemoteOrder<IS> {
69	fn desired_directional_intent_volume(
70		&self,
71	) -> Result<DirectionalIntentVolume<IS>, DesiredVolumeOrderError> {
72		match self {
73			Self::Market(
74				market_order,
75			) => market_order.desired_directional_intent_volume(),
76			Self::Limit(
77				limit_order,
78			) => limit_order.desired_directional_intent_volume(),
79		}
80	}
81
82	fn desired_directionless_volume(
83		&self,
84	) -> Result<&DirectionlessVolume<IS>, DesiredVolumeOrderError> {
85		match self {
86			Self::Market(
87				market_order,
88			) => market_order.desired_directionless_volume(),
89			Self::Limit(
90				limit_order,
91			) => limit_order.desired_directionless_volume(),
92		}
93	}
94}
95
96impl<IS: InstrumentSpec> MatchableOrder<IS> for RemoteOrder<IS> {
97	fn is_liquidable(
98		&self,
99		liquidity_estimation: &LiquidityEstimation<IS>,
100	) -> Option<AbsolutePrice<IS>> {
101		match self {
102			Self::Market(
103				market_order,
104			) => market_order.is_liquidable(liquidity_estimation),
105			Self::Limit(
106				limit_order,
107			) => limit_order.is_liquidable(liquidity_estimation),
108		}
109	}
110}
111
112impl<IS: InstrumentSpec> From<MarketOrder<IS>> for RemoteOrder<IS> {
113	fn from(
114		value: MarketOrder<IS>,
115	) -> Self {
116		Self::Market(value)
117	}
118}
119
120impl<IS: InstrumentSpec> From<LimitOrder<IS>> for RemoteOrder<IS> {
121	fn from(
122		value: LimitOrder<IS>,
123	) -> Self {
124		Self::Limit(value)
125	}
126}
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
129pub struct MarketOrder<IS: InstrumentSpec> {
130	pub aggressive_volume: AggressiveVolume<IS>,
131}
132
133impl<IS: InstrumentSpec> MarketOrder<IS> {
134	pub fn new(
135		aggressive_volume: AggressiveVolume<IS>,
136	) -> Self {
137		Self { aggressive_volume }
138	}
139
140	pub fn new_from_parts(
141		directionless_volume: DirectionlessVolume<IS>,
142		aggressor_side: AggressorSide,
143	) -> Self {
144		Self {
145			aggressive_volume: AggressiveVolume {
146				directionless_volume,
147				aggressor_side,
148			},
149		}
150	}
151
152	pub fn into_remote(
153		self,
154	) -> RemoteOrder<IS> {
155		self.into()
156	}
157}
158
159impl<IS: InstrumentSpec> DesiredVolumeOrder<IS> for MarketOrder<IS> {
160	fn desired_directional_intent_volume(
161		&self,
162	) -> Result<DirectionalIntentVolume<IS>, DesiredVolumeOrderError> {
163		Ok(self.aggressive_volume.as_directional_intent_volume())
164	}
165
166	fn desired_directionless_volume(
167		&self,
168	) -> Result<&DirectionlessVolume<IS>, DesiredVolumeOrderError> {
169		Ok(self.aggressive_volume.as_directionless_volume())
170	}
171}
172
173impl<IS: InstrumentSpec> MatchableOrder<IS> for MarketOrder<IS> {
174	fn is_liquidable(
175		&self,
176		liquidity_estimation: &LiquidityEstimation<IS>,
177	) -> Option<AbsolutePrice<IS>> {
178		let Some((
179			bid_level,
180			ask_level,
181		)) = liquidity_estimation.furthest_bid_ask() else {
182			return None;
183		};
184
185		match self.aggressive_volume.into_aggressor_side() {
186			AggressorSide::Bid => Some(bid_level.price),
187			AggressorSide::Ask => Some(ask_level.price),
188		}
189	}
190}
191
192#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
193pub struct LimitOrder<IS: InstrumentSpec> {
194	pub price: ProtoabsolutePrice<IS>,
195	pub resting_volume: RestingVolume<IS>,
196	pub order_execution_expectation: OrderExecutionExpectation,
197}
198
199impl<IS: InstrumentSpec> LimitOrder<IS> {
200	pub fn new(
201		price: ProtoabsolutePrice<IS>,
202		resting_volume: RestingVolume<IS>,
203		order_execution_expectation: OrderExecutionExpectation,
204	) -> Self {
205		Self {
206			price,
207			resting_volume,
208			order_execution_expectation,
209		}
210	}
211
212	pub(crate) fn parent_processed(
213		&mut self,
214		bid_ask_price_spread: &BidAskPriceSpread<IS>,
215	) {
216		let ProtoabsolutePrice::Relative(
217			relative_price,
218		) = &self.price else {
219			return;
220		};
221
222		let absolute_price = if relative_price.is_positive() {
223			bid_ask_price_spread.ask_price + relative_price
224		} else {
225			bid_ask_price_spread.bid_price + relative_price
226		};
227
228		self.price = absolute_price.into_protoabsolute_price();
229	}
230
231	pub fn into_remote(
232		self,
233	) -> RemoteOrder<IS> {
234		self.into()
235	}
236}
237
238impl<IS: InstrumentSpec> DesiredVolumeOrder<IS> for LimitOrder<IS> {
239	fn desired_directional_intent_volume(
240		&self,
241	) -> Result<DirectionalIntentVolume<IS>, DesiredVolumeOrderError> {
242		Ok(self.resting_volume.as_directional_intent_volume())
243	}
244
245	fn desired_directionless_volume(
246		&self,
247	) -> Result<&DirectionlessVolume<IS>, DesiredVolumeOrderError> {
248		Ok(self.resting_volume.as_directionless_volume())
249	}
250}
251
252impl<IS: InstrumentSpec> MatchableOrder<IS> for LimitOrder<IS> {
253	fn is_liquidable(
254		&self,
255		liquidity_estimation: &LiquidityEstimation<IS>,
256	) -> Option<AbsolutePrice<IS>> {
257		let Some((
258			bid_level,
259			ask_level,
260		)) = liquidity_estimation.furthest_bid_ask() else {
261			return None;
262		};
263
264		match self.resting_volume.resting_side {
265			RestingSide::Bid => {
266				let ProtoabsolutePrice::Absolute(
267					absolute_price,
268				) = self.price else {
269					return None;
270				};
271
272				if bid_level.price <= absolute_price {
273					Some(bid_level.price)
274				} else {
275					None
276				}
277			},
278			RestingSide::Ask => {
279				let ProtoabsolutePrice::Absolute(
280					absolute_price,
281				) = self.price else {
282					return None;
283				};
284
285				if ask_level.price >= absolute_price {
286					Some(ask_level.price)
287				} else {
288					None
289				}
290			},
291		}
292	}
293}