Skip to main content

apple_quant_algorithmic/order_manager/
working.rs

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