1pub mod config;
21pub mod database;
22pub mod fifo;
23pub mod quote;
24pub mod refs;
25
26mod bounded;
27mod error;
28mod index;
29mod position;
30
31#[cfg(test)]
32mod tests;
33
34use std::{
35 borrow::Cow,
36 cell::{Ref, RefCell},
37 fmt::{Debug, Display},
38 rc::Rc,
39 time::{SystemTime, UNIX_EPOCH},
40};
41
42use ahash::{AHashMap, AHashSet};
43use bounded::BoundedVecDeque;
44use bytes::Bytes;
45pub use config::CacheConfig; use database::{CacheDatabaseAdapter, CacheMap};
47pub use error::{
48 ACCOUNT_NOT_FOUND, AccountLookupError, CURRENCY_NOT_FOUND, CurrencyLookupError,
49 INSTRUMENT_NOT_FOUND, InstrumentLookupError, ORDER_BOOK_NOT_FOUND, ORDER_LIST_NOT_FOUND,
50 ORDER_NOT_FOUND, OWN_ORDER_BOOK_NOT_FOUND, OrderBookLookupError, OrderListLookupError,
51 OrderLookupError, OwnOrderBookLookupError, POSITION_NOT_FOUND, PositionLookupError,
52 SYNTHETIC_INSTRUMENT_NOT_FOUND, SyntheticInstrumentLookupError, VenueOrderIdOwnershipError,
53};
54use index::CacheIndex;
55use indexmap::IndexMap;
56use nautilus_core::{
57 SharedCell, UnixNanos,
58 correctness::{
59 check_key_not_in_map, check_predicate_false, check_slice_not_empty,
60 check_valid_string_ascii,
61 },
62 datetime::secs_to_nanos_unchecked,
63};
64#[cfg(feature = "defi")]
65use nautilus_model::defi::{Pool, PoolProfiler};
66use nautilus_model::{
67 accounts::{Account, AccountAny},
68 data::{
69 Bar, BarType, FundingRateUpdate, GreeksData, IndexPriceUpdate, InstrumentStatus,
70 MarkPriceUpdate, QuoteTick, TradeTick, YieldCurveData, option_chain::OptionGreeks,
71 },
72 enums::{
73 AggregationSource, ContingencyType, InstrumentClass, OmsType, OrderSide, PositionSide,
74 PriceType, TriggerType,
75 },
76 events::{AccountState, OrderEventAny},
77 identifiers::{
78 AccountId, ClientId, ClientOrderId, ComponentId, ExecAlgorithmId, InstrumentId,
79 OrderListId, PositionId, StrategyId, Venue, VenueOrderId,
80 },
81 instruments::{Instrument, InstrumentAny, SyntheticInstrument},
82 orderbook::{
83 OrderBook,
84 own::{OwnOrderBook, should_handle_own_book_order},
85 },
86 orders::{Order, OrderAny, OrderError, OrderList},
87 position::Position,
88 types::{Currency, Money, Price, Quantity},
89};
90pub use position::CacheSnapshotRef;
91use position::PositionSnapshotFrame;
92pub use refs::{AccountRef, AccountRefMut, OrderRef, OrderRefMut, PositionRef, PositionRefMut};
93use rust_decimal::Decimal;
94use ustr::Ustr;
95
96use crate::xrate::get_exchange_rate;
97
98#[derive(Clone, Debug)]
105pub struct CacheView {
106 inner: Rc<RefCell<Cache>>,
107}
108
109impl CacheView {
110 #[must_use]
112 pub fn new(inner: Rc<RefCell<Cache>>) -> Self {
113 Self { inner }
114 }
115
116 pub fn borrow(&self) -> Ref<'_, Cache> {
122 self.inner.borrow()
123 }
124}
125
126impl From<Rc<RefCell<Cache>>> for CacheView {
127 fn from(inner: Rc<RefCell<Cache>>) -> Self {
128 Self::new(inner)
129 }
130}
131
132#[derive(Debug)]
139pub struct CacheApi<'a> {
140 cache: &'a RefCell<Cache>,
141}
142
143impl<'a> CacheApi<'a> {
144 pub(crate) fn new(cache: &'a RefCell<Cache>) -> Self {
145 Self { cache }
146 }
147
148 #[must_use]
154 pub fn calculate_unrealized_pnl(&self, position: &Position) -> Option<Money> {
155 self.cache().calculate_unrealized_pnl(position)
156 }
157
158 #[must_use]
164 pub fn oms_type(&self, position_id: &PositionId) -> Option<OmsType> {
165 self.cache().oms_type(position_id)
166 }
167
168 #[must_use]
174 pub fn position_snapshot_bytes(&self, position_id: &PositionId) -> Option<Vec<Vec<u8>>> {
175 self.cache().position_snapshot_bytes(position_id)
176 }
177
178 #[must_use]
184 pub fn position_snapshot_count(&self, position_id: &PositionId) -> usize {
185 self.cache().position_snapshot_count(position_id)
186 }
187
188 #[must_use]
194 pub fn position_snapshots(
195 &self,
196 position_id: Option<&PositionId>,
197 account_id: Option<&AccountId>,
198 ) -> Vec<Position> {
199 self.cache().position_snapshots(position_id, account_id)
200 }
201
202 #[must_use]
208 pub fn position_snapshots_from(&self, position_id: &PositionId, skip: usize) -> Vec<Position> {
209 self.cache().position_snapshots_from(position_id, skip)
210 }
211
212 #[must_use]
218 pub fn position_snapshot_ids(&self, instrument_id: &InstrumentId) -> AHashSet<PositionId> {
219 self.cache().position_snapshot_ids(instrument_id)
220 }
221
222 #[must_use]
228 pub fn client_order_ids(
229 &self,
230 venue: Option<&Venue>,
231 instrument_id: Option<&InstrumentId>,
232 strategy_id: Option<&StrategyId>,
233 account_id: Option<&AccountId>,
234 ) -> AHashSet<ClientOrderId> {
235 self.cache()
236 .client_order_ids(venue, instrument_id, strategy_id, account_id)
237 }
238
239 #[must_use]
245 pub fn client_order_ids_open(
246 &self,
247 venue: Option<&Venue>,
248 instrument_id: Option<&InstrumentId>,
249 strategy_id: Option<&StrategyId>,
250 account_id: Option<&AccountId>,
251 ) -> AHashSet<ClientOrderId> {
252 self.cache()
253 .client_order_ids_open(venue, instrument_id, strategy_id, account_id)
254 }
255
256 #[must_use]
262 pub fn client_order_ids_closed(
263 &self,
264 venue: Option<&Venue>,
265 instrument_id: Option<&InstrumentId>,
266 strategy_id: Option<&StrategyId>,
267 account_id: Option<&AccountId>,
268 ) -> AHashSet<ClientOrderId> {
269 self.cache()
270 .client_order_ids_closed(venue, instrument_id, strategy_id, account_id)
271 }
272
273 #[must_use]
279 pub fn client_order_ids_active_local(
280 &self,
281 venue: Option<&Venue>,
282 instrument_id: Option<&InstrumentId>,
283 strategy_id: Option<&StrategyId>,
284 account_id: Option<&AccountId>,
285 ) -> AHashSet<ClientOrderId> {
286 self.cache()
287 .client_order_ids_active_local(venue, instrument_id, strategy_id, account_id)
288 }
289
290 #[must_use]
296 pub fn client_order_ids_emulated(
297 &self,
298 venue: Option<&Venue>,
299 instrument_id: Option<&InstrumentId>,
300 strategy_id: Option<&StrategyId>,
301 account_id: Option<&AccountId>,
302 ) -> AHashSet<ClientOrderId> {
303 self.cache()
304 .client_order_ids_emulated(venue, instrument_id, strategy_id, account_id)
305 }
306
307 #[must_use]
313 pub fn client_order_ids_inflight(
314 &self,
315 venue: Option<&Venue>,
316 instrument_id: Option<&InstrumentId>,
317 strategy_id: Option<&StrategyId>,
318 account_id: Option<&AccountId>,
319 ) -> AHashSet<ClientOrderId> {
320 self.cache()
321 .client_order_ids_inflight(venue, instrument_id, strategy_id, account_id)
322 }
323
324 #[must_use]
330 pub fn position_ids(
331 &self,
332 venue: Option<&Venue>,
333 instrument_id: Option<&InstrumentId>,
334 strategy_id: Option<&StrategyId>,
335 account_id: Option<&AccountId>,
336 ) -> AHashSet<PositionId> {
337 self.cache()
338 .position_ids(venue, instrument_id, strategy_id, account_id)
339 }
340
341 #[must_use]
347 pub fn position_open_ids(
348 &self,
349 venue: Option<&Venue>,
350 instrument_id: Option<&InstrumentId>,
351 strategy_id: Option<&StrategyId>,
352 account_id: Option<&AccountId>,
353 ) -> AHashSet<PositionId> {
354 self.cache()
355 .position_open_ids(venue, instrument_id, strategy_id, account_id)
356 }
357
358 #[must_use]
364 pub fn position_closed_ids(
365 &self,
366 venue: Option<&Venue>,
367 instrument_id: Option<&InstrumentId>,
368 strategy_id: Option<&StrategyId>,
369 account_id: Option<&AccountId>,
370 ) -> AHashSet<PositionId> {
371 self.cache()
372 .position_closed_ids(venue, instrument_id, strategy_id, account_id)
373 }
374
375 #[must_use]
381 pub fn actor_ids(&self) -> AHashSet<ComponentId> {
382 self.cache().actor_ids()
383 }
384
385 #[must_use]
391 pub fn strategy_ids(&self) -> AHashSet<StrategyId> {
392 self.cache().strategy_ids()
393 }
394
395 #[must_use]
401 pub fn exec_algorithm_ids(&self) -> AHashSet<ExecAlgorithmId> {
402 self.cache().exec_algorithm_ids()
403 }
404
405 #[must_use]
411 pub fn order(&self, client_order_id: &ClientOrderId) -> Option<OrderAny> {
412 self.cache().order_owned(client_order_id)
413 }
414
415 pub fn try_order(&self, client_order_id: &ClientOrderId) -> Result<OrderAny, OrderLookupError> {
426 self.cache().try_order_owned(client_order_id)
427 }
428
429 #[must_use]
435 pub fn orders_for_ids(
436 &self,
437 client_order_ids: &[ClientOrderId],
438 context: &dyn Display,
439 ) -> Vec<OrderAny> {
440 self.cache().orders_for_ids(client_order_ids, context)
441 }
442
443 #[must_use]
449 pub fn client_order_id(&self, venue_order_id: &VenueOrderId) -> Option<ClientOrderId> {
450 self.cache().client_order_id(venue_order_id).copied()
451 }
452
453 #[must_use]
459 pub fn venue_order_id(&self, client_order_id: &ClientOrderId) -> Option<VenueOrderId> {
460 self.cache().venue_order_id(client_order_id).copied()
461 }
462
463 #[must_use]
469 pub fn client_id(&self, client_order_id: &ClientOrderId) -> Option<ClientId> {
470 self.cache().client_id(client_order_id).copied()
471 }
472
473 #[must_use]
479 pub fn orders(
480 &self,
481 venue: Option<&Venue>,
482 instrument_id: Option<&InstrumentId>,
483 strategy_id: Option<&StrategyId>,
484 account_id: Option<&AccountId>,
485 side: Option<OrderSide>,
486 ) -> Vec<OrderAny> {
487 self.cache()
488 .orders_refs(venue, instrument_id, strategy_id, account_id, side)
489 .into_iter()
490 .map(|order| order.cloned())
491 .collect()
492 }
493
494 #[must_use]
500 pub fn orders_open(
501 &self,
502 venue: Option<&Venue>,
503 instrument_id: Option<&InstrumentId>,
504 strategy_id: Option<&StrategyId>,
505 account_id: Option<&AccountId>,
506 side: Option<OrderSide>,
507 ) -> Vec<OrderAny> {
508 self.cache()
509 .orders_open_refs(venue, instrument_id, strategy_id, account_id, side)
510 .into_iter()
511 .map(|order| order.cloned())
512 .collect()
513 }
514
515 #[must_use]
521 pub fn orders_closed(
522 &self,
523 venue: Option<&Venue>,
524 instrument_id: Option<&InstrumentId>,
525 strategy_id: Option<&StrategyId>,
526 account_id: Option<&AccountId>,
527 side: Option<OrderSide>,
528 ) -> Vec<OrderAny> {
529 self.cache()
530 .orders_closed_refs(venue, instrument_id, strategy_id, account_id, side)
531 .into_iter()
532 .map(|order| order.cloned())
533 .collect()
534 }
535
536 #[must_use]
542 pub fn orders_active_local(
543 &self,
544 venue: Option<&Venue>,
545 instrument_id: Option<&InstrumentId>,
546 strategy_id: Option<&StrategyId>,
547 account_id: Option<&AccountId>,
548 side: Option<OrderSide>,
549 ) -> Vec<OrderAny> {
550 self.cache()
551 .orders_active_local_refs(venue, instrument_id, strategy_id, account_id, side)
552 .into_iter()
553 .map(|order| order.cloned())
554 .collect()
555 }
556
557 #[must_use]
563 pub fn orders_emulated(
564 &self,
565 venue: Option<&Venue>,
566 instrument_id: Option<&InstrumentId>,
567 strategy_id: Option<&StrategyId>,
568 account_id: Option<&AccountId>,
569 side: Option<OrderSide>,
570 ) -> Vec<OrderAny> {
571 self.cache()
572 .orders_emulated_refs(venue, instrument_id, strategy_id, account_id, side)
573 .into_iter()
574 .map(|order| order.cloned())
575 .collect()
576 }
577
578 #[must_use]
584 pub fn orders_inflight(
585 &self,
586 venue: Option<&Venue>,
587 instrument_id: Option<&InstrumentId>,
588 strategy_id: Option<&StrategyId>,
589 account_id: Option<&AccountId>,
590 side: Option<OrderSide>,
591 ) -> Vec<OrderAny> {
592 self.cache()
593 .orders_inflight_refs(venue, instrument_id, strategy_id, account_id, side)
594 .into_iter()
595 .map(|order| order.cloned())
596 .collect()
597 }
598
599 #[must_use]
605 pub fn orders_for_position(&self, position_id: &PositionId) -> Vec<OrderAny> {
606 self.cache()
607 .orders_for_position(position_id)
608 .into_iter()
609 .map(|order| order.cloned())
610 .collect()
611 }
612
613 #[must_use]
619 pub fn order_exists(&self, client_order_id: &ClientOrderId) -> bool {
620 self.cache().order_exists(client_order_id)
621 }
622
623 #[must_use]
629 pub fn is_order_open(&self, client_order_id: &ClientOrderId) -> bool {
630 self.cache().is_order_open(client_order_id)
631 }
632
633 #[must_use]
639 pub fn is_order_closed(&self, client_order_id: &ClientOrderId) -> bool {
640 self.cache().is_order_closed(client_order_id)
641 }
642
643 #[must_use]
649 pub fn is_order_active_local(&self, client_order_id: &ClientOrderId) -> bool {
650 self.cache().is_order_active_local(client_order_id)
651 }
652
653 #[must_use]
659 pub fn is_order_emulated(&self, client_order_id: &ClientOrderId) -> bool {
660 self.cache().is_order_emulated(client_order_id)
661 }
662
663 #[must_use]
669 pub fn is_order_inflight(&self, client_order_id: &ClientOrderId) -> bool {
670 self.cache().is_order_inflight(client_order_id)
671 }
672
673 #[must_use]
679 pub fn is_order_pending_cancel_local(&self, client_order_id: &ClientOrderId) -> bool {
680 self.cache().is_order_pending_cancel_local(client_order_id)
681 }
682
683 #[must_use]
689 pub fn orders_open_count(
690 &self,
691 venue: Option<&Venue>,
692 instrument_id: Option<&InstrumentId>,
693 strategy_id: Option<&StrategyId>,
694 account_id: Option<&AccountId>,
695 side: Option<OrderSide>,
696 ) -> usize {
697 self.cache()
698 .orders_open_count(venue, instrument_id, strategy_id, account_id, side)
699 }
700
701 #[must_use]
707 pub fn orders_closed_count(
708 &self,
709 venue: Option<&Venue>,
710 instrument_id: Option<&InstrumentId>,
711 strategy_id: Option<&StrategyId>,
712 account_id: Option<&AccountId>,
713 side: Option<OrderSide>,
714 ) -> usize {
715 self.cache()
716 .orders_closed_count(venue, instrument_id, strategy_id, account_id, side)
717 }
718
719 #[must_use]
725 pub fn orders_active_local_count(
726 &self,
727 venue: Option<&Venue>,
728 instrument_id: Option<&InstrumentId>,
729 strategy_id: Option<&StrategyId>,
730 account_id: Option<&AccountId>,
731 side: Option<OrderSide>,
732 ) -> usize {
733 self.cache()
734 .orders_active_local_count(venue, instrument_id, strategy_id, account_id, side)
735 }
736
737 #[must_use]
743 pub fn orders_emulated_count(
744 &self,
745 venue: Option<&Venue>,
746 instrument_id: Option<&InstrumentId>,
747 strategy_id: Option<&StrategyId>,
748 account_id: Option<&AccountId>,
749 side: Option<OrderSide>,
750 ) -> usize {
751 self.cache()
752 .orders_emulated_count(venue, instrument_id, strategy_id, account_id, side)
753 }
754
755 #[must_use]
761 pub fn orders_inflight_count(
762 &self,
763 venue: Option<&Venue>,
764 instrument_id: Option<&InstrumentId>,
765 strategy_id: Option<&StrategyId>,
766 account_id: Option<&AccountId>,
767 side: Option<OrderSide>,
768 ) -> usize {
769 self.cache()
770 .orders_inflight_count(venue, instrument_id, strategy_id, account_id, side)
771 }
772
773 #[must_use]
779 pub fn orders_total_count(
780 &self,
781 venue: Option<&Venue>,
782 instrument_id: Option<&InstrumentId>,
783 strategy_id: Option<&StrategyId>,
784 account_id: Option<&AccountId>,
785 side: Option<OrderSide>,
786 ) -> usize {
787 self.cache()
788 .orders_total_count(venue, instrument_id, strategy_id, account_id, side)
789 }
790
791 #[must_use]
797 pub fn has_orders_open(
798 &self,
799 venue: Option<&Venue>,
800 instrument_id: Option<&InstrumentId>,
801 strategy_id: Option<&StrategyId>,
802 account_id: Option<&AccountId>,
803 side: Option<OrderSide>,
804 ) -> bool {
805 self.cache()
806 .has_orders_open(venue, instrument_id, strategy_id, account_id, side)
807 }
808
809 #[must_use]
815 pub fn has_orders_closed(
816 &self,
817 venue: Option<&Venue>,
818 instrument_id: Option<&InstrumentId>,
819 strategy_id: Option<&StrategyId>,
820 account_id: Option<&AccountId>,
821 side: Option<OrderSide>,
822 ) -> bool {
823 self.cache()
824 .has_orders_closed(venue, instrument_id, strategy_id, account_id, side)
825 }
826
827 #[must_use]
833 pub fn has_orders_active_local(
834 &self,
835 venue: Option<&Venue>,
836 instrument_id: Option<&InstrumentId>,
837 strategy_id: Option<&StrategyId>,
838 account_id: Option<&AccountId>,
839 side: Option<OrderSide>,
840 ) -> bool {
841 self.cache()
842 .has_orders_active_local(venue, instrument_id, strategy_id, account_id, side)
843 }
844
845 #[must_use]
851 pub fn has_orders_emulated(
852 &self,
853 venue: Option<&Venue>,
854 instrument_id: Option<&InstrumentId>,
855 strategy_id: Option<&StrategyId>,
856 account_id: Option<&AccountId>,
857 side: Option<OrderSide>,
858 ) -> bool {
859 self.cache()
860 .has_orders_emulated(venue, instrument_id, strategy_id, account_id, side)
861 }
862
863 #[must_use]
869 pub fn has_orders_inflight(
870 &self,
871 venue: Option<&Venue>,
872 instrument_id: Option<&InstrumentId>,
873 strategy_id: Option<&StrategyId>,
874 account_id: Option<&AccountId>,
875 side: Option<OrderSide>,
876 ) -> bool {
877 self.cache()
878 .has_orders_inflight(venue, instrument_id, strategy_id, account_id, side)
879 }
880
881 #[must_use]
887 pub fn has_orders(
888 &self,
889 venue: Option<&Venue>,
890 instrument_id: Option<&InstrumentId>,
891 strategy_id: Option<&StrategyId>,
892 account_id: Option<&AccountId>,
893 side: Option<OrderSide>,
894 ) -> bool {
895 self.cache()
896 .has_orders(venue, instrument_id, strategy_id, account_id, side)
897 }
898
899 #[must_use]
905 pub fn order_list(&self, order_list_id: &OrderListId) -> Option<OrderList> {
906 self.cache().order_list(order_list_id).cloned()
907 }
908
909 pub fn try_order_list(
920 &self,
921 order_list_id: &OrderListId,
922 ) -> Result<OrderList, OrderListLookupError> {
923 self.cache().try_order_list(order_list_id).cloned()
924 }
925
926 #[must_use]
932 pub fn order_lists(
933 &self,
934 venue: Option<&Venue>,
935 instrument_id: Option<&InstrumentId>,
936 strategy_id: Option<&StrategyId>,
937 account_id: Option<&AccountId>,
938 ) -> Vec<OrderList> {
939 self.cache()
940 .order_lists(venue, instrument_id, strategy_id, account_id)
941 .into_iter()
942 .cloned()
943 .collect()
944 }
945
946 #[must_use]
952 pub fn order_list_exists(&self, order_list_id: &OrderListId) -> bool {
953 self.cache().order_list_exists(order_list_id)
954 }
955
956 #[must_use]
962 pub fn orders_for_exec_algorithm(
963 &self,
964 exec_algorithm_id: &ExecAlgorithmId,
965 venue: Option<&Venue>,
966 instrument_id: Option<&InstrumentId>,
967 strategy_id: Option<&StrategyId>,
968 account_id: Option<&AccountId>,
969 side: Option<OrderSide>,
970 ) -> Vec<OrderAny> {
971 self.cache()
972 .orders_for_exec_algorithm(
973 exec_algorithm_id,
974 venue,
975 instrument_id,
976 strategy_id,
977 account_id,
978 side,
979 )
980 .into_iter()
981 .map(|order| order.cloned())
982 .collect()
983 }
984
985 #[must_use]
991 pub fn orders_for_exec_spawn(&self, exec_spawn_id: &ClientOrderId) -> Vec<OrderAny> {
992 self.cache()
993 .orders_for_exec_spawn(exec_spawn_id)
994 .into_iter()
995 .map(|order| order.cloned())
996 .collect()
997 }
998
999 #[must_use]
1005 pub fn exec_spawn_total_quantity(
1006 &self,
1007 exec_spawn_id: &ClientOrderId,
1008 active_only: bool,
1009 ) -> Option<Quantity> {
1010 self.cache()
1011 .exec_spawn_total_quantity(exec_spawn_id, active_only)
1012 }
1013
1014 #[must_use]
1020 pub fn exec_spawn_total_filled_qty(
1021 &self,
1022 exec_spawn_id: &ClientOrderId,
1023 active_only: bool,
1024 ) -> Option<Quantity> {
1025 self.cache()
1026 .exec_spawn_total_filled_qty(exec_spawn_id, active_only)
1027 }
1028
1029 #[must_use]
1035 pub fn exec_spawn_total_leaves_qty(
1036 &self,
1037 exec_spawn_id: &ClientOrderId,
1038 active_only: bool,
1039 ) -> Option<Quantity> {
1040 self.cache()
1041 .exec_spawn_total_leaves_qty(exec_spawn_id, active_only)
1042 }
1043
1044 #[must_use]
1050 pub fn position(&self, position_id: &PositionId) -> Option<Position> {
1051 self.cache()
1052 .position_ref(position_id)
1053 .map(|position| position.cloned())
1054 }
1055
1056 pub fn try_position(&self, position_id: &PositionId) -> Result<Position, PositionLookupError> {
1067 self.cache()
1068 .try_position_ref(position_id)
1069 .map(|position| position.cloned())
1070 }
1071
1072 #[must_use]
1078 pub fn position_for_order(&self, client_order_id: &ClientOrderId) -> Option<Position> {
1079 self.cache()
1080 .position_for_order_ref(client_order_id)
1081 .map(|position| position.cloned())
1082 }
1083
1084 #[must_use]
1090 pub fn position_id(&self, client_order_id: &ClientOrderId) -> Option<PositionId> {
1091 self.cache().position_id(client_order_id).copied()
1092 }
1093
1094 #[must_use]
1100 pub fn positions(
1101 &self,
1102 venue: Option<&Venue>,
1103 instrument_id: Option<&InstrumentId>,
1104 strategy_id: Option<&StrategyId>,
1105 account_id: Option<&AccountId>,
1106 side: Option<PositionSide>,
1107 ) -> Vec<Position> {
1108 self.cache()
1109 .positions_refs(venue, instrument_id, strategy_id, account_id, side)
1110 .into_iter()
1111 .map(|position| position.cloned())
1112 .collect()
1113 }
1114
1115 #[must_use]
1121 pub fn positions_open(
1122 &self,
1123 venue: Option<&Venue>,
1124 instrument_id: Option<&InstrumentId>,
1125 strategy_id: Option<&StrategyId>,
1126 account_id: Option<&AccountId>,
1127 side: Option<PositionSide>,
1128 ) -> Vec<Position> {
1129 self.cache()
1130 .positions_open_refs(venue, instrument_id, strategy_id, account_id, side)
1131 .into_iter()
1132 .map(|position| position.cloned())
1133 .collect()
1134 }
1135
1136 #[must_use]
1142 pub fn positions_closed(
1143 &self,
1144 venue: Option<&Venue>,
1145 instrument_id: Option<&InstrumentId>,
1146 strategy_id: Option<&StrategyId>,
1147 account_id: Option<&AccountId>,
1148 side: Option<PositionSide>,
1149 ) -> Vec<Position> {
1150 self.cache()
1151 .positions_closed_refs(venue, instrument_id, strategy_id, account_id, side)
1152 .into_iter()
1153 .map(|position| position.cloned())
1154 .collect()
1155 }
1156
1157 #[must_use]
1163 pub fn position_exists(&self, position_id: &PositionId) -> bool {
1164 self.cache().position_exists(position_id)
1165 }
1166
1167 #[must_use]
1173 pub fn is_position_open(&self, position_id: &PositionId) -> bool {
1174 self.cache().is_position_open(position_id)
1175 }
1176
1177 #[must_use]
1183 pub fn is_position_closed(&self, position_id: &PositionId) -> bool {
1184 self.cache().is_position_closed(position_id)
1185 }
1186
1187 #[must_use]
1193 pub fn positions_open_count(
1194 &self,
1195 venue: Option<&Venue>,
1196 instrument_id: Option<&InstrumentId>,
1197 strategy_id: Option<&StrategyId>,
1198 account_id: Option<&AccountId>,
1199 side: Option<PositionSide>,
1200 ) -> usize {
1201 self.cache()
1202 .positions_open_count(venue, instrument_id, strategy_id, account_id, side)
1203 }
1204
1205 #[must_use]
1211 pub fn positions_closed_count(
1212 &self,
1213 venue: Option<&Venue>,
1214 instrument_id: Option<&InstrumentId>,
1215 strategy_id: Option<&StrategyId>,
1216 account_id: Option<&AccountId>,
1217 side: Option<PositionSide>,
1218 ) -> usize {
1219 self.cache()
1220 .positions_closed_count(venue, instrument_id, strategy_id, account_id, side)
1221 }
1222
1223 #[must_use]
1229 pub fn positions_total_count(
1230 &self,
1231 venue: Option<&Venue>,
1232 instrument_id: Option<&InstrumentId>,
1233 strategy_id: Option<&StrategyId>,
1234 account_id: Option<&AccountId>,
1235 side: Option<PositionSide>,
1236 ) -> usize {
1237 self.cache()
1238 .positions_total_count(venue, instrument_id, strategy_id, account_id, side)
1239 }
1240
1241 #[must_use]
1247 pub fn has_positions_open(
1248 &self,
1249 venue: Option<&Venue>,
1250 instrument_id: Option<&InstrumentId>,
1251 strategy_id: Option<&StrategyId>,
1252 account_id: Option<&AccountId>,
1253 side: Option<PositionSide>,
1254 ) -> bool {
1255 self.cache()
1256 .has_positions_open(venue, instrument_id, strategy_id, account_id, side)
1257 }
1258
1259 #[must_use]
1265 pub fn has_positions_closed(
1266 &self,
1267 venue: Option<&Venue>,
1268 instrument_id: Option<&InstrumentId>,
1269 strategy_id: Option<&StrategyId>,
1270 account_id: Option<&AccountId>,
1271 side: Option<PositionSide>,
1272 ) -> bool {
1273 self.cache()
1274 .has_positions_closed(venue, instrument_id, strategy_id, account_id, side)
1275 }
1276
1277 #[must_use]
1283 pub fn has_positions(
1284 &self,
1285 venue: Option<&Venue>,
1286 instrument_id: Option<&InstrumentId>,
1287 strategy_id: Option<&StrategyId>,
1288 account_id: Option<&AccountId>,
1289 side: Option<PositionSide>,
1290 ) -> bool {
1291 self.cache()
1292 .has_positions(venue, instrument_id, strategy_id, account_id, side)
1293 }
1294
1295 #[must_use]
1301 pub fn strategy_id_for_order(&self, client_order_id: &ClientOrderId) -> Option<StrategyId> {
1302 self.cache().strategy_id_for_order(client_order_id).copied()
1303 }
1304
1305 #[must_use]
1311 pub fn strategy_id_for_position(&self, position_id: &PositionId) -> Option<StrategyId> {
1312 self.cache().strategy_id_for_position(position_id).copied()
1313 }
1314
1315 pub fn get(&self, key: &str) -> anyhow::Result<Option<Bytes>> {
1326 let cache = self.cache();
1327 let value = cache.get(key)?;
1328 Ok(value.cloned())
1329 }
1330
1331 #[must_use]
1338 pub fn price(&self, instrument_id: &InstrumentId, price_type: PriceType) -> Option<Price> {
1339 self.cache().price(instrument_id, price_type)
1340 }
1341
1342 #[must_use]
1348 pub fn quotes(&self, instrument_id: &InstrumentId) -> Option<Vec<QuoteTick>> {
1349 self.cache().quotes(instrument_id)
1350 }
1351
1352 #[must_use]
1358 pub fn trades(&self, instrument_id: &InstrumentId) -> Option<Vec<TradeTick>> {
1359 self.cache().trades(instrument_id)
1360 }
1361
1362 #[must_use]
1368 pub fn mark_prices(&self, instrument_id: &InstrumentId) -> Option<Vec<MarkPriceUpdate>> {
1369 self.cache().mark_prices(instrument_id)
1370 }
1371
1372 #[must_use]
1378 pub fn index_prices(&self, instrument_id: &InstrumentId) -> Option<Vec<IndexPriceUpdate>> {
1379 self.cache().index_prices(instrument_id)
1380 }
1381
1382 #[must_use]
1388 pub fn funding_rates(&self, instrument_id: &InstrumentId) -> Option<Vec<FundingRateUpdate>> {
1389 self.cache().funding_rates(instrument_id)
1390 }
1391
1392 #[must_use]
1398 pub fn instrument_statuses(
1399 &self,
1400 instrument_id: &InstrumentId,
1401 ) -> Option<Vec<InstrumentStatus>> {
1402 self.cache().instrument_statuses(instrument_id)
1403 }
1404
1405 #[must_use]
1411 pub fn bars(&self, bar_type: &BarType) -> Option<Vec<Bar>> {
1412 self.cache().bars(bar_type)
1413 }
1414
1415 #[must_use]
1421 pub fn order_book(&self, instrument_id: &InstrumentId) -> Option<OrderBook> {
1422 self.cache().order_book(instrument_id).cloned()
1423 }
1424
1425 pub fn try_order_book(
1436 &self,
1437 instrument_id: &InstrumentId,
1438 ) -> Result<OrderBook, OrderBookLookupError> {
1439 self.cache().try_order_book(instrument_id).cloned()
1440 }
1441
1442 #[must_use]
1448 pub fn own_order_book(&self, instrument_id: &InstrumentId) -> Option<OwnOrderBook> {
1449 self.cache().own_order_book(instrument_id).cloned()
1450 }
1451
1452 pub fn try_own_order_book(
1464 &self,
1465 instrument_id: &InstrumentId,
1466 ) -> Result<OwnOrderBook, OwnOrderBookLookupError> {
1467 self.cache().try_own_order_book(instrument_id).cloned()
1468 }
1469
1470 #[must_use]
1476 pub fn quote(&self, instrument_id: &InstrumentId) -> Option<QuoteTick> {
1477 self.cache().quote(instrument_id).copied()
1478 }
1479
1480 #[must_use]
1488 pub fn quote_at_index(&self, instrument_id: &InstrumentId, index: usize) -> Option<QuoteTick> {
1489 self.cache().quote_at_index(instrument_id, index).copied()
1490 }
1491
1492 #[must_use]
1498 pub fn trade(&self, instrument_id: &InstrumentId) -> Option<TradeTick> {
1499 self.cache().trade(instrument_id).copied()
1500 }
1501
1502 #[must_use]
1510 pub fn trade_at_index(&self, instrument_id: &InstrumentId, index: usize) -> Option<TradeTick> {
1511 self.cache().trade_at_index(instrument_id, index).copied()
1512 }
1513
1514 #[must_use]
1520 pub fn mark_price(&self, instrument_id: &InstrumentId) -> Option<MarkPriceUpdate> {
1521 self.cache().mark_price(instrument_id).copied()
1522 }
1523
1524 #[must_use]
1530 pub fn index_price(&self, instrument_id: &InstrumentId) -> Option<IndexPriceUpdate> {
1531 self.cache().index_price(instrument_id).copied()
1532 }
1533
1534 #[must_use]
1540 pub fn funding_rate(&self, instrument_id: &InstrumentId) -> Option<FundingRateUpdate> {
1541 self.cache().funding_rate(instrument_id).copied()
1542 }
1543
1544 #[must_use]
1550 pub fn instrument_status(&self, instrument_id: &InstrumentId) -> Option<InstrumentStatus> {
1551 self.cache().instrument_status(instrument_id).copied()
1552 }
1553
1554 #[must_use]
1560 pub fn bar(&self, bar_type: &BarType) -> Option<Bar> {
1561 self.cache().bar(bar_type).copied()
1562 }
1563
1564 #[must_use]
1572 pub fn bar_at_index(&self, bar_type: &BarType, index: usize) -> Option<Bar> {
1573 self.cache().bar_at_index(bar_type, index).copied()
1574 }
1575
1576 #[must_use]
1582 pub fn book_update_count(&self, instrument_id: &InstrumentId) -> usize {
1583 self.cache().book_update_count(instrument_id)
1584 }
1585
1586 #[must_use]
1592 pub fn quote_count(&self, instrument_id: &InstrumentId) -> usize {
1593 self.cache().quote_count(instrument_id)
1594 }
1595
1596 #[must_use]
1602 pub fn trade_count(&self, instrument_id: &InstrumentId) -> usize {
1603 self.cache().trade_count(instrument_id)
1604 }
1605
1606 #[must_use]
1612 pub fn mark_price_count(&self, instrument_id: &InstrumentId) -> usize {
1613 self.cache().mark_price_count(instrument_id)
1614 }
1615
1616 #[must_use]
1622 pub fn index_price_count(&self, instrument_id: &InstrumentId) -> usize {
1623 self.cache().index_price_count(instrument_id)
1624 }
1625
1626 #[must_use]
1632 pub fn funding_rate_count(&self, instrument_id: &InstrumentId) -> usize {
1633 self.cache().funding_rate_count(instrument_id)
1634 }
1635
1636 #[must_use]
1642 pub fn instrument_status_count(&self, instrument_id: &InstrumentId) -> usize {
1643 self.cache().instrument_status_count(instrument_id)
1644 }
1645
1646 #[must_use]
1652 pub fn bar_count(&self, bar_type: &BarType) -> usize {
1653 self.cache().bar_count(bar_type)
1654 }
1655
1656 #[must_use]
1662 pub fn has_order_book(&self, instrument_id: &InstrumentId) -> bool {
1663 self.cache().has_order_book(instrument_id)
1664 }
1665
1666 #[must_use]
1672 pub fn has_quote_ticks(&self, instrument_id: &InstrumentId) -> bool {
1673 self.cache().has_quote_ticks(instrument_id)
1674 }
1675
1676 #[must_use]
1682 pub fn has_trade_ticks(&self, instrument_id: &InstrumentId) -> bool {
1683 self.cache().has_trade_ticks(instrument_id)
1684 }
1685
1686 #[must_use]
1692 pub fn has_mark_prices(&self, instrument_id: &InstrumentId) -> bool {
1693 self.cache().has_mark_prices(instrument_id)
1694 }
1695
1696 #[must_use]
1702 pub fn has_index_prices(&self, instrument_id: &InstrumentId) -> bool {
1703 self.cache().has_index_prices(instrument_id)
1704 }
1705
1706 #[must_use]
1712 pub fn has_funding_rates(&self, instrument_id: &InstrumentId) -> bool {
1713 self.cache().has_funding_rates(instrument_id)
1714 }
1715
1716 #[must_use]
1722 pub fn has_instrument_statuses(&self, instrument_id: &InstrumentId) -> bool {
1723 self.cache().has_instrument_statuses(instrument_id)
1724 }
1725
1726 #[must_use]
1732 pub fn has_bars(&self, bar_type: &BarType) -> bool {
1733 self.cache().has_bars(bar_type)
1734 }
1735
1736 #[must_use]
1742 pub fn get_xrate(
1743 &self,
1744 venue: Venue,
1745 from_currency: Currency,
1746 to_currency: Currency,
1747 price_type: PriceType,
1748 ) -> Option<Decimal> {
1749 self.cache()
1750 .get_xrate(venue, from_currency, to_currency, price_type)
1751 }
1752
1753 #[must_use]
1759 pub fn get_mark_xrate(&self, from_currency: Currency, to_currency: Currency) -> Option<f64> {
1760 self.cache().get_mark_xrate(from_currency, to_currency)
1761 }
1762
1763 #[must_use]
1769 pub fn yield_curve(&self, key: &str) -> Option<Box<dyn Fn(f64) -> f64>> {
1770 self.cache().yield_curve(key)
1771 }
1772
1773 #[must_use]
1779 pub fn greeks(&self, instrument_id: &InstrumentId) -> Option<GreeksData> {
1780 self.cache().greeks(instrument_id)
1781 }
1782
1783 #[must_use]
1789 pub fn option_greeks(&self, instrument_id: &InstrumentId) -> Option<OptionGreeks> {
1790 self.cache().option_greeks(instrument_id).copied()
1791 }
1792
1793 #[must_use]
1799 pub fn currency(&self, code: &Ustr) -> Option<Currency> {
1800 self.cache().currency(code).copied()
1801 }
1802
1803 pub fn try_currency(&self, code: &Ustr) -> Result<Currency, CurrencyLookupError> {
1814 self.cache().try_currency(code).copied()
1815 }
1816
1817 #[must_use]
1823 pub fn instrument(&self, instrument_id: &InstrumentId) -> Option<InstrumentAny> {
1824 self.cache().instrument(instrument_id).cloned()
1825 }
1826
1827 pub fn try_instrument(
1838 &self,
1839 instrument_id: &InstrumentId,
1840 ) -> Result<InstrumentAny, InstrumentLookupError> {
1841 self.cache().try_instrument(instrument_id).cloned()
1842 }
1843
1844 #[must_use]
1850 pub fn instrument_ids(&self, venue: Option<&Venue>) -> Vec<InstrumentId> {
1851 self.cache()
1852 .instrument_ids(venue)
1853 .into_iter()
1854 .copied()
1855 .collect()
1856 }
1857
1858 #[must_use]
1864 pub fn instruments(&self, venue: &Venue, underlying: Option<&Ustr>) -> Vec<InstrumentAny> {
1865 self.cache()
1866 .instruments(venue, underlying)
1867 .into_iter()
1868 .cloned()
1869 .collect()
1870 }
1871
1872 #[must_use]
1879 pub fn instruments_by_parent(
1880 &self,
1881 venue: &Venue,
1882 root: &Ustr,
1883 class: InstrumentClass,
1884 ) -> Vec<InstrumentAny> {
1885 self.cache()
1886 .instruments_by_parent(venue, root, class)
1887 .into_iter()
1888 .cloned()
1889 .collect()
1890 }
1891
1892 #[must_use]
1898 pub fn bar_types(
1899 &self,
1900 instrument_id: Option<&InstrumentId>,
1901 price_type: Option<&PriceType>,
1902 aggregation_source: AggregationSource,
1903 ) -> Vec<BarType> {
1904 self.cache()
1905 .bar_types(instrument_id, price_type, aggregation_source)
1906 .into_iter()
1907 .copied()
1908 .collect()
1909 }
1910
1911 #[must_use]
1917 pub fn synthetic(&self, instrument_id: &InstrumentId) -> Option<SyntheticInstrument> {
1918 self.cache().synthetic(instrument_id).cloned()
1919 }
1920
1921 pub fn try_synthetic(
1933 &self,
1934 instrument_id: &InstrumentId,
1935 ) -> Result<SyntheticInstrument, SyntheticInstrumentLookupError> {
1936 self.cache().try_synthetic(instrument_id).cloned()
1937 }
1938
1939 #[must_use]
1945 pub fn synthetic_ids(&self) -> Vec<InstrumentId> {
1946 self.cache().synthetic_ids().into_iter().copied().collect()
1947 }
1948
1949 #[must_use]
1955 pub fn synthetics(&self) -> Vec<SyntheticInstrument> {
1956 self.cache().synthetics().into_iter().cloned().collect()
1957 }
1958
1959 #[cfg(feature = "defi")]
1965 #[must_use]
1966 pub fn pool(&self, instrument_id: &InstrumentId) -> Option<Pool> {
1967 self.cache().pool(instrument_id).cloned()
1968 }
1969
1970 #[cfg(feature = "defi")]
1976 #[must_use]
1977 pub fn pool_ids(&self, venue: Option<&Venue>) -> Vec<InstrumentId> {
1978 self.cache().pool_ids(venue)
1979 }
1980
1981 #[cfg(feature = "defi")]
1987 #[must_use]
1988 pub fn pools(&self, venue: Option<&Venue>) -> Vec<Pool> {
1989 self.cache().pools(venue).into_iter().cloned().collect()
1990 }
1991
1992 #[cfg(feature = "defi")]
1998 #[must_use]
1999 pub fn pool_profiler(&self, instrument_id: &InstrumentId) -> Option<PoolProfiler> {
2000 self.cache().pool_profiler(instrument_id).cloned()
2001 }
2002
2003 #[cfg(feature = "defi")]
2009 #[must_use]
2010 pub fn pool_profiler_ids(&self, venue: Option<&Venue>) -> Vec<InstrumentId> {
2011 self.cache().pool_profiler_ids(venue)
2012 }
2013
2014 #[cfg(feature = "defi")]
2020 #[must_use]
2021 pub fn pool_profilers(&self, venue: Option<&Venue>) -> Vec<PoolProfiler> {
2022 self.cache()
2023 .pool_profilers(venue)
2024 .into_iter()
2025 .cloned()
2026 .collect()
2027 }
2028
2029 #[must_use]
2035 pub fn account(&self, account_id: &AccountId) -> Option<AccountAny> {
2036 self.cache().account_owned(account_id)
2037 }
2038
2039 pub fn try_account(&self, account_id: &AccountId) -> Result<AccountAny, AccountLookupError> {
2050 self.cache()
2051 .try_account(account_id)
2052 .map(|account| account.cloned())
2053 }
2054
2055 #[must_use]
2061 pub fn account_for_venue(&self, venue: &Venue) -> Option<AccountAny> {
2062 self.cache().account_for_venue_owned(venue)
2063 }
2064
2065 #[must_use]
2071 pub fn account_id(&self, venue: &Venue) -> Option<AccountId> {
2072 self.cache().account_id(venue).copied()
2073 }
2074
2075 #[must_use]
2081 pub fn accounts(&self, account_id: &AccountId) -> Vec<AccountAny> {
2082 self.cache()
2083 .accounts(account_id)
2084 .into_iter()
2085 .map(|account| account.cloned())
2086 .collect()
2087 }
2088
2089 #[must_use]
2095 pub fn accounts_all(&self) -> Vec<AccountAny> {
2096 self.cache().accounts_all_owned()
2097 }
2098
2099 fn cache(&self) -> Ref<'_, Cache> {
2100 self.cache.borrow()
2101 }
2102}
2103
2104enum FilterSources<'a, K> {
2111 Unfiltered,
2112 Empty,
2113 Sets(Vec<&'a AHashSet<K>>),
2114}
2115
2116fn intersect_filter_sources<K>(mut sources: Vec<&AHashSet<K>>) -> AHashSet<K>
2122where
2123 K: Copy + Eq + std::hash::Hash,
2124{
2125 debug_assert!(!sources.is_empty());
2126 sources.sort_unstable_by_key(|s| s.len());
2127 let driver = sources[0];
2128 let rest = &sources[1..];
2129
2130 if rest.is_empty() {
2131 return driver.clone();
2132 }
2133
2134 driver
2135 .iter()
2136 .filter(|id| rest.iter().all(|s| s.contains(id)))
2137 .copied()
2138 .collect()
2139}
2140
2141fn intersect_pair_or_many<'a, K>(
2149 bucket: &'a AHashSet<K>,
2150 mut sources: Vec<&'a AHashSet<K>>,
2151) -> AHashSet<K>
2152where
2153 K: Copy + Eq + std::hash::Hash,
2154{
2155 debug_assert!(!sources.is_empty());
2156 if sources.len() == 1 {
2157 let filter = sources[0];
2158 let (larger, smaller) = if bucket.len() >= filter.len() {
2159 (bucket, filter)
2160 } else {
2161 (filter, bucket)
2162 };
2163 return larger.intersection(smaller).copied().collect();
2164 }
2165
2166 sources.push(bucket);
2167 intersect_filter_sources(sources)
2168}
2169
2170#[cfg_attr(
2172 feature = "python",
2173 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.common", unsendable)
2174)]
2175pub struct Cache {
2176 config: CacheConfig,
2177 index: CacheIndex,
2178 database: Option<Box<dyn CacheDatabaseAdapter>>,
2179 general: AHashMap<String, Bytes>,
2180 currencies: AHashMap<Ustr, Currency>,
2181 instruments: AHashMap<InstrumentId, InstrumentAny>,
2182 synthetics: AHashMap<InstrumentId, SyntheticInstrument>,
2183 books: AHashMap<InstrumentId, OrderBook>,
2184 own_books: AHashMap<InstrumentId, OwnOrderBook>,
2185 quotes: AHashMap<InstrumentId, BoundedVecDeque<QuoteTick>>,
2186 trades: AHashMap<InstrumentId, BoundedVecDeque<TradeTick>>,
2187 mark_xrates: AHashMap<(Currency, Currency), f64>,
2188 mark_prices: AHashMap<InstrumentId, BoundedVecDeque<MarkPriceUpdate>>,
2189 index_prices: AHashMap<InstrumentId, BoundedVecDeque<IndexPriceUpdate>>,
2190 funding_rates: AHashMap<InstrumentId, BoundedVecDeque<FundingRateUpdate>>,
2191 instrument_statuses: AHashMap<InstrumentId, BoundedVecDeque<InstrumentStatus>>,
2192 bars: AHashMap<BarType, BoundedVecDeque<Bar>>,
2193 greeks: AHashMap<InstrumentId, GreeksData>,
2194 option_greeks: AHashMap<InstrumentId, OptionGreeks>,
2195 yield_curves: AHashMap<String, YieldCurveData>,
2196 accounts: AHashMap<AccountId, SharedCell<AccountAny>>,
2197 orders: AHashMap<ClientOrderId, SharedCell<OrderAny>>,
2198 order_lists: AHashMap<OrderListId, OrderList>,
2199 positions: AHashMap<PositionId, SharedCell<Position>>,
2200 position_snapshots: AHashMap<PositionId, Vec<PositionSnapshotFrame>>,
2201 position_snapshot_revisions: AHashMap<PositionId, u64>,
2202 #[cfg(feature = "defi")]
2203 pub(crate) defi: crate::defi::cache::DefiCache,
2204}
2205
2206impl Debug for Cache {
2207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2208 f.debug_struct(stringify!(Cache))
2209 .field("config", &self.config)
2210 .field("index", &self.index)
2211 .field("general", &self.general)
2212 .field("currencies", &self.currencies)
2213 .field("instruments", &self.instruments)
2214 .field("synthetics", &self.synthetics)
2215 .field("books", &self.books)
2216 .field("own_books", &self.own_books)
2217 .field("quotes", &self.quotes)
2218 .field("trades", &self.trades)
2219 .field("mark_xrates", &self.mark_xrates)
2220 .field("mark_prices", &self.mark_prices)
2221 .field("index_prices", &self.index_prices)
2222 .field("funding_rates", &self.funding_rates)
2223 .field("instrument_statuses", &self.instrument_statuses)
2224 .field("bars", &self.bars)
2225 .field("greeks", &self.greeks)
2226 .field("option_greeks", &self.option_greeks)
2227 .field("yield_curves", &self.yield_curves)
2228 .field("accounts", &self.accounts)
2229 .field("orders", &self.orders)
2230 .field("order_lists", &self.order_lists)
2231 .field("positions", &self.positions)
2232 .field("position_snapshots", &self.position_snapshots)
2233 .finish()
2234 }
2235}
2236
2237impl Default for Cache {
2238 fn default() -> Self {
2240 Self::new(Some(CacheConfig::default()), None)
2241 }
2242}
2243
2244impl Cache {
2245 #[must_use]
2247 pub fn new(
2255 config: Option<CacheConfig>,
2256 database: Option<Box<dyn CacheDatabaseAdapter>>,
2257 ) -> Self {
2258 let config = config.unwrap_or_default();
2259 config.validate().expect("invalid `CacheConfig`");
2260
2261 Self {
2262 config,
2263 index: CacheIndex::default(),
2264 database,
2265 general: AHashMap::new(),
2266 currencies: AHashMap::new(),
2267 instruments: AHashMap::new(),
2268 synthetics: AHashMap::new(),
2269 books: AHashMap::new(),
2270 own_books: AHashMap::new(),
2271 quotes: AHashMap::new(),
2272 trades: AHashMap::new(),
2273 mark_xrates: AHashMap::new(),
2274 mark_prices: AHashMap::new(),
2275 index_prices: AHashMap::new(),
2276 funding_rates: AHashMap::new(),
2277 instrument_statuses: AHashMap::new(),
2278 bars: AHashMap::new(),
2279 greeks: AHashMap::new(),
2280 option_greeks: AHashMap::new(),
2281 yield_curves: AHashMap::new(),
2282 accounts: AHashMap::new(),
2283 orders: AHashMap::new(),
2284 order_lists: AHashMap::new(),
2285 positions: AHashMap::new(),
2286 position_snapshots: AHashMap::new(),
2287 position_snapshot_revisions: AHashMap::new(),
2288 #[cfg(feature = "defi")]
2289 defi: crate::defi::cache::DefiCache::default(),
2290 }
2291 }
2292
2293 #[must_use]
2295 pub fn memory_address(&self) -> String {
2296 format!("{:?}", std::ptr::from_ref(self))
2297 }
2298
2299 pub fn set_database(&mut self, database: Box<dyn CacheDatabaseAdapter>) {
2303 let type_name = std::any::type_name_of_val(&*database);
2304 log::info!("Cache database adapter set: {type_name}");
2305 self.database = Some(database);
2306 }
2307
2308 pub fn cache_general(&mut self) -> anyhow::Result<()> {
2316 self.general = match &mut self.database {
2317 Some(db) => db.load()?,
2318 None => AHashMap::new(),
2319 };
2320
2321 log::info!(
2322 "Cached {} general object(s) from database",
2323 self.general.len()
2324 );
2325 Ok(())
2326 }
2327
2328 pub async fn cache_all(&mut self) -> anyhow::Result<()> {
2334 let cache_map = match &self.database {
2335 Some(db) => db.load_all().await?,
2336 None => CacheMap::default(),
2337 };
2338
2339 self.currencies = cache_map.currencies;
2340 self.instruments = cache_map.instruments;
2341 self.synthetics = cache_map.synthetics;
2342 self.accounts = cache_map
2343 .accounts
2344 .into_iter()
2345 .map(|(id, account)| (id, SharedCell::new(account)))
2346 .collect();
2347 self.orders = cache_map
2348 .orders
2349 .into_iter()
2350 .map(|(id, order)| (id, SharedCell::new(order)))
2351 .collect();
2352 self.positions = cache_map
2353 .positions
2354 .into_iter()
2355 .map(|(id, position)| (id, SharedCell::new(position)))
2356 .collect();
2357
2358 if let Some(db) = &self.database {
2359 self.index.order_position = db.load_index_order_position()?;
2360 self.index.order_client = db.load_index_order_client()?;
2361 }
2362
2363 self.cache_position_oms()?;
2364 self.assign_position_ids_to_contingencies();
2365 Ok(())
2366 }
2367
2368 pub async fn cache_currencies(&mut self) -> anyhow::Result<()> {
2374 self.currencies = match &mut self.database {
2375 Some(db) => db.load_currencies().await?,
2376 None => AHashMap::new(),
2377 };
2378
2379 log::info!("Cached {} currencies from database", self.general.len());
2380 Ok(())
2381 }
2382
2383 pub async fn cache_instruments(&mut self) -> anyhow::Result<()> {
2389 self.instruments = match &mut self.database {
2390 Some(db) => db.load_instruments().await?,
2391 None => AHashMap::new(),
2392 };
2393
2394 log::info!("Cached {} instruments from database", self.general.len());
2395 Ok(())
2396 }
2397
2398 pub async fn cache_synthetics(&mut self) -> anyhow::Result<()> {
2404 self.synthetics = match &mut self.database {
2405 Some(db) => db.load_synthetics().await?,
2406 None => AHashMap::new(),
2407 };
2408
2409 log::info!(
2410 "Cached {} synthetic instruments from database",
2411 self.general.len()
2412 );
2413 Ok(())
2414 }
2415
2416 pub async fn cache_accounts(&mut self) -> anyhow::Result<()> {
2422 self.accounts = match &mut self.database {
2423 Some(db) => db
2424 .load_accounts()
2425 .await?
2426 .into_iter()
2427 .map(|(id, account)| (id, SharedCell::new(account)))
2428 .collect(),
2429 None => AHashMap::new(),
2430 };
2431
2432 log::info!(
2433 "Cached {} synthetic instruments from database",
2434 self.general.len()
2435 );
2436 Ok(())
2437 }
2438
2439 pub async fn cache_orders(&mut self) -> anyhow::Result<()> {
2445 self.orders = match &mut self.database {
2446 Some(db) => db
2447 .load_orders()
2448 .await?
2449 .into_iter()
2450 .map(|(id, order)| (id, SharedCell::new(order)))
2451 .collect(),
2452 None => AHashMap::new(),
2453 };
2454
2455 if let Some(db) = &self.database {
2456 self.index.order_position = db.load_index_order_position()?;
2457 self.index.order_client = db.load_index_order_client()?;
2458 }
2459
2460 log::info!("Cached {} orders from database", self.general.len());
2461
2462 self.assign_position_ids_to_contingencies();
2463 Ok(())
2464 }
2465
2466 pub async fn cache_positions(&mut self) -> anyhow::Result<()> {
2472 self.positions = match &mut self.database {
2473 Some(db) => db
2474 .load_positions()
2475 .await?
2476 .into_iter()
2477 .map(|(id, position)| (id, SharedCell::new(position)))
2478 .collect(),
2479 None => AHashMap::new(),
2480 };
2481
2482 self.cache_position_oms()?;
2483 log::info!("Cached {} positions from database", self.general.len());
2484 Ok(())
2485 }
2486
2487 fn cache_position_oms(&mut self) -> anyhow::Result<()> {
2488 let persisted = match &self.database {
2489 Some(database) => database.load()?,
2490 None => self.general.clone(),
2491 };
2492
2493 self.general
2494 .retain(|key, _| !key.starts_with(POSITION_OMS_KEY_PREFIX));
2495
2496 for (key, value) in persisted {
2497 if !key.starts_with(POSITION_OMS_KEY_PREFIX) {
2498 continue;
2499 }
2500 self.general.insert(key, value);
2501 }
2502
2503 self.index_position_oms();
2504 Ok(())
2505 }
2506
2507 pub fn build_index(&mut self) {
2509 log::debug!("Building index");
2510
2511 for account_id in self.accounts.keys() {
2513 self.index
2514 .venue_account
2515 .insert(account_id.get_issuer(), *account_id);
2516 }
2517
2518 for (client_order_id, order_cell) in &self.orders {
2520 let order = order_cell.borrow();
2521 let instrument_id = order.instrument_id();
2522 let venue = instrument_id.venue;
2523 let strategy_id = order.strategy_id();
2524
2525 self.index
2527 .venue_orders
2528 .entry(venue)
2529 .or_default()
2530 .insert(*client_order_id);
2531
2532 if let Some(venue_order_id) = order.venue_order_id() {
2535 self.index
2536 .venue_order_ids
2537 .insert(venue_order_id, *client_order_id);
2538 self.index
2539 .client_order_ids
2540 .insert(*client_order_id, venue_order_id);
2541 }
2542
2543 if let Some(position_id) = order.position_id() {
2545 self.index
2546 .order_position
2547 .insert(*client_order_id, position_id);
2548 }
2549
2550 self.index
2552 .order_strategy
2553 .insert(*client_order_id, order.strategy_id());
2554
2555 self.index
2557 .instrument_orders
2558 .entry(instrument_id)
2559 .or_default()
2560 .insert(*client_order_id);
2561
2562 self.index
2564 .strategy_orders
2565 .entry(strategy_id)
2566 .or_default()
2567 .insert(*client_order_id);
2568
2569 if let Some(account_id) = order.account_id() {
2571 self.index
2572 .account_orders
2573 .entry(account_id)
2574 .or_default()
2575 .insert(*client_order_id);
2576 }
2577
2578 if let Some(exec_algorithm_id) = order.exec_algorithm_id() {
2580 self.index
2581 .exec_algorithm_orders
2582 .entry(exec_algorithm_id)
2583 .or_default()
2584 .insert(*client_order_id);
2585 }
2586
2587 if let Some(exec_spawn_id) = order.exec_spawn_id() {
2589 self.index
2590 .exec_spawn_orders
2591 .entry(exec_spawn_id)
2592 .or_default()
2593 .insert(*client_order_id);
2594 }
2595
2596 self.index.orders.insert(*client_order_id);
2598
2599 if order.is_active_local() {
2601 self.index.orders_active_local.insert(*client_order_id);
2602 }
2603
2604 if order.is_open() {
2606 self.index.orders_open.insert(*client_order_id);
2607 }
2608
2609 if order.is_closed() {
2611 self.index.orders_closed.insert(*client_order_id);
2612 }
2613
2614 if let Some(emulation_trigger) = order.emulation_trigger()
2616 && emulation_trigger != TriggerType::NoTrigger
2617 && !order.is_closed()
2618 {
2619 self.index.orders_emulated.insert(*client_order_id);
2620 }
2621
2622 if order.is_inflight() {
2624 self.index.orders_inflight.insert(*client_order_id);
2625 }
2626
2627 self.index.strategies.insert(strategy_id);
2629
2630 if let Some(exec_algorithm_id) = order.exec_algorithm_id() {
2632 self.index.exec_algorithms.insert(exec_algorithm_id);
2633 }
2634 }
2635
2636 for (position_id, position_cell) in &self.positions {
2638 let position = position_cell.borrow();
2639 let instrument_id = position.instrument_id;
2640 let venue = instrument_id.venue;
2641 let strategy_id = position.strategy_id;
2642
2643 self.index
2645 .venue_positions
2646 .entry(venue)
2647 .or_default()
2648 .insert(*position_id);
2649
2650 self.index
2652 .position_strategy
2653 .insert(*position_id, position.strategy_id);
2654
2655 self.index
2657 .position_orders
2658 .entry(*position_id)
2659 .or_default()
2660 .extend(position.client_order_ids());
2661
2662 self.index
2664 .instrument_positions
2665 .entry(instrument_id)
2666 .or_default()
2667 .insert(*position_id);
2668
2669 self.index
2671 .strategy_positions
2672 .entry(strategy_id)
2673 .or_default()
2674 .insert(*position_id);
2675
2676 self.index
2678 .account_positions
2679 .entry(position.account_id)
2680 .or_default()
2681 .insert(*position_id);
2682
2683 self.index.positions.insert(*position_id);
2685
2686 if position.is_open() {
2688 self.index.positions_open.insert(*position_id);
2689 }
2690
2691 if position.is_closed() {
2693 self.index.positions_closed.insert(*position_id);
2694 }
2695
2696 self.index.strategies.insert(strategy_id);
2698 }
2699
2700 self.index_position_oms();
2701 }
2702
2703 fn index_position_oms(&mut self) {
2704 self.index.position_oms.clear();
2705
2706 for (key, value) in &self.general {
2707 let Some(position_id) = key.strip_prefix(POSITION_OMS_KEY_PREFIX) else {
2708 continue;
2709 };
2710 let position_id = PositionId::new(position_id);
2711 if !self.positions.contains_key(&position_id) {
2712 continue;
2713 }
2714
2715 match serde_json::from_slice::<OmsType>(value) {
2716 Ok(oms_type) => {
2717 self.index.position_oms.insert(position_id, oms_type);
2718 }
2719 Err(e) => {
2720 log::error!("Failed to decode position OMS for {position_id}: {e}");
2721 }
2722 }
2723 }
2724
2725 for position in self.positions.values().map(|cell| cell.borrow()) {
2726 if !self.index.position_oms.contains_key(&position.id)
2727 && position.id.as_str()
2728 == format!("{}-{}", position.instrument_id, position.strategy_id)
2729 {
2730 self.index
2731 .position_oms
2732 .insert(position.id, OmsType::Netting);
2733 }
2734 }
2735 }
2736
2737 #[must_use]
2739 pub const fn has_backing(&self) -> bool {
2740 self.database.is_some()
2741 }
2742
2743 pub fn load_actor_state(
2751 &self,
2752 component_id: &ComponentId,
2753 ) -> anyhow::Result<Option<IndexMap<String, Vec<u8>>>> {
2754 self.database
2755 .as_ref()
2756 .map(|database| database.load_actor(component_id))
2757 .transpose()
2758 .map(|state| state.map(Self::decode_component_state))
2759 }
2760
2761 pub fn load_strategy_state(
2769 &self,
2770 strategy_id: &StrategyId,
2771 ) -> anyhow::Result<Option<IndexMap<String, Vec<u8>>>> {
2772 self.database
2773 .as_ref()
2774 .map(|database| database.load_strategy(strategy_id))
2775 .transpose()
2776 .map(|state| state.map(Self::decode_component_state))
2777 }
2778
2779 pub fn update_actor_state(
2785 &self,
2786 component_id: &ComponentId,
2787 state: &IndexMap<String, Vec<u8>>,
2788 ) -> anyhow::Result<()> {
2789 if let Some(database) = &self.database {
2790 database.update_actor(component_id, &Self::encode_component_state(state))?;
2791 }
2792 Ok(())
2793 }
2794
2795 pub fn update_strategy_state(
2801 &self,
2802 strategy_id: &StrategyId,
2803 state: &IndexMap<String, Vec<u8>>,
2804 ) -> anyhow::Result<()> {
2805 if let Some(database) = &self.database {
2806 database.update_strategy(strategy_id, &Self::encode_component_state(state))?;
2807 }
2808 Ok(())
2809 }
2810
2811 fn decode_component_state(state: AHashMap<String, Bytes>) -> IndexMap<String, Vec<u8>> {
2812 state
2813 .into_iter()
2814 .map(|(key, value)| (key, value.to_vec()))
2815 .collect()
2816 }
2817
2818 fn encode_component_state(state: &IndexMap<String, Vec<u8>>) -> AHashMap<String, Bytes> {
2819 state
2820 .iter()
2821 .map(|(key, value)| (key.clone(), Bytes::copy_from_slice(value)))
2822 .collect()
2823 }
2824
2825 #[must_use]
2827 pub fn calculate_unrealized_pnl(&self, position: &Position) -> Option<Money> {
2828 let Some(quote) = self.quote(&position.instrument_id) else {
2829 log::warn!(
2830 "Cannot calculate unrealized PnL for {}, no quotes for {}",
2831 position.id,
2832 position.instrument_id
2833 );
2834 return None;
2835 };
2836
2837 let last = match position.side {
2839 PositionSide::Flat | PositionSide::NoPositionSide => {
2840 return Some(Money::zero(position.settlement_currency));
2841 }
2842 PositionSide::Long => quote.bid_price,
2843 PositionSide::Short => quote.ask_price,
2844 };
2845
2846 match position.try_unrealized_pnl(last) {
2847 Ok(pnl) => Some(pnl),
2848 Err(e) => {
2849 log::error!("Cannot calculate unrealized PnL for {}: {e}", position.id);
2850 None
2851 }
2852 }
2853 }
2854
2855 #[must_use]
2864 pub fn check_integrity(&mut self) -> bool {
2865 let mut error_count = 0;
2866 let failure = "Integrity failure";
2867
2868 let timestamp_us = SystemTime::now()
2870 .duration_since(UNIX_EPOCH)
2871 .expect("Time went backwards")
2872 .as_micros();
2873
2874 log::info!("Checking data integrity");
2875
2876 for account_id in self.accounts.keys() {
2878 if !self
2879 .index
2880 .venue_account
2881 .contains_key(&account_id.get_issuer())
2882 {
2883 log::error!(
2884 "{failure} in accounts: {account_id} not found in `self.index.venue_account`",
2885 );
2886 error_count += 1;
2887 }
2888 }
2889
2890 for (client_order_id, order_cell) in &self.orders {
2891 let order = order_cell.borrow();
2892
2893 if !self.index.order_strategy.contains_key(client_order_id) {
2894 log::error!(
2895 "{failure} in orders: {client_order_id} not found in `self.index.order_strategy`"
2896 );
2897 error_count += 1;
2898 }
2899
2900 if !self.index.orders.contains(client_order_id) {
2901 log::error!(
2902 "{failure} in orders: {client_order_id} not found in `self.index.orders`",
2903 );
2904 error_count += 1;
2905 }
2906
2907 if order.is_inflight() && !self.index.orders_inflight.contains(client_order_id) {
2908 log::error!(
2909 "{failure} in orders: {client_order_id} not found in `self.index.orders_inflight`",
2910 );
2911 error_count += 1;
2912 }
2913
2914 if order.is_active_local() && !self.index.orders_active_local.contains(client_order_id)
2915 {
2916 log::error!(
2917 "{failure} in orders: {client_order_id} not found in `self.index.orders_active_local`",
2918 );
2919 error_count += 1;
2920 }
2921
2922 if order.is_open() && !self.index.orders_open.contains(client_order_id) {
2923 log::error!(
2924 "{failure} in orders: {client_order_id} not found in `self.index.orders_open`",
2925 );
2926 error_count += 1;
2927 }
2928
2929 if order.is_closed() && !self.index.orders_closed.contains(client_order_id) {
2930 log::error!(
2931 "{failure} in orders: {client_order_id} not found in `self.index.orders_closed`",
2932 );
2933 error_count += 1;
2934 }
2935
2936 if let Some(exec_algorithm_id) = order.exec_algorithm_id() {
2937 if !self
2938 .index
2939 .exec_algorithm_orders
2940 .contains_key(&exec_algorithm_id)
2941 {
2942 log::error!(
2943 "{failure} in orders: {client_order_id} not found in `self.index.exec_algorithm_orders`",
2944 );
2945 error_count += 1;
2946 }
2947
2948 if order.exec_spawn_id().is_none()
2949 && !self.index.exec_spawn_orders.contains_key(client_order_id)
2950 {
2951 log::error!(
2952 "{failure} in orders: {client_order_id} not found in `self.index.exec_spawn_orders`",
2953 );
2954 error_count += 1;
2955 }
2956 }
2957 }
2958
2959 for (position_id, position_cell) in &self.positions {
2960 let position = position_cell.borrow();
2961
2962 if !self.index.position_strategy.contains_key(position_id) {
2963 log::error!(
2964 "{failure} in positions: {position_id} not found in `self.index.position_strategy`",
2965 );
2966 error_count += 1;
2967 }
2968
2969 if !self.index.position_orders.contains_key(position_id) {
2970 log::error!(
2971 "{failure} in positions: {position_id} not found in `self.index.position_orders`",
2972 );
2973 error_count += 1;
2974 }
2975
2976 if !self.index.positions.contains(position_id) {
2977 log::error!(
2978 "{failure} in positions: {position_id} not found in `self.index.positions`",
2979 );
2980 error_count += 1;
2981 }
2982
2983 if position.is_open() && !self.index.positions_open.contains(position_id) {
2984 log::error!(
2985 "{failure} in positions: {position_id} not found in `self.index.positions_open`",
2986 );
2987 error_count += 1;
2988 }
2989
2990 if position.is_closed() && !self.index.positions_closed.contains(position_id) {
2991 log::error!(
2992 "{failure} in positions: {position_id} not found in `self.index.positions_closed`",
2993 );
2994 error_count += 1;
2995 }
2996 }
2997
2998 for account_id in self.index.venue_account.values() {
3000 if !self.accounts.contains_key(account_id) {
3001 log::error!(
3002 "{failure} in `index.venue_account`: {account_id} not found in `self.accounts`",
3003 );
3004 error_count += 1;
3005 }
3006 }
3007
3008 for client_order_id in self.index.venue_order_ids.values() {
3009 if !self.orders.contains_key(client_order_id) {
3010 log::error!(
3011 "{failure} in `index.venue_order_ids`: {client_order_id} not found in `self.orders`",
3012 );
3013 error_count += 1;
3014 }
3015 }
3016
3017 for client_order_id in self.index.client_order_ids.keys() {
3018 if !self.orders.contains_key(client_order_id) {
3019 log::error!(
3020 "{failure} in `index.client_order_ids`: {client_order_id} not found in `self.orders`",
3021 );
3022 error_count += 1;
3023 }
3024 }
3025
3026 for client_order_id in self.index.order_position.keys() {
3027 if !self.orders.contains_key(client_order_id) {
3028 log::error!(
3029 "{failure} in `index.order_position`: {client_order_id} not found in `self.orders`",
3030 );
3031 error_count += 1;
3032 }
3033 }
3034
3035 for client_order_id in self.index.order_strategy.keys() {
3037 if !self.orders.contains_key(client_order_id) {
3038 log::error!(
3039 "{failure} in `index.order_strategy`: {client_order_id} not found in `self.orders`",
3040 );
3041 error_count += 1;
3042 }
3043 }
3044
3045 for position_id in self.index.position_strategy.keys() {
3046 if !self.positions.contains_key(position_id) {
3047 log::error!(
3048 "{failure} in `index.position_strategy`: {position_id} not found in `self.positions`",
3049 );
3050 error_count += 1;
3051 }
3052 }
3053
3054 for position_id in self.index.position_orders.keys() {
3055 if !self.positions.contains_key(position_id) {
3056 log::error!(
3057 "{failure} in `index.position_orders`: {position_id} not found in `self.positions`",
3058 );
3059 error_count += 1;
3060 }
3061 }
3062
3063 for (instrument_id, client_order_ids) in &self.index.instrument_orders {
3064 for client_order_id in client_order_ids {
3065 if !self.orders.contains_key(client_order_id) {
3066 log::error!(
3067 "{failure} in `index.instrument_orders`: {instrument_id} not found in `self.orders`",
3068 );
3069 error_count += 1;
3070 }
3071 }
3072 }
3073
3074 for instrument_id in self.index.instrument_positions.keys() {
3075 if !self.index.instrument_orders.contains_key(instrument_id) {
3076 log::error!(
3077 "{failure} in `index.instrument_positions`: {instrument_id} not found in `index.instrument_orders`",
3078 );
3079 error_count += 1;
3080 }
3081 }
3082
3083 for client_order_ids in self.index.strategy_orders.values() {
3084 for client_order_id in client_order_ids {
3085 if !self.orders.contains_key(client_order_id) {
3086 log::error!(
3087 "{failure} in `index.strategy_orders`: {client_order_id} not found in `self.orders`",
3088 );
3089 error_count += 1;
3090 }
3091 }
3092 }
3093
3094 for position_ids in self.index.strategy_positions.values() {
3095 for position_id in position_ids {
3096 if !self.positions.contains_key(position_id) {
3097 log::error!(
3098 "{failure} in `index.strategy_positions`: {position_id} not found in `self.positions`",
3099 );
3100 error_count += 1;
3101 }
3102 }
3103 }
3104
3105 for client_order_id in &self.index.orders {
3106 if !self.orders.contains_key(client_order_id) {
3107 log::error!(
3108 "{failure} in `index.orders`: {client_order_id} not found in `self.orders`",
3109 );
3110 error_count += 1;
3111 }
3112 }
3113
3114 for client_order_id in &self.index.orders_emulated {
3115 if !self.orders.contains_key(client_order_id) {
3116 log::error!(
3117 "{failure} in `index.orders_emulated`: {client_order_id} not found in `self.orders`",
3118 );
3119 error_count += 1;
3120 }
3121 }
3122
3123 for client_order_id in &self.index.orders_active_local {
3124 if !self.orders.contains_key(client_order_id) {
3125 log::error!(
3126 "{failure} in `index.orders_active_local`: {client_order_id} not found in `self.orders`",
3127 );
3128 error_count += 1;
3129 }
3130 }
3131
3132 for client_order_id in &self.index.orders_inflight {
3133 if !self.orders.contains_key(client_order_id) {
3134 log::error!(
3135 "{failure} in `index.orders_inflight`: {client_order_id} not found in `self.orders`",
3136 );
3137 error_count += 1;
3138 }
3139 }
3140
3141 for client_order_id in &self.index.orders_open {
3142 if !self.orders.contains_key(client_order_id) {
3143 log::error!(
3144 "{failure} in `index.orders_open`: {client_order_id} not found in `self.orders`",
3145 );
3146 error_count += 1;
3147 }
3148 }
3149
3150 for client_order_id in &self.index.orders_closed {
3151 if !self.orders.contains_key(client_order_id) {
3152 log::error!(
3153 "{failure} in `index.orders_closed`: {client_order_id} not found in `self.orders`",
3154 );
3155 error_count += 1;
3156 }
3157 }
3158
3159 for position_id in &self.index.positions {
3160 if !self.positions.contains_key(position_id) {
3161 log::error!(
3162 "{failure} in `index.positions`: {position_id} not found in `self.positions`",
3163 );
3164 error_count += 1;
3165 }
3166 }
3167
3168 for position_id in &self.index.positions_open {
3169 if !self.positions.contains_key(position_id) {
3170 log::error!(
3171 "{failure} in `index.positions_open`: {position_id} not found in `self.positions`",
3172 );
3173 error_count += 1;
3174 }
3175 }
3176
3177 for position_id in &self.index.positions_closed {
3178 if !self.positions.contains_key(position_id) {
3179 log::error!(
3180 "{failure} in `index.positions_closed`: {position_id} not found in `self.positions`",
3181 );
3182 error_count += 1;
3183 }
3184 }
3185
3186 for strategy_id in &self.index.strategies {
3187 if !self.index.strategy_orders.contains_key(strategy_id) {
3188 log::error!(
3189 "{failure} in `index.strategies`: {strategy_id} not found in `index.strategy_orders`",
3190 );
3191 error_count += 1;
3192 }
3193 }
3194
3195 for exec_algorithm_id in &self.index.exec_algorithms {
3196 if !self
3197 .index
3198 .exec_algorithm_orders
3199 .contains_key(exec_algorithm_id)
3200 {
3201 log::error!(
3202 "{failure} in `index.exec_algorithms`: {exec_algorithm_id} not found in `index.exec_algorithm_orders`",
3203 );
3204 error_count += 1;
3205 }
3206 }
3207
3208 let total_us = SystemTime::now()
3209 .duration_since(UNIX_EPOCH)
3210 .expect("Time went backwards")
3211 .as_micros()
3212 - timestamp_us;
3213
3214 if error_count == 0 {
3215 log::info!("Integrity check passed in {total_us}μs");
3216 true
3217 } else {
3218 log::error!(
3219 "Integrity check failed with {error_count} error{} in {total_us}μs",
3220 if error_count == 1 { "" } else { "s" },
3221 );
3222 false
3223 }
3224 }
3225
3226 #[must_use]
3230 pub fn check_residuals(&self) -> bool {
3231 log::debug!("Checking residuals");
3232
3233 let mut residuals = false;
3234
3235 for order in self.orders_open(None, None, None, None, None) {
3237 residuals = true;
3238 log::warn!("Residual {order}");
3239 }
3240
3241 for position in self.positions_open(None, None, None, None, None) {
3243 residuals = true;
3244 log::warn!("Residual {position}");
3245 }
3246
3247 residuals
3248 }
3249
3250 pub fn purge_closed_orders(&mut self, ts_now: UnixNanos, buffer_secs: u64) {
3256 log::debug!(
3257 "Purging closed orders{}",
3258 if buffer_secs > 0 {
3259 format!(" with buffer_secs={buffer_secs}")
3260 } else {
3261 String::new()
3262 }
3263 );
3264
3265 let buffer_ns = secs_to_nanos_unchecked(buffer_secs as f64);
3266
3267 let mut affected_order_list_ids: AHashSet<OrderListId> = AHashSet::new();
3268
3269 'outer: for client_order_id in self.index.orders_closed.clone() {
3270 let purge_target = self.orders.get(&client_order_id).and_then(|order_cell| {
3271 let order = order_cell.borrow();
3272 if order.is_closed()
3273 && let Some(ts_closed) = order.ts_closed()
3274 && ts_closed + buffer_ns <= ts_now
3275 {
3276 let linked = order.linked_order_ids().map(<[_]>::to_vec);
3277 let order_list_id = order.order_list_id();
3278 Some((linked, order_list_id))
3279 } else {
3280 None
3281 }
3282 });
3283
3284 let Some((linked, order_list_id)) = purge_target else {
3285 continue;
3286 };
3287
3288 if let Some(linked_order_ids) = linked {
3290 for linked_order_id in &linked_order_ids {
3291 if let Some(linked_order_cell) = self.orders.get(linked_order_id)
3292 && linked_order_cell.borrow().is_open()
3293 {
3294 continue 'outer;
3296 }
3297 }
3298 }
3299
3300 if let Some(order_list_id) = order_list_id {
3301 affected_order_list_ids.insert(order_list_id);
3302 }
3303
3304 self.purge_order(client_order_id);
3305 }
3306
3307 for order_list_id in affected_order_list_ids {
3308 if let Some(order_list) = self.order_lists.get(&order_list_id) {
3309 let all_purged = order_list
3310 .client_order_ids
3311 .iter()
3312 .all(|id| !self.orders.contains_key(id));
3313
3314 if all_purged {
3315 self.order_lists.remove(&order_list_id);
3316 log::info!("Purged {order_list_id}");
3317 }
3318 }
3319 }
3320 }
3321
3322 pub fn purge_closed_positions(&mut self, ts_now: UnixNanos, buffer_secs: u64) {
3324 log::debug!(
3325 "Purging closed positions{}",
3326 if buffer_secs > 0 {
3327 format!(" with buffer_secs={buffer_secs}")
3328 } else {
3329 String::new()
3330 }
3331 );
3332
3333 let buffer_ns = secs_to_nanos_unchecked(buffer_secs as f64);
3334
3335 for position_id in self.index.positions_closed.clone() {
3336 let should_purge = self.positions.get(&position_id).is_some_and(|cell| {
3337 let position = cell.borrow();
3338 position.is_closed()
3339 && position
3340 .ts_closed
3341 .is_some_and(|ts_closed| ts_closed + buffer_ns <= ts_now)
3342 });
3343
3344 if should_purge {
3345 self.purge_position(position_id);
3346 }
3347 }
3348 }
3349
3350 pub fn purge_order(&mut self, client_order_id: ClientOrderId) {
3354 struct OrderDetails {
3355 is_open: bool,
3356 instrument_id: InstrumentId,
3357 strategy_id: StrategyId,
3358 account_id: Option<AccountId>,
3359 exec_algorithm_id: Option<ExecAlgorithmId>,
3360 exec_spawn_id: Option<ClientOrderId>,
3361 position_id: Option<PositionId>,
3362 venue_order_id: Option<VenueOrderId>,
3363 venue_order_ids: Vec<VenueOrderId>,
3364 }
3365
3366 let order_cell = self.orders.get(&client_order_id).cloned();
3367 let order_details = order_cell.as_ref().map(|cell| {
3368 let order = cell.borrow();
3369 OrderDetails {
3370 is_open: order.is_open(),
3371 instrument_id: order.instrument_id(),
3372 strategy_id: order.strategy_id(),
3373 account_id: order.account_id(),
3374 exec_algorithm_id: order.exec_algorithm_id(),
3375 exec_spawn_id: order.exec_spawn_id(),
3376 position_id: order.position_id(),
3377 venue_order_id: order.venue_order_id(),
3378 venue_order_ids: order.venue_order_ids().into_iter().copied().collect(),
3379 }
3380 });
3381
3382 if order_details
3383 .as_ref()
3384 .is_some_and(|details| details.is_open)
3385 {
3386 log::warn!("Order {client_order_id} found open when purging, skipping purge");
3387 return;
3388 }
3389
3390 if order_details.is_some() {
3391 self.orders.remove(&client_order_id);
3392 } else {
3393 log::warn!("Order {client_order_id} not found when purging");
3394 }
3395
3396 let indexed_position_id = self.index.order_position.remove(&client_order_id);
3397 let indexed_strategy_id = self.index.order_strategy.remove(&client_order_id);
3398 self.index.order_client.remove(&client_order_id);
3399 let indexed_venue_order_id = self.index.client_order_ids.remove(&client_order_id);
3400
3401 if let Some(details) = &order_details {
3402 if let Some(venue_orders) = self
3403 .index
3404 .venue_orders
3405 .get_mut(&details.instrument_id.venue)
3406 {
3407 venue_orders.remove(&client_order_id);
3408 if venue_orders.is_empty() {
3409 self.index.venue_orders.remove(&details.instrument_id.venue);
3410 }
3411 }
3412
3413 let instrument_orders_became_empty = self
3418 .index
3419 .instrument_orders
3420 .get_mut(&details.instrument_id)
3421 .is_some_and(|instrument_orders| {
3422 instrument_orders.remove(&client_order_id);
3423 instrument_orders.is_empty()
3424 });
3425
3426 let has_instrument_positions = self
3427 .index
3428 .instrument_positions
3429 .get(&details.instrument_id)
3430 .is_some_and(|positions| !positions.is_empty());
3431
3432 if instrument_orders_became_empty && !has_instrument_positions {
3433 self.index.instrument_orders.remove(&details.instrument_id);
3434 }
3435
3436 if let Some(exec_algorithm_id) = details.exec_algorithm_id {
3437 let became_empty = self
3438 .index
3439 .exec_algorithm_orders
3440 .get_mut(&exec_algorithm_id)
3441 .is_some_and(|orders| {
3442 orders.remove(&client_order_id);
3443 orders.is_empty()
3444 });
3445
3446 if became_empty {
3447 self.index.exec_algorithm_orders.remove(&exec_algorithm_id);
3448 self.index.exec_algorithms.remove(&exec_algorithm_id);
3449 }
3450 }
3451
3452 if let Some(account_id) = details.account_id
3453 && let Some(account_orders) = self.index.account_orders.get_mut(&account_id)
3454 {
3455 account_orders.remove(&client_order_id);
3456 if account_orders.is_empty() {
3457 self.index.account_orders.remove(&account_id);
3458 }
3459 }
3460
3461 if let Some(exec_spawn_id) = details.exec_spawn_id
3462 && let Some(spawn_orders) = self.index.exec_spawn_orders.get_mut(&exec_spawn_id)
3463 {
3464 spawn_orders.remove(&client_order_id);
3465 if spawn_orders.is_empty() {
3466 self.index.exec_spawn_orders.remove(&exec_spawn_id);
3467 }
3468 }
3469 }
3470
3471 let mut position_ids = AHashSet::new();
3472 if let Some(position_id) = indexed_position_id {
3473 position_ids.insert(position_id);
3474 }
3475
3476 if let Some(position_id) = order_details
3477 .as_ref()
3478 .and_then(|details| details.position_id)
3479 {
3480 position_ids.insert(position_id);
3481 }
3482
3483 let mut strategy_ids = AHashSet::new();
3484 if let Some(strategy_id) = indexed_strategy_id {
3485 strategy_ids.insert(strategy_id);
3486 }
3487
3488 if let Some(details) = &order_details {
3489 strategy_ids.insert(details.strategy_id);
3490 }
3491
3492 for position_id in position_ids {
3493 if self.positions.contains_key(&position_id) {
3494 if let Some(position_orders) = self.index.position_orders.get_mut(&position_id) {
3495 position_orders.remove(&client_order_id);
3496 }
3497 continue;
3498 }
3499
3500 let has_other_orders =
3501 if let Some(position_orders) = self.index.position_orders.get_mut(&position_id) {
3502 position_orders.remove(&client_order_id);
3503 !position_orders.is_empty()
3504 } else {
3505 self.index
3506 .order_position
3507 .values()
3508 .any(|candidate| *candidate == position_id)
3509 };
3510
3511 if has_other_orders {
3512 continue;
3513 }
3514
3515 self.index.position_orders.remove(&position_id);
3516 if let Some(strategy_id) = self.index.position_strategy.remove(&position_id) {
3517 strategy_ids.insert(strategy_id);
3518 if let Some(strategy_positions) =
3519 self.index.strategy_positions.get_mut(&strategy_id)
3520 {
3521 strategy_positions.remove(&position_id);
3522 if strategy_positions.is_empty() {
3523 self.index.strategy_positions.remove(&strategy_id);
3524 }
3525 }
3526 }
3527
3528 if let Some(details) = &order_details
3529 && let Some(venue_positions) = self
3530 .index
3531 .venue_positions
3532 .get_mut(&details.instrument_id.venue)
3533 {
3534 venue_positions.remove(&position_id);
3535 if venue_positions.is_empty() {
3536 self.index
3537 .venue_positions
3538 .remove(&details.instrument_id.venue);
3539 }
3540 }
3541 }
3542
3543 for strategy_id in strategy_ids {
3544 let strategy_orders_became_empty = self
3550 .index
3551 .strategy_orders
3552 .get_mut(&strategy_id)
3553 .is_some_and(|strategy_orders| {
3554 strategy_orders.remove(&client_order_id);
3555 strategy_orders.is_empty()
3556 });
3557
3558 let has_positions = self
3559 .index
3560 .strategy_positions
3561 .get(&strategy_id)
3562 .is_some_and(|strategy_positions| !strategy_positions.is_empty());
3563
3564 if strategy_orders_became_empty && !has_positions {
3565 self.index.strategy_orders.remove(&strategy_id);
3566 self.index.strategies.remove(&strategy_id);
3567 }
3568 }
3569
3570 let mut venue_order_ids = AHashSet::new();
3571 if let Some(venue_order_id) = indexed_venue_order_id {
3572 venue_order_ids.insert(venue_order_id);
3573 }
3574
3575 if let Some(details) = &order_details {
3576 venue_order_ids.extend(details.venue_order_ids.iter().copied());
3577 if let Some(venue_order_id) = details.venue_order_id {
3578 venue_order_ids.insert(venue_order_id);
3579 }
3580 }
3581
3582 for venue_order_id in venue_order_ids {
3583 if self.index.venue_order_ids.get(&venue_order_id) == Some(&client_order_id) {
3584 self.index.venue_order_ids.remove(&venue_order_id);
3585 }
3586 }
3587
3588 self.index.exec_spawn_orders.remove(&client_order_id);
3589
3590 self.index.orders.remove(&client_order_id);
3591 self.index.orders_active_local.remove(&client_order_id);
3592 self.index.orders_open.remove(&client_order_id);
3593 self.index.orders_closed.remove(&client_order_id);
3594 self.index.orders_emulated.remove(&client_order_id);
3595 self.index.orders_inflight.remove(&client_order_id);
3596 self.index.orders_pending_cancel.remove(&client_order_id);
3597
3598 if order_details.is_some() {
3599 log::info!("Purged order {client_order_id}");
3600 }
3601 }
3602
3603 pub fn purge_position(&mut self, position_id: PositionId) {
3607 let position = self
3609 .positions
3610 .get(&position_id)
3611 .map(|cell| cell.borrow().clone());
3612
3613 if let Some(ref pos) = position
3615 && pos.is_open()
3616 {
3617 log::warn!("Position {position_id} found open when purging, skipping purge");
3618 return;
3619 }
3620
3621 if let Some(ref pos) = position {
3623 self.positions.remove(&position_id);
3624
3625 if let Some(venue_positions) =
3627 self.index.venue_positions.get_mut(&pos.instrument_id.venue)
3628 {
3629 venue_positions.remove(&position_id);
3630 if venue_positions.is_empty() {
3631 self.index.venue_positions.remove(&pos.instrument_id.venue);
3632 }
3633 }
3634
3635 let instrument_positions_became_empty = self
3637 .index
3638 .instrument_positions
3639 .get_mut(&pos.instrument_id)
3640 .is_some_and(|positions| {
3641 positions.remove(&position_id);
3642 positions.is_empty()
3643 });
3644
3645 if instrument_positions_became_empty {
3646 self.index.instrument_positions.remove(&pos.instrument_id);
3647 let instrument_orders_empty = self
3648 .index
3649 .instrument_orders
3650 .get(&pos.instrument_id)
3651 .is_some_and(|orders| orders.is_empty());
3652
3653 if instrument_orders_empty {
3654 self.index.instrument_orders.remove(&pos.instrument_id);
3655 }
3656 }
3657
3658 let strategy_positions_became_empty = self
3660 .index
3661 .strategy_positions
3662 .get_mut(&pos.strategy_id)
3663 .is_some_and(|positions| {
3664 positions.remove(&position_id);
3665 positions.is_empty()
3666 });
3667
3668 if strategy_positions_became_empty {
3669 self.index.strategy_positions.remove(&pos.strategy_id);
3670 let strategy_orders_empty = self
3671 .index
3672 .strategy_orders
3673 .get(&pos.strategy_id)
3674 .is_some_and(|orders| orders.is_empty());
3675
3676 if strategy_orders_empty {
3677 self.index.strategy_orders.remove(&pos.strategy_id);
3678 self.index.strategies.remove(&pos.strategy_id);
3679 }
3680 }
3681
3682 if let Some(account_positions) = self.index.account_positions.get_mut(&pos.account_id) {
3684 account_positions.remove(&position_id);
3685 if account_positions.is_empty() {
3686 self.index.account_positions.remove(&pos.account_id);
3687 }
3688 }
3689
3690 for client_order_id in pos.client_order_ids() {
3692 self.index.order_position.remove(&client_order_id);
3693 }
3694
3695 log::info!("Purged position {position_id}");
3696 } else {
3697 log::warn!("Position {position_id} not found when purging");
3698 }
3699
3700 self.index.position_strategy.remove(&position_id);
3702 self.index.position_oms.remove(&position_id);
3703 self.index.position_orders.remove(&position_id);
3704 self.index.positions.remove(&position_id);
3705 self.index.positions_open.remove(&position_id);
3706 self.index.positions_closed.remove(&position_id);
3707
3708 self.position_snapshots.remove(&position_id);
3710 self.bump_position_snapshot_revision(position_id);
3711 }
3712
3713 fn purge_instrument_inner(&mut self, instrument_id: InstrumentId, skip_order_guard: bool) {
3737 #[cfg(feature = "defi")]
3738 let defi_found = self.defi.pools.contains_key(&instrument_id)
3739 || self.defi.pool_profilers.contains_key(&instrument_id);
3740 #[cfg(not(feature = "defi"))]
3741 let defi_found = false;
3742
3743 let found = self.instruments.contains_key(&instrument_id)
3744 || self.synthetics.contains_key(&instrument_id)
3745 || defi_found;
3746
3747 if !found {
3748 log::warn!("Instrument {instrument_id} not found when purging");
3749 return;
3750 }
3751
3752 if !skip_order_guard && let Some(orders) = self.index.instrument_orders.get(&instrument_id)
3753 {
3754 let has_non_terminal = orders
3755 .iter()
3756 .any(|client_order_id| !self.index.orders_closed.contains(client_order_id));
3757
3758 if has_non_terminal {
3759 log::warn!(
3760 "Instrument {instrument_id} has non-terminal orders when purging, skipping purge"
3761 );
3762 return;
3763 }
3764 }
3765
3766 if let Some(positions) = self.index.instrument_positions.get(&instrument_id) {
3767 let has_non_closed = positions
3768 .iter()
3769 .any(|position_id| !self.index.positions_closed.contains(position_id));
3770
3771 if has_non_closed {
3772 log::warn!(
3773 "Instrument {instrument_id} has non-closed positions when purging, skipping purge"
3774 );
3775 return;
3776 }
3777 }
3778
3779 self.instruments.remove(&instrument_id);
3780 self.synthetics.remove(&instrument_id);
3781 self.books.remove(&instrument_id);
3782 self.own_books.remove(&instrument_id);
3783 self.quotes.remove(&instrument_id);
3784 self.trades.remove(&instrument_id);
3785 self.mark_prices.remove(&instrument_id);
3786 self.index_prices.remove(&instrument_id);
3787 self.funding_rates.remove(&instrument_id);
3788 self.instrument_statuses.remove(&instrument_id);
3789 self.greeks.remove(&instrument_id);
3790 self.option_greeks.remove(&instrument_id);
3791
3792 self.bars
3793 .retain(|bar_type, _| bar_type.instrument_id() != instrument_id);
3794
3795 #[cfg(feature = "defi")]
3796 {
3797 self.defi.pools.remove(&instrument_id);
3798 self.defi.pool_profilers.remove(&instrument_id);
3799 }
3800
3801 self.index.instrument_orders.remove(&instrument_id);
3802 self.index.instrument_positions.remove(&instrument_id);
3803
3804 log::info!("Purged instrument {instrument_id}");
3805 }
3806
3807 pub fn purge_instrument(&mut self, instrument_id: InstrumentId) {
3812 self.purge_instrument_inner(instrument_id, false);
3813 }
3814
3815 pub fn purge_instrument_skip_order_guard(&mut self, instrument_id: InstrumentId) {
3824 self.purge_instrument_inner(instrument_id, true);
3825 }
3826
3827 pub fn purge_account_events(&mut self, ts_now: UnixNanos, lookback_secs: u64) {
3832 log::debug!(
3833 "Purging account events{}",
3834 if lookback_secs > 0 {
3835 format!(" with lookback_secs={lookback_secs}")
3836 } else {
3837 String::new()
3838 }
3839 );
3840
3841 for account_cell in self.accounts.values() {
3842 let mut account = account_cell.borrow_mut();
3843 let event_count = account.event_count();
3844 account.purge_account_events(ts_now, lookback_secs);
3845 let count_diff = event_count - account.event_count();
3846 if count_diff > 0 {
3847 log::info!(
3848 "Purged {} event(s) from account {}",
3849 count_diff,
3850 account.id()
3851 );
3852 }
3853 }
3854 }
3855
3856 pub fn clear_index(&mut self) {
3858 self.index.clear();
3859 log::debug!("Cleared index");
3860 }
3861
3862 pub fn reset(&mut self) {
3868 log::debug!("Resetting cache");
3869
3870 self.general.clear();
3871 self.books.clear();
3872 self.own_books.clear();
3873 self.quotes.clear();
3874 self.trades.clear();
3875 self.mark_xrates.clear();
3876 self.mark_prices.clear();
3877 self.index_prices.clear();
3878 self.funding_rates.clear();
3879 self.instrument_statuses.clear();
3880 self.bars.clear();
3881 self.accounts.clear();
3882 self.orders.clear();
3883 self.order_lists.clear();
3884 self.positions.clear();
3885 self.position_snapshots.clear();
3886 self.position_snapshot_revisions.clear();
3887 self.greeks.clear();
3888 self.yield_curves.clear();
3889
3890 if self.config.drop_instruments_on_reset {
3891 self.currencies.clear();
3892 self.instruments.clear();
3893 self.synthetics.clear();
3894 }
3895
3896 #[cfg(feature = "defi")]
3897 {
3898 self.defi.pools.clear();
3899 self.defi.pool_profilers.clear();
3900 }
3901
3902 self.clear_index();
3903
3904 log::info!("Reset cache");
3905 }
3906
3907 pub fn dispose(&mut self) {
3911 self.reset();
3912
3913 if let Some(database) = &mut self.database
3914 && let Err(e) = database.close()
3915 {
3916 log::error!("Failed to close database during dispose: {e}");
3917 }
3918 }
3919
3920 pub fn flush_db(&mut self) {
3924 if let Some(database) = &mut self.database
3925 && let Err(e) = database.flush()
3926 {
3927 log::error!("Failed to flush database: {e}");
3928 }
3929 }
3930
3931 pub fn add(&mut self, key: &str, value: Bytes) -> anyhow::Result<()> {
3939 check_valid_string_ascii(key, stringify!(key))?;
3940 check_predicate_false(value.is_empty(), stringify!(value))?;
3941
3942 log::debug!("Adding general {key}");
3943 self.general.insert(key.to_string(), value.clone());
3944
3945 if let Some(database) = &mut self.database {
3946 database.add(key.to_string(), value)?;
3947 }
3948 Ok(())
3949 }
3950
3951 pub fn add_order_book(&mut self, book: OrderBook) -> anyhow::Result<()> {
3957 log::debug!("Adding `OrderBook` {}", book.instrument_id);
3958
3959 if self.config.save_market_data
3960 && let Some(database) = &mut self.database
3961 {
3962 database.add_order_book(&book)?;
3963 }
3964
3965 self.books.insert(book.instrument_id, book);
3966 Ok(())
3967 }
3968
3969 pub fn add_own_order_book(&mut self, own_book: OwnOrderBook) -> anyhow::Result<()> {
3975 log::debug!("Adding `OwnOrderBook` {}", own_book.instrument_id);
3976
3977 self.own_books.insert(own_book.instrument_id, own_book);
3978 Ok(())
3979 }
3980
3981 pub fn add_mark_price(&mut self, mark_price: MarkPriceUpdate) -> anyhow::Result<()> {
3987 log::debug!("Adding `MarkPriceUpdate` for {}", mark_price.instrument_id);
3988
3989 if self.config.save_market_data {
3990 }
3992
3993 let mark_prices_deque = self
3994 .mark_prices
3995 .entry(mark_price.instrument_id)
3996 .or_insert_with(|| BoundedVecDeque::new(self.config.tick_capacity));
3997 mark_prices_deque.push_front(mark_price);
3998 Ok(())
3999 }
4000
4001 pub fn add_index_price(&mut self, index_price: IndexPriceUpdate) -> anyhow::Result<()> {
4007 log::debug!(
4008 "Adding `IndexPriceUpdate` for {}",
4009 index_price.instrument_id
4010 );
4011
4012 if self.config.save_market_data {
4013 }
4015
4016 let index_prices_deque = self
4017 .index_prices
4018 .entry(index_price.instrument_id)
4019 .or_insert_with(|| BoundedVecDeque::new(self.config.tick_capacity));
4020 index_prices_deque.push_front(index_price);
4021 Ok(())
4022 }
4023
4024 pub fn add_funding_rate(&mut self, funding_rate: FundingRateUpdate) -> anyhow::Result<()> {
4030 log::debug!(
4031 "Adding `FundingRateUpdate` for {}",
4032 funding_rate.instrument_id
4033 );
4034
4035 if self.config.save_market_data {
4036 }
4038
4039 let funding_rates_deque = self
4040 .funding_rates
4041 .entry(funding_rate.instrument_id)
4042 .or_insert_with(|| BoundedVecDeque::new(self.config.tick_capacity));
4043 funding_rates_deque.push_front(funding_rate);
4044 Ok(())
4045 }
4046
4047 pub fn add_funding_rates(&mut self, funding_rates: &[FundingRateUpdate]) -> anyhow::Result<()> {
4053 check_slice_not_empty(funding_rates, stringify!(funding_rates))?;
4054
4055 let instrument_id = funding_rates[0].instrument_id;
4056 log::debug!(
4057 "Adding `FundingRateUpdate`[{}] {instrument_id}",
4058 funding_rates.len()
4059 );
4060
4061 if self.config.save_market_data
4062 && let Some(database) = &mut self.database
4063 {
4064 for funding_rate in funding_rates {
4065 database.add_funding_rate(funding_rate)?;
4066 }
4067 }
4068
4069 let funding_rate_deque = self
4070 .funding_rates
4071 .entry(instrument_id)
4072 .or_insert_with(|| BoundedVecDeque::new(self.config.tick_capacity));
4073
4074 for funding_rate in funding_rates {
4075 funding_rate_deque.push_front(*funding_rate);
4076 }
4077 Ok(())
4078 }
4079
4080 pub fn add_instrument_status(&mut self, status: InstrumentStatus) -> anyhow::Result<()> {
4086 log::debug!("Adding `InstrumentStatus` for {}", status.instrument_id);
4087
4088 if self.config.save_market_data {
4089 }
4091
4092 let statuses_deque = self
4093 .instrument_statuses
4094 .entry(status.instrument_id)
4095 .or_insert_with(|| BoundedVecDeque::new(self.config.tick_capacity));
4096 statuses_deque.push_front(status);
4097 Ok(())
4098 }
4099
4100 pub fn add_quote(&mut self, quote: QuoteTick) -> anyhow::Result<()> {
4106 log::debug!("Adding `QuoteTick` {}", quote.instrument_id);
4107
4108 if self.config.save_market_data
4109 && let Some(database) = &mut self.database
4110 {
4111 database.add_quote("e)?;
4112 }
4113
4114 let quotes_deque = self
4115 .quotes
4116 .entry(quote.instrument_id)
4117 .or_insert_with(|| BoundedVecDeque::new(self.config.tick_capacity));
4118 quotes_deque.push_front(quote);
4119 Ok(())
4120 }
4121
4122 pub fn add_quotes(&mut self, quotes: &[QuoteTick]) -> anyhow::Result<()> {
4128 check_slice_not_empty(quotes, stringify!(quotes))?;
4129
4130 let instrument_id = quotes[0].instrument_id;
4131 log::debug!("Adding `QuoteTick`[{}] {instrument_id}", quotes.len());
4132
4133 if self.config.save_market_data
4134 && let Some(database) = &mut self.database
4135 {
4136 for quote in quotes {
4137 database.add_quote(quote)?;
4138 }
4139 }
4140
4141 let quotes_deque = self
4142 .quotes
4143 .entry(instrument_id)
4144 .or_insert_with(|| BoundedVecDeque::new(self.config.tick_capacity));
4145
4146 for quote in quotes {
4147 quotes_deque.push_front(*quote);
4148 }
4149 Ok(())
4150 }
4151
4152 pub fn add_trade(&mut self, trade: TradeTick) -> anyhow::Result<()> {
4158 log::debug!("Adding `TradeTick` {}", trade.instrument_id);
4159
4160 if self.config.save_market_data
4161 && let Some(database) = &mut self.database
4162 {
4163 database.add_trade(&trade)?;
4164 }
4165
4166 let trades_deque = self
4167 .trades
4168 .entry(trade.instrument_id)
4169 .or_insert_with(|| BoundedVecDeque::new(self.config.tick_capacity));
4170 trades_deque.push_front(trade);
4171 Ok(())
4172 }
4173
4174 pub fn add_trades(&mut self, trades: &[TradeTick]) -> anyhow::Result<()> {
4180 check_slice_not_empty(trades, stringify!(trades))?;
4181
4182 let instrument_id = trades[0].instrument_id;
4183 log::debug!("Adding `TradeTick`[{}] {instrument_id}", trades.len());
4184
4185 if self.config.save_market_data
4186 && let Some(database) = &mut self.database
4187 {
4188 for trade in trades {
4189 database.add_trade(trade)?;
4190 }
4191 }
4192
4193 let trades_deque = self
4194 .trades
4195 .entry(instrument_id)
4196 .or_insert_with(|| BoundedVecDeque::new(self.config.tick_capacity));
4197
4198 for trade in trades {
4199 trades_deque.push_front(*trade);
4200 }
4201 Ok(())
4202 }
4203
4204 pub fn add_bar(&mut self, bar: Bar) -> anyhow::Result<()> {
4210 log::debug!("Adding `Bar` {}", bar.bar_type);
4211
4212 if self.config.save_market_data
4213 && let Some(database) = &mut self.database
4214 {
4215 database.add_bar(&bar)?;
4216 }
4217
4218 let bars = self
4219 .bars
4220 .entry(bar.bar_type)
4221 .or_insert_with(|| BoundedVecDeque::new(self.config.bar_capacity));
4222 bars.push_front(bar);
4223 Ok(())
4224 }
4225
4226 pub fn add_bars(&mut self, bars: &[Bar]) -> anyhow::Result<()> {
4232 check_slice_not_empty(bars, stringify!(bars))?;
4233
4234 let bar_type = bars[0].bar_type;
4235 log::debug!("Adding `Bar`[{}] {bar_type}", bars.len());
4236
4237 if self.config.save_market_data
4238 && let Some(database) = &mut self.database
4239 {
4240 for bar in bars {
4241 database.add_bar(bar)?;
4242 }
4243 }
4244
4245 let bars_deque = self
4246 .bars
4247 .entry(bar_type)
4248 .or_insert_with(|| BoundedVecDeque::new(self.config.bar_capacity));
4249
4250 for bar in bars {
4251 bars_deque.push_front(*bar);
4252 }
4253 Ok(())
4254 }
4255
4256 pub fn add_greeks(&mut self, greeks: GreeksData) -> anyhow::Result<()> {
4262 log::debug!("Adding `GreeksData` {}", greeks.instrument_id);
4263
4264 if self.config.save_market_data
4265 && let Some(_database) = &mut self.database
4266 {
4267 }
4269
4270 self.greeks.insert(greeks.instrument_id, greeks);
4271 Ok(())
4272 }
4273
4274 pub fn greeks(&self, instrument_id: &InstrumentId) -> Option<GreeksData> {
4276 self.greeks.get(instrument_id).cloned()
4277 }
4278
4279 pub fn add_option_greeks(&mut self, greeks: OptionGreeks) {
4281 log::debug!("Adding `OptionGreeks` {}", greeks.instrument_id);
4282 self.option_greeks.insert(greeks.instrument_id, greeks);
4283 }
4284
4285 #[must_use]
4287 pub fn option_greeks(&self, instrument_id: &InstrumentId) -> Option<&OptionGreeks> {
4288 self.option_greeks.get(instrument_id)
4289 }
4290
4291 pub fn add_yield_curve(&mut self, yield_curve: YieldCurveData) -> anyhow::Result<()> {
4297 log::debug!("Adding `YieldCurveData` {}", yield_curve.curve_name);
4298
4299 if self.config.save_market_data
4300 && let Some(_database) = &mut self.database
4301 {
4302 }
4304
4305 self.yield_curves
4306 .insert(yield_curve.curve_name.clone(), yield_curve);
4307 Ok(())
4308 }
4309
4310 pub fn yield_curve(&self, key: &str) -> Option<Box<dyn Fn(f64) -> f64>> {
4312 self.yield_curves.get(key).map(|curve| {
4313 let curve_clone = curve.clone();
4314 Box::new(move |expiry_in_years: f64| curve_clone.get_rate(expiry_in_years))
4315 as Box<dyn Fn(f64) -> f64>
4316 })
4317 }
4318
4319 pub fn add_currency(&mut self, currency: Currency) -> anyhow::Result<()> {
4325 if self.currencies.contains_key(¤cy.code) {
4326 return Ok(());
4327 }
4328 log::debug!("Adding `Currency` {}", currency.code);
4329
4330 if let Some(database) = &mut self.database {
4331 database.add_currency(¤cy)?;
4332 }
4333
4334 self.currencies.insert(currency.code, currency);
4335 Ok(())
4336 }
4337
4338 pub fn add_instrument(&mut self, instrument: InstrumentAny) -> anyhow::Result<()> {
4344 log::debug!("Adding `Instrument` {}", instrument.id());
4345
4346 if let Some(base_currency) = instrument.base_currency() {
4348 self.add_currency(base_currency)?;
4349 }
4350 self.add_currency(instrument.quote_currency())?;
4351 self.add_currency(instrument.settlement_currency())?;
4352
4353 if let Some(database) = &mut self.database {
4354 database.add_instrument(&instrument)?;
4355 }
4356
4357 self.instruments.insert(instrument.id(), instrument);
4358 Ok(())
4359 }
4360
4361 pub fn add_synthetic(&mut self, synthetic: SyntheticInstrument) -> anyhow::Result<()> {
4367 log::debug!("Adding `SyntheticInstrument` {}", synthetic.id);
4368
4369 if let Some(database) = &mut self.database {
4370 database.add_synthetic(&synthetic)?;
4371 }
4372
4373 self.synthetics.insert(synthetic.id, synthetic);
4374 Ok(())
4375 }
4376
4377 pub fn add_account(&mut self, account: AccountAny) -> anyhow::Result<()> {
4383 log::debug!("Adding `Account` {}", account.id());
4384
4385 if let Some(database) = &mut self.database {
4386 database.add_account(&account)?;
4387 }
4388
4389 let account_id = account.id();
4390 self.accounts.insert(account_id, SharedCell::new(account));
4391 self.index
4392 .venue_account
4393 .insert(account_id.get_issuer(), account_id);
4394 Ok(())
4395 }
4396
4397 pub fn add_venue_order_id(
4406 &mut self,
4407 client_order_id: &ClientOrderId,
4408 venue_order_id: &VenueOrderId,
4409 overwrite: bool,
4410 ) -> anyhow::Result<()> {
4411 self.validate_venue_order_id_claim(client_order_id, venue_order_id, overwrite)?;
4412
4413 self.index
4414 .client_order_ids
4415 .insert(*client_order_id, *venue_order_id);
4416 self.index
4417 .venue_order_ids
4418 .insert(*venue_order_id, *client_order_id);
4419
4420 Ok(())
4421 }
4422
4423 fn validate_venue_order_id_claim(
4424 &self,
4425 client_order_id: &ClientOrderId,
4426 venue_order_id: &VenueOrderId,
4427 overwrite: bool,
4428 ) -> anyhow::Result<()> {
4429 self.validate_venue_order_id_ownership(client_order_id, venue_order_id)?;
4430
4431 if let Some(existing_venue_order_id) = self.index.client_order_ids.get(client_order_id)
4432 && !overwrite
4433 && existing_venue_order_id != venue_order_id
4434 {
4435 anyhow::bail!(
4436 "Existing {existing_venue_order_id} for {client_order_id}
4437 did not match the given {venue_order_id}.
4438 If you are writing a test then try a different `venue_order_id`,
4439 otherwise this is probably a bug."
4440 );
4441 }
4442
4443 Ok(())
4444 }
4445
4446 fn validate_venue_order_id_ownership(
4447 &self,
4448 client_order_id: &ClientOrderId,
4449 venue_order_id: &VenueOrderId,
4450 ) -> anyhow::Result<()> {
4451 if let Some(existing_client_order_id) = self.index.venue_order_ids.get(venue_order_id)
4452 && existing_client_order_id != client_order_id
4453 {
4454 return Err(VenueOrderIdOwnershipError {
4455 venue_order_id: *venue_order_id,
4456 existing_client_order_id: *existing_client_order_id,
4457 claimant_client_order_id: *client_order_id,
4458 }
4459 .into());
4460 }
4461
4462 Ok(())
4463 }
4464
4465 pub fn add_order(
4477 &mut self,
4478 order: OrderAny,
4479 position_id: Option<PositionId>,
4480 client_id: Option<ClientId>,
4481 replace_existing: bool,
4482 ) -> anyhow::Result<()> {
4483 let instrument_id = order.instrument_id();
4484 let venue = instrument_id.venue;
4485 let client_order_id = order.client_order_id();
4486 let strategy_id = order.strategy_id();
4487 let exec_algorithm_id = order.exec_algorithm_id();
4488 let exec_spawn_id = order.exec_spawn_id();
4489
4490 if !replace_existing {
4491 check_key_not_in_map(
4492 &client_order_id,
4493 &self.orders,
4494 stringify!(client_order_id),
4495 stringify!(orders),
4496 )?;
4497 }
4498
4499 log::debug!("Adding {order:?}");
4500
4501 self.index.orders.insert(client_order_id);
4502
4503 if order.is_active_local() {
4504 self.index.orders_active_local.insert(client_order_id);
4505 }
4506 self.index
4507 .order_strategy
4508 .insert(client_order_id, strategy_id);
4509 self.index.strategies.insert(strategy_id);
4510
4511 self.index
4513 .venue_orders
4514 .entry(venue)
4515 .or_default()
4516 .insert(client_order_id);
4517
4518 self.index
4520 .instrument_orders
4521 .entry(instrument_id)
4522 .or_default()
4523 .insert(client_order_id);
4524
4525 self.index
4527 .strategy_orders
4528 .entry(strategy_id)
4529 .or_default()
4530 .insert(client_order_id);
4531
4532 if let Some(account_id) = order.account_id() {
4534 self.index
4535 .account_orders
4536 .entry(account_id)
4537 .or_default()
4538 .insert(client_order_id);
4539 }
4540
4541 if let Some(exec_algorithm_id) = exec_algorithm_id {
4543 self.index.exec_algorithms.insert(exec_algorithm_id);
4544
4545 self.index
4546 .exec_algorithm_orders
4547 .entry(exec_algorithm_id)
4548 .or_default()
4549 .insert(client_order_id);
4550 }
4551
4552 if let Some(exec_spawn_id) = exec_spawn_id {
4554 self.index
4555 .exec_spawn_orders
4556 .entry(exec_spawn_id)
4557 .or_default()
4558 .insert(client_order_id);
4559 }
4560
4561 if let Some(emulation_trigger) = order.emulation_trigger()
4563 && emulation_trigger != TriggerType::NoTrigger
4564 {
4565 self.index.orders_emulated.insert(client_order_id);
4566 }
4567
4568 if let Some(position_id) = position_id {
4570 self.add_position_id(
4571 &position_id,
4572 &order.instrument_id().venue,
4573 &client_order_id,
4574 &strategy_id,
4575 )?;
4576 }
4577
4578 if let Some(client_id) = client_id {
4580 self.index.order_client.insert(client_order_id, client_id);
4581 log::debug!("Indexed {client_id:?}");
4582 }
4583
4584 if let Some(database) = &mut self.database {
4585 database.add_order(&order, client_id)?;
4586 }
4591
4592 match self.orders.get(&client_order_id) {
4593 Some(order_cell) => *order_cell.borrow_mut() = order,
4596 None => {
4597 self.orders.insert(client_order_id, SharedCell::new(order));
4598 }
4599 }
4600
4601 Ok(())
4602 }
4603
4604 pub fn add_order_list(&mut self, order_list: OrderList) -> anyhow::Result<()> {
4610 let order_list_id = order_list.id;
4611 check_key_not_in_map(
4612 &order_list_id,
4613 &self.order_lists,
4614 stringify!(order_list_id),
4615 stringify!(order_lists),
4616 )?;
4617
4618 log::debug!("Adding {order_list:?}");
4619 self.order_lists.insert(order_list_id, order_list);
4620 Ok(())
4621 }
4622
4623 pub fn add_position_id(
4629 &mut self,
4630 position_id: &PositionId,
4631 venue: &Venue,
4632 client_order_id: &ClientOrderId,
4633 strategy_id: &StrategyId,
4634 ) -> anyhow::Result<()> {
4635 self.index
4636 .order_position
4637 .insert(*client_order_id, *position_id);
4638
4639 if let Some(database) = &mut self.database {
4641 database.index_order_position(*client_order_id, *position_id)?;
4642 }
4643
4644 self.index
4646 .position_strategy
4647 .insert(*position_id, *strategy_id);
4648
4649 self.index
4651 .position_orders
4652 .entry(*position_id)
4653 .or_default()
4654 .insert(*client_order_id);
4655
4656 self.index
4658 .strategy_positions
4659 .entry(*strategy_id)
4660 .or_default()
4661 .insert(*position_id);
4662
4663 self.index
4665 .venue_positions
4666 .entry(*venue)
4667 .or_default()
4668 .insert(*position_id);
4669
4670 Ok(())
4671 }
4672
4673 fn assign_position_ids_to_contingencies(&mut self) {
4682 let mut assignments: Vec<(PositionId, ClientOrderId)> = Vec::new();
4683
4684 for parent_order_cell in self.orders.values() {
4685 let parent = parent_order_cell.borrow();
4686 if parent.contingency_type() != Some(ContingencyType::Oto) {
4687 continue;
4688 }
4689 let Some(parent_position_id) = parent.position_id() else {
4690 continue;
4691 };
4692 let Some(linked_order_ids) = parent.linked_order_ids() else {
4693 continue;
4694 };
4695
4696 for client_order_id in linked_order_ids {
4697 match self.orders.get(client_order_id) {
4698 None => {
4699 log::error!("Contingency order {client_order_id} not found");
4700 }
4701 Some(contingent_order_cell) => {
4702 if contingent_order_cell.borrow().position_id().is_none() {
4703 assignments.push((parent_position_id, *client_order_id));
4704 }
4705 }
4706 }
4707 }
4708 }
4709
4710 for (position_id, client_order_id) in assignments {
4711 let Some((venue, strategy_id)) = self.orders.get(&client_order_id).map(|order_cell| {
4712 let mut contingent = order_cell.borrow_mut();
4713 contingent.set_position_id(Some(position_id));
4714 (contingent.instrument_id().venue, contingent.strategy_id())
4715 }) else {
4716 continue;
4717 };
4718
4719 if let Err(e) =
4722 self.add_position_id(&position_id, &venue, &client_order_id, &strategy_id)
4723 {
4724 log::error!("Failed to re-index {client_order_id} -> {position_id}: {e}");
4725 }
4726 }
4727 }
4728
4729 pub fn add_position(&mut self, position: &Position, oms_type: OmsType) -> anyhow::Result<()> {
4735 self.positions
4736 .insert(position.id, SharedCell::new(position.clone()));
4737 self.index.position_oms.insert(position.id, oms_type);
4738 self.index.positions.insert(position.id);
4739 self.index.positions_open.insert(position.id);
4740 self.index.positions_closed.remove(&position.id); log::debug!("Adding {position}");
4743
4744 self.add_position_id(
4745 &position.id,
4746 &position.instrument_id.venue,
4747 &position.opening_order_id,
4748 &position.strategy_id,
4749 )?;
4750
4751 let venue = position.instrument_id.venue;
4752 let venue_positions = self.index.venue_positions.entry(venue).or_default();
4753 venue_positions.insert(position.id);
4754
4755 let instrument_id = position.instrument_id;
4757 let instrument_positions = self
4758 .index
4759 .instrument_positions
4760 .entry(instrument_id)
4761 .or_default();
4762 instrument_positions.insert(position.id);
4763
4764 self.index
4766 .account_positions
4767 .entry(position.account_id)
4768 .or_default()
4769 .insert(position.id);
4770
4771 if let Some(database) = &mut self.database {
4772 database.add_position(position)?;
4773 }
4782
4783 let key = position_oms_key(position.id);
4784 let value = Bytes::from(serde_json::to_vec(&oms_type)?);
4785 self.add(&key, value)?;
4786
4787 Ok(())
4788 }
4789
4790 pub fn update_account(&mut self, account: &AccountAny) -> anyhow::Result<()> {
4799 let account_id = account.id();
4800 match self.accounts.get(&account_id) {
4801 Some(account_cell) => *account_cell.borrow_mut() = account.clone(),
4802 None => {
4803 self.accounts
4804 .insert(account_id, SharedCell::new(account.clone()));
4805 }
4806 }
4807
4808 if let Some(database) = &mut self.database {
4809 database.update_account(account)?;
4810 }
4811 Ok(())
4812 }
4813
4814 #[must_use]
4829 pub fn take_account(&mut self, account_id: &AccountId) -> Option<AccountAny> {
4830 self.accounts.remove(account_id).map(|cell| {
4831 let rc: Rc<RefCell<AccountAny>> = cell.into();
4832 Rc::try_unwrap(rc).map_or_else(
4833 |_| panic!("take_account: cache must be sole owner of {account_id} cell"),
4834 RefCell::into_inner,
4835 )
4836 })
4837 }
4838
4839 pub fn cache_account_owned(&mut self, account: AccountAny) {
4841 let account_id = account.id();
4842 self.index
4843 .venue_account
4844 .insert(account_id.get_issuer(), account_id);
4845 match self.accounts.get(&account_id) {
4846 Some(account_cell) => *account_cell.borrow_mut() = account,
4847 None => {
4848 self.accounts.insert(account_id, SharedCell::new(account));
4849 }
4850 }
4851 }
4852
4853 pub fn update_account_owned(&mut self, account: AccountAny) -> anyhow::Result<()> {
4859 let account_id = account.id();
4860 self.cache_account_owned(account);
4861
4862 if let Some(database) = &mut self.database {
4863 let Some(account_cell) = self.accounts.get(&account_id) else {
4864 anyhow::bail!("Account {account_id} not found after cache update");
4865 };
4866 database.update_account(&account_cell.borrow())?;
4867 }
4868 Ok(())
4869 }
4870
4871 pub fn update_account_state(&mut self, event: &AccountState) -> anyhow::Result<()> {
4881 let Some(cell) = self.accounts.get(&event.account_id) else {
4882 return self.add_account(AccountAny::from_events(std::slice::from_ref(event))?);
4883 };
4884
4885 cell.borrow_mut().apply(event.clone())?;
4886
4887 if let Some(database) = &mut self.database {
4888 database.update_account(&cell.borrow())?;
4889 }
4890 Ok(())
4891 }
4892
4893 pub fn replace_order(&mut self, order: &OrderAny) -> anyhow::Result<()> {
4902 self.refresh_order(order)?;
4903
4904 let client_order_id = order.client_order_id();
4905 match self.orders.get(&client_order_id) {
4906 Some(order_cell) => *order_cell.borrow_mut() = order.clone(),
4909 None => {
4910 self.orders
4911 .insert(client_order_id, SharedCell::new(order.clone()));
4912 }
4913 }
4914
4915 Ok(())
4916 }
4917
4918 pub fn update_order(&mut self, event: &OrderEventAny) -> anyhow::Result<OrderAny> {
4924 let event_client_order_id = event.client_order_id();
4925 let client_order_id = if self.order_exists(&event_client_order_id) {
4926 event_client_order_id
4927 } else if let Some(venue_order_id) = event.venue_order_id() {
4928 self.index
4929 .venue_order_ids
4930 .get(&venue_order_id)
4931 .copied()
4932 .ok_or(OrderError::NotFound(event_client_order_id))?
4933 } else {
4934 return Err(OrderError::NotFound(event_client_order_id).into());
4935 };
4936
4937 let order_cell = self
4938 .orders
4939 .get(&client_order_id)
4940 .cloned()
4941 .ok_or(OrderError::NotFound(client_order_id))?;
4942
4943 let mut snapshot = order_cell.borrow().clone();
4947 snapshot.apply(event.clone())?;
4948
4949 if let Some(venue_order_id) = snapshot.venue_order_id() {
4953 self.validate_venue_order_id_ownership(&client_order_id, &venue_order_id)?;
4954 }
4955
4956 *order_cell.borrow_mut() = snapshot.clone();
4957
4958 if let Err(e) = self.refresh_order(&snapshot) {
4959 log::error!("Error updating order in cache: {e}");
4960 }
4961
4962 Ok(snapshot)
4963 }
4964
4965 fn refresh_order(&mut self, order: &OrderAny) -> anyhow::Result<()> {
4966 let client_order_id = order.client_order_id();
4967
4968 if let Some(venue_order_id) = order.venue_order_id() {
4971 let overwrite = matches!(order.last_event(), OrderEventAny::Updated(_));
4972 if let Err(e) = self.add_venue_order_id(&client_order_id, &venue_order_id, overwrite) {
4973 if e.is::<VenueOrderIdOwnershipError>() {
4974 return Err(e);
4975 }
4976 log::error!("Error indexing venue order ID in cache: {e}");
4977 }
4978 }
4979
4980 if order.is_active_local() {
4981 self.index.orders_active_local.insert(client_order_id);
4982 } else {
4983 self.index.orders_active_local.remove(&client_order_id);
4984 }
4985
4986 if order.is_inflight() {
4988 self.index.orders_inflight.insert(client_order_id);
4989 } else {
4990 self.index.orders_inflight.remove(&client_order_id);
4991 }
4992
4993 if order.is_open() {
4995 self.index.orders_closed.remove(&client_order_id);
4996 self.index.orders_open.insert(client_order_id);
4997 } else if order.is_closed() {
4998 self.index.orders_open.remove(&client_order_id);
4999 self.index.orders_pending_cancel.remove(&client_order_id);
5000 self.index.orders_closed.insert(client_order_id);
5001 }
5002
5003 if matches!(order.last_event(), OrderEventAny::CancelRejected(_)) {
5005 self.index.orders_pending_cancel.remove(&client_order_id);
5006 }
5007
5008 if let Some(emulation_trigger) = order.emulation_trigger()
5010 && emulation_trigger != TriggerType::NoTrigger
5011 && !order.is_closed()
5012 {
5013 self.index.orders_emulated.insert(client_order_id);
5014 } else {
5015 self.index.orders_emulated.remove(&client_order_id);
5016 }
5017
5018 if let Some(account_id) = order.account_id() {
5020 self.index
5021 .account_orders
5022 .entry(account_id)
5023 .or_default()
5024 .insert(client_order_id);
5025 }
5026
5027 if !self.own_books.is_empty() {
5029 let own_book = self.own_order_book(&order.instrument_id());
5030 if (own_book.is_some() && order.is_closed()) || should_handle_own_book_order(order) {
5031 self.update_own_order_book(order);
5032 }
5033 }
5034
5035 if let Some(database) = &mut self.database {
5036 database.update_order(order.last_event())?;
5037 }
5042
5043 Ok(())
5044 }
5045
5046 pub fn update_order_pending_cancel_local(&mut self, order: &OrderAny) {
5048 self.index
5049 .orders_pending_cancel
5050 .insert(order.client_order_id());
5051 }
5052
5053 pub fn update_position(&mut self, position: &Position) -> anyhow::Result<()> {
5062 if position.is_open() {
5065 self.index.positions_open.insert(position.id);
5066 self.index.positions_closed.remove(&position.id);
5067 } else {
5068 self.index.positions_closed.insert(position.id);
5069 self.index.positions_open.remove(&position.id);
5070 }
5071
5072 if let Some(database) = &mut self.database {
5073 database.update_position(position)?;
5074 }
5079
5080 match self.positions.get(&position.id) {
5081 Some(position_cell) => *position_cell.borrow_mut() = position.clone(),
5082 None => {
5083 self.positions
5084 .insert(position.id, SharedCell::new(position.clone()));
5085 }
5086 }
5087
5088 Ok(())
5089 }
5090
5091 #[must_use]
5093 pub fn oms_type(&self, position_id: &PositionId) -> Option<OmsType> {
5094 self.index.position_oms.get(position_id).copied()
5095 }
5096
5097 pub fn snapshot_order_state(&self, order: &OrderAny) -> anyhow::Result<()> {
5103 let Some(database) = &self.database else {
5104 log::warn!(
5105 "Cannot snapshot order state for {} (no database configured)",
5106 order.client_order_id()
5107 );
5108 return Ok(());
5109 };
5110
5111 database.snapshot_order_state(order)
5112 }
5113
5114 fn collect_order_filter_sources<'a>(
5125 &'a self,
5126 venue: Option<&Venue>,
5127 instrument_id: Option<&InstrumentId>,
5128 strategy_id: Option<&StrategyId>,
5129 account_id: Option<&AccountId>,
5130 ) -> FilterSources<'a, ClientOrderId> {
5131 let mut sources: Vec<&AHashSet<ClientOrderId>> = Vec::with_capacity(4);
5132
5133 if let Some(venue) = venue {
5134 match self.index.venue_orders.get(venue) {
5135 Some(set) => sources.push(set),
5136 None => return FilterSources::Empty,
5137 }
5138 }
5139
5140 if let Some(instrument_id) = instrument_id {
5141 match self.index.instrument_orders.get(instrument_id) {
5142 Some(set) => sources.push(set),
5143 None => return FilterSources::Empty,
5144 }
5145 }
5146
5147 if let Some(strategy_id) = strategy_id {
5148 match self.index.strategy_orders.get(strategy_id) {
5149 Some(set) => sources.push(set),
5150 None => return FilterSources::Empty,
5151 }
5152 }
5153
5154 if let Some(account_id) = account_id {
5155 match self.index.account_orders.get(account_id) {
5156 Some(set) => sources.push(set),
5157 None => return FilterSources::Empty,
5158 }
5159 }
5160
5161 if sources.is_empty() {
5162 FilterSources::Unfiltered
5163 } else {
5164 FilterSources::Sets(sources)
5165 }
5166 }
5167
5168 fn collect_position_filter_sources<'a>(
5169 &'a self,
5170 venue: Option<&Venue>,
5171 instrument_id: Option<&InstrumentId>,
5172 strategy_id: Option<&StrategyId>,
5173 account_id: Option<&AccountId>,
5174 ) -> FilterSources<'a, PositionId> {
5175 let mut sources: Vec<&AHashSet<PositionId>> = Vec::with_capacity(4);
5176
5177 if let Some(venue) = venue {
5178 match self.index.venue_positions.get(venue) {
5179 Some(set) => sources.push(set),
5180 None => return FilterSources::Empty,
5181 }
5182 }
5183
5184 if let Some(instrument_id) = instrument_id {
5185 match self.index.instrument_positions.get(instrument_id) {
5186 Some(set) => sources.push(set),
5187 None => return FilterSources::Empty,
5188 }
5189 }
5190
5191 if let Some(strategy_id) = strategy_id {
5192 match self.index.strategy_positions.get(strategy_id) {
5193 Some(set) => sources.push(set),
5194 None => return FilterSources::Empty,
5195 }
5196 }
5197
5198 if let Some(account_id) = account_id {
5199 match self.index.account_positions.get(account_id) {
5200 Some(set) => sources.push(set),
5201 None => return FilterSources::Empty,
5202 }
5203 }
5204
5205 if sources.is_empty() {
5206 FilterSources::Unfiltered
5207 } else {
5208 FilterSources::Sets(sources)
5209 }
5210 }
5211
5212 fn query_orders_in_bucket(
5218 &self,
5219 bucket: &AHashSet<ClientOrderId>,
5220 venue: Option<&Venue>,
5221 instrument_id: Option<&InstrumentId>,
5222 strategy_id: Option<&StrategyId>,
5223 account_id: Option<&AccountId>,
5224 ) -> AHashSet<ClientOrderId> {
5225 match self.collect_order_filter_sources(venue, instrument_id, strategy_id, account_id) {
5226 FilterSources::Empty => AHashSet::new(),
5227 FilterSources::Unfiltered => bucket.clone(),
5228 FilterSources::Sets(sources) => intersect_pair_or_many(bucket, sources),
5229 }
5230 }
5231
5232 fn query_positions_in_bucket(
5233 &self,
5234 bucket: &AHashSet<PositionId>,
5235 venue: Option<&Venue>,
5236 instrument_id: Option<&InstrumentId>,
5237 strategy_id: Option<&StrategyId>,
5238 account_id: Option<&AccountId>,
5239 ) -> AHashSet<PositionId> {
5240 match self.collect_position_filter_sources(venue, instrument_id, strategy_id, account_id) {
5241 FilterSources::Empty => AHashSet::new(),
5242 FilterSources::Unfiltered => bucket.clone(),
5243 FilterSources::Sets(sources) => intersect_pair_or_many(bucket, sources),
5244 }
5245 }
5246
5247 fn view_orders_in_bucket<'a>(
5250 &'a self,
5251 bucket: &'a AHashSet<ClientOrderId>,
5252 venue: Option<&Venue>,
5253 instrument_id: Option<&InstrumentId>,
5254 strategy_id: Option<&StrategyId>,
5255 account_id: Option<&AccountId>,
5256 ) -> Cow<'a, AHashSet<ClientOrderId>> {
5257 match self.collect_order_filter_sources(venue, instrument_id, strategy_id, account_id) {
5258 FilterSources::Empty => Cow::Owned(AHashSet::new()),
5259 FilterSources::Unfiltered => Cow::Borrowed(bucket),
5260 FilterSources::Sets(sources) => Cow::Owned(intersect_pair_or_many(bucket, sources)),
5261 }
5262 }
5263
5264 fn view_positions_in_bucket<'a>(
5265 &'a self,
5266 bucket: &'a AHashSet<PositionId>,
5267 venue: Option<&Venue>,
5268 instrument_id: Option<&InstrumentId>,
5269 strategy_id: Option<&StrategyId>,
5270 account_id: Option<&AccountId>,
5271 ) -> Cow<'a, AHashSet<PositionId>> {
5272 match self.collect_position_filter_sources(venue, instrument_id, strategy_id, account_id) {
5273 FilterSources::Empty => Cow::Owned(AHashSet::new()),
5274 FilterSources::Unfiltered => Cow::Borrowed(bucket),
5275 FilterSources::Sets(sources) => Cow::Owned(intersect_pair_or_many(bucket, sources)),
5276 }
5277 }
5278
5279 fn iter_orders_in_bucket<'a>(
5284 &'a self,
5285 bucket: &'a AHashSet<ClientOrderId>,
5286 venue: Option<&Venue>,
5287 instrument_id: Option<&InstrumentId>,
5288 strategy_id: Option<&StrategyId>,
5289 account_id: Option<&AccountId>,
5290 ) -> Box<dyn Iterator<Item = ClientOrderId> + 'a> {
5291 match self.collect_order_filter_sources(venue, instrument_id, strategy_id, account_id) {
5292 FilterSources::Empty => Box::new(std::iter::empty()),
5293 FilterSources::Unfiltered => Box::new(bucket.iter().copied()),
5294 FilterSources::Sets(mut sources) => {
5295 sources.push(bucket);
5296 sources.sort_unstable_by_key(|s| s.len());
5297 let driver = sources[0];
5298 let rest: Vec<&'a AHashSet<ClientOrderId>> = sources[1..].to_vec();
5299 Box::new(
5300 driver
5301 .iter()
5302 .copied()
5303 .filter(move |id| rest.iter().all(|s| s.contains(id))),
5304 )
5305 }
5306 }
5307 }
5308
5309 fn iter_positions_in_bucket<'a>(
5310 &'a self,
5311 bucket: &'a AHashSet<PositionId>,
5312 venue: Option<&Venue>,
5313 instrument_id: Option<&InstrumentId>,
5314 strategy_id: Option<&StrategyId>,
5315 account_id: Option<&AccountId>,
5316 ) -> Box<dyn Iterator<Item = PositionId> + 'a> {
5317 match self.collect_position_filter_sources(venue, instrument_id, strategy_id, account_id) {
5318 FilterSources::Empty => Box::new(std::iter::empty()),
5319 FilterSources::Unfiltered => Box::new(bucket.iter().copied()),
5320 FilterSources::Sets(mut sources) => {
5321 sources.push(bucket);
5322 sources.sort_unstable_by_key(|s| s.len());
5323 let driver = sources[0];
5324 let rest: Vec<&'a AHashSet<PositionId>> = sources[1..].to_vec();
5325 Box::new(
5326 driver
5327 .iter()
5328 .copied()
5329 .filter(move |id| rest.iter().all(|s| s.contains(id))),
5330 )
5331 }
5332 }
5333 }
5334
5335 fn count_orders_in_bucket(
5341 &self,
5342 bucket: &AHashSet<ClientOrderId>,
5343 venue: Option<&Venue>,
5344 instrument_id: Option<&InstrumentId>,
5345 strategy_id: Option<&StrategyId>,
5346 account_id: Option<&AccountId>,
5347 side: Option<OrderSide>,
5348 ) -> usize {
5349 let side = side.unwrap_or(OrderSide::NoOrderSide);
5350
5351 match self.collect_order_filter_sources(venue, instrument_id, strategy_id, account_id) {
5352 FilterSources::Empty => 0,
5353 FilterSources::Unfiltered => {
5354 if side == OrderSide::NoOrderSide {
5355 bucket.len()
5356 } else {
5357 bucket
5358 .iter()
5359 .filter(|id| self.order_side_matches(id, side))
5360 .count()
5361 }
5362 }
5363 FilterSources::Sets(mut sources) => {
5364 sources.push(bucket);
5365 sources.sort_unstable_by_key(|s| s.len());
5366 let driver = sources[0];
5367 let rest = &sources[1..];
5368
5369 driver
5370 .iter()
5371 .filter(|id| rest.iter().all(|s| s.contains(id)))
5372 .filter(|id| {
5373 side == OrderSide::NoOrderSide || self.order_side_matches(id, side)
5374 })
5375 .count()
5376 }
5377 }
5378 }
5379
5380 fn count_positions_in_bucket(
5381 &self,
5382 bucket: &AHashSet<PositionId>,
5383 venue: Option<&Venue>,
5384 instrument_id: Option<&InstrumentId>,
5385 strategy_id: Option<&StrategyId>,
5386 account_id: Option<&AccountId>,
5387 side: Option<PositionSide>,
5388 ) -> usize {
5389 let side = side.unwrap_or(PositionSide::NoPositionSide);
5390
5391 match self.collect_position_filter_sources(venue, instrument_id, strategy_id, account_id) {
5392 FilterSources::Empty => 0,
5393 FilterSources::Unfiltered => {
5394 if side == PositionSide::NoPositionSide {
5395 bucket.len()
5396 } else {
5397 bucket
5398 .iter()
5399 .filter(|id| self.position_side_matches(id, side))
5400 .count()
5401 }
5402 }
5403 FilterSources::Sets(mut sources) => {
5404 sources.push(bucket);
5405 sources.sort_unstable_by_key(|s| s.len());
5406 let driver = sources[0];
5407 let rest = &sources[1..];
5408
5409 driver
5410 .iter()
5411 .filter(|id| rest.iter().all(|s| s.contains(id)))
5412 .filter(|id| {
5413 side == PositionSide::NoPositionSide || self.position_side_matches(id, side)
5414 })
5415 .count()
5416 }
5417 }
5418 }
5419
5420 fn any_orders_in_bucket(
5426 &self,
5427 bucket: &AHashSet<ClientOrderId>,
5428 venue: Option<&Venue>,
5429 instrument_id: Option<&InstrumentId>,
5430 strategy_id: Option<&StrategyId>,
5431 account_id: Option<&AccountId>,
5432 side: Option<OrderSide>,
5433 ) -> bool {
5434 let side = side.unwrap_or(OrderSide::NoOrderSide);
5435
5436 match self.collect_order_filter_sources(venue, instrument_id, strategy_id, account_id) {
5437 FilterSources::Empty => false,
5438 FilterSources::Unfiltered => {
5439 if side == OrderSide::NoOrderSide {
5440 !bucket.is_empty()
5441 } else {
5442 bucket.iter().any(|id| self.order_side_matches(id, side))
5443 }
5444 }
5445 FilterSources::Sets(mut sources) => {
5446 sources.push(bucket);
5447 sources.sort_unstable_by_key(|s| s.len());
5448 let driver = sources[0];
5449 let rest = &sources[1..];
5450
5451 driver
5452 .iter()
5453 .filter(|id| rest.iter().all(|s| s.contains(id)))
5454 .any(|id| side == OrderSide::NoOrderSide || self.order_side_matches(id, side))
5455 }
5456 }
5457 }
5458
5459 fn any_positions_in_bucket(
5460 &self,
5461 bucket: &AHashSet<PositionId>,
5462 venue: Option<&Venue>,
5463 instrument_id: Option<&InstrumentId>,
5464 strategy_id: Option<&StrategyId>,
5465 account_id: Option<&AccountId>,
5466 side: Option<PositionSide>,
5467 ) -> bool {
5468 let side = side.unwrap_or(PositionSide::NoPositionSide);
5469
5470 match self.collect_position_filter_sources(venue, instrument_id, strategy_id, account_id) {
5471 FilterSources::Empty => false,
5472 FilterSources::Unfiltered => {
5473 if side == PositionSide::NoPositionSide {
5474 !bucket.is_empty()
5475 } else {
5476 bucket.iter().any(|id| self.position_side_matches(id, side))
5477 }
5478 }
5479 FilterSources::Sets(mut sources) => {
5480 sources.push(bucket);
5481 sources.sort_unstable_by_key(|s| s.len());
5482 let driver = sources[0];
5483 let rest = &sources[1..];
5484
5485 driver
5486 .iter()
5487 .filter(|id| rest.iter().all(|s| s.contains(id)))
5488 .any(|id| {
5489 side == PositionSide::NoPositionSide || self.position_side_matches(id, side)
5490 })
5491 }
5492 }
5493 }
5494
5495 fn order_side_matches(&self, client_order_id: &ClientOrderId, side: OrderSide) -> bool {
5496 self.orders
5497 .get(client_order_id)
5498 .is_some_and(|cell| cell.borrow().order_side() == side)
5499 }
5500
5501 fn position_side_matches(&self, position_id: &PositionId, side: PositionSide) -> bool {
5502 self.positions
5503 .get(position_id)
5504 .is_some_and(|cell| cell.borrow().side == side)
5505 }
5506
5507 fn get_orders_for_ids(
5513 &self,
5514 client_order_ids: &AHashSet<ClientOrderId>,
5515 side: Option<OrderSide>,
5516 ) -> Vec<OrderRef<'_>> {
5517 let side = side.unwrap_or(OrderSide::NoOrderSide);
5518 let mut orders = Vec::new();
5519
5520 for client_order_id in client_order_ids {
5521 let order_cell = self
5522 .orders
5523 .get(client_order_id)
5524 .unwrap_or_else(|| panic!("Order {client_order_id} not found"));
5525 let order = OrderRef::new(order_cell.borrow());
5526
5527 if side == OrderSide::NoOrderSide || side == order.order_side() {
5528 orders.push(order);
5529 }
5530 }
5531
5532 orders.sort_by_key(|o| o.client_order_id());
5535 orders
5536 }
5537
5538 fn get_positions_for_ids(
5548 &self,
5549 position_ids: &AHashSet<PositionId>,
5550 side: Option<PositionSide>,
5551 ) -> Vec<PositionRef<'_>> {
5552 let side = side.unwrap_or(PositionSide::NoPositionSide);
5553 let mut positions = Vec::new();
5554
5555 for position_id in position_ids {
5556 let position_cell = self
5557 .positions
5558 .get(position_id)
5559 .unwrap_or_else(|| panic!("Position {position_id} not found"));
5560 let position = PositionRef::new(position_cell.borrow());
5561
5562 if side == PositionSide::NoPositionSide || side == position.side {
5563 positions.push(position);
5564 }
5565 }
5566
5567 positions.sort_by_key(|p| p.id);
5570 positions
5571 }
5572
5573 #[must_use]
5575 pub fn client_order_ids(
5576 &self,
5577 venue: Option<&Venue>,
5578 instrument_id: Option<&InstrumentId>,
5579 strategy_id: Option<&StrategyId>,
5580 account_id: Option<&AccountId>,
5581 ) -> AHashSet<ClientOrderId> {
5582 self.query_orders_in_bucket(
5583 &self.index.orders,
5584 venue,
5585 instrument_id,
5586 strategy_id,
5587 account_id,
5588 )
5589 }
5590
5591 #[must_use]
5593 pub fn client_order_ids_open(
5594 &self,
5595 venue: Option<&Venue>,
5596 instrument_id: Option<&InstrumentId>,
5597 strategy_id: Option<&StrategyId>,
5598 account_id: Option<&AccountId>,
5599 ) -> AHashSet<ClientOrderId> {
5600 self.query_orders_in_bucket(
5601 &self.index.orders_open,
5602 venue,
5603 instrument_id,
5604 strategy_id,
5605 account_id,
5606 )
5607 }
5608
5609 #[must_use]
5611 pub fn client_order_ids_closed(
5612 &self,
5613 venue: Option<&Venue>,
5614 instrument_id: Option<&InstrumentId>,
5615 strategy_id: Option<&StrategyId>,
5616 account_id: Option<&AccountId>,
5617 ) -> AHashSet<ClientOrderId> {
5618 self.query_orders_in_bucket(
5619 &self.index.orders_closed,
5620 venue,
5621 instrument_id,
5622 strategy_id,
5623 account_id,
5624 )
5625 }
5626
5627 #[must_use]
5632 pub fn client_order_ids_active_local(
5633 &self,
5634 venue: Option<&Venue>,
5635 instrument_id: Option<&InstrumentId>,
5636 strategy_id: Option<&StrategyId>,
5637 account_id: Option<&AccountId>,
5638 ) -> AHashSet<ClientOrderId> {
5639 self.query_orders_in_bucket(
5640 &self.index.orders_active_local,
5641 venue,
5642 instrument_id,
5643 strategy_id,
5644 account_id,
5645 )
5646 }
5647
5648 #[must_use]
5650 pub fn client_order_ids_emulated(
5651 &self,
5652 venue: Option<&Venue>,
5653 instrument_id: Option<&InstrumentId>,
5654 strategy_id: Option<&StrategyId>,
5655 account_id: Option<&AccountId>,
5656 ) -> AHashSet<ClientOrderId> {
5657 self.query_orders_in_bucket(
5658 &self.index.orders_emulated,
5659 venue,
5660 instrument_id,
5661 strategy_id,
5662 account_id,
5663 )
5664 }
5665
5666 #[must_use]
5668 pub fn client_order_ids_inflight(
5669 &self,
5670 venue: Option<&Venue>,
5671 instrument_id: Option<&InstrumentId>,
5672 strategy_id: Option<&StrategyId>,
5673 account_id: Option<&AccountId>,
5674 ) -> AHashSet<ClientOrderId> {
5675 self.query_orders_in_bucket(
5676 &self.index.orders_inflight,
5677 venue,
5678 instrument_id,
5679 strategy_id,
5680 account_id,
5681 )
5682 }
5683
5684 #[must_use]
5686 pub fn position_ids(
5687 &self,
5688 venue: Option<&Venue>,
5689 instrument_id: Option<&InstrumentId>,
5690 strategy_id: Option<&StrategyId>,
5691 account_id: Option<&AccountId>,
5692 ) -> AHashSet<PositionId> {
5693 self.query_positions_in_bucket(
5694 &self.index.positions,
5695 venue,
5696 instrument_id,
5697 strategy_id,
5698 account_id,
5699 )
5700 }
5701
5702 #[must_use]
5704 pub fn position_open_ids(
5705 &self,
5706 venue: Option<&Venue>,
5707 instrument_id: Option<&InstrumentId>,
5708 strategy_id: Option<&StrategyId>,
5709 account_id: Option<&AccountId>,
5710 ) -> AHashSet<PositionId> {
5711 self.query_positions_in_bucket(
5712 &self.index.positions_open,
5713 venue,
5714 instrument_id,
5715 strategy_id,
5716 account_id,
5717 )
5718 }
5719
5720 #[must_use]
5722 pub fn position_closed_ids(
5723 &self,
5724 venue: Option<&Venue>,
5725 instrument_id: Option<&InstrumentId>,
5726 strategy_id: Option<&StrategyId>,
5727 account_id: Option<&AccountId>,
5728 ) -> AHashSet<PositionId> {
5729 self.query_positions_in_bucket(
5730 &self.index.positions_closed,
5731 venue,
5732 instrument_id,
5733 strategy_id,
5734 account_id,
5735 )
5736 }
5737
5738 #[must_use]
5745 pub fn client_order_ids_view(
5746 &self,
5747 venue: Option<&Venue>,
5748 instrument_id: Option<&InstrumentId>,
5749 strategy_id: Option<&StrategyId>,
5750 account_id: Option<&AccountId>,
5751 ) -> Cow<'_, AHashSet<ClientOrderId>> {
5752 self.view_orders_in_bucket(
5753 &self.index.orders,
5754 venue,
5755 instrument_id,
5756 strategy_id,
5757 account_id,
5758 )
5759 }
5760
5761 #[must_use]
5763 pub fn client_order_ids_open_view(
5764 &self,
5765 venue: Option<&Venue>,
5766 instrument_id: Option<&InstrumentId>,
5767 strategy_id: Option<&StrategyId>,
5768 account_id: Option<&AccountId>,
5769 ) -> Cow<'_, AHashSet<ClientOrderId>> {
5770 self.view_orders_in_bucket(
5771 &self.index.orders_open,
5772 venue,
5773 instrument_id,
5774 strategy_id,
5775 account_id,
5776 )
5777 }
5778
5779 #[must_use]
5781 pub fn client_order_ids_closed_view(
5782 &self,
5783 venue: Option<&Venue>,
5784 instrument_id: Option<&InstrumentId>,
5785 strategy_id: Option<&StrategyId>,
5786 account_id: Option<&AccountId>,
5787 ) -> Cow<'_, AHashSet<ClientOrderId>> {
5788 self.view_orders_in_bucket(
5789 &self.index.orders_closed,
5790 venue,
5791 instrument_id,
5792 strategy_id,
5793 account_id,
5794 )
5795 }
5796
5797 #[must_use]
5799 pub fn client_order_ids_active_local_view(
5800 &self,
5801 venue: Option<&Venue>,
5802 instrument_id: Option<&InstrumentId>,
5803 strategy_id: Option<&StrategyId>,
5804 account_id: Option<&AccountId>,
5805 ) -> Cow<'_, AHashSet<ClientOrderId>> {
5806 self.view_orders_in_bucket(
5807 &self.index.orders_active_local,
5808 venue,
5809 instrument_id,
5810 strategy_id,
5811 account_id,
5812 )
5813 }
5814
5815 #[must_use]
5817 pub fn client_order_ids_emulated_view(
5818 &self,
5819 venue: Option<&Venue>,
5820 instrument_id: Option<&InstrumentId>,
5821 strategy_id: Option<&StrategyId>,
5822 account_id: Option<&AccountId>,
5823 ) -> Cow<'_, AHashSet<ClientOrderId>> {
5824 self.view_orders_in_bucket(
5825 &self.index.orders_emulated,
5826 venue,
5827 instrument_id,
5828 strategy_id,
5829 account_id,
5830 )
5831 }
5832
5833 #[must_use]
5835 pub fn client_order_ids_inflight_view(
5836 &self,
5837 venue: Option<&Venue>,
5838 instrument_id: Option<&InstrumentId>,
5839 strategy_id: Option<&StrategyId>,
5840 account_id: Option<&AccountId>,
5841 ) -> Cow<'_, AHashSet<ClientOrderId>> {
5842 self.view_orders_in_bucket(
5843 &self.index.orders_inflight,
5844 venue,
5845 instrument_id,
5846 strategy_id,
5847 account_id,
5848 )
5849 }
5850
5851 #[must_use]
5853 pub fn position_ids_view(
5854 &self,
5855 venue: Option<&Venue>,
5856 instrument_id: Option<&InstrumentId>,
5857 strategy_id: Option<&StrategyId>,
5858 account_id: Option<&AccountId>,
5859 ) -> Cow<'_, AHashSet<PositionId>> {
5860 self.view_positions_in_bucket(
5861 &self.index.positions,
5862 venue,
5863 instrument_id,
5864 strategy_id,
5865 account_id,
5866 )
5867 }
5868
5869 #[must_use]
5871 pub fn position_open_ids_view(
5872 &self,
5873 venue: Option<&Venue>,
5874 instrument_id: Option<&InstrumentId>,
5875 strategy_id: Option<&StrategyId>,
5876 account_id: Option<&AccountId>,
5877 ) -> Cow<'_, AHashSet<PositionId>> {
5878 self.view_positions_in_bucket(
5879 &self.index.positions_open,
5880 venue,
5881 instrument_id,
5882 strategy_id,
5883 account_id,
5884 )
5885 }
5886
5887 #[must_use]
5889 pub fn position_closed_ids_view(
5890 &self,
5891 venue: Option<&Venue>,
5892 instrument_id: Option<&InstrumentId>,
5893 strategy_id: Option<&StrategyId>,
5894 account_id: Option<&AccountId>,
5895 ) -> Cow<'_, AHashSet<PositionId>> {
5896 self.view_positions_in_bucket(
5897 &self.index.positions_closed,
5898 venue,
5899 instrument_id,
5900 strategy_id,
5901 account_id,
5902 )
5903 }
5904
5905 pub fn iter_client_order_ids(
5911 &self,
5912 venue: Option<&Venue>,
5913 instrument_id: Option<&InstrumentId>,
5914 strategy_id: Option<&StrategyId>,
5915 account_id: Option<&AccountId>,
5916 ) -> Box<dyn Iterator<Item = ClientOrderId> + '_> {
5917 self.iter_orders_in_bucket(
5918 &self.index.orders,
5919 venue,
5920 instrument_id,
5921 strategy_id,
5922 account_id,
5923 )
5924 }
5925
5926 pub fn iter_client_order_ids_open(
5928 &self,
5929 venue: Option<&Venue>,
5930 instrument_id: Option<&InstrumentId>,
5931 strategy_id: Option<&StrategyId>,
5932 account_id: Option<&AccountId>,
5933 ) -> Box<dyn Iterator<Item = ClientOrderId> + '_> {
5934 self.iter_orders_in_bucket(
5935 &self.index.orders_open,
5936 venue,
5937 instrument_id,
5938 strategy_id,
5939 account_id,
5940 )
5941 }
5942
5943 pub fn iter_client_order_ids_closed(
5945 &self,
5946 venue: Option<&Venue>,
5947 instrument_id: Option<&InstrumentId>,
5948 strategy_id: Option<&StrategyId>,
5949 account_id: Option<&AccountId>,
5950 ) -> Box<dyn Iterator<Item = ClientOrderId> + '_> {
5951 self.iter_orders_in_bucket(
5952 &self.index.orders_closed,
5953 venue,
5954 instrument_id,
5955 strategy_id,
5956 account_id,
5957 )
5958 }
5959
5960 pub fn iter_client_order_ids_active_local(
5962 &self,
5963 venue: Option<&Venue>,
5964 instrument_id: Option<&InstrumentId>,
5965 strategy_id: Option<&StrategyId>,
5966 account_id: Option<&AccountId>,
5967 ) -> Box<dyn Iterator<Item = ClientOrderId> + '_> {
5968 self.iter_orders_in_bucket(
5969 &self.index.orders_active_local,
5970 venue,
5971 instrument_id,
5972 strategy_id,
5973 account_id,
5974 )
5975 }
5976
5977 pub fn iter_client_order_ids_emulated(
5979 &self,
5980 venue: Option<&Venue>,
5981 instrument_id: Option<&InstrumentId>,
5982 strategy_id: Option<&StrategyId>,
5983 account_id: Option<&AccountId>,
5984 ) -> Box<dyn Iterator<Item = ClientOrderId> + '_> {
5985 self.iter_orders_in_bucket(
5986 &self.index.orders_emulated,
5987 venue,
5988 instrument_id,
5989 strategy_id,
5990 account_id,
5991 )
5992 }
5993
5994 pub fn iter_client_order_ids_inflight(
5996 &self,
5997 venue: Option<&Venue>,
5998 instrument_id: Option<&InstrumentId>,
5999 strategy_id: Option<&StrategyId>,
6000 account_id: Option<&AccountId>,
6001 ) -> Box<dyn Iterator<Item = ClientOrderId> + '_> {
6002 self.iter_orders_in_bucket(
6003 &self.index.orders_inflight,
6004 venue,
6005 instrument_id,
6006 strategy_id,
6007 account_id,
6008 )
6009 }
6010
6011 pub fn iter_position_ids(
6013 &self,
6014 venue: Option<&Venue>,
6015 instrument_id: Option<&InstrumentId>,
6016 strategy_id: Option<&StrategyId>,
6017 account_id: Option<&AccountId>,
6018 ) -> Box<dyn Iterator<Item = PositionId> + '_> {
6019 self.iter_positions_in_bucket(
6020 &self.index.positions,
6021 venue,
6022 instrument_id,
6023 strategy_id,
6024 account_id,
6025 )
6026 }
6027
6028 pub fn iter_position_open_ids(
6030 &self,
6031 venue: Option<&Venue>,
6032 instrument_id: Option<&InstrumentId>,
6033 strategy_id: Option<&StrategyId>,
6034 account_id: Option<&AccountId>,
6035 ) -> Box<dyn Iterator<Item = PositionId> + '_> {
6036 self.iter_positions_in_bucket(
6037 &self.index.positions_open,
6038 venue,
6039 instrument_id,
6040 strategy_id,
6041 account_id,
6042 )
6043 }
6044
6045 pub fn iter_position_closed_ids(
6047 &self,
6048 venue: Option<&Venue>,
6049 instrument_id: Option<&InstrumentId>,
6050 strategy_id: Option<&StrategyId>,
6051 account_id: Option<&AccountId>,
6052 ) -> Box<dyn Iterator<Item = PositionId> + '_> {
6053 self.iter_positions_in_bucket(
6054 &self.index.positions_closed,
6055 venue,
6056 instrument_id,
6057 strategy_id,
6058 account_id,
6059 )
6060 }
6061
6062 #[must_use]
6064 pub fn actor_ids(&self) -> AHashSet<ComponentId> {
6065 self.index.actors.clone()
6066 }
6067
6068 #[must_use]
6070 pub fn strategy_ids(&self) -> AHashSet<StrategyId> {
6071 self.index.strategies.clone()
6072 }
6073
6074 #[must_use]
6076 pub fn exec_algorithm_ids(&self) -> AHashSet<ExecAlgorithmId> {
6077 self.index.exec_algorithms.clone()
6078 }
6079
6080 #[must_use]
6089 pub fn order_ref(&self, client_order_id: &ClientOrderId) -> Option<OrderRef<'_>> {
6090 self.orders
6091 .get(client_order_id)
6092 .map(|order_cell| OrderRef::new(order_cell.borrow()))
6093 }
6094
6095 #[must_use]
6099 pub fn order(&self, client_order_id: &ClientOrderId) -> Option<OrderRef<'_>> {
6100 self.order_ref(client_order_id)
6101 }
6102
6103 pub fn try_order_ref(
6109 &self,
6110 client_order_id: &ClientOrderId,
6111 ) -> Result<OrderRef<'_>, OrderLookupError> {
6112 self.orders
6113 .get(client_order_id)
6114 .map(|order_cell| OrderRef::new(order_cell.borrow()))
6115 .ok_or_else(|| OrderLookupError::not_found(*client_order_id))
6116 }
6117
6118 pub fn try_order(
6126 &self,
6127 client_order_id: &ClientOrderId,
6128 ) -> Result<OrderRef<'_>, OrderLookupError> {
6129 self.try_order_ref(client_order_id)
6130 }
6131
6132 #[must_use]
6142 pub fn order_mut(&mut self, client_order_id: &ClientOrderId) -> Option<OrderRefMut<'_>> {
6143 self.orders
6144 .get(client_order_id)
6145 .map(|order_cell| OrderRefMut::new(order_cell.borrow_mut()))
6146 }
6147
6148 #[must_use]
6153 pub fn order_owned(&self, client_order_id: &ClientOrderId) -> Option<OrderAny> {
6154 self.orders
6155 .get(client_order_id)
6156 .map(|order_cell| order_cell.borrow().clone())
6157 }
6158
6159 pub fn try_order_owned(
6165 &self,
6166 client_order_id: &ClientOrderId,
6167 ) -> Result<OrderAny, OrderLookupError> {
6168 self.try_order_ref(client_order_id)
6169 .map(|order| order.cloned())
6170 }
6171
6172 #[must_use]
6174 pub fn orders_for_ids(
6175 &self,
6176 client_order_ids: &[ClientOrderId],
6177 context: &dyn Display,
6178 ) -> Vec<OrderAny> {
6179 let mut orders = Vec::with_capacity(client_order_ids.len());
6180 for id in client_order_ids {
6181 match self.orders.get(id) {
6182 Some(order_cell) => orders.push(order_cell.borrow().clone()),
6183 None => log::error!("Order {id} not found in cache for {context}"),
6184 }
6185 }
6186 orders
6187 }
6188
6189 #[must_use]
6191 pub fn client_order_id(&self, venue_order_id: &VenueOrderId) -> Option<&ClientOrderId> {
6192 self.index.venue_order_ids.get(venue_order_id)
6193 }
6194
6195 #[must_use]
6197 pub fn venue_order_id(&self, client_order_id: &ClientOrderId) -> Option<&VenueOrderId> {
6198 self.index.client_order_ids.get(client_order_id)
6199 }
6200
6201 #[must_use]
6203 pub fn client_id(&self, client_order_id: &ClientOrderId) -> Option<&ClientId> {
6204 self.index.order_client.get(client_order_id)
6205 }
6206
6207 #[must_use]
6213 pub fn orders_refs(
6214 &self,
6215 venue: Option<&Venue>,
6216 instrument_id: Option<&InstrumentId>,
6217 strategy_id: Option<&StrategyId>,
6218 account_id: Option<&AccountId>,
6219 side: Option<OrderSide>,
6220 ) -> Vec<OrderRef<'_>> {
6221 let client_order_ids = self.client_order_ids(venue, instrument_id, strategy_id, account_id);
6222 self.get_orders_for_ids(&client_order_ids, side)
6223 }
6224
6225 #[must_use]
6229 pub fn orders(
6230 &self,
6231 venue: Option<&Venue>,
6232 instrument_id: Option<&InstrumentId>,
6233 strategy_id: Option<&StrategyId>,
6234 account_id: Option<&AccountId>,
6235 side: Option<OrderSide>,
6236 ) -> Vec<OrderRef<'_>> {
6237 self.orders_refs(venue, instrument_id, strategy_id, account_id, side)
6238 }
6239
6240 #[must_use]
6242 pub fn orders_open_refs(
6243 &self,
6244 venue: Option<&Venue>,
6245 instrument_id: Option<&InstrumentId>,
6246 strategy_id: Option<&StrategyId>,
6247 account_id: Option<&AccountId>,
6248 side: Option<OrderSide>,
6249 ) -> Vec<OrderRef<'_>> {
6250 let client_order_ids =
6251 self.client_order_ids_open(venue, instrument_id, strategy_id, account_id);
6252 self.get_orders_for_ids(&client_order_ids, side)
6253 }
6254
6255 #[must_use]
6259 pub fn orders_open(
6260 &self,
6261 venue: Option<&Venue>,
6262 instrument_id: Option<&InstrumentId>,
6263 strategy_id: Option<&StrategyId>,
6264 account_id: Option<&AccountId>,
6265 side: Option<OrderSide>,
6266 ) -> Vec<OrderRef<'_>> {
6267 self.orders_open_refs(venue, instrument_id, strategy_id, account_id, side)
6268 }
6269
6270 #[must_use]
6272 pub fn orders_closed_refs(
6273 &self,
6274 venue: Option<&Venue>,
6275 instrument_id: Option<&InstrumentId>,
6276 strategy_id: Option<&StrategyId>,
6277 account_id: Option<&AccountId>,
6278 side: Option<OrderSide>,
6279 ) -> Vec<OrderRef<'_>> {
6280 let client_order_ids =
6281 self.client_order_ids_closed(venue, instrument_id, strategy_id, account_id);
6282 self.get_orders_for_ids(&client_order_ids, side)
6283 }
6284
6285 #[must_use]
6289 pub fn orders_closed(
6290 &self,
6291 venue: Option<&Venue>,
6292 instrument_id: Option<&InstrumentId>,
6293 strategy_id: Option<&StrategyId>,
6294 account_id: Option<&AccountId>,
6295 side: Option<OrderSide>,
6296 ) -> Vec<OrderRef<'_>> {
6297 self.orders_closed_refs(venue, instrument_id, strategy_id, account_id, side)
6298 }
6299
6300 #[must_use]
6305 pub fn orders_active_local_refs(
6306 &self,
6307 venue: Option<&Venue>,
6308 instrument_id: Option<&InstrumentId>,
6309 strategy_id: Option<&StrategyId>,
6310 account_id: Option<&AccountId>,
6311 side: Option<OrderSide>,
6312 ) -> Vec<OrderRef<'_>> {
6313 let client_order_ids =
6314 self.client_order_ids_active_local(venue, instrument_id, strategy_id, account_id);
6315 self.get_orders_for_ids(&client_order_ids, side)
6316 }
6317
6318 #[must_use]
6322 pub fn orders_active_local(
6323 &self,
6324 venue: Option<&Venue>,
6325 instrument_id: Option<&InstrumentId>,
6326 strategy_id: Option<&StrategyId>,
6327 account_id: Option<&AccountId>,
6328 side: Option<OrderSide>,
6329 ) -> Vec<OrderRef<'_>> {
6330 self.orders_active_local_refs(venue, instrument_id, strategy_id, account_id, side)
6331 }
6332
6333 #[must_use]
6335 pub fn orders_emulated_refs(
6336 &self,
6337 venue: Option<&Venue>,
6338 instrument_id: Option<&InstrumentId>,
6339 strategy_id: Option<&StrategyId>,
6340 account_id: Option<&AccountId>,
6341 side: Option<OrderSide>,
6342 ) -> Vec<OrderRef<'_>> {
6343 let client_order_ids =
6344 self.client_order_ids_emulated(venue, instrument_id, strategy_id, account_id);
6345 self.get_orders_for_ids(&client_order_ids, side)
6346 }
6347
6348 #[must_use]
6352 pub fn orders_emulated(
6353 &self,
6354 venue: Option<&Venue>,
6355 instrument_id: Option<&InstrumentId>,
6356 strategy_id: Option<&StrategyId>,
6357 account_id: Option<&AccountId>,
6358 side: Option<OrderSide>,
6359 ) -> Vec<OrderRef<'_>> {
6360 self.orders_emulated_refs(venue, instrument_id, strategy_id, account_id, side)
6361 }
6362
6363 #[must_use]
6365 pub fn orders_inflight_refs(
6366 &self,
6367 venue: Option<&Venue>,
6368 instrument_id: Option<&InstrumentId>,
6369 strategy_id: Option<&StrategyId>,
6370 account_id: Option<&AccountId>,
6371 side: Option<OrderSide>,
6372 ) -> Vec<OrderRef<'_>> {
6373 let client_order_ids =
6374 self.client_order_ids_inflight(venue, instrument_id, strategy_id, account_id);
6375 self.get_orders_for_ids(&client_order_ids, side)
6376 }
6377
6378 #[must_use]
6382 pub fn orders_inflight(
6383 &self,
6384 venue: Option<&Venue>,
6385 instrument_id: Option<&InstrumentId>,
6386 strategy_id: Option<&StrategyId>,
6387 account_id: Option<&AccountId>,
6388 side: Option<OrderSide>,
6389 ) -> Vec<OrderRef<'_>> {
6390 self.orders_inflight_refs(venue, instrument_id, strategy_id, account_id, side)
6391 }
6392
6393 #[must_use]
6395 pub fn orders_for_position(&self, position_id: &PositionId) -> Vec<OrderRef<'_>> {
6396 match self.index.position_orders.get(position_id) {
6397 Some(client_order_ids) => self.get_orders_for_ids(client_order_ids, None),
6398 None => Vec::new(),
6399 }
6400 }
6401
6402 #[must_use]
6404 pub fn order_exists(&self, client_order_id: &ClientOrderId) -> bool {
6405 self.index.orders.contains(client_order_id)
6406 }
6407
6408 #[must_use]
6410 pub fn is_order_open(&self, client_order_id: &ClientOrderId) -> bool {
6411 self.index.orders_open.contains(client_order_id)
6412 }
6413
6414 #[must_use]
6416 pub fn is_order_closed(&self, client_order_id: &ClientOrderId) -> bool {
6417 self.index.orders_closed.contains(client_order_id)
6418 }
6419
6420 #[must_use]
6425 pub fn is_order_active_local(&self, client_order_id: &ClientOrderId) -> bool {
6426 self.index.orders_active_local.contains(client_order_id)
6427 }
6428
6429 #[must_use]
6431 pub fn is_order_emulated(&self, client_order_id: &ClientOrderId) -> bool {
6432 self.index.orders_emulated.contains(client_order_id)
6433 }
6434
6435 #[must_use]
6437 pub fn is_order_inflight(&self, client_order_id: &ClientOrderId) -> bool {
6438 self.index.orders_inflight.contains(client_order_id)
6439 }
6440
6441 #[must_use]
6443 pub fn is_order_pending_cancel_local(&self, client_order_id: &ClientOrderId) -> bool {
6444 self.index.orders_pending_cancel.contains(client_order_id)
6445 }
6446
6447 #[must_use]
6449 pub fn orders_open_count(
6450 &self,
6451 venue: Option<&Venue>,
6452 instrument_id: Option<&InstrumentId>,
6453 strategy_id: Option<&StrategyId>,
6454 account_id: Option<&AccountId>,
6455 side: Option<OrderSide>,
6456 ) -> usize {
6457 self.count_orders_in_bucket(
6458 &self.index.orders_open,
6459 venue,
6460 instrument_id,
6461 strategy_id,
6462 account_id,
6463 side,
6464 )
6465 }
6466
6467 #[must_use]
6469 pub fn orders_closed_count(
6470 &self,
6471 venue: Option<&Venue>,
6472 instrument_id: Option<&InstrumentId>,
6473 strategy_id: Option<&StrategyId>,
6474 account_id: Option<&AccountId>,
6475 side: Option<OrderSide>,
6476 ) -> usize {
6477 self.count_orders_in_bucket(
6478 &self.index.orders_closed,
6479 venue,
6480 instrument_id,
6481 strategy_id,
6482 account_id,
6483 side,
6484 )
6485 }
6486
6487 #[must_use]
6492 pub fn orders_active_local_count(
6493 &self,
6494 venue: Option<&Venue>,
6495 instrument_id: Option<&InstrumentId>,
6496 strategy_id: Option<&StrategyId>,
6497 account_id: Option<&AccountId>,
6498 side: Option<OrderSide>,
6499 ) -> usize {
6500 self.count_orders_in_bucket(
6501 &self.index.orders_active_local,
6502 venue,
6503 instrument_id,
6504 strategy_id,
6505 account_id,
6506 side,
6507 )
6508 }
6509
6510 #[must_use]
6512 pub fn orders_emulated_count(
6513 &self,
6514 venue: Option<&Venue>,
6515 instrument_id: Option<&InstrumentId>,
6516 strategy_id: Option<&StrategyId>,
6517 account_id: Option<&AccountId>,
6518 side: Option<OrderSide>,
6519 ) -> usize {
6520 self.count_orders_in_bucket(
6521 &self.index.orders_emulated,
6522 venue,
6523 instrument_id,
6524 strategy_id,
6525 account_id,
6526 side,
6527 )
6528 }
6529
6530 #[must_use]
6532 pub fn orders_inflight_count(
6533 &self,
6534 venue: Option<&Venue>,
6535 instrument_id: Option<&InstrumentId>,
6536 strategy_id: Option<&StrategyId>,
6537 account_id: Option<&AccountId>,
6538 side: Option<OrderSide>,
6539 ) -> usize {
6540 self.count_orders_in_bucket(
6541 &self.index.orders_inflight,
6542 venue,
6543 instrument_id,
6544 strategy_id,
6545 account_id,
6546 side,
6547 )
6548 }
6549
6550 #[must_use]
6552 pub fn orders_total_count(
6553 &self,
6554 venue: Option<&Venue>,
6555 instrument_id: Option<&InstrumentId>,
6556 strategy_id: Option<&StrategyId>,
6557 account_id: Option<&AccountId>,
6558 side: Option<OrderSide>,
6559 ) -> usize {
6560 self.count_orders_in_bucket(
6561 &self.index.orders,
6562 venue,
6563 instrument_id,
6564 strategy_id,
6565 account_id,
6566 side,
6567 )
6568 }
6569
6570 #[must_use]
6576 pub fn has_orders_open(
6577 &self,
6578 venue: Option<&Venue>,
6579 instrument_id: Option<&InstrumentId>,
6580 strategy_id: Option<&StrategyId>,
6581 account_id: Option<&AccountId>,
6582 side: Option<OrderSide>,
6583 ) -> bool {
6584 self.any_orders_in_bucket(
6585 &self.index.orders_open,
6586 venue,
6587 instrument_id,
6588 strategy_id,
6589 account_id,
6590 side,
6591 )
6592 }
6593
6594 #[must_use]
6596 pub fn has_orders_closed(
6597 &self,
6598 venue: Option<&Venue>,
6599 instrument_id: Option<&InstrumentId>,
6600 strategy_id: Option<&StrategyId>,
6601 account_id: Option<&AccountId>,
6602 side: Option<OrderSide>,
6603 ) -> bool {
6604 self.any_orders_in_bucket(
6605 &self.index.orders_closed,
6606 venue,
6607 instrument_id,
6608 strategy_id,
6609 account_id,
6610 side,
6611 )
6612 }
6613
6614 #[must_use]
6618 pub fn has_orders_active_local(
6619 &self,
6620 venue: Option<&Venue>,
6621 instrument_id: Option<&InstrumentId>,
6622 strategy_id: Option<&StrategyId>,
6623 account_id: Option<&AccountId>,
6624 side: Option<OrderSide>,
6625 ) -> bool {
6626 self.any_orders_in_bucket(
6627 &self.index.orders_active_local,
6628 venue,
6629 instrument_id,
6630 strategy_id,
6631 account_id,
6632 side,
6633 )
6634 }
6635
6636 #[must_use]
6638 pub fn has_orders_emulated(
6639 &self,
6640 venue: Option<&Venue>,
6641 instrument_id: Option<&InstrumentId>,
6642 strategy_id: Option<&StrategyId>,
6643 account_id: Option<&AccountId>,
6644 side: Option<OrderSide>,
6645 ) -> bool {
6646 self.any_orders_in_bucket(
6647 &self.index.orders_emulated,
6648 venue,
6649 instrument_id,
6650 strategy_id,
6651 account_id,
6652 side,
6653 )
6654 }
6655
6656 #[must_use]
6658 pub fn has_orders_inflight(
6659 &self,
6660 venue: Option<&Venue>,
6661 instrument_id: Option<&InstrumentId>,
6662 strategy_id: Option<&StrategyId>,
6663 account_id: Option<&AccountId>,
6664 side: Option<OrderSide>,
6665 ) -> bool {
6666 self.any_orders_in_bucket(
6667 &self.index.orders_inflight,
6668 venue,
6669 instrument_id,
6670 strategy_id,
6671 account_id,
6672 side,
6673 )
6674 }
6675
6676 #[must_use]
6678 pub fn has_orders(
6679 &self,
6680 venue: Option<&Venue>,
6681 instrument_id: Option<&InstrumentId>,
6682 strategy_id: Option<&StrategyId>,
6683 account_id: Option<&AccountId>,
6684 side: Option<OrderSide>,
6685 ) -> bool {
6686 self.any_orders_in_bucket(
6687 &self.index.orders,
6688 venue,
6689 instrument_id,
6690 strategy_id,
6691 account_id,
6692 side,
6693 )
6694 }
6695
6696 #[must_use]
6698 pub fn order_list(&self, order_list_id: &OrderListId) -> Option<&OrderList> {
6699 self.order_lists.get(order_list_id)
6700 }
6701
6702 pub fn try_order_list(
6708 &self,
6709 order_list_id: &OrderListId,
6710 ) -> Result<&OrderList, OrderListLookupError> {
6711 self.order_lists
6712 .get(order_list_id)
6713 .ok_or_else(|| OrderListLookupError::not_found(*order_list_id))
6714 }
6715
6716 #[must_use]
6718 pub fn order_lists(
6719 &self,
6720 venue: Option<&Venue>,
6721 instrument_id: Option<&InstrumentId>,
6722 strategy_id: Option<&StrategyId>,
6723 account_id: Option<&AccountId>,
6724 ) -> Vec<&OrderList> {
6725 let mut order_lists = self.order_lists.values().collect::<Vec<&OrderList>>();
6726
6727 if let Some(venue) = venue {
6728 order_lists.retain(|ol| &ol.instrument_id.venue == venue);
6729 }
6730
6731 if let Some(instrument_id) = instrument_id {
6732 order_lists.retain(|ol| &ol.instrument_id == instrument_id);
6733 }
6734
6735 if let Some(strategy_id) = strategy_id {
6736 order_lists.retain(|ol| &ol.strategy_id == strategy_id);
6737 }
6738
6739 if let Some(account_id) = account_id {
6740 order_lists.retain(|ol| {
6741 ol.client_order_ids.iter().any(|client_order_id| {
6742 self.orders.get(client_order_id).is_some_and(|order_cell| {
6743 order_cell.borrow().account_id().as_ref() == Some(account_id)
6744 })
6745 })
6746 });
6747 }
6748
6749 order_lists
6750 }
6751
6752 #[must_use]
6754 pub fn order_list_exists(&self, order_list_id: &OrderListId) -> bool {
6755 self.order_lists.contains_key(order_list_id)
6756 }
6757
6758 #[must_use]
6763 pub fn orders_for_exec_algorithm(
6764 &self,
6765 exec_algorithm_id: &ExecAlgorithmId,
6766 venue: Option<&Venue>,
6767 instrument_id: Option<&InstrumentId>,
6768 strategy_id: Option<&StrategyId>,
6769 account_id: Option<&AccountId>,
6770 side: Option<OrderSide>,
6771 ) -> Vec<OrderRef<'_>> {
6772 let Some(exec_algorithm_order_ids) =
6773 self.index.exec_algorithm_orders.get(exec_algorithm_id)
6774 else {
6775 return Vec::new();
6776 };
6777
6778 let filtered = self.query_orders_in_bucket(
6779 exec_algorithm_order_ids,
6780 venue,
6781 instrument_id,
6782 strategy_id,
6783 account_id,
6784 );
6785 self.get_orders_for_ids(&filtered, side)
6786 }
6787
6788 #[must_use]
6790 pub fn orders_for_exec_spawn(&self, exec_spawn_id: &ClientOrderId) -> Vec<OrderRef<'_>> {
6791 match self.index.exec_spawn_orders.get(exec_spawn_id) {
6792 Some(ids) => self.get_orders_for_ids(ids, None),
6793 None => Vec::new(),
6794 }
6795 }
6796
6797 #[must_use]
6799 pub fn exec_spawn_total_quantity(
6800 &self,
6801 exec_spawn_id: &ClientOrderId,
6802 active_only: bool,
6803 ) -> Option<Quantity> {
6804 let exec_spawn_orders = self.orders_for_exec_spawn(exec_spawn_id);
6805
6806 let mut total_quantity: Option<Quantity> = None;
6807
6808 for spawn_order in exec_spawn_orders {
6809 if active_only && spawn_order.is_closed() {
6810 continue;
6811 }
6812
6813 match total_quantity.as_mut() {
6814 Some(total) => *total = *total + spawn_order.quantity(),
6815 None => total_quantity = Some(spawn_order.quantity()),
6816 }
6817 }
6818
6819 total_quantity
6820 }
6821
6822 #[must_use]
6824 pub fn exec_spawn_total_filled_qty(
6825 &self,
6826 exec_spawn_id: &ClientOrderId,
6827 active_only: bool,
6828 ) -> Option<Quantity> {
6829 let exec_spawn_orders = self.orders_for_exec_spawn(exec_spawn_id);
6830
6831 let mut total_quantity: Option<Quantity> = None;
6832
6833 for spawn_order in exec_spawn_orders {
6834 if active_only && spawn_order.is_closed() {
6835 continue;
6836 }
6837
6838 match total_quantity.as_mut() {
6839 Some(total) => *total = *total + spawn_order.filled_qty(),
6840 None => total_quantity = Some(spawn_order.filled_qty()),
6841 }
6842 }
6843
6844 total_quantity
6845 }
6846
6847 #[must_use]
6849 pub fn exec_spawn_total_leaves_qty(
6850 &self,
6851 exec_spawn_id: &ClientOrderId,
6852 active_only: bool,
6853 ) -> Option<Quantity> {
6854 let exec_spawn_orders = self.orders_for_exec_spawn(exec_spawn_id);
6855
6856 let mut total_quantity: Option<Quantity> = None;
6857
6858 for spawn_order in exec_spawn_orders {
6859 if active_only && spawn_order.is_closed() {
6860 continue;
6861 }
6862
6863 match total_quantity.as_mut() {
6864 Some(total) => *total = *total + spawn_order.leaves_qty(),
6865 None => total_quantity = Some(spawn_order.leaves_qty()),
6866 }
6867 }
6868
6869 total_quantity
6870 }
6871
6872 #[must_use]
6876 pub fn position_ref(&self, position_id: &PositionId) -> Option<PositionRef<'_>> {
6877 self.positions
6878 .get(position_id)
6879 .map(|position_cell| PositionRef::new(position_cell.borrow()))
6880 }
6881
6882 #[must_use]
6886 pub fn position(&self, position_id: &PositionId) -> Option<PositionRef<'_>> {
6887 self.position_ref(position_id)
6888 }
6889
6890 pub fn try_position_ref(
6896 &self,
6897 position_id: &PositionId,
6898 ) -> Result<PositionRef<'_>, PositionLookupError> {
6899 self.positions
6900 .get(position_id)
6901 .map(|position_cell| PositionRef::new(position_cell.borrow()))
6902 .ok_or_else(|| PositionLookupError::not_found(*position_id))
6903 }
6904
6905 pub fn try_position(
6913 &self,
6914 position_id: &PositionId,
6915 ) -> Result<PositionRef<'_>, PositionLookupError> {
6916 self.try_position_ref(position_id)
6917 }
6918
6919 #[must_use]
6929 pub fn position_mut(&mut self, position_id: &PositionId) -> Option<PositionRefMut<'_>> {
6930 self.positions
6931 .get(position_id)
6932 .map(|position_cell| PositionRefMut::new(position_cell.borrow_mut()))
6933 }
6934
6935 #[must_use]
6940 pub fn position_owned(&self, position_id: &PositionId) -> Option<Position> {
6941 self.positions
6942 .get(position_id)
6943 .map(|position_cell| position_cell.borrow().clone())
6944 }
6945
6946 #[must_use]
6948 pub fn position_for_order_ref(
6949 &self,
6950 client_order_id: &ClientOrderId,
6951 ) -> Option<PositionRef<'_>> {
6952 self.index
6953 .order_position
6954 .get(client_order_id)
6955 .and_then(|position_id| self.positions.get(position_id))
6956 .map(|position_cell| PositionRef::new(position_cell.borrow()))
6957 }
6958
6959 #[must_use]
6963 pub fn position_for_order(&self, client_order_id: &ClientOrderId) -> Option<PositionRef<'_>> {
6964 self.position_for_order_ref(client_order_id)
6965 }
6966
6967 #[must_use]
6969 pub fn position_id(&self, client_order_id: &ClientOrderId) -> Option<&PositionId> {
6970 self.index.order_position.get(client_order_id)
6971 }
6972
6973 #[must_use]
6979 pub fn positions_refs(
6980 &self,
6981 venue: Option<&Venue>,
6982 instrument_id: Option<&InstrumentId>,
6983 strategy_id: Option<&StrategyId>,
6984 account_id: Option<&AccountId>,
6985 side: Option<PositionSide>,
6986 ) -> Vec<PositionRef<'_>> {
6987 let position_ids = self.position_ids(venue, instrument_id, strategy_id, account_id);
6988 self.get_positions_for_ids(&position_ids, side)
6989 }
6990
6991 #[must_use]
6995 pub fn positions(
6996 &self,
6997 venue: Option<&Venue>,
6998 instrument_id: Option<&InstrumentId>,
6999 strategy_id: Option<&StrategyId>,
7000 account_id: Option<&AccountId>,
7001 side: Option<PositionSide>,
7002 ) -> Vec<PositionRef<'_>> {
7003 self.positions_refs(venue, instrument_id, strategy_id, account_id, side)
7004 }
7005
7006 #[must_use]
7008 pub fn positions_open_refs(
7009 &self,
7010 venue: Option<&Venue>,
7011 instrument_id: Option<&InstrumentId>,
7012 strategy_id: Option<&StrategyId>,
7013 account_id: Option<&AccountId>,
7014 side: Option<PositionSide>,
7015 ) -> Vec<PositionRef<'_>> {
7016 let position_ids = self.position_open_ids(venue, instrument_id, strategy_id, account_id);
7017 self.get_positions_for_ids(&position_ids, side)
7018 }
7019
7020 #[must_use]
7024 pub fn positions_open(
7025 &self,
7026 venue: Option<&Venue>,
7027 instrument_id: Option<&InstrumentId>,
7028 strategy_id: Option<&StrategyId>,
7029 account_id: Option<&AccountId>,
7030 side: Option<PositionSide>,
7031 ) -> Vec<PositionRef<'_>> {
7032 self.positions_open_refs(venue, instrument_id, strategy_id, account_id, side)
7033 }
7034
7035 #[must_use]
7037 pub fn positions_closed_refs(
7038 &self,
7039 venue: Option<&Venue>,
7040 instrument_id: Option<&InstrumentId>,
7041 strategy_id: Option<&StrategyId>,
7042 account_id: Option<&AccountId>,
7043 side: Option<PositionSide>,
7044 ) -> Vec<PositionRef<'_>> {
7045 let position_ids = self.position_closed_ids(venue, instrument_id, strategy_id, account_id);
7046 self.get_positions_for_ids(&position_ids, side)
7047 }
7048
7049 #[must_use]
7053 pub fn positions_closed(
7054 &self,
7055 venue: Option<&Venue>,
7056 instrument_id: Option<&InstrumentId>,
7057 strategy_id: Option<&StrategyId>,
7058 account_id: Option<&AccountId>,
7059 side: Option<PositionSide>,
7060 ) -> Vec<PositionRef<'_>> {
7061 self.positions_closed_refs(venue, instrument_id, strategy_id, account_id, side)
7062 }
7063
7064 #[must_use]
7066 pub fn position_exists(&self, position_id: &PositionId) -> bool {
7067 self.index.positions.contains(position_id)
7068 }
7069
7070 #[must_use]
7072 pub fn is_position_open(&self, position_id: &PositionId) -> bool {
7073 self.index.positions_open.contains(position_id)
7074 }
7075
7076 #[must_use]
7078 pub fn is_position_closed(&self, position_id: &PositionId) -> bool {
7079 self.index.positions_closed.contains(position_id)
7080 }
7081
7082 #[must_use]
7084 pub fn positions_open_count(
7085 &self,
7086 venue: Option<&Venue>,
7087 instrument_id: Option<&InstrumentId>,
7088 strategy_id: Option<&StrategyId>,
7089 account_id: Option<&AccountId>,
7090 side: Option<PositionSide>,
7091 ) -> usize {
7092 self.count_positions_in_bucket(
7093 &self.index.positions_open,
7094 venue,
7095 instrument_id,
7096 strategy_id,
7097 account_id,
7098 side,
7099 )
7100 }
7101
7102 #[must_use]
7104 pub fn positions_closed_count(
7105 &self,
7106 venue: Option<&Venue>,
7107 instrument_id: Option<&InstrumentId>,
7108 strategy_id: Option<&StrategyId>,
7109 account_id: Option<&AccountId>,
7110 side: Option<PositionSide>,
7111 ) -> usize {
7112 self.count_positions_in_bucket(
7113 &self.index.positions_closed,
7114 venue,
7115 instrument_id,
7116 strategy_id,
7117 account_id,
7118 side,
7119 )
7120 }
7121
7122 #[must_use]
7124 pub fn positions_total_count(
7125 &self,
7126 venue: Option<&Venue>,
7127 instrument_id: Option<&InstrumentId>,
7128 strategy_id: Option<&StrategyId>,
7129 account_id: Option<&AccountId>,
7130 side: Option<PositionSide>,
7131 ) -> usize {
7132 self.count_positions_in_bucket(
7133 &self.index.positions,
7134 venue,
7135 instrument_id,
7136 strategy_id,
7137 account_id,
7138 side,
7139 )
7140 }
7141
7142 #[must_use]
7148 pub fn has_positions_open(
7149 &self,
7150 venue: Option<&Venue>,
7151 instrument_id: Option<&InstrumentId>,
7152 strategy_id: Option<&StrategyId>,
7153 account_id: Option<&AccountId>,
7154 side: Option<PositionSide>,
7155 ) -> bool {
7156 self.any_positions_in_bucket(
7157 &self.index.positions_open,
7158 venue,
7159 instrument_id,
7160 strategy_id,
7161 account_id,
7162 side,
7163 )
7164 }
7165
7166 #[must_use]
7168 pub fn has_positions_closed(
7169 &self,
7170 venue: Option<&Venue>,
7171 instrument_id: Option<&InstrumentId>,
7172 strategy_id: Option<&StrategyId>,
7173 account_id: Option<&AccountId>,
7174 side: Option<PositionSide>,
7175 ) -> bool {
7176 self.any_positions_in_bucket(
7177 &self.index.positions_closed,
7178 venue,
7179 instrument_id,
7180 strategy_id,
7181 account_id,
7182 side,
7183 )
7184 }
7185
7186 #[must_use]
7188 pub fn has_positions(
7189 &self,
7190 venue: Option<&Venue>,
7191 instrument_id: Option<&InstrumentId>,
7192 strategy_id: Option<&StrategyId>,
7193 account_id: Option<&AccountId>,
7194 side: Option<PositionSide>,
7195 ) -> bool {
7196 self.any_positions_in_bucket(
7197 &self.index.positions,
7198 venue,
7199 instrument_id,
7200 strategy_id,
7201 account_id,
7202 side,
7203 )
7204 }
7205
7206 #[must_use]
7210 pub fn strategy_id_for_order(&self, client_order_id: &ClientOrderId) -> Option<&StrategyId> {
7211 self.index.order_strategy.get(client_order_id)
7212 }
7213
7214 #[must_use]
7216 pub fn strategy_id_for_position(&self, position_id: &PositionId) -> Option<&StrategyId> {
7217 self.index.position_strategy.get(position_id)
7218 }
7219
7220 pub fn get(&self, key: &str) -> anyhow::Result<Option<&Bytes>> {
7228 check_valid_string_ascii(key, stringify!(key))?;
7229
7230 Ok(self.general.get(key))
7231 }
7232
7233 #[must_use]
7242 pub fn price(&self, instrument_id: &InstrumentId, price_type: PriceType) -> Option<Price> {
7243 match price_type {
7244 PriceType::Bid => self
7245 .quotes
7246 .get(instrument_id)
7247 .and_then(|quotes| quotes.front().map(|quote| quote.bid_price)),
7248 PriceType::Ask => self
7249 .quotes
7250 .get(instrument_id)
7251 .and_then(|quotes| quotes.front().map(|quote| quote.ask_price)),
7252 PriceType::Mid => self.quotes.get(instrument_id).and_then(|quotes| {
7253 quotes.front().map(|quote| {
7254 let mid = (quote.ask_price.as_decimal() + quote.bid_price.as_decimal())
7255 / Decimal::TWO;
7256
7257 Price::from_decimal_dp(mid, quote.bid_price.precision + 1)
7258 .expect("Invalid mid price for Cache::price")
7259 })
7260 }),
7261 PriceType::Last => self
7262 .trades
7263 .get(instrument_id)
7264 .and_then(|trades| trades.front().map(|trade| trade.price)),
7265 PriceType::Mark => self
7266 .mark_prices
7267 .get(instrument_id)
7268 .and_then(|marks| marks.front().map(|mark| mark.value)),
7269 }
7270 }
7271
7272 #[must_use]
7274 pub fn quotes(&self, instrument_id: &InstrumentId) -> Option<Vec<QuoteTick>> {
7275 self.quotes
7276 .get(instrument_id)
7277 .map(|quotes| quotes.iter().copied().collect())
7278 }
7279
7280 #[must_use]
7282 pub fn trades(&self, instrument_id: &InstrumentId) -> Option<Vec<TradeTick>> {
7283 self.trades
7284 .get(instrument_id)
7285 .map(|trades| trades.iter().copied().collect())
7286 }
7287
7288 #[must_use]
7290 pub fn mark_prices(&self, instrument_id: &InstrumentId) -> Option<Vec<MarkPriceUpdate>> {
7291 self.mark_prices
7292 .get(instrument_id)
7293 .map(|mark_prices| mark_prices.iter().copied().collect())
7294 }
7295
7296 #[must_use]
7298 pub fn index_prices(&self, instrument_id: &InstrumentId) -> Option<Vec<IndexPriceUpdate>> {
7299 self.index_prices
7300 .get(instrument_id)
7301 .map(|index_prices| index_prices.iter().copied().collect())
7302 }
7303
7304 #[must_use]
7306 pub fn funding_rates(&self, instrument_id: &InstrumentId) -> Option<Vec<FundingRateUpdate>> {
7307 self.funding_rates
7308 .get(instrument_id)
7309 .map(|funding_rates| funding_rates.iter().copied().collect())
7310 }
7311
7312 #[must_use]
7314 pub fn instrument_statuses(
7315 &self,
7316 instrument_id: &InstrumentId,
7317 ) -> Option<Vec<InstrumentStatus>> {
7318 self.instrument_statuses
7319 .get(instrument_id)
7320 .map(|statuses| statuses.iter().copied().collect())
7321 }
7322
7323 #[must_use]
7325 pub fn bars(&self, bar_type: &BarType) -> Option<Vec<Bar>> {
7326 self.bars
7327 .get(bar_type)
7328 .map(|bars| bars.iter().copied().collect())
7329 }
7330
7331 #[must_use]
7333 pub fn order_book(&self, instrument_id: &InstrumentId) -> Option<&OrderBook> {
7334 self.books.get(instrument_id)
7335 }
7336
7337 pub fn try_order_book(
7343 &self,
7344 instrument_id: &InstrumentId,
7345 ) -> Result<&OrderBook, OrderBookLookupError> {
7346 self.books
7347 .get(instrument_id)
7348 .ok_or_else(|| OrderBookLookupError::not_found(*instrument_id))
7349 }
7350
7351 #[must_use]
7353 pub fn order_book_mut(&mut self, instrument_id: &InstrumentId) -> Option<&mut OrderBook> {
7354 self.books.get_mut(instrument_id)
7355 }
7356
7357 #[must_use]
7359 pub fn own_order_book(&self, instrument_id: &InstrumentId) -> Option<&OwnOrderBook> {
7360 self.own_books.get(instrument_id)
7361 }
7362
7363 pub fn try_own_order_book(
7370 &self,
7371 instrument_id: &InstrumentId,
7372 ) -> Result<&OwnOrderBook, OwnOrderBookLookupError> {
7373 self.own_books
7374 .get(instrument_id)
7375 .ok_or_else(|| OwnOrderBookLookupError::not_found(*instrument_id))
7376 }
7377
7378 #[must_use]
7380 pub fn own_order_book_mut(
7381 &mut self,
7382 instrument_id: &InstrumentId,
7383 ) -> Option<&mut OwnOrderBook> {
7384 self.own_books.get_mut(instrument_id)
7385 }
7386
7387 #[must_use]
7389 pub fn quote(&self, instrument_id: &InstrumentId) -> Option<&QuoteTick> {
7390 self.quotes
7391 .get(instrument_id)
7392 .and_then(|quotes| quotes.front())
7393 }
7394
7395 #[must_use]
7399 pub fn quote_at_index(&self, instrument_id: &InstrumentId, index: usize) -> Option<&QuoteTick> {
7400 self.quotes
7401 .get(instrument_id)
7402 .and_then(|quotes| quotes.get(index))
7403 }
7404
7405 #[must_use]
7407 pub fn trade(&self, instrument_id: &InstrumentId) -> Option<&TradeTick> {
7408 self.trades
7409 .get(instrument_id)
7410 .and_then(|trades| trades.front())
7411 }
7412
7413 #[must_use]
7417 pub fn trade_at_index(&self, instrument_id: &InstrumentId, index: usize) -> Option<&TradeTick> {
7418 self.trades
7419 .get(instrument_id)
7420 .and_then(|trades| trades.get(index))
7421 }
7422
7423 #[must_use]
7425 pub fn mark_price(&self, instrument_id: &InstrumentId) -> Option<&MarkPriceUpdate> {
7426 self.mark_prices
7427 .get(instrument_id)
7428 .and_then(|mark_prices| mark_prices.front())
7429 }
7430
7431 #[must_use]
7433 pub fn index_price(&self, instrument_id: &InstrumentId) -> Option<&IndexPriceUpdate> {
7434 self.index_prices
7435 .get(instrument_id)
7436 .and_then(|index_prices| index_prices.front())
7437 }
7438
7439 #[must_use]
7441 pub fn funding_rate(&self, instrument_id: &InstrumentId) -> Option<&FundingRateUpdate> {
7442 self.funding_rates
7443 .get(instrument_id)
7444 .and_then(|funding_rates| funding_rates.front())
7445 }
7446
7447 #[must_use]
7449 pub fn instrument_status(&self, instrument_id: &InstrumentId) -> Option<&InstrumentStatus> {
7450 self.instrument_statuses
7451 .get(instrument_id)
7452 .and_then(|statuses| statuses.front())
7453 }
7454
7455 #[must_use]
7457 pub fn bar(&self, bar_type: &BarType) -> Option<&Bar> {
7458 self.bars.get(bar_type).and_then(|bars| bars.front())
7459 }
7460
7461 #[must_use]
7465 pub fn bar_at_index(&self, bar_type: &BarType, index: usize) -> Option<&Bar> {
7466 self.bars.get(bar_type).and_then(|bars| bars.get(index))
7467 }
7468
7469 #[must_use]
7471 pub fn book_update_count(&self, instrument_id: &InstrumentId) -> usize {
7472 self.books
7473 .get(instrument_id)
7474 .map_or(0, |book| book.update_count) as usize
7475 }
7476
7477 #[must_use]
7479 pub fn quote_count(&self, instrument_id: &InstrumentId) -> usize {
7480 self.quotes
7481 .get(instrument_id)
7482 .map_or(0, BoundedVecDeque::len)
7483 }
7484
7485 #[must_use]
7487 pub fn trade_count(&self, instrument_id: &InstrumentId) -> usize {
7488 self.trades
7489 .get(instrument_id)
7490 .map_or(0, BoundedVecDeque::len)
7491 }
7492
7493 #[must_use]
7495 pub fn mark_price_count(&self, instrument_id: &InstrumentId) -> usize {
7496 self.mark_prices
7497 .get(instrument_id)
7498 .map_or(0, BoundedVecDeque::len)
7499 }
7500
7501 #[must_use]
7503 pub fn index_price_count(&self, instrument_id: &InstrumentId) -> usize {
7504 self.index_prices
7505 .get(instrument_id)
7506 .map_or(0, BoundedVecDeque::len)
7507 }
7508
7509 #[must_use]
7511 pub fn funding_rate_count(&self, instrument_id: &InstrumentId) -> usize {
7512 self.funding_rates
7513 .get(instrument_id)
7514 .map_or(0, BoundedVecDeque::len)
7515 }
7516
7517 #[must_use]
7519 pub fn instrument_status_count(&self, instrument_id: &InstrumentId) -> usize {
7520 self.instrument_statuses
7521 .get(instrument_id)
7522 .map_or(0, BoundedVecDeque::len)
7523 }
7524
7525 #[must_use]
7527 pub fn bar_count(&self, bar_type: &BarType) -> usize {
7528 self.bars.get(bar_type).map_or(0, BoundedVecDeque::len)
7529 }
7530
7531 #[must_use]
7533 pub fn has_order_book(&self, instrument_id: &InstrumentId) -> bool {
7534 self.books.contains_key(instrument_id)
7535 }
7536
7537 #[must_use]
7539 pub fn has_quote_ticks(&self, instrument_id: &InstrumentId) -> bool {
7540 self.quote_count(instrument_id) > 0
7541 }
7542
7543 #[must_use]
7545 pub fn has_trade_ticks(&self, instrument_id: &InstrumentId) -> bool {
7546 self.trade_count(instrument_id) > 0
7547 }
7548
7549 #[must_use]
7551 pub fn has_mark_prices(&self, instrument_id: &InstrumentId) -> bool {
7552 self.mark_price_count(instrument_id) > 0
7553 }
7554
7555 #[must_use]
7557 pub fn has_index_prices(&self, instrument_id: &InstrumentId) -> bool {
7558 self.index_price_count(instrument_id) > 0
7559 }
7560
7561 #[must_use]
7563 pub fn has_funding_rates(&self, instrument_id: &InstrumentId) -> bool {
7564 self.funding_rate_count(instrument_id) > 0
7565 }
7566
7567 #[must_use]
7569 pub fn has_instrument_statuses(&self, instrument_id: &InstrumentId) -> bool {
7570 self.instrument_status_count(instrument_id) > 0
7571 }
7572
7573 #[must_use]
7575 pub fn has_bars(&self, bar_type: &BarType) -> bool {
7576 self.bar_count(bar_type) > 0
7577 }
7578
7579 #[must_use]
7580 pub fn get_xrate(
7581 &self,
7582 venue: Venue,
7583 from_currency: Currency,
7584 to_currency: Currency,
7585 price_type: PriceType,
7586 ) -> Option<Decimal> {
7587 match self.try_get_xrate(venue, from_currency, to_currency, price_type) {
7588 Ok(rate) => rate,
7589 Err(e) => {
7590 log::error!("Failed to calculate xrate: {e}");
7591 None
7592 }
7593 }
7594 }
7595
7596 pub fn try_get_xrate(
7603 &self,
7604 venue: Venue,
7605 from_currency: Currency,
7606 to_currency: Currency,
7607 price_type: PriceType,
7608 ) -> anyhow::Result<Option<Decimal>> {
7609 if from_currency == to_currency {
7610 return Ok(Some(Decimal::ONE));
7613 }
7614
7615 let (bid_quote, ask_quote) = self.build_quote_table(&venue);
7616
7617 get_exchange_rate(
7618 from_currency.code,
7619 to_currency.code,
7620 price_type,
7621 bid_quote,
7622 ask_quote,
7623 )
7624 }
7625
7626 fn build_quote_table(
7627 &self,
7628 venue: &Venue,
7629 ) -> (AHashMap<Ustr, Decimal>, AHashMap<Ustr, Decimal>) {
7630 let mut bid_quotes = AHashMap::new();
7631 let mut ask_quotes = AHashMap::new();
7632
7633 for instrument_id in self.instruments.keys() {
7634 if instrument_id.venue != *venue {
7635 continue;
7636 }
7637
7638 let (bid_price, ask_price) = if let Some(ticks) = self.quotes.get(instrument_id) {
7639 if let Some(tick) = ticks.front() {
7640 (tick.bid_price, tick.ask_price)
7641 } else {
7642 continue; }
7644 } else {
7645 let mut latest_bid: Option<(&BarType, &Bar)> = None;
7649 let mut latest_ask: Option<(&BarType, &Bar)> = None;
7650
7651 for (bar_type, bars) in &self.bars {
7652 if bar_type.instrument_id() != *instrument_id {
7653 continue;
7654 }
7655
7656 let Some(bar) = bars.front() else {
7657 continue;
7658 };
7659
7660 let slot = match bar_type.spec().price_type {
7661 PriceType::Bid => &mut latest_bid,
7662 PriceType::Ask => &mut latest_ask,
7663 _ => continue,
7664 };
7665
7666 if slot.is_none_or(|(current_type, current)| {
7667 (current.ts_init, current_type) < (bar.ts_init, bar_type)
7668 }) {
7669 *slot = Some((bar_type, bar));
7670 }
7671 }
7672
7673 match (latest_bid, latest_ask) {
7674 (Some((_, bid_bar)), Some((_, ask_bar))) => (bid_bar.close, ask_bar.close),
7675 _ => continue,
7676 }
7677 };
7678
7679 bid_quotes.insert(instrument_id.symbol.inner(), bid_price.as_decimal());
7680 ask_quotes.insert(instrument_id.symbol.inner(), ask_price.as_decimal());
7681 }
7682
7683 (bid_quotes, ask_quotes)
7684 }
7685
7686 #[must_use]
7688 pub fn get_mark_xrate(&self, from_currency: Currency, to_currency: Currency) -> Option<f64> {
7689 self.mark_xrates.get(&(from_currency, to_currency)).copied()
7690 }
7691
7692 pub fn set_mark_xrate(&mut self, from_currency: Currency, to_currency: Currency, xrate: f64) {
7698 assert!(xrate > 0.0, "xrate was zero");
7699 self.mark_xrates.insert((from_currency, to_currency), xrate);
7700 self.mark_xrates
7701 .insert((to_currency, from_currency), 1.0 / xrate);
7702 }
7703
7704 pub fn clear_mark_xrate(&mut self, from_currency: Currency, to_currency: Currency) {
7710 let _ = self.mark_xrates.remove(&(from_currency, to_currency));
7711 }
7712
7713 pub fn clear_mark_xrates(&mut self) {
7715 self.mark_xrates.clear();
7716 }
7717
7718 #[must_use]
7720 pub fn currency(&self, code: &Ustr) -> Option<&Currency> {
7721 self.currencies.get(code)
7722 }
7723
7724 pub fn try_currency(&self, code: &Ustr) -> Result<&Currency, CurrencyLookupError> {
7730 self.currencies
7731 .get(code)
7732 .ok_or_else(|| CurrencyLookupError::not_found(*code))
7733 }
7734
7735 #[must_use]
7739 pub fn instrument(&self, instrument_id: &InstrumentId) -> Option<&InstrumentAny> {
7740 self.instruments.get(instrument_id)
7741 }
7742
7743 pub fn try_instrument(
7749 &self,
7750 instrument_id: &InstrumentId,
7751 ) -> Result<&InstrumentAny, InstrumentLookupError> {
7752 self.instruments
7753 .get(instrument_id)
7754 .ok_or_else(|| InstrumentLookupError::not_found(*instrument_id))
7755 }
7756
7757 #[must_use]
7759 pub fn instrument_ids(&self, venue: Option<&Venue>) -> Vec<&InstrumentId> {
7760 match venue {
7761 Some(v) => self.instruments.keys().filter(|i| &i.venue == v).collect(),
7762 None => self.instruments.keys().collect(),
7763 }
7764 }
7765
7766 #[must_use]
7768 pub fn instruments(&self, venue: &Venue, underlying: Option<&Ustr>) -> Vec<&InstrumentAny> {
7769 self.instruments
7770 .values()
7771 .filter(|i| &i.id().venue == venue)
7772 .filter(|i| underlying.is_none_or(|u| i.underlying() == Some(*u)))
7773 .collect()
7774 }
7775
7776 #[must_use]
7783 pub fn instruments_by_parent(
7784 &self,
7785 venue: &Venue,
7786 root: &Ustr,
7787 class: InstrumentClass,
7788 ) -> Vec<&InstrumentAny> {
7789 self.instruments
7790 .values()
7791 .filter(|i| &i.id().venue == venue)
7792 .filter(|i| i.underlying() == Some(*root))
7793 .filter(|i| i.instrument_class() == class)
7794 .collect()
7795 }
7796
7797 #[must_use]
7799 pub fn bar_types(
7800 &self,
7801 instrument_id: Option<&InstrumentId>,
7802 price_type: Option<&PriceType>,
7803 aggregation_source: AggregationSource,
7804 ) -> Vec<&BarType> {
7805 let mut bar_types = self
7806 .bars
7807 .keys()
7808 .filter(|bar_type| bar_type.aggregation_source() == aggregation_source)
7809 .collect::<Vec<&BarType>>();
7810
7811 if let Some(instrument_id) = instrument_id {
7812 bar_types.retain(|bar_type| bar_type.instrument_id() == *instrument_id);
7813 }
7814
7815 if let Some(price_type) = price_type {
7816 bar_types.retain(|bar_type| &bar_type.spec().price_type == price_type);
7817 }
7818
7819 bar_types
7820 }
7821
7822 #[must_use]
7826 pub fn synthetic(&self, instrument_id: &InstrumentId) -> Option<&SyntheticInstrument> {
7827 self.synthetics.get(instrument_id)
7828 }
7829
7830 pub fn try_synthetic(
7837 &self,
7838 instrument_id: &InstrumentId,
7839 ) -> Result<&SyntheticInstrument, SyntheticInstrumentLookupError> {
7840 self.synthetics
7841 .get(instrument_id)
7842 .ok_or_else(|| SyntheticInstrumentLookupError::not_found(*instrument_id))
7843 }
7844
7845 #[must_use]
7847 pub fn synthetic_ids(&self) -> Vec<&InstrumentId> {
7848 self.synthetics.keys().collect()
7849 }
7850
7851 #[must_use]
7853 pub fn synthetics(&self) -> Vec<&SyntheticInstrument> {
7854 self.synthetics.values().collect()
7855 }
7856
7857 #[must_use]
7861 pub fn account_ref(&self, account_id: &AccountId) -> Option<AccountRef<'_>> {
7862 self.accounts
7863 .get(account_id)
7864 .map(|account_cell| AccountRef::new(account_cell.borrow()))
7865 }
7866
7867 #[must_use]
7871 pub fn account(&self, account_id: &AccountId) -> Option<AccountRef<'_>> {
7872 self.account_ref(account_id)
7873 }
7874
7875 pub fn try_account_ref(
7881 &self,
7882 account_id: &AccountId,
7883 ) -> Result<AccountRef<'_>, AccountLookupError> {
7884 self.accounts
7885 .get(account_id)
7886 .map(|account_cell| AccountRef::new(account_cell.borrow()))
7887 .ok_or_else(|| AccountLookupError::not_found(*account_id))
7888 }
7889
7890 pub fn try_account(
7898 &self,
7899 account_id: &AccountId,
7900 ) -> Result<AccountRef<'_>, AccountLookupError> {
7901 self.try_account_ref(account_id)
7902 }
7903
7904 #[must_use]
7914 pub fn account_mut(&mut self, account_id: &AccountId) -> Option<AccountRefMut<'_>> {
7915 self.accounts
7916 .get(account_id)
7917 .map(|account_cell| AccountRefMut::new(account_cell.borrow_mut()))
7918 }
7919
7920 #[must_use]
7925 pub fn account_owned(&self, account_id: &AccountId) -> Option<AccountAny> {
7926 self.accounts
7927 .get(account_id)
7928 .map(|account_cell| account_cell.borrow().clone())
7929 }
7930
7931 #[must_use]
7933 pub fn account_for_venue(&self, venue: &Venue) -> Option<AccountRef<'_>> {
7934 self.index
7935 .venue_account
7936 .get(venue)
7937 .and_then(|account_id| self.accounts.get(account_id))
7938 .map(|account_cell| AccountRef::new(account_cell.borrow()))
7939 }
7940
7941 #[must_use]
7946 pub fn account_for_venue_owned(&self, venue: &Venue) -> Option<AccountAny> {
7947 self.index
7948 .venue_account
7949 .get(venue)
7950 .and_then(|account_id| self.accounts.get(account_id))
7951 .map(|account_cell| account_cell.borrow().clone())
7952 }
7953
7954 #[must_use]
7956 pub fn account_id(&self, venue: &Venue) -> Option<&AccountId> {
7957 self.index.venue_account.get(venue)
7958 }
7959
7960 #[must_use]
7966 pub fn accounts(&self, account_id: &AccountId) -> Vec<AccountRef<'_>> {
7967 self.accounts
7968 .values()
7969 .filter(|account_cell| &account_cell.borrow().id() == account_id)
7970 .map(|account_cell| AccountRef::new(account_cell.borrow()))
7971 .collect()
7972 }
7973
7974 #[must_use]
7976 pub fn accounts_all_owned(&self) -> Vec<AccountAny> {
7977 self.accounts
7978 .values()
7979 .map(|account_cell| account_cell.borrow().clone())
7980 .collect()
7981 }
7982
7983 pub fn update_own_order_book(&mut self, order: &OrderAny) {
7991 if !order.has_price() {
7992 return;
7993 }
7994
7995 let instrument_id = order.instrument_id();
7996
7997 if !self.own_books.contains_key(&instrument_id) {
7998 if order.is_closed() {
7999 return;
8000 }
8001
8002 self.own_books
8003 .insert(instrument_id, OwnOrderBook::new(instrument_id));
8004 }
8005
8006 let Some(own_book) = self.own_books.get_mut(&instrument_id) else {
8007 return;
8008 };
8009
8010 let own_book_order = order.to_own_book_order();
8011
8012 if order.is_closed() {
8013 if let Err(e) = own_book.delete(own_book_order) {
8014 log::debug!(
8015 "Failed to delete order {} from own book: {e}",
8016 order.client_order_id(),
8017 );
8018 } else {
8019 log::debug!("Deleted order {} from own book", order.client_order_id());
8020 }
8021 } else {
8022 if let Err(e) = own_book.update(own_book_order) {
8024 log::debug!(
8025 "Failed to update order {} in own book: {e}; inserting instead",
8026 order.client_order_id(),
8027 );
8028 own_book.add(own_book_order);
8029 }
8030 log::debug!("Updated order {} in own book", order.client_order_id());
8031 }
8032 }
8033
8034 pub fn force_remove_from_own_order_book(&mut self, client_order_id: &ClientOrderId) {
8040 let Some(order_cell) = self.orders.get(client_order_id) else {
8041 return;
8042 };
8043 let order = order_cell.borrow();
8044 let instrument_id = order.instrument_id();
8045 let own_book_order = if order.has_price() {
8046 Some(order.to_own_book_order())
8047 } else {
8048 None
8049 };
8050 drop(order);
8051
8052 self.index.orders_open.remove(client_order_id);
8053 self.index.orders_pending_cancel.remove(client_order_id);
8054 self.index.orders_inflight.remove(client_order_id);
8055 self.index.orders_emulated.remove(client_order_id);
8056 self.index.orders_active_local.remove(client_order_id);
8057
8058 if let Some(own_book) = self.own_books.get_mut(&instrument_id)
8059 && let Some(own_book_order) = own_book_order
8060 {
8061 if let Err(e) = own_book.delete(own_book_order) {
8062 log::debug!("Could not force delete {client_order_id} from own book: {e}");
8063 } else {
8064 log::debug!("Force deleted {client_order_id} from own book");
8065 }
8066 }
8067
8068 self.index.orders_closed.insert(*client_order_id);
8069 }
8070
8071 pub fn audit_own_order_books(&mut self) {
8078 log::debug!("Starting own books audit");
8079 let start = std::time::Instant::now();
8080
8081 let valid_order_ids: AHashSet<ClientOrderId> = self
8084 .index
8085 .orders_open
8086 .union(&self.index.orders_inflight)
8087 .copied()
8088 .collect();
8089
8090 for own_book in self.own_books.values_mut() {
8091 own_book.audit_open_orders(&valid_order_ids);
8092 }
8093
8094 log::debug!("Completed own books audit in {:?}", start.elapsed());
8095 }
8096}
8097
8098const POSITION_OMS_KEY_PREFIX: &str = "position_oms:";
8099
8100fn position_oms_key(position_id: PositionId) -> String {
8101 format!("{POSITION_OMS_KEY_PREFIX}{position_id}")
8102}