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 queried_account_ids: Rc<RefCell<Vec<AccountId>>>,
64 registered_external_order_ids: Rc<RefCell<Vec<ClientOrderId>>>,
65 handles_all_order_venues: bool,
66 submit_order_error: Option<String>,
67 submit_order_list_error: Option<String>,
68}
69
70impl StubExecutionClient {
71 #[allow(dead_code)]
73 pub fn new(
74 client_id: ClientId,
75 account_id: AccountId,
76 venue: Venue,
77 oms_type: OmsType,
78 clock: Option<Rc<RefCell<dyn Clock>>>,
79 ) -> Self {
80 Self {
81 client_id,
82 account_id,
83 venue,
84 oms_type,
85 is_connected: false,
86 clock: clock.unwrap_or_else(|| Rc::new(RefCell::new(TestClock::new()))),
87 cache: Rc::new(RefCell::new(Cache::new(None, None))),
88 received_instruments: Rc::new(RefCell::new(Vec::new())),
89 start_count: Rc::new(Cell::new(0)),
90 stop_count: Rc::new(Cell::new(0)),
91 reset_count: Rc::new(Cell::new(0)),
92 dispose_count: Rc::new(Cell::new(0)),
93 submitted_order_ids: Rc::new(RefCell::new(Vec::new())),
94 modified_order_ids: Rc::new(RefCell::new(Vec::new())),
95 queried_account_ids: Rc::new(RefCell::new(Vec::new())),
96 registered_external_order_ids: Rc::new(RefCell::new(Vec::new())),
97 handles_all_order_venues: false,
98 submit_order_error: None,
99 submit_order_list_error: None,
100 }
101 }
102
103 #[must_use]
105 pub fn with_handles_all_order_venues(mut self) -> Self {
106 self.handles_all_order_venues = true;
107 self
108 }
109
110 #[must_use]
112 pub fn with_submit_order_error(mut self, error: impl Into<String>) -> Self {
113 self.submit_order_error = Some(error.into());
114 self
115 }
116
117 #[must_use]
119 pub fn with_submit_order_list_error(mut self, error: impl Into<String>) -> Self {
120 self.submit_order_list_error = Some(error.into());
121 self
122 }
123
124 #[must_use]
127 pub fn registered_external_order_ids(&self) -> Rc<RefCell<Vec<ClientOrderId>>> {
128 self.registered_external_order_ids.clone()
129 }
130
131 #[must_use]
133 pub fn received_instruments(&self) -> Rc<RefCell<Vec<InstrumentAny>>> {
134 self.received_instruments.clone()
135 }
136
137 #[must_use]
139 pub fn submitted_order_ids(&self) -> Rc<RefCell<Vec<ClientOrderId>>> {
140 self.submitted_order_ids.clone()
141 }
142
143 #[must_use]
145 pub fn modified_order_ids(&self) -> Rc<RefCell<Vec<ClientOrderId>>> {
146 self.modified_order_ids.clone()
147 }
148
149 #[must_use]
151 pub fn queried_account_ids(&self) -> Rc<RefCell<Vec<AccountId>>> {
152 self.queried_account_ids.clone()
153 }
154
155 #[must_use]
157 pub fn start_count(&self) -> usize {
158 self.start_count.get()
159 }
160
161 #[must_use]
163 pub fn stop_count(&self) -> usize {
164 self.stop_count.get()
165 }
166
167 #[must_use]
169 pub fn reset_count(&self) -> usize {
170 self.reset_count.get()
171 }
172
173 #[must_use]
175 pub fn dispose_count(&self) -> usize {
176 self.dispose_count.get()
177 }
178}
179
180#[async_trait(?Send)]
181impl ExecutionClient for StubExecutionClient {
182 fn is_connected(&self) -> bool {
183 self.is_connected
184 }
185
186 fn client_id(&self) -> ClientId {
187 self.client_id
188 }
189
190 fn account_id(&self) -> AccountId {
191 self.account_id
192 }
193
194 fn venue(&self) -> Venue {
195 self.venue
196 }
197
198 fn handles_order_venue(&self, venue: Venue) -> bool {
199 self.handles_all_order_venues || self.venue == venue
200 }
201
202 fn oms_type(&self) -> OmsType {
203 self.oms_type
204 }
205
206 fn get_account(&self) -> Option<AccountAny> {
207 None }
209
210 fn generate_account_state(
211 &self,
212 _balances: Vec<AccountBalance>,
213 _margins: Vec<MarginBalance>,
214 _reported: bool,
215 _ts_event: UnixNanos,
216 _info: Option<Params>,
217 ) -> anyhow::Result<()> {
218 Ok(()) }
220
221 fn start(&mut self) -> anyhow::Result<()> {
222 self.is_connected = true;
223 self.start_count.set(self.start_count.get() + 1);
224 Ok(())
225 }
226
227 fn stop(&mut self) -> anyhow::Result<()> {
228 self.is_connected = false;
229 self.stop_count.set(self.stop_count.get() + 1);
230 Ok(())
231 }
232
233 fn reset(&mut self) -> anyhow::Result<()> {
234 self.reset_count.set(self.reset_count.get() + 1);
235 Ok(())
236 }
237
238 fn dispose(&mut self) -> anyhow::Result<()> {
239 self.dispose_count.set(self.dispose_count.get() + 1);
240 Ok(())
241 }
242
243 fn submit_order(&self, cmd: SubmitOrder) -> anyhow::Result<()> {
244 if let Some(error) = &self.submit_order_error {
245 anyhow::bail!("{error}");
246 }
247
248 self.submitted_order_ids
249 .borrow_mut()
250 .push(cmd.client_order_id);
251
252 Ok(()) }
254
255 fn submit_order_list(&self, cmd: SubmitOrderList) -> anyhow::Result<()> {
256 if let Some(error) = &self.submit_order_list_error {
257 anyhow::bail!("{error}");
258 }
259
260 self.submitted_order_ids
261 .borrow_mut()
262 .extend(cmd.order_list.client_order_ids);
263
264 Ok(()) }
266
267 fn modify_order(&self, cmd: ModifyOrder) -> anyhow::Result<()> {
268 self.modified_order_ids
269 .borrow_mut()
270 .push(cmd.client_order_id);
271
272 Ok(()) }
274
275 fn batch_modify_orders(&self, cmd: BatchModifyOrders) -> anyhow::Result<()> {
276 self.modified_order_ids.borrow_mut().extend(
277 cmd.modifies
278 .into_iter()
279 .map(|modify| modify.client_order_id),
280 );
281
282 Ok(()) }
284
285 fn cancel_order(&self, _cmd: CancelOrder) -> anyhow::Result<()> {
286 Ok(()) }
288
289 fn cancel_all_orders(&self, _cmd: CancelAllOrders) -> anyhow::Result<()> {
290 Ok(()) }
292
293 fn batch_cancel_orders(&self, _cmd: BatchCancelOrders) -> anyhow::Result<()> {
294 Ok(()) }
296
297 fn query_account(&self, cmd: QueryAccount) -> anyhow::Result<()> {
298 self.queried_account_ids.borrow_mut().push(cmd.account_id);
299
300 Ok(()) }
302
303 fn query_order(&self, _cmd: QueryOrder) -> anyhow::Result<()> {
304 Ok(()) }
306
307 fn register_external_order(
308 &self,
309 client_order_id: ClientOrderId,
310 _venue_order_id: VenueOrderId,
311 _instrument_id: InstrumentId,
312 _strategy_id: StrategyId,
313 _ts_init: UnixNanos,
314 ) {
315 self.registered_external_order_ids
316 .borrow_mut()
317 .push(client_order_id);
318 }
319
320 fn on_instrument(&mut self, instrument: InstrumentAny) {
321 self.received_instruments.borrow_mut().push(instrument);
322 }
323}