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::UnixNanos;
32use nautilus_model::{
33 accounts::AccountAny,
34 enums::OmsType,
35 identifiers::{AccountId, ClientId, ClientOrderId, Venue},
36 instruments::InstrumentAny,
37 types::{AccountBalance, MarginBalance},
38};
39
40#[derive(Clone, Debug)]
45#[allow(dead_code)]
46pub struct StubExecutionClient {
47 client_id: ClientId,
48 account_id: AccountId,
49 venue: Venue,
50 oms_type: OmsType,
51 is_connected: bool,
52 clock: Rc<RefCell<dyn Clock>>,
53 cache: Rc<RefCell<Cache>>,
54 received_instruments: Rc<RefCell<Vec<InstrumentAny>>>,
55 start_count: Rc<Cell<usize>>,
56 stop_count: Rc<Cell<usize>>,
57 reset_count: Rc<Cell<usize>>,
58 dispose_count: Rc<Cell<usize>>,
59 submitted_order_ids: Rc<RefCell<Vec<ClientOrderId>>>,
60 modified_order_ids: Rc<RefCell<Vec<ClientOrderId>>>,
61 queried_account_ids: Rc<RefCell<Vec<AccountId>>>,
62 handles_all_order_venues: bool,
63 submit_order_error: Option<String>,
64 submit_order_list_error: Option<String>,
65}
66
67impl StubExecutionClient {
68 #[allow(dead_code)]
70 pub fn new(
71 client_id: ClientId,
72 account_id: AccountId,
73 venue: Venue,
74 oms_type: OmsType,
75 clock: Option<Rc<RefCell<dyn Clock>>>,
76 ) -> Self {
77 Self {
78 client_id,
79 account_id,
80 venue,
81 oms_type,
82 is_connected: false,
83 clock: clock.unwrap_or_else(|| Rc::new(RefCell::new(TestClock::new()))),
84 cache: Rc::new(RefCell::new(Cache::new(None, None))),
85 received_instruments: Rc::new(RefCell::new(Vec::new())),
86 start_count: Rc::new(Cell::new(0)),
87 stop_count: Rc::new(Cell::new(0)),
88 reset_count: Rc::new(Cell::new(0)),
89 dispose_count: Rc::new(Cell::new(0)),
90 submitted_order_ids: Rc::new(RefCell::new(Vec::new())),
91 modified_order_ids: Rc::new(RefCell::new(Vec::new())),
92 queried_account_ids: Rc::new(RefCell::new(Vec::new())),
93 handles_all_order_venues: false,
94 submit_order_error: None,
95 submit_order_list_error: None,
96 }
97 }
98
99 #[must_use]
101 pub fn with_handles_all_order_venues(mut self) -> Self {
102 self.handles_all_order_venues = true;
103 self
104 }
105
106 #[must_use]
108 pub fn with_submit_order_error(mut self, error: impl Into<String>) -> Self {
109 self.submit_order_error = Some(error.into());
110 self
111 }
112
113 #[must_use]
115 pub fn with_submit_order_list_error(mut self, error: impl Into<String>) -> Self {
116 self.submit_order_list_error = Some(error.into());
117 self
118 }
119
120 #[must_use]
122 pub fn received_instruments(&self) -> Rc<RefCell<Vec<InstrumentAny>>> {
123 self.received_instruments.clone()
124 }
125
126 #[must_use]
128 pub fn submitted_order_ids(&self) -> Rc<RefCell<Vec<ClientOrderId>>> {
129 self.submitted_order_ids.clone()
130 }
131
132 #[must_use]
134 pub fn modified_order_ids(&self) -> Rc<RefCell<Vec<ClientOrderId>>> {
135 self.modified_order_ids.clone()
136 }
137
138 #[must_use]
140 pub fn queried_account_ids(&self) -> Rc<RefCell<Vec<AccountId>>> {
141 self.queried_account_ids.clone()
142 }
143
144 #[must_use]
146 pub fn start_count(&self) -> usize {
147 self.start_count.get()
148 }
149
150 #[must_use]
152 pub fn stop_count(&self) -> usize {
153 self.stop_count.get()
154 }
155
156 #[must_use]
158 pub fn reset_count(&self) -> usize {
159 self.reset_count.get()
160 }
161
162 #[must_use]
164 pub fn dispose_count(&self) -> usize {
165 self.dispose_count.get()
166 }
167}
168
169#[async_trait(?Send)]
170impl ExecutionClient for StubExecutionClient {
171 fn is_connected(&self) -> bool {
172 self.is_connected
173 }
174
175 fn client_id(&self) -> ClientId {
176 self.client_id
177 }
178
179 fn account_id(&self) -> AccountId {
180 self.account_id
181 }
182
183 fn venue(&self) -> Venue {
184 self.venue
185 }
186
187 fn handles_order_venue(&self, venue: Venue) -> bool {
188 self.handles_all_order_venues || self.venue == venue
189 }
190
191 fn oms_type(&self) -> OmsType {
192 self.oms_type
193 }
194
195 fn get_account(&self) -> Option<AccountAny> {
196 None }
198
199 fn generate_account_state(
200 &self,
201 _balances: Vec<AccountBalance>,
202 _margins: Vec<MarginBalance>,
203 _reported: bool,
204 _ts_event: UnixNanos,
205 ) -> anyhow::Result<()> {
206 Ok(()) }
208
209 fn start(&mut self) -> anyhow::Result<()> {
210 self.is_connected = true;
211 self.start_count.set(self.start_count.get() + 1);
212 Ok(())
213 }
214
215 fn stop(&mut self) -> anyhow::Result<()> {
216 self.is_connected = false;
217 self.stop_count.set(self.stop_count.get() + 1);
218 Ok(())
219 }
220
221 fn reset(&mut self) -> anyhow::Result<()> {
222 self.reset_count.set(self.reset_count.get() + 1);
223 Ok(())
224 }
225
226 fn dispose(&mut self) -> anyhow::Result<()> {
227 self.dispose_count.set(self.dispose_count.get() + 1);
228 Ok(())
229 }
230
231 fn submit_order(&self, cmd: SubmitOrder) -> anyhow::Result<()> {
232 if let Some(error) = &self.submit_order_error {
233 anyhow::bail!("{error}");
234 }
235
236 self.submitted_order_ids
237 .borrow_mut()
238 .push(cmd.client_order_id);
239
240 Ok(()) }
242
243 fn submit_order_list(&self, cmd: SubmitOrderList) -> anyhow::Result<()> {
244 if let Some(error) = &self.submit_order_list_error {
245 anyhow::bail!("{error}");
246 }
247
248 self.submitted_order_ids
249 .borrow_mut()
250 .extend(cmd.order_list.client_order_ids);
251
252 Ok(()) }
254
255 fn modify_order(&self, cmd: ModifyOrder) -> anyhow::Result<()> {
256 self.modified_order_ids
257 .borrow_mut()
258 .push(cmd.client_order_id);
259
260 Ok(()) }
262
263 fn batch_modify_orders(&self, cmd: BatchModifyOrders) -> anyhow::Result<()> {
264 self.modified_order_ids.borrow_mut().extend(
265 cmd.modifies
266 .into_iter()
267 .map(|modify| modify.client_order_id),
268 );
269
270 Ok(()) }
272
273 fn cancel_order(&self, _cmd: CancelOrder) -> anyhow::Result<()> {
274 Ok(()) }
276
277 fn cancel_all_orders(&self, _cmd: CancelAllOrders) -> anyhow::Result<()> {
278 Ok(()) }
280
281 fn batch_cancel_orders(&self, _cmd: BatchCancelOrders) -> anyhow::Result<()> {
282 Ok(()) }
284
285 fn query_account(&self, cmd: QueryAccount) -> anyhow::Result<()> {
286 self.queried_account_ids.borrow_mut().push(cmd.account_id);
287
288 Ok(()) }
290
291 fn query_order(&self, _cmd: QueryOrder) -> anyhow::Result<()> {
292 Ok(()) }
294
295 fn on_instrument(&mut self, instrument: InstrumentAny) {
296 self.received_instruments.borrow_mut().push(instrument);
297 }
298}