1use std::{cell::RefCell, fmt::Debug, rc::Rc};
19
20use ahash::AHashMap;
21use async_trait::async_trait;
22use nautilus_common::{
23 cache::Cache,
24 clients::ExecutionClient,
25 clock::Clock,
26 factories::OrderEventFactory,
27 live::try_get_exec_event_sender,
28 messages::{
29 ExecutionEvent,
30 execution::{
31 BatchCancelOrders, CancelAllOrders, CancelOrder, GenerateFillReports,
32 GenerateOrderStatusReport, GenerateOrderStatusReports, GeneratePositionStatusReports,
33 ModifyOrder, QueryAccount, QueryOrder, SubmitOrder, SubmitOrderList,
34 },
35 },
36 msgbus::{self, MStr, MessagingSwitchboard, Pattern, TypedHandler},
37};
38use nautilus_core::{UnixNanos, WeakCell};
39use nautilus_execution::{
40 client::core::ExecutionClientCore,
41 matching_engine::adapter::OrderEngineAdapter,
42 models::{
43 fee::{FeeModelAny, MakerTakerFeeModel},
44 fill::FillModelAny,
45 },
46};
47use nautilus_model::{
48 accounts::AccountAny,
49 data::{Bar, OrderBookDeltas, QuoteTick, TradeTick},
50 enums::OmsType,
51 events::OrderEventAny,
52 identifiers::{AccountId, ClientId, ClientOrderId, InstrumentId, Venue},
53 instruments::{Instrument, InstrumentAny},
54 orders::{Order, OrderAny},
55 reports::{ExecutionMassStatus, FillReport, OrderStatusReport, PositionStatusReport},
56 types::{AccountBalance, MarginBalance, Money},
57};
58
59use crate::config::SandboxExecutionClientConfig;
60
61struct SandboxInner {
65 clock: Rc<RefCell<dyn Clock>>,
67 cache: Rc<RefCell<Cache>>,
69 config: SandboxExecutionClientConfig,
71 matching_engines: AHashMap<InstrumentId, OrderEngineAdapter>,
73 next_engine_raw_id: u32,
75 balances: AHashMap<String, Money>,
77 event_handler: Option<Rc<dyn Fn(OrderEventAny)>>,
78}
79
80impl SandboxInner {
81 fn ensure_matching_engine(&mut self, instrument: &InstrumentAny) {
83 let instrument_id = instrument.id();
84
85 if !self.matching_engines.contains_key(&instrument_id) {
86 let engine_config = self.config.to_matching_engine_config();
87 let fill_model = FillModelAny::default();
88 let fee_model = FeeModelAny::MakerTaker(MakerTakerFeeModel);
89 let raw_id = self.next_engine_raw_id;
90 self.next_engine_raw_id = self.next_engine_raw_id.wrapping_add(1);
91
92 let engine = OrderEngineAdapter::new(
93 instrument.clone(),
94 raw_id,
95 fill_model,
96 fee_model,
97 self.config.book_type,
98 self.config.oms_type,
99 self.config.account_type,
100 self.clock.clone(),
101 self.cache.clone(),
102 engine_config,
103 );
104
105 if let Some(handler) = &self.event_handler {
106 engine.get_engine_mut().set_event_handler(handler.clone());
107 }
108
109 self.matching_engines.insert(instrument_id, engine);
110 }
111 }
112
113 fn process_quote_tick(&mut self, quote: &QuoteTick) {
115 let instrument_id = quote.instrument_id;
116
117 let instrument = self.cache.borrow().instrument(&instrument_id).cloned();
119 if let Some(instrument) = instrument {
120 self.ensure_matching_engine(&instrument);
121
122 if let Some(engine) = self.matching_engines.get_mut(&instrument_id) {
123 engine.get_engine_mut().process_quote_tick(quote);
124 }
125 }
126 }
127
128 fn process_trade_tick(&mut self, trade: &TradeTick) {
130 if !self.config.trade_execution {
131 return;
132 }
133
134 let instrument_id = trade.instrument_id;
135
136 let instrument = self.cache.borrow().instrument(&instrument_id).cloned();
137 if let Some(instrument) = instrument {
138 self.ensure_matching_engine(&instrument);
139
140 if let Some(engine) = self.matching_engines.get_mut(&instrument_id) {
141 engine.get_engine_mut().process_trade_tick(trade);
142 }
143 }
144 }
145
146 fn process_bar(&mut self, bar: &Bar) {
148 if !self.config.bar_execution {
149 return;
150 }
151
152 let instrument_id = bar.bar_type.instrument_id();
153
154 let instrument = self.cache.borrow().instrument(&instrument_id).cloned();
155 if let Some(instrument) = instrument {
156 self.ensure_matching_engine(&instrument);
157
158 if let Some(engine) = self.matching_engines.get_mut(&instrument_id) {
159 engine.get_engine_mut().process_bar(bar);
160 }
161 }
162 }
163
164 fn process_order_book_deltas(&mut self, deltas: &OrderBookDeltas) {
165 let instrument_id = deltas.instrument_id;
166
167 let instrument = self.cache.borrow().instrument(&instrument_id).cloned();
168 if let Some(instrument) = instrument {
169 self.ensure_matching_engine(&instrument);
170
171 if let Some(engine) = self.matching_engines.get_mut(&instrument_id)
172 && let Err(e) = engine.get_engine_mut().process_order_book_deltas(deltas)
173 {
174 log::error!("Error processing order book deltas: {e}");
175 }
176 }
177 }
178}
179
180struct RegisteredHandlers {
182 deltas_pattern: MStr<Pattern>,
183 deltas_handler: TypedHandler<OrderBookDeltas>,
184 quote_pattern: MStr<Pattern>,
185 quote_handler: TypedHandler<QuoteTick>,
186 trade_pattern: MStr<Pattern>,
187 trade_handler: TypedHandler<TradeTick>,
188 bar_pattern: MStr<Pattern>,
189 bar_handler: TypedHandler<Bar>,
190}
191
192pub struct SandboxExecutionClient {
198 core: RefCell<ExecutionClientCore>,
200 factory: OrderEventFactory,
202 config: SandboxExecutionClientConfig,
204 inner: Rc<RefCell<SandboxInner>>,
206 handlers: RefCell<Option<RegisteredHandlers>>,
208 clock: Rc<RefCell<dyn Clock>>,
210 cache: Rc<RefCell<Cache>>,
212}
213
214impl Debug for SandboxExecutionClient {
215 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216 f.debug_struct(stringify!(SandboxExecutionClient))
217 .field("venue", &self.config.venue)
218 .field("account_id", &self.core.borrow().account_id)
219 .field("connected", &self.core.borrow().is_connected())
220 .field(
221 "matching_engines",
222 &self.inner.borrow().matching_engines.len(),
223 )
224 .finish()
225 }
226}
227
228impl SandboxExecutionClient {
229 #[must_use]
231 pub fn new(
232 core: ExecutionClientCore,
233 config: SandboxExecutionClientConfig,
234 clock: Rc<RefCell<dyn Clock>>,
235 cache: Rc<RefCell<Cache>>,
236 ) -> Self {
237 let mut balances = AHashMap::new();
238 for money in &config.starting_balances {
239 balances.insert(money.currency.code.to_string(), *money);
240 }
241
242 let inner = Rc::new(RefCell::new(SandboxInner {
243 clock: clock.clone(),
244 cache: cache.clone(),
245 config: config.clone(),
246 matching_engines: AHashMap::new(),
247 next_engine_raw_id: 0,
248 balances,
249 event_handler: None,
250 }));
251
252 let factory = OrderEventFactory::new(
253 core.trader_id,
254 core.account_id,
255 core.account_type,
256 core.base_currency,
257 );
258
259 Self {
260 core: RefCell::new(core),
261 factory,
262 config,
263 inner,
264 handlers: RefCell::new(None),
265 clock,
266 cache,
267 }
268 }
269
270 #[must_use]
272 pub const fn config(&self) -> &SandboxExecutionClientConfig {
273 &self.config
274 }
275
276 #[must_use]
278 pub fn matching_engine_count(&self) -> usize {
279 self.inner.borrow().matching_engines.len()
280 }
281
282 fn dispatch_order_event(&self, event: OrderEventAny) {
283 if let Some(handler) = &self.inner.borrow().event_handler {
284 handler(event);
285 } else {
286 let endpoint = MessagingSwitchboard::exec_engine_process();
287 msgbus::send_order_event(endpoint, event);
288 }
289 }
290
291 fn register_message_handlers(&self) {
296 if self.handlers.borrow().is_some() {
297 log::warn!("Sandbox message handlers already registered");
298 return;
299 }
300
301 let inner_weak = WeakCell::from(Rc::downgrade(&self.inner));
302 let venue = self.config.venue;
303
304 let deltas_handler = {
306 let inner = inner_weak.clone();
307 TypedHandler::from(move |deltas: &OrderBookDeltas| {
308 if deltas.instrument_id.venue == venue
309 && let Some(inner_rc) = inner.upgrade()
310 {
311 inner_rc.borrow_mut().process_order_book_deltas(deltas);
312 }
313 })
314 };
315
316 let quote_handler = {
318 let inner = inner_weak.clone();
319 TypedHandler::from(move |quote: &QuoteTick| {
320 if quote.instrument_id.venue == venue
321 && let Some(inner_rc) = inner.upgrade()
322 {
323 inner_rc.borrow_mut().process_quote_tick(quote);
324 }
325 })
326 };
327
328 let trade_handler = {
330 let inner = inner_weak.clone();
331 TypedHandler::from(move |trade: &TradeTick| {
332 if trade.instrument_id.venue == venue
333 && let Some(inner_rc) = inner.upgrade()
334 {
335 inner_rc.borrow_mut().process_trade_tick(trade);
336 }
337 })
338 };
339
340 let bar_handler = {
342 let inner = inner_weak;
343 TypedHandler::from(move |bar: &Bar| {
344 if bar.bar_type.instrument_id().venue == venue
345 && let Some(inner_rc) = inner.upgrade()
346 {
347 inner_rc.borrow_mut().process_bar(bar);
348 }
349 })
350 };
351
352 let deltas_pattern: MStr<Pattern> = format!("data.book.deltas.{venue}.*").into();
354 let quote_pattern: MStr<Pattern> = format!("data.quotes.{venue}.*").into();
355 let trade_pattern: MStr<Pattern> = format!("data.trades.{venue}.*").into();
356 let bar_pattern: MStr<Pattern> = "data.bars.*".into();
357
358 msgbus::subscribe_book_deltas(deltas_pattern, deltas_handler.clone(), Some(10));
359 msgbus::subscribe_quotes(quote_pattern, quote_handler.clone(), Some(10));
360 msgbus::subscribe_trades(trade_pattern, trade_handler.clone(), Some(10));
361 msgbus::subscribe_bars(bar_pattern, bar_handler.clone(), Some(10));
362
363 *self.handlers.borrow_mut() = Some(RegisteredHandlers {
365 deltas_pattern,
366 deltas_handler,
367 quote_pattern,
368 quote_handler,
369 trade_pattern,
370 trade_handler,
371 bar_pattern,
372 bar_handler,
373 });
374
375 log::info!(
376 "Sandbox registered message handlers for venue={}",
377 self.config.venue
378 );
379 }
380
381 fn deregister_message_handlers(&self) {
383 if let Some(handlers) = self.handlers.borrow_mut().take() {
384 msgbus::unsubscribe_book_deltas(handlers.deltas_pattern, &handlers.deltas_handler);
385 msgbus::unsubscribe_quotes(handlers.quote_pattern, &handlers.quote_handler);
386 msgbus::unsubscribe_trades(handlers.trade_pattern, &handlers.trade_handler);
387 msgbus::unsubscribe_bars(handlers.bar_pattern, &handlers.bar_handler);
388
389 log::info!(
390 "Sandbox deregistered message handlers for venue={}",
391 self.config.venue
392 );
393 }
394 }
395
396 fn get_current_account_balances(&self) -> Vec<AccountBalance> {
398 let account_id = self.core.borrow().account_id;
399 let cache = self.cache.borrow();
400
401 if let Some(account) = cache.account(&account_id) {
403 return account.balances().into_values().collect();
404 }
405
406 self.get_account_balances()
408 }
409
410 pub fn process_quote_tick(&self, quote: &QuoteTick) -> anyhow::Result<()> {
416 let instrument_id = quote.instrument_id;
417 let instrument = self
418 .cache
419 .borrow()
420 .instrument(&instrument_id)
421 .cloned()
422 .ok_or_else(|| anyhow::anyhow!("Instrument not found: {instrument_id}"))?;
423
424 let mut inner = self.inner.borrow_mut();
425 inner.ensure_matching_engine(&instrument);
426 if let Some(engine) = inner.matching_engines.get_mut(&instrument_id) {
427 engine.get_engine_mut().process_quote_tick(quote);
428 }
429 Ok(())
430 }
431
432 pub fn process_trade_tick(&self, trade: &TradeTick) -> anyhow::Result<()> {
438 if !self.config.trade_execution {
439 return Ok(());
440 }
441
442 let instrument_id = trade.instrument_id;
443 let instrument = self
444 .cache
445 .borrow()
446 .instrument(&instrument_id)
447 .cloned()
448 .ok_or_else(|| anyhow::anyhow!("Instrument not found: {instrument_id}"))?;
449
450 let mut inner = self.inner.borrow_mut();
451 inner.ensure_matching_engine(&instrument);
452 if let Some(engine) = inner.matching_engines.get_mut(&instrument_id) {
453 engine.get_engine_mut().process_trade_tick(trade);
454 }
455 Ok(())
456 }
457
458 pub fn process_bar(&self, bar: &Bar) -> anyhow::Result<()> {
464 if !self.config.bar_execution {
465 return Ok(());
466 }
467
468 let instrument_id = bar.bar_type.instrument_id();
469 let instrument = self
470 .cache
471 .borrow()
472 .instrument(&instrument_id)
473 .cloned()
474 .ok_or_else(|| anyhow::anyhow!("Instrument not found: {instrument_id}"))?;
475
476 let mut inner = self.inner.borrow_mut();
477 inner.ensure_matching_engine(&instrument);
478 if let Some(engine) = inner.matching_engines.get_mut(&instrument_id) {
479 engine.get_engine_mut().process_bar(bar);
480 }
481 Ok(())
482 }
483
484 pub fn process_order_book_deltas(&self, deltas: &OrderBookDeltas) -> anyhow::Result<()> {
490 let instrument_id = deltas.instrument_id;
491 let instrument = self
492 .cache
493 .borrow()
494 .instrument(&instrument_id)
495 .cloned()
496 .ok_or_else(|| anyhow::anyhow!("Instrument not found: {instrument_id}"))?;
497
498 let mut inner = self.inner.borrow_mut();
499 inner.ensure_matching_engine(&instrument);
500 if let Some(engine) = inner.matching_engines.get_mut(&instrument_id) {
501 engine.get_engine_mut().process_order_book_deltas(deltas)?;
502 }
503 Ok(())
504 }
505
506 pub fn reset(&self) {
508 let mut inner = self.inner.borrow_mut();
509 for engine in inner.matching_engines.values_mut() {
510 engine.get_engine_mut().reset();
511 }
512
513 inner.balances.clear();
514 for money in &self.config.starting_balances {
515 inner
516 .balances
517 .insert(money.currency.code.to_string(), *money);
518 }
519
520 log::info!(
521 "Sandbox execution client reset: venue={}",
522 self.config.venue
523 );
524 }
525
526 fn get_account_balances(&self) -> Vec<AccountBalance> {
528 self.inner
529 .borrow()
530 .balances
531 .values()
532 .map(|money| AccountBalance::new(*money, Money::new(0.0, money.currency), *money))
533 .collect()
534 }
535
536 fn get_order(&self, client_order_id: &ClientOrderId) -> anyhow::Result<OrderAny> {
537 self.cache
538 .borrow()
539 .order(client_order_id)
540 .cloned()
541 .ok_or_else(|| anyhow::anyhow!("Order not found in cache for {client_order_id}"))
542 }
543}
544
545#[async_trait(?Send)]
546impl ExecutionClient for SandboxExecutionClient {
547 fn is_connected(&self) -> bool {
548 self.core.borrow().is_connected()
549 }
550
551 fn client_id(&self) -> ClientId {
552 self.core.borrow().client_id
553 }
554
555 fn account_id(&self) -> AccountId {
556 self.core.borrow().account_id
557 }
558
559 fn venue(&self) -> Venue {
560 self.core.borrow().venue
561 }
562
563 fn oms_type(&self) -> OmsType {
564 self.config.oms_type
565 }
566
567 fn get_account(&self) -> Option<AccountAny> {
568 let account_id = self.core.borrow().account_id;
569 self.cache.borrow().account(&account_id).cloned()
570 }
571
572 fn generate_account_state(
573 &self,
574 balances: Vec<AccountBalance>,
575 margins: Vec<MarginBalance>,
576 reported: bool,
577 ts_event: UnixNanos,
578 ) -> anyhow::Result<()> {
579 let ts_init = self.clock.borrow().timestamp_ns();
580 let state = self
581 .factory
582 .generate_account_state(balances, margins, reported, ts_event, ts_init);
583 let endpoint = MessagingSwitchboard::portfolio_update_account();
584 msgbus::send_account_state(endpoint, &state);
585 Ok(())
586 }
587
588 fn start(&mut self) -> anyhow::Result<()> {
589 if self.core.borrow().is_started() {
590 return Ok(());
591 }
592
593 if let Some(sender) = try_get_exec_event_sender() {
594 let handler: Rc<dyn Fn(OrderEventAny)> = Rc::new(move |event: OrderEventAny| {
595 if let Err(e) = sender.send(ExecutionEvent::Order(event)) {
596 log::warn!("Failed to send order event: {e}");
597 }
598 });
599 let mut inner = self.inner.borrow_mut();
600 inner.event_handler = Some(handler.clone());
601 for engine in inner.matching_engines.values_mut() {
602 engine.get_engine_mut().set_event_handler(handler.clone());
603 }
604 }
605
606 self.register_message_handlers();
608
609 self.core.borrow().set_started();
610 let core = self.core.borrow();
611 log::info!(
612 "Sandbox execution client started: venue={}, account_id={}, oms_type={:?}, account_type={:?}",
613 self.config.venue,
614 core.account_id,
615 self.config.oms_type,
616 self.config.account_type,
617 );
618 Ok(())
619 }
620
621 fn stop(&mut self) -> anyhow::Result<()> {
622 if self.core.borrow().is_stopped() {
623 return Ok(());
624 }
625
626 self.deregister_message_handlers();
628
629 self.core.borrow().set_stopped();
630 self.core.borrow().set_disconnected();
631 log::info!(
632 "Sandbox execution client stopped: venue={}",
633 self.config.venue
634 );
635 Ok(())
636 }
637
638 async fn connect(&mut self) -> anyhow::Result<()> {
639 if self.core.borrow().is_connected() {
640 return Ok(());
641 }
642
643 let balances = self.get_account_balances();
644 let ts_event = self.clock.borrow().timestamp_ns();
645 self.generate_account_state(balances, vec![], false, ts_event)?;
646
647 self.core.borrow().set_connected();
648 log::info!(
649 "Sandbox execution client connected: venue={}",
650 self.config.venue
651 );
652 Ok(())
653 }
654
655 async fn disconnect(&mut self) -> anyhow::Result<()> {
656 if self.core.borrow().is_disconnected() {
657 return Ok(());
658 }
659
660 self.core.borrow().set_disconnected();
661 log::info!(
662 "Sandbox execution client disconnected: venue={}",
663 self.config.venue
664 );
665 Ok(())
666 }
667
668 fn submit_order(&self, cmd: SubmitOrder) -> anyhow::Result<()> {
669 let mut order = self.get_order(&cmd.client_order_id)?;
670
671 if order.is_closed() {
672 log::warn!("Cannot submit closed order {}", order.client_order_id());
673 return Ok(());
674 }
675
676 let ts_init = self.clock.borrow().timestamp_ns();
677 let event = self.factory.generate_order_submitted(&order, ts_init);
678 self.dispatch_order_event(event);
679
680 let instrument_id = order.instrument_id();
681 let instrument = self
682 .cache
683 .borrow()
684 .instrument(&instrument_id)
685 .cloned()
686 .ok_or_else(|| anyhow::anyhow!("Instrument not found: {instrument_id}"))?;
687
688 let mut inner = self.inner.borrow_mut();
689 inner.ensure_matching_engine(&instrument);
690
691 let cache = self.cache.borrow();
693
694 if let Some(engine) = inner.matching_engines.get_mut(&instrument_id) {
695 if let Some(quote) = cache.quote(&instrument_id) {
696 engine.get_engine_mut().process_quote_tick(quote);
697 }
698
699 if self.config.trade_execution
700 && let Some(trade) = cache.trade(&instrument_id)
701 {
702 engine.get_engine_mut().process_trade_tick(trade);
703 }
704 }
705 drop(cache);
706
707 let account_id = self.core.borrow().account_id;
708
709 if let Some(engine) = inner.matching_engines.get_mut(&instrument_id) {
710 engine
711 .get_engine_mut()
712 .process_order(&mut order, account_id);
713 }
714
715 Ok(())
716 }
717
718 fn submit_order_list(&self, cmd: SubmitOrderList) -> anyhow::Result<()> {
719 let ts_init = self.clock.borrow().timestamp_ns();
720
721 let orders: Vec<OrderAny> = self
722 .cache
723 .borrow()
724 .orders_for_ids(&cmd.order_list.client_order_ids, &cmd);
725
726 for order in &orders {
727 if order.is_closed() {
728 log::warn!("Cannot submit closed order {}", order.client_order_id());
729 continue;
730 }
731
732 let event = self.factory.generate_order_submitted(order, ts_init);
733 self.dispatch_order_event(event);
734 }
735
736 let account_id = self.core.borrow().account_id;
737
738 for order in &orders {
739 if order.is_closed() {
740 continue;
741 }
742
743 let instrument_id = order.instrument_id();
744 let instrument = self.cache.borrow().instrument(&instrument_id).cloned();
745
746 if let Some(instrument) = instrument {
747 let mut inner = self.inner.borrow_mut();
748 inner.ensure_matching_engine(&instrument);
749
750 let cache = self.cache.borrow();
752
753 if let Some(engine) = inner.matching_engines.get_mut(&instrument_id) {
754 if let Some(quote) = cache.quote(&instrument_id) {
755 engine.get_engine_mut().process_quote_tick(quote);
756 }
757
758 if self.config.trade_execution
759 && let Some(trade) = cache.trade(&instrument_id)
760 {
761 engine.get_engine_mut().process_trade_tick(trade);
762 }
763 }
764 drop(cache);
765
766 if let Some(engine) = inner.matching_engines.get_mut(&instrument_id) {
767 let mut order_clone = order.clone();
768 engine
769 .get_engine_mut()
770 .process_order(&mut order_clone, account_id);
771 }
772 }
773 }
774
775 Ok(())
776 }
777
778 fn modify_order(&self, cmd: ModifyOrder) -> anyhow::Result<()> {
779 let instrument_id = cmd.instrument_id;
780 let account_id = self.core.borrow().account_id;
781
782 let mut inner = self.inner.borrow_mut();
783 if let Some(engine) = inner.matching_engines.get_mut(&instrument_id) {
784 engine.get_engine_mut().process_modify(&cmd, account_id);
785 }
786 Ok(())
787 }
788
789 fn cancel_order(&self, cmd: CancelOrder) -> anyhow::Result<()> {
790 let instrument_id = cmd.instrument_id;
791 let account_id = self.core.borrow().account_id;
792
793 let mut inner = self.inner.borrow_mut();
794 if let Some(engine) = inner.matching_engines.get_mut(&instrument_id) {
795 engine.get_engine_mut().process_cancel(&cmd, account_id);
796 }
797 Ok(())
798 }
799
800 fn cancel_all_orders(&self, cmd: CancelAllOrders) -> anyhow::Result<()> {
801 let instrument_id = cmd.instrument_id;
802 let account_id = self.core.borrow().account_id;
803
804 let mut inner = self.inner.borrow_mut();
805 if let Some(engine) = inner.matching_engines.get_mut(&instrument_id) {
806 engine.get_engine_mut().process_cancel_all(&cmd, account_id);
807 }
808 Ok(())
809 }
810
811 fn batch_cancel_orders(&self, cmd: BatchCancelOrders) -> anyhow::Result<()> {
812 let instrument_id = cmd.instrument_id;
813 let account_id = self.core.borrow().account_id;
814
815 let mut inner = self.inner.borrow_mut();
816 if let Some(engine) = inner.matching_engines.get_mut(&instrument_id) {
817 engine
818 .get_engine_mut()
819 .process_batch_cancel(&cmd, account_id);
820 }
821 Ok(())
822 }
823
824 fn query_account(&self, _cmd: QueryAccount) -> anyhow::Result<()> {
825 let balances = self.get_current_account_balances();
826 let ts_event = self.clock.borrow().timestamp_ns();
827 self.generate_account_state(balances, vec![], false, ts_event)?;
828 Ok(())
829 }
830
831 fn query_order(&self, _cmd: QueryOrder) -> anyhow::Result<()> {
832 Ok(())
834 }
835
836 async fn generate_order_status_report(
837 &self,
838 _cmd: &GenerateOrderStatusReport,
839 ) -> anyhow::Result<Option<OrderStatusReport>> {
840 Ok(None)
842 }
843
844 async fn generate_order_status_reports(
845 &self,
846 _cmd: &GenerateOrderStatusReports,
847 ) -> anyhow::Result<Vec<OrderStatusReport>> {
848 Ok(Vec::new())
850 }
851
852 async fn generate_fill_reports(
853 &self,
854 _cmd: GenerateFillReports,
855 ) -> anyhow::Result<Vec<FillReport>> {
856 Ok(Vec::new())
858 }
859
860 async fn generate_position_status_reports(
861 &self,
862 _cmd: &GeneratePositionStatusReports,
863 ) -> anyhow::Result<Vec<PositionStatusReport>> {
864 Ok(Vec::new())
866 }
867
868 async fn generate_mass_status(
869 &self,
870 _lookback_mins: Option<u64>,
871 ) -> anyhow::Result<Option<ExecutionMassStatus>> {
872 Ok(None)
874 }
875}