apple_quant_algorithmic/order/
remote.rs1#[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}