Skip to main content

apple_quant_algorithmic/backends/
simulated.rs

1use std::{
2	marker::PhantomData,
3	sync::{
4		Arc,
5		atomic::{self, AtomicBool},
6	},
7	time::Instant,
8};
9
10use rand::rngs::SmallRng;
11use rand_distr::Normal;
12use smallvec::SmallVec;
13use time::Duration;
14use tokio::{sync::mpsc, task::JoinHandle};
15
16use crate::{
17	aggregation::TradeTradeTimestamp,
18	backend::{
19		LocalOrderId, MarketDataStream, OrdersBackend, OrdersBackendSubmitRemoteOrderError,
20		RemoteOrderId,
21	},
22	instrument::InstrumentSpec,
23	order::{OrderStateUpdate, RemoteOrder},
24	order_manager::CancelRemoteOrderError,
25	timestamp::Timestamp,
26	volume::DirectionlessVolume,
27};
28
29mod orders;
30mod remote;
31mod requests;
32mod specs;
33
34use orders::*;
35use remote::*;
36use requests::*;
37
38pub use specs::*;
39
40pub struct SimulatedOrdersBackend<
41	IS: InstrumentSpec,
42	CapacitySpec: specs::CapacitySpec = CapacitySpecLowFrequencyTrades,
43	PhysicalLocationLD: specs::PhysicalLocationLD = PhysicalLocationLDProximityBareMetal,
44	OrderRouterLD: specs::OrderRouterLD = OrderRounterLDRithmicFull,
45	ExchangeLD: specs::ExchangeLD = ExchangeLD_CME,
46> {
47	rng: SmallRng,
48	normal_ns: Normal<f64>,
49
50	min_ns: u32,
51	max_ns: u32,
52
53	link_request_sender: mpsc::Sender<(Instant, RemoteRequest<IS>)>,
54
55	tick_trade_trade_timestamps: SmallVec<[TradeTradeTimestamp<IS>; 10]>,
56	tick_previous_send_instant: Instant,
57	send_trades_flag: Arc<AtomicBool>,
58
59	tick_trades_sender: mpsc::Sender<SmallVec<[TradeTradeTimestamp<IS>; 10]>>,
60
61	remote_join_handle: JoinHandle<()>,
62
63	_capacity_spec: PhantomData<CapacitySpec>,
64	_physical_location_ld: PhantomData<PhysicalLocationLD>,
65	_order_router_ld: PhantomData<OrderRouterLD>,
66	_exchange_ld: PhantomData<ExchangeLD>,
67}
68
69impl<
70	IS: InstrumentSpec + Send + 'static,
71	CapacitySpec: specs::CapacitySpec,
72	PhysicalLocationLD: specs::PhysicalLocationLD,
73	OrderRouterLD: specs::OrderRouterLD,
74	ExchangeLD: specs::ExchangeLD,
75> OrdersBackend<IS>
76	for SimulatedOrdersBackend<IS, CapacitySpec, PhysicalLocationLD, OrderRouterLD, ExchangeLD>
77{
78	async fn new() -> (
79		mpsc::Receiver<OrderStateUpdate<IS>>,
80		Self,
81	) {
82		let mean_ns = PhysicalLocationLD::LATENCY_DISTRIBUTION.mean_ns
83			+ OrderRouterLD::LATENCY_DISTRIBUTION.mean_ns
84			+ ExchangeLD::LATENCY_DISTRIBUTION.mean_ns;
85
86		let std_dev_ns = PhysicalLocationLD::LATENCY_DISTRIBUTION.std_dev_ns
87			+ OrderRouterLD::LATENCY_DISTRIBUTION.std_dev_ns
88			+ ExchangeLD::LATENCY_DISTRIBUTION.std_dev_ns;
89
90		let min_ns = PhysicalLocationLD::LATENCY_DISTRIBUTION.min_ns
91			+ OrderRouterLD::LATENCY_DISTRIBUTION.min_ns
92			+ ExchangeLD::LATENCY_DISTRIBUTION.min_ns;
93
94		let max_ns = PhysicalLocationLD::LATENCY_DISTRIBUTION.max_ns
95			+ OrderRouterLD::LATENCY_DISTRIBUTION.max_ns
96			+ ExchangeLD::LATENCY_DISTRIBUTION.max_ns;
97
98		let (link_request_sender, link_request_receiver) = mpsc::channel(8);
99
100		let (order_state_update_sender, order_state_update_receiver) = mpsc::channel(8);
101
102		let (tick_trades_sender, tick_trades_receiver) = mpsc::channel(8);
103
104		let send_trades_flag = Arc::new(AtomicBool::new(false));
105
106		let remote_send_trades_flag = send_trades_flag.clone();
107
108		let remote_join_handle = tokio::spawn(async move {
109			remote_link::<IS, CapacitySpec>(
110				link_request_receiver,
111				order_state_update_sender,
112				tick_trades_receiver,
113				remote_send_trades_flag,
114			)
115			.await;
116		});
117
118		(
119			order_state_update_receiver,
120			Self {
121				rng: rand::make_rng(),
122
123				normal_ns: Normal::new(
124					mean_ns as f64,
125					std_dev_ns as f64,
126				)
127				.unwrap(),
128				min_ns,
129				max_ns,
130
131				link_request_sender,
132
133				tick_trade_trade_timestamps: SmallVec::default(),
134				tick_previous_send_instant: Instant::now(),
135				send_trades_flag,
136
137				tick_trades_sender,
138
139				remote_join_handle,
140
141				_capacity_spec: PhantomData::default(),
142				_physical_location_ld: PhantomData::default(),
143				_order_router_ld: PhantomData::default(),
144				_exchange_ld: PhantomData::default(),
145			},
146		)
147	}
148
149	async fn submit_order(
150		&mut self,
151		local_order_id: &LocalOrderId,
152		client_submission_timestamp: &Timestamp,
153		remote_order: RemoteOrder<IS>,
154	) -> Result<(), OrdersBackendSubmitRemoteOrderError> {
155		// let mut sample_ns: f64 = self
156		// 	.normal_ns
157		// 	.sample(&mut self.rng)
158		// 	.max(self.min_ns as f64)
159		// 	.min(self.max_ns as f64);
160
161		// if !sample_ns.is_finite() {
162		// 	sample_ns = 0.0;
163		// }
164		// let sample_ns = 100_000_000.0;
165
166		let trigger_instant = Instant::now() + Duration::milliseconds(1);
167		// let trigger_timestamp = *client_submission_timestamp + Duration::milliseconds(1);
168
169		let remote_request = RemoteRequest::SubmitOrder {
170			local_order_id: *local_order_id,
171			remote_order,
172		};
173
174		self.link_request_sender
175			.send((
176				trigger_instant,
177				remote_request,
178			))
179			.await;
180
181		Ok(())
182	}
183
184	async fn modify_order_volume(
185		&mut self,
186		remote_order_id: &RemoteOrderId,
187		volume: &DirectionlessVolume<IS>,
188	) {
189		let instant = Instant::now() + Duration::milliseconds(1);
190
191		let remote_request = RemoteRequest::ModifyVolume {
192			remote_order_id: *remote_order_id,
193			volume: *volume,
194		};
195
196		self.link_request_sender
197			.send((instant, remote_request))
198			.await
199			.unwrap();
200	}
201
202	async fn initiate_cancel_order(
203		&mut self,
204		remote_order_id: &RemoteOrderId,
205	) -> Result<(), CancelRemoteOrderError> {
206		// let trigger_timestamp = *client_submission_timestamp + Duration::milliseconds(1);
207		let instant = Instant::now() + Duration::milliseconds(1);
208		let remote_request = RemoteRequest::CancelOrder(*remote_order_id);
209
210		self.link_request_sender
211			.send((instant, remote_request))
212			.await
213			.unwrap();
214
215		Ok(())
216	}
217
218	async fn initiate_cancel_all(&mut self) {
219		// let _ = client_submission_timestamp;
220		// let trigger_timestamp = *client_submission_timestamp + Duration::milliseconds(1);
221		let instant = Instant::now() + Duration::milliseconds(1);
222		let remote_request = RemoteRequest::CancelAll;
223
224		self.link_request_sender
225			.send((instant, remote_request))
226			.await
227			.unwrap();
228	}
229
230	async fn initiate_cancel_flatten_all(&mut self) {
231		// let _ = client_submission_timestamp;
232		// let trigger_timestamp = *client_submission_timestamp + Duration::milliseconds(1);
233		let instant = Instant::now() + Duration::milliseconds(1);
234		let remote_request = RemoteRequest::CancelFlattenAll;
235
236		self.link_request_sender
237			.send((instant, remote_request))
238			.await
239			.unwrap();
240	}
241}
242
243impl<
244	IS: InstrumentSpec,
245	CapacitySpec: specs::CapacitySpec,
246	PhysicalLocationLD: specs::PhysicalLocationLD,
247	OrderRouterLD: specs::OrderRouterLD,
248	ExchangeLD: specs::ExchangeLD,
249> MarketDataStream<IS>
250	for SimulatedOrdersBackend<IS, CapacitySpec, PhysicalLocationLD, OrderRouterLD, ExchangeLD>
251{
252	async fn trades_stream<'a>(
253		&mut self,
254		mut just_added: impl ExactSizeIterator<Item = &'a TradeTradeTimestamp<IS>> + Clone,
255	) where
256		IS: 'a,
257	{
258		if just_added.is_empty() {
259			return;
260		}
261
262		if !self
263			.send_trades_flag
264			.load(atomic::Ordering::Relaxed)
265		{
266			return;
267		}
268
269		let now = Instant::now();
270
271		'just_added: loop {
272			for _ in (self
273				.tick_trade_trade_timestamps
274				.len())
275				..(self
276					.tick_trade_trade_timestamps
277					.capacity())
278			{
279				let Some(trade_trade_timestamp) = just_added.next() else {
280					break 'just_added;
281				};
282
283				self.tick_trade_trade_timestamps
284					.push(*trade_trade_timestamp);
285			}
286
287			debug_assert!(
288				!self
289					.tick_trade_trade_timestamps
290					.spilled()
291			);
292
293			if self
294				.tick_trade_trade_timestamps
295				.len() == self
296				.tick_trade_trade_timestamps
297				.capacity()
298			{
299				self.tick_trades_sender
300					.send(
301						self.tick_trade_trade_timestamps
302							.clone(),
303					)
304					.await
305					.unwrap();
306
307				self.link_request_sender
308					.send((
309						Instant::now(),
310						RemoteRequest::MarketDataUpdate,
311					))
312					.await
313					.unwrap();
314
315				self.tick_trade_trade_timestamps
316					.clear();
317
318				self.tick_previous_send_instant = now;
319			}
320		}
321
322		if self
323			.tick_trade_trade_timestamps
324			.is_empty()
325		{
326			return;
327		}
328
329		if self
330			.tick_previous_send_instant
331			.elapsed()
332			.as_micros() as u64
333			>= 100
334		{
335			self.tick_trades_sender
336				.send(
337					self.tick_trade_trade_timestamps
338						.clone(),
339				)
340				.await
341				.unwrap();
342
343			self.link_request_sender
344				.send((
345					Instant::now(),
346					RemoteRequest::MarketDataUpdate,
347				))
348				.await
349				.unwrap();
350
351			self.tick_trade_trade_timestamps
352				.clear();
353
354			self.tick_previous_send_instant = now;
355		}
356	}
357}