1use apple_quant_core::{AddUnchecked, SubChecked, SubUnchecked};
2
3use smallvec::SmallVec;
4use thiserror::Error;
5use tracing::instrument;
6
7#[allow(unused_imports)]
8use tracing::trace;
9
10use crate::backend::LocalOrderId;
11use crate::order::OrderAction;
12use crate::order::dependency::remote::CancelRemoteOrder;
13use crate::volume::ZeroableExt;
14
15use crate::{
16 backend::{OrderId, OrderIdError, OrdersBackend, RemoteOrderId},
17 order::{
18 DeferredOrderActions, DesiredVolumeOrderError, PartialOrderFill,
19 RemoteTimingCondition,
20 },
21 price::{AbsolutePrice, BidAskPriceSpread},
22 timestamp::{TickTimestamp, Timestamp, Timestamped},
23 volume::{
24 DirectionalExposure, DirectionalIntentVolume, DirectionlessVolume, Zeroable,
25 ZeroableVolume,
26 },
27 instrument::InstrumentSpec,
28};
29
30use super::{CompletedRemoteOrders, OrdersCapacitySpec, PendingRemoteOrder};
31
32#[derive(Debug, Error)]
33pub enum WorkingRemoteOrderSubmitError {
34 #[error("{0:?}")]
35 DesiredVolumeOrder(#[from] DesiredVolumeOrderError),
36
37 #[error("{0:?}")]
38 OrderId(#[from] OrderIdError),
39}
40
41pub struct WorkingRemoteOrder<
42 IS: InstrumentSpec,
43 CS: OrdersCapacitySpec,
44> {
45 pub(crate) local_order_id: LocalOrderId,
46 pub(crate) remote_order_id: RemoteOrderId,
47
48 pub(crate) dependencies: SmallVec<[(
49 RemoteTimingCondition,
50 OrderAction<IS>,
51 ); core::direct_const_arg!(CS::DEPENDENCY)]>,
52
53 pub(crate) desired_directional_intent_volume: DirectionalIntentVolume<IS>,
54 pub(crate) booking_timestamp: Timestamp,
55
56 pub(crate) partial_order_fills: SmallVec<[PartialOrderFill<IS>; core::direct_const_arg!(
57 CS::PARTIAL_FILL
58 )]>,
59
60 pub(crate) armed_directional_exposure: Zeroable<DirectionalIntentVolume<IS>>,
61 pub(crate) effective_directional_exposure: Zeroable<DirectionalIntentVolume<IS>>,
62 pub(crate) rest_at: Option<AbsolutePrice<IS>>,
63}
64
65impl<
66 IS: InstrumentSpec,
67 CS: OrdersCapacitySpec,
68> WorkingRemoteOrder<IS, CS> {
69 #[instrument(skip_all)]
70 pub(crate) fn get_fully_filled(
71 &self,
72 ) -> Option<BidAskPriceSpread<IS>> {
73 let mut filled_volume = Zeroable::ZERO;
74 let mut iter_partial_order_fills = self.partial_order_fills.iter();
75
76 let Some(
77 mut bid_ask_price_spread,
78 ) = iter_partial_order_fills
79 .next()
80 .map(|
81 partial_order_fill,
82 | {
83 filled_volume = filled_volume.add_unchecked(
84 partial_order_fill.directional_intent_volume.directionless_volume.as_zeroable(),
85 );
86
87 BidAskPriceSpread {
88 ask_price: partial_order_fill.price,
89 bid_price: partial_order_fill.price,
90 }
91 }) else {
92 return None;
93 };
94
95 for partial_order_fill in iter_partial_order_fills {
96 filled_volume = filled_volume.add_unchecked(
97 partial_order_fill.directional_intent_volume.directionless_volume.as_zeroable(),
98 );
99
100 if partial_order_fill.price > bid_ask_price_spread.ask_price {
101 bid_ask_price_spread.ask_price = partial_order_fill.price;
102 }
103
104 if partial_order_fill.price < bid_ask_price_spread.bid_price {
105 bid_ask_price_spread.bid_price = partial_order_fill.price;
106 }
107 }
108
109 if (
110 filled_volume <
111 self.desired_directional_intent_volume.directionless_volume.as_zeroable()
112 ) {
113 return None;
114 }
115
116 Some(bid_ask_price_spread)
117 }
118
119 #[instrument(skip_all)]
120 pub(crate) fn modify_volume(
121 &mut self,
122 directional_exposure: &mut DirectionalExposure<IS>,
123 volume: &DirectionlessVolume<IS>,
124 ) {
125 let Ok(
126 desired_volume_delta,
127 ) = self.desired_directional_intent_volume.directionless_volume.sub_checked(
128 *volume,
129 ) else {
130 return;
131 };
132
133 let desired_volume_delta = desired_volume_delta.with_directional_intent(
134 self.desired_directional_intent_volume.directional_intent,
135 ).as_zeroable();
136
137 directional_exposure.change_armed_directional_exposure(&desired_volume_delta);
138
139 self.desired_directional_intent_volume.directionless_volume = *volume;
140
141 self.armed_directional_exposure = self.armed_directional_exposure.add_unchecked(
142 desired_volume_delta,
143 );
144
145 #[cfg(feature = "log-trace-order-manager")]
146 trace!(
147 "Modifing working order volume. New desired: `{:?}` armed: `{:?}`",
148 self.desired_directional_intent_volume,
149 self.armed_directional_exposure
150 );
151
152 if let Some(
153 directional_intent_volume,
154 ) = self.armed_directional_exposure.as_optional_nonzero_ref() {
155 if (
156 directional_intent_volume.directional_intent !=
157 self.desired_directional_intent_volume.directional_intent
158 ) {
159 unimplemented!()
160 }
161 } else {
162 unimplemented!()
163 }
164 }
165}
166
167impl<
168 IS: InstrumentSpec,
169 CS: OrdersCapacitySpec,
170> WorkingRemoteOrder<IS, CS> {
171 pub(crate) fn new(
172 local_order_id: LocalOrderId,
173 remote_order_id: RemoteOrderId,
174 dependencies: impl IntoIterator<Item = (
175 RemoteTimingCondition,
176 OrderAction<IS>,
177 )>,
178 desired_directional_intent_volume: DirectionalIntentVolume<IS>,
179 booking_timestamp: Timestamp,
180 rest_at: Option<AbsolutePrice<IS>>,
181 ) -> Self {
182 Self {
183 local_order_id,
184 remote_order_id,
185 dependencies: dependencies.into_iter().collect(),
186 desired_directional_intent_volume,
187 booking_timestamp,
188 partial_order_fills: SmallVec::default(),
189 armed_directional_exposure: desired_directional_intent_volume.as_zeroable(),
190 effective_directional_exposure: Zeroable::ZERO,
191 rest_at,
192 }
193 }
194}
195
196pub struct WorkingRemoteOrders<
198 IS: InstrumentSpec,
199 CS: OrdersCapacitySpec,
200>(SmallVec<[WorkingRemoteOrder<IS, CS>; core::direct_const_arg!(CS::WORKING_REMOTE)]>);
201
202impl<
203 IS: InstrumentSpec,
204 CS: OrdersCapacitySpec,
205> WorkingRemoteOrders<IS, CS> {
206 #[instrument(skip_all)]
207 pub(crate) fn submit<OB: OrdersBackend<IS>>(
208 &mut self,
209 directional_exposure: &mut DirectionalExposure<IS>,
210 deferred_order_actions: &mut DeferredOrderActions<IS>,
211 tick_timestamp: &TickTimestamp,
212 pending_remote_order: PendingRemoteOrder<IS, CS>,
213 remote_order_id: RemoteOrderId,
214 ) -> Result<(), WorkingRemoteOrderSubmitError>
215 where
216 IS: Send,
217 {
218 #[cfg(feature = "log-trace-order-manager")]
219 trace!("Adding id: `{:?}`.", remote_order_id);
220
221 let PendingRemoteOrder {
222 submission_timestamp: _,
223 local_order_id,
224 dependencies,
225 desired_directional_intent_volume,
226 rest_at,
227 cancel_on_process,
228 } = pending_remote_order;
229
230 let booking_timestamp = tick_timestamp.timestamp();
231
232 let working_remote_order = WorkingRemoteOrder::new(
233 local_order_id,
234 remote_order_id,
235 dependencies,
236 desired_directional_intent_volume,
237 booking_timestamp,
238 rest_at,
239 );
240
241 directional_exposure.change_armed_directional_exposure(
242 &working_remote_order.armed_directional_exposure,
243 );
244
245 self.0.push(working_remote_order);
246
247 if cancel_on_process {
248 let order_action = OrderAction::CancelRemote(
249 CancelRemoteOrder::new(local_order_id),
250 );
251
252 deferred_order_actions.push(order_action);
253 }
254
255 Ok(())
256 }
257
258 pub fn get(
259 &self,
260 order_id: impl Into<OrderId>,
261 ) -> Result<&WorkingRemoteOrder<IS, CS>, OrderIdError> {
262 match &order_id.into() {
263 OrderId::Local(
264 local_order_id,
265 ) => self.get_with_local(local_order_id),
266 OrderId::Remote(
267 remote_order_id,
268 ) => self.get_with_remote(remote_order_id),
269 }
270 }
271
272 #[instrument(skip_all)]
273 pub fn get_with_local(
274 &self,
275 local_order_id: &LocalOrderId,
276 ) -> Result<&WorkingRemoteOrder<IS, CS>, OrderIdError> {
277 let Some(
278 working_remote_order,
279 ) = self.0.iter().find(|
280 working_remote_order,
281 | &working_remote_order.local_order_id == local_order_id) else {
282 return local_order_id.err_invalid();
283 };
284
285 Ok(working_remote_order)
286 }
287
288 #[instrument(skip_all)]
289 pub fn get_with_remote(
290 &self,
291 remote_order_id: &RemoteOrderId,
292 ) -> Result<&WorkingRemoteOrder<IS, CS>, OrderIdError> {
293 let Some(
294 working_remote_order,
295 ) = self.0.iter().find(|
296 working_remote_order,
297 | &working_remote_order.remote_order_id == remote_order_id) else {
298 return remote_order_id.err_invalid();
299 };
300
301 Ok(working_remote_order)
302 }
303
304 pub(crate) fn get_mut(
305 &mut self,
306 order_id: impl Into<OrderId>,
307 ) -> Result<&mut WorkingRemoteOrder<IS, CS>, OrderIdError> {
308 match &order_id.into() {
309 OrderId::Local(
310 local_order_id,
311 ) => self.get_mut_with_local(local_order_id),
312 OrderId::Remote(
313 remote_order_id,
314 ) => self.get_mut_with_remote(remote_order_id),
315 }
316 }
317
318 #[instrument(skip_all)]
319 pub(crate) fn get_mut_with_local(
320 &mut self,
321 local_order_id: &LocalOrderId,
322 ) -> Result<&mut WorkingRemoteOrder<IS, CS>, OrderIdError> {
323 let Some(
324 working_remote_order,
325 ) = self.0.iter_mut().find(|
326 working_remote_order,
327 | &working_remote_order.local_order_id == local_order_id) else {
328 return local_order_id.err_invalid();
329 };
330
331 Ok(working_remote_order)
332 }
333
334 #[instrument(skip_all)]
335 pub(crate) fn get_mut_with_remote(
336 &mut self,
337 remote_order_id: &RemoteOrderId,
338 ) -> Result<&mut WorkingRemoteOrder<IS, CS>, OrderIdError> {
339 let Some(
340 working_remote_order,
341 ) = self.0.iter_mut().find(|
342 working_remote_order,
343 | &working_remote_order.remote_order_id == remote_order_id) else {
344 return remote_order_id.err_invalid();
345 };
346
347 Ok(working_remote_order)
348 }
349
350 #[instrument(skip_all)]
351 pub(crate) fn remove(
352 &mut self,
353 directional_exposure: &mut DirectionalExposure<IS>,
354 order_id: impl Into<OrderId>,
355 ) -> Result<WorkingRemoteOrder<IS, CS>, OrderIdError>
356 where
357 IS: Send,
358 {
359 let order_id = order_id.into();
360
361 #[cfg(feature = "log-trace-order-manager")]
362 trace!("Removing id: `{:?}`.", order_id);
363
364 let idx = match order_id {
365 OrderId::Local(
366 local_order_id,
367 ) => {
368 self.0.iter().position(|
369 working_remote_order,
370 | working_remote_order.local_order_id == local_order_id)
371 },
372 OrderId::Remote(
373 remote_order_id,
374 ) => {
375 self.0.iter().position(|
376 working_remote_order,
377 | working_remote_order.remote_order_id == remote_order_id)
378 },
379 };
380
381 let Some(
382 idx,
383 ) = idx else {
384 return order_id.err_invalid();
385 };
386
387 let mut working_remote_order = self.0.swap_remove(idx);
388
389 if let Some(
390 armed_directional_exposure,
391 ) = working_remote_order.armed_directional_exposure.as_optional_nonzero_ref() {
392 #[cfg(feature = "log-trace-directional-exposure")]
393 trace!(
394 "Reverting armed directional exposure `{:?}` during removing order from working state.",
395 armed_directional_exposure
396 );
397
398 directional_exposure.change_armed_directional_exposure(
399 &armed_directional_exposure.as_flipped().as_zeroable(),
400 );
401 }
402
403 working_remote_order.armed_directional_exposure = Zeroable::ZERO;
404 Ok(working_remote_order)
405 }
406
407 #[instrument(skip_all)]
408 pub(crate) fn processed<OB: OrdersBackend<IS>>(
409 &mut self,
410 remote_order_id: &RemoteOrderId,
411 ) -> Result<(), OrderIdError>
412 where
413 IS: Send,
414 {
415 #[cfg(feature = "log-trace-order-manager")]
416 trace!("Processing id: `{:?}`.", remote_order_id);
417
418 let working_remote_order = self.get_mut_with_remote(remote_order_id)?;
419
420 let Some(
421 rest_at,
422 ) = &working_remote_order.rest_at else {
423 return Ok(());
424 };
425
426 let bid_ask_price_spread = BidAskPriceSpread {
427 ask_price: *rest_at,
428 bid_price: *rest_at,
429 };
430
431 for (
432 _,
433 remote_order_action,
434 ) in working_remote_order.dependencies.iter_mut() {
435 remote_order_action.parent_processed(&bid_ask_price_spread);
436 }
437
438 Ok(())
439 }
440
441 #[instrument(skip_all)]
442 pub(crate) async fn partial_fill<OB: OrdersBackend<IS>>(
443 &mut self,
444 tick_timestamp: &TickTimestamp,
445 completed_remote_orders: &mut CompletedRemoteOrders<IS, CS>,
446 deferred_order_actions: &mut DeferredOrderActions<IS>,
447 directional_exposure: &mut DirectionalExposure<IS>,
448 partial_order_fill: PartialOrderFill<IS>,
449 remote_order_id: &RemoteOrderId,
450 ) -> Result<(), OrderIdError>
451 where
452 IS: Send,
453 {
454 #[cfg(feature = "log-trace-order-manager")]
455 trace!(
456 "Partial filling `{partial_order_fill:?}` for id: `{:?}`.",
457 remote_order_id,
458 );
459
460 let working_remote_order = self.get_mut_with_remote(remote_order_id)?;
461
462 working_remote_order.armed_directional_exposure = working_remote_order.armed_directional_exposure.sub_unchecked(
463 partial_order_fill.directional_intent_volume.as_zeroable(),
464 );
465
466 directional_exposure.change_armed_directional_exposure(
467 &partial_order_fill
468 .directional_intent_volume
469 .as_flipped().as_zeroable(),
470 );
471
472 working_remote_order.effective_directional_exposure = working_remote_order.effective_directional_exposure.add_unchecked(
473 partial_order_fill.directional_intent_volume.as_zeroable(),
474 );
475
476 directional_exposure.apply_partial_order_fill(
477 &partial_order_fill,
478 ).await;
479
480 working_remote_order.partial_order_fills.push(partial_order_fill);
481
482 for (
483 remote_timing_condition,
484 remote_order_action,
485 ) in working_remote_order.dependencies.iter() {
486 if remote_timing_condition != &RemoteTimingCondition::PartialFill {
487 continue;
488 }
489
490 deferred_order_actions.push(remote_order_action.clone());
491 }
492
493 let Some(
494 bid_ask_price_spread,
495 ) = working_remote_order.get_fully_filled() else {
496 return Ok(());
497 };
498
499 #[cfg(feature = "log-trace-order-manager")]
500 trace!("Partial fill fully filled working order with spread: `{bid_ask_price_spread:?}`.");
501
502 let mut working_remote_order = self.remove(
503 directional_exposure,
504 remote_order_id,
505 )?;
506
507 if working_remote_order.rest_at.is_none() {
508 for (
509 _,
510 remote_order_action,
511 ) in working_remote_order.dependencies.iter_mut() {
512 remote_order_action.parent_processed(&bid_ask_price_spread);
513 }
514 }
515
516 for (
517 remote_timing_condition,
518 remote_order_action,
519 ) in working_remote_order.dependencies.iter() {
520 if remote_timing_condition != &RemoteTimingCondition::FullyFilled {
521 continue;
522 }
523
524 deferred_order_actions.push(remote_order_action.clone());
525 }
526
527 completed_remote_orders.submit::<OB>(tick_timestamp, working_remote_order);
528 Ok(())
529 }
530
531 #[instrument(skip_all)]
532 pub(crate) async fn modify_volume<OB: OrdersBackend<IS>>(
533 &mut self,
534 orders_backend: &mut OB,
535 directional_exposure: &mut DirectionalExposure<IS>,
536 local_order_id: &LocalOrderId,
537 volume: &DirectionlessVolume<IS>,
538 ) -> Result<(), OrderIdError>
539 where
540 IS: Send,
541 {
542 let working_remote_order = self.get_mut_with_local(local_order_id)?;
543
544 working_remote_order.modify_volume(directional_exposure, volume);
545
546 orders_backend.modify_order_volume(
547 &working_remote_order.remote_order_id,
548 volume,
549 ).await;
550
551 Ok(())
552 }
553}
554
555impl<
556 IS: InstrumentSpec,
557 CS: OrdersCapacitySpec,
558> Default for WorkingRemoteOrders<IS, CS> {
559 fn default() -> Self {
560 Self(SmallVec::default())
561 }
562}