nautilus_execution/engine/
stubs.rs1use std::{
17 cell::{Cell, RefCell},
18 rc::Rc,
19};
20
21use async_trait::async_trait;
22use nautilus_common::{
23 cache::Cache,
24 clients::ExecutionClient,
25 clock::{Clock, TestClock},
26 messages::execution::{
27 BatchCancelOrders, BatchModifyOrders, CancelAllOrders, CancelOrder, ModifyOrder,
28 QueryAccount, QueryOrder, SubmitOrder, SubmitOrderList,
29 },
30};
31use nautilus_core::{Params, UnixNanos};
32use nautilus_model::{
33 accounts::AccountAny,
34 enums::OmsType,
35 identifiers::{
36 AccountId, ClientId, ClientOrderId, InstrumentId, StrategyId, Venue, VenueOrderId,
37 },
38 instruments::InstrumentAny,
39 types::{AccountBalance, MarginBalance},
40};
41
42#[derive(Clone, Debug)]
47#[allow(dead_code)]
48pub struct StubExecutionClient {
49 client_id: ClientId,
50 account_id: AccountId,
51 venue: Venue,
52 oms_type: OmsType,
53 is_connected: bool,
54 clock: Rc<RefCell<dyn Clock>>,
55 cache: Rc<RefCell<Cache>>,
56 received_instruments: Rc<RefCell<Vec<InstrumentAny>>>,
57 start_count: Rc<Cell<usize>>,
58 stop_count: Rc<Cell<usize>>,
59 reset_count: Rc<Cell<usize>>,
60 dispose_count: Rc<Cell<usize>>,
61 submitted_order_ids: Rc<RefCell<Vec<ClientOrderId>>>,
62 modified_order_ids: Rc<RefCell<Vec<ClientOrderId>>>,
63 cancel_all_commands: Rc<RefCell<Vec<CancelAllOrders>>>,
64 queried_account_ids: Rc<RefCell<Vec<AccountId>>>,
65 registered_external_order_ids: Rc<RefCell<Vec<ClientOrderId>>>,
66 handles_all_order_venues: bool,
67 submit_order_error: Option<String>,
68 submit_order_list_error: Option<String>,
69}
70
71impl StubExecutionClient {
72 #[allow(dead_code)]
74 pub fn new(
75 client_id: ClientId,
76 account_id: AccountId,
77 venue: Venue,
78 oms_type: OmsType,
79 clock: Option<Rc<RefCell<dyn Clock>>>,
80 ) -> Self {
81 Self {
82 client_id,
83 account_id,
84 venue,
85 oms_type,
86 is_connected: false,
87 clock: clock.unwrap_or_else(|| Rc::new(RefCell::new(TestClock::new()))),
88 cache: Rc::new(RefCell::new(Cache::new(None, None))),
89 received_instruments: Rc::new(RefCell::new(Vec::new())),
90 start_count: Rc::new(Cell::new(0)),
91 stop_count: Rc::new(Cell::new(0)),
92 reset_count: Rc::new(Cell::new(0)),
93 dispose_count: Rc::new(Cell::new(0)),
94 submitted_order_ids: Rc::new(RefCell::new(Vec::new())),
95 modified_order_ids: Rc::new(RefCell::new(Vec::new())),
96 cancel_all_commands: Rc::new(RefCell::new(Vec::new())),
97 queried_account_ids: Rc::new(RefCell::new(Vec::new())),
98 registered_external_order_ids: Rc::new(RefCell::new(Vec::new())),
99 handles_all_order_venues: false,
100 submit_order_error: None,
101 submit_order_list_error: None,
102 }
103 }
104
105 #[must_use]
107 pub fn with_handles_all_order_venues(mut self) -> Self {
108 self.handles_all_order_venues = true;
109 self
110 }
111
112 #[must_use]
114 pub fn with_submit_order_error(mut self, error: impl Into<String>) -> Self {
115 self.submit_order_error = Some(error.into());
116 self
117 }
118
119 #[must_use]
121 pub fn with_submit_order_list_error(mut self, error: impl Into<String>) -> Self {
122 self.submit_order_list_error = Some(error.into());
123 self
124 }
125
126 #[must_use]
129 pub fn registered_external_order_ids(&self) -> Rc<RefCell<Vec<ClientOrderId>>> {
130 self.registered_external_order_ids.clone()
131 }
132
133 #[must_use]
135 pub fn received_instruments(&self) -> Rc<RefCell<Vec<InstrumentAny>>> {
136 self.received_instruments.clone()
137 }
138
139 #[must_use]
141 pub fn submitted_order_ids(&self) -> Rc<RefCell<Vec<ClientOrderId>>> {
142 self.submitted_order_ids.clone()
143 }
144
145 #[must_use]
147 pub fn modified_order_ids(&self) -> Rc<RefCell<Vec<ClientOrderId>>> {
148 self.modified_order_ids.clone()
149 }
150
151 #[must_use]
153 pub fn cancel_all_commands(&self) -> Rc<RefCell<Vec<CancelAllOrders>>> {
154 self.cancel_all_commands.clone()
155 }
156
157 #[must_use]
159 pub fn queried_account_ids(&self) -> Rc<RefCell<Vec<AccountId>>> {
160 self.queried_account_ids.clone()
161 }
162
163 #[must_use]
165 pub fn start_count(&self) -> usize {
166 self.start_count.get()
167 }
168
169 #[must_use]
171 pub fn stop_count(&self) -> usize {
172 self.stop_count.get()
173 }
174
175 #[must_use]
177 pub fn reset_count(&self) -> usize {
178 self.reset_count.get()
179 }
180
181 #[must_use]
183 pub fn dispose_count(&self) -> usize {
184 self.dispose_count.get()
185 }
186}
187
188#[async_trait(?Send)]
189impl ExecutionClient for StubExecutionClient {
190 fn is_connected(&self) -> bool {
191 self.is_connected
192 }
193
194 fn client_id(&self) -> ClientId {
195 self.client_id
196 }
197
198 fn account_id(&self) -> AccountId {
199 self.account_id
200 }
201
202 fn venue(&self) -> Venue {
203 self.venue
204 }
205
206 fn handles_order_venue(&self, venue: Venue) -> bool {
207 self.handles_all_order_venues || self.venue == venue
208 }
209
210 fn oms_type(&self) -> OmsType {
211 self.oms_type
212 }
213
214 fn get_account(&self) -> Option<AccountAny> {
215 None }
217
218 fn generate_account_state(
219 &self,
220 _balances: Vec<AccountBalance>,
221 _margins: Vec<MarginBalance>,
222 _reported: bool,
223 _ts_event: UnixNanos,
224 _info: Option<Params>,
225 ) -> anyhow::Result<()> {
226 Ok(()) }
228
229 fn start(&mut self) -> anyhow::Result<()> {
230 self.is_connected = true;
231 self.start_count.set(self.start_count.get() + 1);
232 Ok(())
233 }
234
235 fn stop(&mut self) -> anyhow::Result<()> {
236 self.is_connected = false;
237 self.stop_count.set(self.stop_count.get() + 1);
238 Ok(())
239 }
240
241 fn reset(&mut self) -> anyhow::Result<()> {
242 self.reset_count.set(self.reset_count.get() + 1);
243 Ok(())
244 }
245
246 fn dispose(&mut self) -> anyhow::Result<()> {
247 self.dispose_count.set(self.dispose_count.get() + 1);
248 Ok(())
249 }
250
251 fn submit_order(&self, cmd: SubmitOrder) -> anyhow::Result<()> {
252 if let Some(error) = &self.submit_order_error {
253 anyhow::bail!("{error}");
254 }
255
256 self.submitted_order_ids
257 .borrow_mut()
258 .push(cmd.client_order_id);
259
260 Ok(()) }
262
263 fn submit_order_list(&self, cmd: SubmitOrderList) -> anyhow::Result<()> {
264 if let Some(error) = &self.submit_order_list_error {
265 anyhow::bail!("{error}");
266 }
267
268 self.submitted_order_ids
269 .borrow_mut()
270 .extend(cmd.order_list.client_order_ids);
271
272 Ok(()) }
274
275 fn modify_order(&self, cmd: ModifyOrder) -> anyhow::Result<()> {
276 self.modified_order_ids
277 .borrow_mut()
278 .push(cmd.client_order_id);
279
280 Ok(()) }
282
283 fn batch_modify_orders(&self, cmd: BatchModifyOrders) -> anyhow::Result<()> {
284 self.modified_order_ids.borrow_mut().extend(
285 cmd.modifies
286 .into_iter()
287 .map(|modify| modify.client_order_id),
288 );
289
290 Ok(()) }
292
293 fn cancel_order(&self, _cmd: CancelOrder) -> anyhow::Result<()> {
294 Ok(()) }
296
297 fn cancel_all_orders(&self, cmd: CancelAllOrders) -> anyhow::Result<()> {
298 self.cancel_all_commands.borrow_mut().push(cmd);
299 Ok(()) }
301
302 fn batch_cancel_orders(&self, _cmd: BatchCancelOrders) -> anyhow::Result<()> {
303 Ok(()) }
305
306 fn query_account(&self, cmd: QueryAccount) -> anyhow::Result<()> {
307 self.queried_account_ids.borrow_mut().push(cmd.account_id);
308
309 Ok(()) }
311
312 fn query_order(&self, _cmd: QueryOrder) -> anyhow::Result<()> {
313 Ok(()) }
315
316 fn register_external_order(
317 &self,
318 client_order_id: ClientOrderId,
319 _venue_order_id: VenueOrderId,
320 _instrument_id: InstrumentId,
321 _strategy_id: StrategyId,
322 _ts_init: UnixNanos,
323 ) {
324 self.registered_external_order_ids
325 .borrow_mut()
326 .push(client_order_id);
327 }
328
329 fn on_instrument(&mut self, instrument: InstrumentAny) {
330 self.received_instruments.borrow_mut().push(instrument);
331 }
332}