apple_quant_algorithmic/backends/
simulated.rs1use 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 trigger_instant = Instant::now() + Duration::milliseconds(1);
167 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 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 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 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}