apple_quant_algorithmic/order_manager/
client_pending.rs1use smallvec::SmallVec;
2use thiserror::Error;
3
4use crate::{
5 aggregation::TradeTradeTimestamp,
6 backend::{LocalOrderId, OrderIdError, OrdersBackend},
7 instrument::InstrumentSpec,
8 liquidity::LiquidityEstimation,
9 order::{
10 ClientOrder, ClientOrderTracker, DeferredOrderActions, DesiredVolumeOrder,
11 DesiredVolumeOrderError, MatchableOrder, TriggerError,
12 dependency::client::ClientDeployedRemoteDependency,
13 },
14 timestamp::{TickTimestamp, Timestamp},
15 volume::DirectionalExposure,
16};
17
18use super::{OrdersCapacitySpec, PendingRemoteSubmitError};
19
20#[derive(Debug, Error)]
21pub enum PendingClientCancelError {
22 #[error("{0:?}")]
23 OrderId(#[from] OrderIdError),
24
25 #[error("{0:?}")]
26 DesiredVolumeOrder(#[from] DesiredVolumeOrderError),
27}
28
29#[derive(Debug, Error)]
30pub enum PendingClientActivateError {
31 #[error("{0:?}")]
32 PendingClientCancel(#[from] PendingClientCancelError),
33
34 #[error("{0:?}")]
35 PendingRemoteSubmit(#[from] PendingRemoteSubmitError),
36
37 #[error("{0:?}")]
38 Trigger(#[from] TriggerError),
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, Hash)]
42pub struct PendingClientOrder<IS: InstrumentSpec> {
43 pub(crate) submission_timestamp: Timestamp,
44 pub(crate) local_order_id: LocalOrderId,
45 pub(crate) client_deployed_remote_dependency: ClientDeployedRemoteDependency<IS>,
46 pub(crate) client_order: ClientOrder<IS>,
47 pub(crate) liquidity_estimation: LiquidityEstimation<IS>,
48}
49
50impl<IS: InstrumentSpec> PendingClientOrder<IS> {
51 pub(crate) fn new(
52 submission_timestamp: Timestamp,
53 local_order_id: LocalOrderId,
54 client_deployed_remote_dependency: ClientDeployedRemoteDependency<IS>,
55 client_order: ClientOrder<IS>,
56 ) -> Self {
57 Self {
58 submission_timestamp,
59 local_order_id,
60 client_deployed_remote_dependency,
61 client_order,
62 liquidity_estimation: LiquidityEstimation::default(),
63 }
64 }
65}
66
67#[derive(Debug)]
69pub struct PendingClientOrders<IS: InstrumentSpec, CS: OrdersCapacitySpec>(
70 SmallVec<[PendingClientOrder<IS>; CS::PENDING_CLIENT]>,
71);
72
73impl<IS: InstrumentSpec, CS: OrdersCapacitySpec> PendingClientOrders<IS, CS> {
74 pub fn submit<OB: OrdersBackend<IS>>(
75 &mut self,
76 tick_timestamp: &TickTimestamp,
77 directional_exposure: &mut DirectionalExposure<IS>,
78 client_order_tracker: &ClientOrderTracker,
79 client_order: ClientOrder<IS>,
80 client_deployed_remote_dependency: ClientDeployedRemoteDependency<IS>,
81 ) -> Result<(), DesiredVolumeOrderError>
82 where
83 IS: Send,
84 {
85 let submission_timestamp = tick_timestamp.timestamp();
86 let local_order_id = *client_order_tracker.as_local_order_id();
87
88 let desired_directional_intent_volume = client_deployed_remote_dependency
89 .remote_order
90 .desired_directional_intent_volume()?;
91
92 let pending_client_order = PendingClientOrder::new(
93 submission_timestamp,
94 local_order_id,
95 client_deployed_remote_dependency,
96 client_order,
97 );
98
99 self.0
100 .push(pending_client_order);
101
102 directional_exposure
103 .change_armed_directional_exposure(&desired_directional_intent_volume.as_zeroable());
104
105 Ok(())
106 }
107
108 pub fn get(
109 &self,
110 local_order_id: &LocalOrderId,
111 ) -> Result<&PendingClientOrder<IS>, OrderIdError> {
112 let Some(pending_client_order) = self
113 .0
114 .iter()
115 .find(|pending_client_order| &pending_client_order.local_order_id == local_order_id)
116 else {
117 return local_order_id.err_invalid();
118 };
119
120 Ok(pending_client_order)
121 }
122
123 pub(crate) fn get_mut(
124 &mut self,
125 local_order_id: &LocalOrderId,
126 ) -> Result<&mut PendingClientOrder<IS>, OrderIdError> {
127 let Some(pending_client_order) = self
128 .0
129 .iter_mut()
130 .find(|pending_client_order| &pending_client_order.local_order_id == local_order_id)
131 else {
132 return local_order_id.err_invalid();
133 };
134
135 Ok(pending_client_order)
136 }
137
138 pub(crate) fn remove(
139 &mut self,
140 directional_exposure: &mut DirectionalExposure<IS>,
141 local_order_id: &LocalOrderId,
142 ) -> Result<PendingClientOrder<IS>, PendingClientCancelError> {
143 let Some(idx) = self
144 .0
145 .iter()
146 .position(|pending_client_order| {
147 &pending_client_order.local_order_id == local_order_id
148 })
149 else {
150 return local_order_id.err_invalid();
151 };
152
153 let pending_client_order = self.0.swap_remove(idx);
154
155 let desired_directional_intent_volume = pending_client_order
156 .client_deployed_remote_dependency
157 .remote_order
158 .desired_directional_intent_volume()?;
159
160 directional_exposure.change_armed_directional_exposure(
161 &desired_directional_intent_volume
162 .as_zeroable()
163 .as_flipped(),
164 );
165
166 Ok(pending_client_order)
167 }
168
169 pub(crate) async fn activate<OB: OrdersBackend<IS>>(
170 &mut self,
171 tick_timestamp: &TickTimestamp,
172 directional_exposure: &mut DirectionalExposure<IS>,
173 deferred_order_actions: &mut DeferredOrderActions<IS>,
174 local_order_id: &LocalOrderId,
175 ) -> Result<(), PendingClientActivateError>
176 where
177 IS: Send,
178 {
179 let PendingClientOrder {
180 submission_timestamp,
181 local_order_id,
182 client_deployed_remote_dependency,
183 client_order,
184 liquidity_estimation,
185 } = self.remove(
186 directional_exposure,
187 local_order_id,
188 )?;
189
190 deferred_order_actions.push(client_deployed_remote_dependency.into_order_action());
191
192 Ok(())
193 }
194
195 pub fn tick_client_orders<'a>(
196 &mut self,
197 deferred_order_actions: &mut DeferredOrderActions<IS>,
198 directional_exposure: &mut DirectionalExposure<IS>,
199 just_added: impl ExactSizeIterator<Item = &'a TradeTradeTimestamp<IS>> + Clone,
200 ) where
201 IS: 'a,
202 {
203 let pending_client_orders = self
204 .0
205 .drain_filter(|pending_client_order| {
206 trades_stream_drain_filter(
207 pending_client_order,
208 directional_exposure,
209 just_added.clone(),
210 )
211 });
212
213 for pending_client_order in pending_client_orders {
214 deferred_order_actions.push(
215 pending_client_order
216 .client_deployed_remote_dependency
217 .into_order_action(),
218 );
219 }
220 }
221}
222
223impl<IS: InstrumentSpec, CS: OrdersCapacitySpec> Default for PendingClientOrders<IS, CS> {
224 fn default() -> Self {
225 Self(SmallVec::default())
226 }
227}
228
229fn trades_stream_drain_filter<'a, IS: InstrumentSpec>(
235 pending_client_order: &mut PendingClientOrder<IS>,
236 directional_exposure: &mut DirectionalExposure<IS>,
237 just_added: impl ExactSizeIterator<Item = &'a TradeTradeTimestamp<IS>> + Clone,
238) -> bool
239where
240 IS: 'a,
241{
242 pending_client_order
243 .liquidity_estimation
244 .walk_trades(just_added);
245
246 let is_liquidable = pending_client_order
247 .client_order
248 .is_liquidable(&pending_client_order.liquidity_estimation)
249 .is_some();
250
251 if is_liquidable {
252 let delta_directional_exposure = pending_client_order
253 .client_deployed_remote_dependency
254 .remote_order
255 .desired_directional_intent_volume()
256 .unwrap()
257 .as_zeroable()
258 .as_flipped();
259
260 directional_exposure.change_armed_directional_exposure(&delta_directional_exposure);
261 }
262
263 is_liquidable
264}