Skip to main content

apple_quant_algorithmic/order/
remote.rs

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