Skip to main content

apple_quant_algorithmic/order_manager/
remote_pending.rs

1use smallvec::SmallVec;
2use thiserror::Error;
3use tracing::instrument;
4
5#[allow(unused_imports)]
6use tracing::trace;
7
8use crate::{
9	backend::{
10		LocalOrderId, OrderIdError, OrdersBackend, OrdersBackendSubmitRemoteOrderError,
11		RemoteOrderId,
12	},
13	order::{
14		DeferredOrderActions, DesiredVolumeOrder, DesiredVolumeOrderError, OrderAction,
15		RemoteOrder, RemoteOrderTracker, RemoteTimingCondition, TriggerError,
16	},
17	timestamp::{TickTimestamp, Timestamp, Timestamped},
18	volume::{DirectionalExposure, DirectionalIntentVolume, ZeroableVolume},
19	instrument::InstrumentSpec, price::AbsolutePrice,
20};
21
22use super::{
23	OrdersCapacitySpec, PendingClientCancelError, WorkingRemoteOrderSubmitError,
24	WorkingRemoteOrders,
25};
26
27#[derive(Debug, Error)]
28pub enum PendingRemoteSubmitError {
29	#[error("{0:?}")]
30	DesiredVolumeOrder(#[from] DesiredVolumeOrderError),
31
32	#[error("{0:?}")]
33	OrdersBackendSubmitRemoteOrder(#[from] OrdersBackendSubmitRemoteOrderError),
34}
35
36#[derive(Debug, Error)]
37pub enum PendingRemoteProcessedError {
38	#[error("{0:?}")]
39	OrderId(#[from] OrderIdError),
40
41	#[error("{0:?}")]
42	PendingClientCancel(#[from] PendingClientCancelError),
43
44	#[error("{0:?}")]
45	WorkingRemoteOrderSubmit(#[from] WorkingRemoteOrderSubmitError),
46
47	#[error("{0:?}")]
48	Trigger(#[from] TriggerError),
49}
50
51pub struct PendingRemoteOrder<
52	IS: InstrumentSpec,
53	CS: OrdersCapacitySpec,
54> {
55	pub(crate) submission_timestamp: Timestamp,
56	pub(crate) local_order_id: LocalOrderId,
57
58	pub(crate) dependencies: SmallVec<[(
59		RemoteTimingCondition,
60		OrderAction<IS>,
61	); core::direct_const_arg!(CS::DEPENDENCY)]>,
62
63	pub(crate) desired_directional_intent_volume: DirectionalIntentVolume<IS>,
64	pub(crate) rest_at: Option<AbsolutePrice<IS>>,
65	pub(crate) cancel_on_process: bool,
66}
67
68impl<
69	IS: InstrumentSpec,
70	CS: OrdersCapacitySpec,
71> PendingRemoteOrder<IS, CS> {
72	pub(crate) fn new(
73		submission_timestamp: Timestamp,
74		local_order_id: LocalOrderId,
75		dependencies: impl IntoIterator<Item = (
76			RemoteTimingCondition,
77			OrderAction<IS>,
78		)>,
79		desired_directional_intent_volume: DirectionalIntentVolume<IS>,
80		rest_at: Option<AbsolutePrice<IS>>,
81	) -> Self {
82		Self {
83			submission_timestamp,
84			local_order_id,
85			dependencies: dependencies.into_iter().collect(),
86			desired_directional_intent_volume,
87			rest_at,
88			cancel_on_process: false,
89		}
90	}
91}
92
93/// Unordered list of pending remote orders. The order will be booked into a fill, partial fill, or resting state before this client knows. Once the client recognizes the booking, the order will be moved to [`working_remote_orders`].
94pub struct PendingRemoteOrders<
95	IS: InstrumentSpec,
96	CS: OrdersCapacitySpec,
97>(SmallVec<[PendingRemoteOrder<IS, CS>; core::direct_const_arg!(CS::PENDING_REMOTE)]>);
98
99impl<
100	IS: InstrumentSpec,
101	CS: OrdersCapacitySpec,
102> PendingRemoteOrders<IS, CS> {
103	#[instrument(skip_all)]
104	pub async fn submit<OB: OrdersBackend<IS>>(
105		&mut self,
106		directional_exposure: &mut DirectionalExposure<IS>,
107		orders_backend: &mut OB,
108		tick_timestamp: &TickTimestamp,
109		remote_order_tracker: RemoteOrderTracker,
110		remote_order: RemoteOrder<IS>,
111		dependencies: impl IntoIterator<Item = (
112			RemoteTimingCondition,
113			OrderAction<IS>,
114		)>,
115	) -> Result<(), PendingRemoteSubmitError>
116	where
117		IS: Send,
118	{
119		let submission_timestamp = tick_timestamp.timestamp();
120		let local_order_id = *remote_order_tracker.as_local_order_id();
121
122		#[cfg(feature = "log-trace-order-manager")]
123		trace!(
124			"Adding id: `{:?}` order: `{:?}`.",
125			local_order_id,
126			remote_order,
127		);
128
129		let desired_directional_intent_volume = remote_order.desired_directional_intent_volume()?;
130
131		let rest_at = if let RemoteOrder::Limit(
132			limit_order,
133		) = &remote_order {
134			Some(limit_order.price.into_absolute().unwrap())
135		} else {
136			None
137		};
138
139		orders_backend.submit_order(
140			&local_order_id,
141			&submission_timestamp,
142			remote_order,
143		).await?;
144
145		let pending_remote_order = PendingRemoteOrder::new(
146			submission_timestamp,
147			local_order_id,
148			dependencies,
149			desired_directional_intent_volume,
150			rest_at,
151		);
152
153		self.0.push(pending_remote_order);
154
155		directional_exposure.change_armed_directional_exposure(
156			&desired_directional_intent_volume.as_zeroable(),
157		);
158
159		Ok(())
160	}
161
162	#[instrument(skip_all)]
163	pub fn get(
164		&self,
165		local_order_id: &LocalOrderId,
166	) -> Result<&PendingRemoteOrder<IS, CS>, OrderIdError> {
167		let Some(
168			pending_remote_order,
169		) = self.0.iter().find(|
170			pending_remote_order,
171		| &pending_remote_order.local_order_id == local_order_id) else {
172			return local_order_id.err_invalid();
173		};
174
175		Ok(pending_remote_order)
176	}
177
178	#[instrument(skip_all)]
179	pub(crate) fn get_mut(
180		&mut self,
181		local_order_id: &LocalOrderId,
182	) -> Result<&mut PendingRemoteOrder<IS, CS>, OrderIdError> {
183		let Some(
184			pending_remote_order,
185		) = self.0.iter_mut().find(|
186			pending_remote_order,
187		| &pending_remote_order.local_order_id == local_order_id) else {
188			return local_order_id.err_invalid();
189		};
190
191		Ok(pending_remote_order)
192	}
193
194	#[instrument(skip_all)]
195	pub(crate) fn remove(
196		&mut self,
197		directional_exposure: &mut DirectionalExposure<IS>,
198		local_order_id: &LocalOrderId,
199	) -> Result<PendingRemoteOrder<IS, CS>, PendingClientCancelError> {
200		#[cfg(feature = "log-trace-order-manager")]
201		trace!("Removing id: `{:?}`.", local_order_id);
202
203		let Some(
204			idx,
205		) = self.0.iter().position(|
206			pending_remote_order,
207		| &pending_remote_order.local_order_id == local_order_id) else {
208			return local_order_id.err_invalid();
209		};
210
211		let pending_remote_order = self.0.swap_remove(idx);
212
213		let desired_directional_intent_volume = &pending_remote_order.desired_directional_intent_volume;
214
215		directional_exposure.change_armed_directional_exposure(
216			&desired_directional_intent_volume.as_flipped().as_zeroable(),
217		);
218
219		Ok(pending_remote_order)
220	}
221
222	#[instrument(skip_all)]
223	pub(crate) async fn acknowledged<OB: OrdersBackend<IS>>(
224		&mut self,
225		tick_timestamp: &TickTimestamp,
226		working_remote_orders: &mut WorkingRemoteOrders<IS, CS>,
227		directional_exposure: &mut DirectionalExposure<IS>,
228		deferred_order_actions: &mut DeferredOrderActions<IS>,
229		local_order_id: &LocalOrderId,
230		remote_order_id: RemoteOrderId,
231	) -> Result<(), PendingRemoteProcessedError>
232	where
233		IS: Send,
234	{
235		#[cfg(feature = "log-trace-order-manager")]
236		trace!(
237			"Acknowledging `{:?}` with `{:?}`.",
238			local_order_id,
239			remote_order_id,
240		);
241
242		let mut pending_remote_order = self.remove(
243			directional_exposure,
244			local_order_id,
245		)?;
246
247		for (
248			remote_timing_condition,
249			remote_order_action,
250		) in pending_remote_order.dependencies.iter_mut() {
251			if remote_timing_condition != &RemoteTimingCondition::Acknowledged {
252				continue;
253			}
254
255			deferred_order_actions.push(remote_order_action.clone());
256		}
257
258		working_remote_orders.submit::<OB>(
259			directional_exposure,
260			deferred_order_actions,
261			tick_timestamp,
262			pending_remote_order,
263			remote_order_id,
264		)?;
265
266		Ok(())
267	}
268}
269
270impl<
271	IS: InstrumentSpec,
272	CS: OrdersCapacitySpec,
273> Default for PendingRemoteOrders<IS, CS> {
274	fn default() -> Self {
275		Self(SmallVec::default())
276	}
277}