Skip to main content

apple_quant_algorithmic/order_manager/
remote_pending.rs

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