1use std::{
17 any::Any,
18 cell::{Ref, RefCell, RefMut},
19 collections::HashMap,
20 fmt::Debug,
21 num::NonZeroUsize,
22 rc::Rc,
23 sync::Arc,
24};
25
26use ahash::{AHashMap, AHashSet};
27use indexmap::IndexMap;
28use jiff::Timestamp;
29use nautilus_core::{Params, UUID4, UnixNanos, correctness::check_predicate_true};
30#[cfg(feature = "defi")]
31use nautilus_model::defi::{
32 Block, Blockchain, Pool, PoolLiquidityUpdate, PoolSwap, data::PoolFeeCollect, data::PoolFlash,
33};
34use nautilus_model::{
35 data::{
36 Bar, BarType, CustomData, DataType, FundingRateUpdate, IndexPriceUpdate, InstrumentStatus,
37 MarkPriceUpdate, OrderBookDelta, OrderBookDeltas, OrderBookDepth10, QuoteTick, TradeTick,
38 close::InstrumentClose,
39 option_chain::{OptionChainSlice, OptionGreeks, StrikeRange},
40 },
41 enums::BookType,
42 identifiers::{ActorId, ClientId, ComponentId, InstrumentId, OptionSeriesId, TraderId, Venue},
43 instruments::{InstrumentAny, SyntheticInstrument},
44 orderbook::OrderBook,
45};
46use serde::{Deserialize, Serialize};
47use ustr::Ustr;
48
49use super::{
50 Actor,
51 indicators::{Indicators, SharedActorIndicator},
52 registry::try_get_actor_unchecked,
53};
54#[cfg(feature = "defi")]
55use crate::defi;
56#[cfg(feature = "defi")]
57#[allow(unused_imports)]
58use crate::defi::data_actor as _; use crate::{
60 cache::{Cache, CacheApi},
61 clock::{Clock, ClockApi},
62 component::Component,
63 enums::{ComponentState, ComponentTrigger},
64 logging::{CMD, RECV, REQ, SEND},
65 messages::{
66 data::{
67 BarsResponse, BookDeltasResponse, BookDepthResponse, BookResponse, CustomDataResponse,
68 DataCommand, FundingRatesResponse, InstrumentResponse, InstrumentsResponse,
69 QuotesResponse, RequestBars, RequestBookDeltas, RequestBookDepth, RequestBookSnapshot,
70 RequestCommand, RequestCustomData, RequestFundingRates, RequestInstrument,
71 RequestInstruments, RequestQuotes, RequestTrades, SubscribeBars, SubscribeBookDeltas,
72 SubscribeBookDepth10, SubscribeBookSnapshots, SubscribeCommand, SubscribeCustomData,
73 SubscribeFundingRates, SubscribeIndexPrices, SubscribeInstrument,
74 SubscribeInstrumentClose, SubscribeInstrumentStatus, SubscribeInstruments,
75 SubscribeMarkPrices, SubscribeOptionChain, SubscribeOptionGreeks, SubscribeQuotes,
76 SubscribeTrades, TradesResponse, UnsubscribeBars, UnsubscribeBookDeltas,
77 UnsubscribeBookDepth10, UnsubscribeBookSnapshots, UnsubscribeCommand,
78 UnsubscribeCustomData, UnsubscribeFundingRates, UnsubscribeIndexPrices,
79 UnsubscribeInstrument, UnsubscribeInstrumentClose, UnsubscribeInstrumentStatus,
80 UnsubscribeInstruments, UnsubscribeMarkPrices, UnsubscribeOptionChain,
81 UnsubscribeOptionGreeks, UnsubscribeQuotes, UnsubscribeTrades, is_parent_subscription,
82 },
83 system::{QueueStateChanged, ShutdownSystem, SocketStateChanged},
84 },
85 msgbus::{
86 self, MStr, Pattern, ShareableMessageHandler, Topic, TypedHandler, get_message_bus,
87 switchboard::{
88 MessagingSwitchboard, get_bars_topic, get_book_deltas_pattern, get_book_deltas_topic,
89 get_book_depth10_pattern, get_book_depth10_topic, get_book_snapshots_topic,
90 get_custom_topic, get_funding_rate_topic, get_index_price_topic,
91 get_instrument_close_topic, get_instrument_status_topic, get_instrument_topic,
92 get_instruments_pattern, get_mark_price_topic, get_option_chain_topic,
93 get_option_greeks_topic, get_quotes_topic, get_signal_pattern, get_trades_topic,
94 },
95 },
96 signal::Signal,
97 timer::{TimeEvent, TimeEventCallback},
98};
99#[cfg(feature = "live")]
100use crate::{
101 live::try_get_system_command_sender,
102 messages::{
103 SystemCommand,
104 system::{ReconnectSocket, socket_endpoint},
105 },
106};
107
108#[derive(Debug, Clone, Deserialize, Serialize)]
110#[serde(default, deny_unknown_fields)]
111#[cfg_attr(
112 feature = "python",
113 pyo3::pyclass(module = "nautilus_trader.common", subclass, from_py_object)
114)]
115#[cfg_attr(
116 feature = "python",
117 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.common")
118)]
119pub struct DataActorConfig {
120 pub actor_id: Option<ActorId>,
122 pub log_events: bool,
124 pub log_commands: bool,
126}
127
128impl Default for DataActorConfig {
129 fn default() -> Self {
130 Self {
131 actor_id: None,
132 log_events: true,
133 log_commands: true,
134 }
135 }
136}
137
138#[derive(Debug, Clone, Deserialize, Serialize)]
140#[serde(deny_unknown_fields)]
141#[cfg_attr(
142 feature = "python",
143 pyo3::pyclass(module = "nautilus_trader.common", from_py_object)
144)]
145#[cfg_attr(
146 feature = "python",
147 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.common")
148)]
149pub struct ImportableActorConfig {
150 pub actor_path: String,
152 pub config_path: String,
154 pub config: HashMap<String, serde_json::Value>,
156}
157
158type RequestCallback = Arc<dyn Fn(UUID4) + Send + Sync>;
159
160pub trait DataActorNative {
172 fn core(&self) -> &DataActorCore;
174
175 fn core_mut(&mut self) -> &mut DataActorCore;
177
178 fn clock_mut(&mut self) -> RefMut<'_, dyn Clock> {
184 let core = self.core_mut();
185 core.clock
186 .as_ref()
187 .unwrap_or_else(|| {
188 panic!(
189 "DataActor {} must be registered before calling `clock_mut()` - trader_id: {:?}",
190 core.actor_id, core.trader_id
191 )
192 })
193 .borrow_mut()
194 }
195
196 fn clock_rc(&self) -> Rc<RefCell<dyn Clock>> {
202 self.core()
203 .clock
204 .as_ref()
205 .expect("DataActor must be registered before accessing clock")
206 .clone()
207 }
208
209 fn cache_ref(&self) -> Ref<'_, Cache> {
215 self.core()
216 .cache
217 .as_ref()
218 .expect("DataActor must be registered before accessing cache")
219 .borrow()
220 }
221
222 fn cache_rc(&self) -> Rc<RefCell<Cache>> {
228 self.core()
229 .cache
230 .as_ref()
231 .expect("DataActor must be registered before accessing cache")
232 .clone()
233 }
234}
235
236pub trait DataActor {
243 fn actor_id(&self) -> ActorId
245 where
246 Self: DataActorNative,
247 {
248 self.core().actor_id()
249 }
250
251 fn trader_id(&self) -> Option<TraderId>
253 where
254 Self: DataActorNative,
255 {
256 self.core().trader_id()
257 }
258
259 fn is_registered(&self) -> bool
261 where
262 Self: DataActorNative,
263 {
264 self.core().is_registered()
265 }
266
267 fn config(&self) -> &DataActorConfig
269 where
270 Self: DataActorNative,
271 {
272 &self.core().config
273 }
274
275 fn on_save(&self) -> anyhow::Result<IndexMap<String, Vec<u8>>> {
281 Ok(IndexMap::new())
282 }
283
284 #[allow(unused_variables)]
290 fn on_load(&mut self, state: IndexMap<String, Vec<u8>>) -> anyhow::Result<()> {
291 Ok(())
292 }
293
294 fn on_start(&mut self) -> anyhow::Result<()> {
300 log::warn!(
301 "The `on_start` handler was called when not overridden, \
302 it's expected that any actions required when starting the actor \
303 occur here, such as subscribing/requesting data"
304 );
305 Ok(())
306 }
307
308 fn on_stop(&mut self) -> anyhow::Result<()> {
314 log::warn!(
315 "The `on_stop` handler was called when not overridden, \
316 it's expected that any actions required when stopping the actor \
317 occur here, such as unsubscribing from data",
318 );
319 Ok(())
320 }
321
322 fn on_resume(&mut self) -> anyhow::Result<()> {
328 log::warn!(
329 "The `on_resume` handler was called when not overridden, \
330 it's expected that any actions required when resuming the actor \
331 following a stop occur here"
332 );
333 Ok(())
334 }
335
336 fn on_reset(&mut self) -> anyhow::Result<()> {
342 log::warn!(
343 "The `on_reset` handler was called when not overridden, \
344 it's expected that any actions required when resetting the actor \
345 occur here, such as resetting indicators and other state"
346 );
347 Ok(())
348 }
349
350 fn on_dispose(&mut self) -> anyhow::Result<()> {
356 Ok(())
357 }
358
359 fn on_degrade(&mut self) -> anyhow::Result<()> {
365 Ok(())
366 }
367
368 fn on_fault(&mut self) -> anyhow::Result<()> {
374 Ok(())
375 }
376
377 #[allow(unused_variables)]
383 fn on_time_event(&mut self, event: &TimeEvent) -> anyhow::Result<()> {
384 Ok(())
385 }
386
387 #[allow(unused_variables)]
393 fn on_data(&mut self, data: &CustomData) -> anyhow::Result<()> {
394 Ok(())
395 }
396
397 #[allow(unused_variables)]
403 fn on_signal(&mut self, signal: &Signal) -> anyhow::Result<()> {
404 Ok(())
405 }
406
407 #[allow(unused_variables)]
413 fn on_queue_state(&mut self, event: &QueueStateChanged) -> anyhow::Result<()> {
414 Ok(())
415 }
416
417 #[allow(unused_variables)]
423 fn on_socket_state(&mut self, event: &SocketStateChanged) -> anyhow::Result<()> {
424 Ok(())
425 }
426
427 #[allow(unused_variables)]
433 fn on_instrument(&mut self, instrument: &InstrumentAny) -> anyhow::Result<()> {
434 Ok(())
435 }
436
437 #[allow(unused_variables)]
443 fn on_book_deltas(&mut self, deltas: &OrderBookDeltas) -> anyhow::Result<()> {
444 Ok(())
445 }
446
447 #[allow(unused_variables)]
453 fn on_book_depth(&mut self, depth: &OrderBookDepth10) -> anyhow::Result<()> {
454 Ok(())
455 }
456
457 #[allow(unused_variables)]
463 fn on_book(&mut self, order_book: &OrderBook) -> anyhow::Result<()> {
464 Ok(())
465 }
466
467 #[allow(unused_variables)]
473 fn on_quote(&mut self, quote: &QuoteTick) -> anyhow::Result<()> {
474 Ok(())
475 }
476
477 #[allow(unused_variables)]
483 fn on_trade(&mut self, tick: &TradeTick) -> anyhow::Result<()> {
484 Ok(())
485 }
486
487 #[allow(unused_variables)]
493 fn on_bar(&mut self, bar: &Bar) -> anyhow::Result<()> {
494 Ok(())
495 }
496
497 #[allow(unused_variables)]
503 fn on_mark_price(&mut self, mark_price: &MarkPriceUpdate) -> anyhow::Result<()> {
504 Ok(())
505 }
506
507 #[allow(unused_variables)]
513 fn on_index_price(&mut self, index_price: &IndexPriceUpdate) -> anyhow::Result<()> {
514 Ok(())
515 }
516
517 #[allow(unused_variables)]
523 fn on_funding_rate(&mut self, funding_rate: &FundingRateUpdate) -> anyhow::Result<()> {
524 Ok(())
525 }
526
527 #[allow(unused_variables)]
533 fn on_option_greeks(&mut self, greeks: &OptionGreeks) -> anyhow::Result<()> {
534 Ok(())
535 }
536
537 #[allow(unused_variables)]
543 fn on_option_chain(&mut self, slice: &OptionChainSlice) -> anyhow::Result<()> {
544 Ok(())
545 }
546
547 #[allow(unused_variables)]
553 fn on_instrument_status(&mut self, data: &InstrumentStatus) -> anyhow::Result<()> {
554 Ok(())
555 }
556
557 #[allow(unused_variables)]
563 fn on_instrument_close(&mut self, update: &InstrumentClose) -> anyhow::Result<()> {
564 Ok(())
565 }
566
567 #[cfg(feature = "defi")]
568 #[allow(unused_variables)]
574 fn on_block(&mut self, block: &Block) -> anyhow::Result<()> {
575 Ok(())
576 }
577
578 #[cfg(feature = "defi")]
579 #[allow(unused_variables)]
585 fn on_pool(&mut self, pool: &Pool) -> anyhow::Result<()> {
586 Ok(())
587 }
588
589 #[cfg(feature = "defi")]
590 #[allow(unused_variables)]
596 fn on_pool_swap(&mut self, swap: &PoolSwap) -> anyhow::Result<()> {
597 Ok(())
598 }
599
600 #[cfg(feature = "defi")]
601 #[allow(unused_variables)]
607 fn on_pool_liquidity_update(&mut self, update: &PoolLiquidityUpdate) -> anyhow::Result<()> {
608 Ok(())
609 }
610
611 #[cfg(feature = "defi")]
612 #[allow(unused_variables)]
618 fn on_pool_fee_collect(&mut self, collect: &PoolFeeCollect) -> anyhow::Result<()> {
619 Ok(())
620 }
621
622 #[cfg(feature = "defi")]
623 #[allow(unused_variables)]
629 fn on_pool_flash(&mut self, flash: &PoolFlash) -> anyhow::Result<()> {
630 Ok(())
631 }
632
633 #[allow(unused_variables)]
642 fn on_historical_data(&mut self, data: &dyn Any) -> anyhow::Result<()> {
643 Ok(())
644 }
645
646 #[allow(unused_variables)]
652 fn on_historical_book_deltas(&mut self, deltas: &[OrderBookDelta]) -> anyhow::Result<()> {
653 Ok(())
654 }
655
656 #[allow(unused_variables)]
662 fn on_historical_book_depth(&mut self, depths: &[OrderBookDepth10]) -> anyhow::Result<()> {
663 Ok(())
664 }
665
666 #[allow(unused_variables)]
672 fn on_historical_quotes(&mut self, quotes: &[QuoteTick]) -> anyhow::Result<()> {
673 Ok(())
674 }
675
676 #[allow(unused_variables)]
682 fn on_historical_trades(&mut self, trades: &[TradeTick]) -> anyhow::Result<()> {
683 Ok(())
684 }
685
686 #[allow(unused_variables)]
692 fn on_historical_bars(&mut self, bars: &[Bar]) -> anyhow::Result<()> {
693 Ok(())
694 }
695
696 #[allow(unused_variables)]
702 fn on_historical_mark_prices(&mut self, mark_prices: &[MarkPriceUpdate]) -> anyhow::Result<()> {
703 Ok(())
704 }
705
706 #[allow(unused_variables)]
712 fn on_historical_index_prices(
713 &mut self,
714 index_prices: &[IndexPriceUpdate],
715 ) -> anyhow::Result<()> {
716 Ok(())
717 }
718
719 #[allow(unused_variables)]
725 fn on_historical_funding_rates(
726 &mut self,
727 funding_rates: &[FundingRateUpdate],
728 ) -> anyhow::Result<()> {
729 Ok(())
730 }
731
732 fn clock(&self) -> ClockApi<'_>
734 where
735 Self: DataActorNative,
736 {
737 self.core().clock_api()
738 }
739
740 fn cache(&self) -> CacheApi<'_>
742 where
743 Self: DataActorNative,
744 {
745 self.core().cache_api()
746 }
747
748 fn shutdown_system(&self, reason: Option<String>)
754 where
755 Self: DataActorNative,
756 {
757 self.core().shutdown_system(reason);
758 }
759
760 fn publish_data(&self, data_type: &DataType, data: &CustomData)
769 where
770 Self: DataActorNative,
771 {
772 self.core().publish_data(data_type, data);
773 }
774
775 fn publish_signal(&self, name: &str, value: String, ts_event: UnixNanos)
781 where
782 Self: DataActorNative,
783 {
784 self.core().publish_signal(name, value, ts_event);
785 }
786
787 fn add_synthetic(&self, synthetic: SyntheticInstrument) -> anyhow::Result<()>
799 where
800 Self: DataActorNative,
801 {
802 self.core().add_synthetic(synthetic)
803 }
804
805 fn update_synthetic(&self, synthetic: SyntheticInstrument) -> anyhow::Result<()>
817 where
818 Self: DataActorNative,
819 {
820 self.core().update_synthetic(synthetic)
821 }
822
823 fn handle_time_event(&mut self, event: &TimeEvent)
825 where
826 Self: Component,
827 {
828 log_received(&event);
829
830 if self.not_running() {
831 log_not_running(&event);
832 return;
833 }
834
835 if let Err(e) = DataActor::on_time_event(self, event) {
836 log_error(&e);
837 }
838 }
839
840 fn handle_data(&mut self, data: &CustomData)
842 where
843 Self: Component,
844 {
845 log_received(&data);
846
847 if self.not_running() {
848 log_not_running(&data);
849 return;
850 }
851
852 if let Err(e) = self.on_data(data) {
853 log_error(&e);
854 }
855 }
856
857 fn handle_signal(&mut self, signal: &Signal)
859 where
860 Self: Component,
861 {
862 log_received(&signal);
863
864 if self.not_running() {
865 log_not_running(&signal);
866 return;
867 }
868
869 if let Err(e) = self.on_signal(signal) {
870 log_error(&e);
871 }
872 }
873
874 fn handle_queue_state(&mut self, event: &QueueStateChanged)
876 where
877 Self: Component,
878 {
879 log_received(&event);
880
881 if self.not_running() {
882 log_not_running(&event);
883 return;
884 }
885
886 if let Err(e) = self.on_queue_state(event) {
887 log_error(&e);
888 }
889 }
890
891 fn handle_socket_state(&mut self, event: &SocketStateChanged)
893 where
894 Self: Component,
895 {
896 log_received(&event);
897
898 if self.not_running() {
899 log_not_running(&event);
900 return;
901 }
902
903 if let Err(e) = self.on_socket_state(event) {
904 log_error(&e);
905 }
906 }
907
908 fn handle_instrument(&mut self, instrument: &InstrumentAny)
910 where
911 Self: Component,
912 {
913 log_received(&instrument);
914
915 if self.not_running() {
916 log_not_running(&instrument);
917 return;
918 }
919
920 if let Err(e) = self.on_instrument(instrument) {
921 log_error(&e);
922 }
923 }
924
925 fn handle_book_deltas(&mut self, deltas: &OrderBookDeltas)
927 where
928 Self: Component,
929 {
930 log_received(&deltas);
931
932 if self.not_running() {
933 log_not_running(&deltas);
934 return;
935 }
936
937 if let Err(e) = self.on_book_deltas(deltas) {
938 log_error(&e);
939 }
940 }
941
942 fn handle_book_depth(&mut self, depth: &OrderBookDepth10)
944 where
945 Self: Component,
946 {
947 log_received(&depth);
948
949 if self.not_running() {
950 log_not_running(&depth);
951 return;
952 }
953
954 if let Err(e) = self.on_book_depth(depth) {
955 log_error(&e);
956 }
957 }
958
959 fn handle_book(&mut self, book: &OrderBook)
961 where
962 Self: Component,
963 {
964 log_received(&book);
965
966 if self.not_running() {
967 log_not_running(&book);
968 return;
969 }
970
971 if let Err(e) = self.on_book(book) {
972 log_error(&e);
973 }
974 }
975
976 fn handle_quote(&mut self, quote: &QuoteTick)
978 where
979 Self: DataActorNative + Component,
980 {
981 log_received("e);
982
983 if let Err(e) = self.core().handle_indicators_for_quote(quote) {
984 log_error(&e);
985 return;
986 }
987
988 if self.not_running() {
989 log_not_running("e);
990 return;
991 }
992
993 if let Err(e) = self.on_quote(quote) {
994 log_error(&e);
995 }
996 }
997
998 fn handle_trade(&mut self, trade: &TradeTick)
1000 where
1001 Self: DataActorNative + Component,
1002 {
1003 log_received(&trade);
1004
1005 if let Err(e) = self.core().handle_indicators_for_trade(trade) {
1006 log_error(&e);
1007 return;
1008 }
1009
1010 if self.not_running() {
1011 log_not_running(&trade);
1012 return;
1013 }
1014
1015 if let Err(e) = self.on_trade(trade) {
1016 log_error(&e);
1017 }
1018 }
1019
1020 fn handle_bar(&mut self, bar: &Bar)
1022 where
1023 Self: DataActorNative + Component,
1024 {
1025 log_received(&bar);
1026
1027 if let Err(e) = self.core().handle_indicators_for_bar(bar) {
1028 log_error(&e);
1029 return;
1030 }
1031
1032 if self.not_running() {
1033 log_not_running(&bar);
1034 return;
1035 }
1036
1037 if let Err(e) = self.on_bar(bar) {
1038 log_error(&e);
1039 }
1040 }
1041
1042 fn handle_mark_price(&mut self, mark_price: &MarkPriceUpdate)
1044 where
1045 Self: Component,
1046 {
1047 log_received(&mark_price);
1048
1049 if self.not_running() {
1050 log_not_running(&mark_price);
1051 return;
1052 }
1053
1054 if let Err(e) = self.on_mark_price(mark_price) {
1055 log_error(&e);
1056 }
1057 }
1058
1059 fn handle_index_price(&mut self, index_price: &IndexPriceUpdate)
1061 where
1062 Self: Component,
1063 {
1064 log_received(&index_price);
1065
1066 if self.not_running() {
1067 log_not_running(&index_price);
1068 return;
1069 }
1070
1071 if let Err(e) = self.on_index_price(index_price) {
1072 log_error(&e);
1073 }
1074 }
1075
1076 fn handle_funding_rate(&mut self, funding_rate: &FundingRateUpdate)
1078 where
1079 Self: Component,
1080 {
1081 log_received(&funding_rate);
1082
1083 if self.not_running() {
1084 log_not_running(&funding_rate);
1085 return;
1086 }
1087
1088 if let Err(e) = self.on_funding_rate(funding_rate) {
1089 log_error(&e);
1090 }
1091 }
1092
1093 fn handle_option_greeks(&mut self, greeks: &OptionGreeks)
1095 where
1096 Self: Component,
1097 {
1098 log_received(&greeks);
1099
1100 if self.not_running() {
1101 log_not_running(&greeks);
1102 return;
1103 }
1104
1105 if let Err(e) = self.on_option_greeks(greeks) {
1106 log_error(&e);
1107 }
1108 }
1109
1110 fn handle_option_chain(&mut self, slice: &OptionChainSlice)
1112 where
1113 Self: Component,
1114 {
1115 log_received(&slice);
1116
1117 if self.not_running() {
1118 log_not_running(&slice);
1119 return;
1120 }
1121
1122 if let Err(e) = self.on_option_chain(slice) {
1123 log_error(&e);
1124 }
1125 }
1126
1127 fn handle_instrument_status(&mut self, status: &InstrumentStatus)
1129 where
1130 Self: Component,
1131 {
1132 log_received(&status);
1133
1134 if self.not_running() {
1135 log_not_running(&status);
1136 return;
1137 }
1138
1139 if let Err(e) = self.on_instrument_status(status) {
1140 log_error(&e);
1141 }
1142 }
1143
1144 fn handle_instrument_close(&mut self, close: &InstrumentClose)
1146 where
1147 Self: Component,
1148 {
1149 log_received(&close);
1150
1151 if self.not_running() {
1152 log_not_running(&close);
1153 return;
1154 }
1155
1156 if let Err(e) = self.on_instrument_close(close) {
1157 log_error(&e);
1158 }
1159 }
1160
1161 #[cfg(feature = "defi")]
1162 fn handle_block(&mut self, block: &Block)
1164 where
1165 Self: Component,
1166 {
1167 log_received(&block);
1168
1169 if self.not_running() {
1170 log_not_running(&block);
1171 return;
1172 }
1173
1174 if let Err(e) = self.on_block(block) {
1175 log_error(&e);
1176 }
1177 }
1178
1179 #[cfg(feature = "defi")]
1180 fn handle_pool(&mut self, pool: &Pool)
1182 where
1183 Self: Component,
1184 {
1185 log_received(&pool);
1186
1187 if self.not_running() {
1188 log_not_running(&pool);
1189 return;
1190 }
1191
1192 if let Err(e) = self.on_pool(pool) {
1193 log_error(&e);
1194 }
1195 }
1196
1197 #[cfg(feature = "defi")]
1198 fn handle_pool_swap(&mut self, swap: &PoolSwap)
1200 where
1201 Self: Component,
1202 {
1203 log_received(&swap);
1204
1205 if self.not_running() {
1206 log_not_running(&swap);
1207 return;
1208 }
1209
1210 if let Err(e) = self.on_pool_swap(swap) {
1211 log_error(&e);
1212 }
1213 }
1214
1215 #[cfg(feature = "defi")]
1216 fn handle_pool_liquidity_update(&mut self, update: &PoolLiquidityUpdate)
1218 where
1219 Self: Component,
1220 {
1221 log_received(&update);
1222
1223 if self.not_running() {
1224 log_not_running(&update);
1225 return;
1226 }
1227
1228 if let Err(e) = self.on_pool_liquidity_update(update) {
1229 log_error(&e);
1230 }
1231 }
1232
1233 #[cfg(feature = "defi")]
1234 fn handle_pool_fee_collect(&mut self, collect: &PoolFeeCollect)
1236 where
1237 Self: Component,
1238 {
1239 log_received(&collect);
1240
1241 if self.not_running() {
1242 log_not_running(&collect);
1243 return;
1244 }
1245
1246 if let Err(e) = self.on_pool_fee_collect(collect) {
1247 log_error(&e);
1248 }
1249 }
1250
1251 #[cfg(feature = "defi")]
1252 fn handle_pool_flash(&mut self, flash: &PoolFlash)
1254 where
1255 Self: Component,
1256 {
1257 log_received(&flash);
1258
1259 if self.not_running() {
1260 log_not_running(&flash);
1261 return;
1262 }
1263
1264 if let Err(e) = self.on_pool_flash(flash) {
1265 log_error(&e);
1266 }
1267 }
1268
1269 fn handle_historical_data(&mut self, data: &dyn Any) {
1271 log_received(&data);
1272
1273 if let Err(e) = self.on_historical_data(data) {
1274 log_error(&e);
1275 }
1276 }
1277
1278 fn handle_data_response(&mut self, resp: &CustomDataResponse) {
1280 if let Some(data) = resp.data.as_ref().downcast_ref::<Vec<CustomData>>() {
1281 log_received_bulk("CustomDataResponse", &resp.correlation_id, data.len());
1282 log::trace!("{RECV} {resp:?}");
1283 } else {
1284 log_received(&resp);
1285 }
1286
1287 if let Err(e) = self.on_historical_data(resp.data.as_ref()) {
1288 log_error(&e);
1289 }
1290 }
1291
1292 fn handle_instrument_response(&mut self, resp: &InstrumentResponse) {
1294 log_received(&resp);
1295
1296 if let Err(e) = self.on_instrument(&resp.data) {
1297 log_error(&e);
1298 }
1299 }
1300
1301 fn handle_instruments_response(&mut self, resp: &InstrumentsResponse) {
1303 log_received_bulk("InstrumentsResponse", &resp.correlation_id, resp.data.len());
1304 log::trace!("{RECV} {resp:?}");
1305
1306 for inst in &resp.data {
1307 if let Err(e) = self.on_instrument(inst) {
1308 log_error(&e);
1309 }
1310 }
1311 }
1312
1313 fn handle_book_response(&mut self, resp: &BookResponse) {
1315 log_received(&resp);
1316
1317 if let Err(e) = self.on_book(&resp.data) {
1318 log_error(&e);
1319 }
1320 }
1321
1322 fn handle_book_deltas_response(&mut self, resp: &BookDeltasResponse) {
1324 log_received_bulk("BookDeltasResponse", &resp.correlation_id, resp.data.len());
1325 log::trace!("{RECV} {resp:?}");
1326
1327 if let Err(e) = self.on_historical_book_deltas(&resp.data) {
1328 log_error(&e);
1329 }
1330 }
1331
1332 fn handle_book_depth_response(&mut self, resp: &BookDepthResponse) {
1334 log_received_bulk("BookDepthResponse", &resp.correlation_id, resp.data.len());
1335 log::trace!("{RECV} {resp:?}");
1336
1337 if let Err(e) = self.on_historical_book_depth(&resp.data) {
1338 log_error(&e);
1339 }
1340 }
1341
1342 fn handle_quotes_response(&mut self, resp: &QuotesResponse)
1344 where
1345 Self: DataActorNative,
1346 {
1347 log_received_bulk("QuotesResponse", &resp.correlation_id, resp.data.len());
1348 log::trace!("{RECV} {resp:?}");
1349
1350 if let Err(e) = self.core().handle_indicators_for_quotes(&resp.data) {
1351 log_error(&e);
1352 return;
1353 }
1354
1355 if let Err(e) = self.on_historical_quotes(&resp.data) {
1356 log_error(&e);
1357 }
1358 }
1359
1360 fn handle_trades_response(&mut self, resp: &TradesResponse)
1362 where
1363 Self: DataActorNative,
1364 {
1365 log_received_bulk("TradesResponse", &resp.correlation_id, resp.data.len());
1366 log::trace!("{RECV} {resp:?}");
1367
1368 if let Err(e) = self.core().handle_indicators_for_trades(&resp.data) {
1369 log_error(&e);
1370 return;
1371 }
1372
1373 if let Err(e) = self.on_historical_trades(&resp.data) {
1374 log_error(&e);
1375 }
1376 }
1377
1378 fn handle_bars_response(&mut self, resp: &BarsResponse)
1380 where
1381 Self: DataActorNative,
1382 {
1383 log_received_bulk("BarsResponse", &resp.correlation_id, resp.data.len());
1384 log::trace!("{RECV} {resp:?}");
1385
1386 if let Err(e) = self.core().handle_indicators_for_bars(&resp.data) {
1387 log_error(&e);
1388 return;
1389 }
1390
1391 if let Err(e) = self.on_historical_bars(&resp.data) {
1392 log_error(&e);
1393 }
1394 }
1395
1396 fn handle_funding_rates_response(&mut self, resp: &FundingRatesResponse) {
1398 log_received_bulk(
1399 "FundingRatesResponse",
1400 &resp.correlation_id,
1401 resp.data.len(),
1402 );
1403 log::trace!("{RECV} {resp:?}");
1404
1405 if let Err(e) = self.on_historical_funding_rates(&resp.data) {
1406 log_error(&e);
1407 }
1408 }
1409
1410 fn subscribe_data(
1412 &mut self,
1413 data_type: DataType,
1414 client_id: Option<ClientId>,
1415 params: Option<Params>,
1416 ) where
1417 Self: DataActorNative,
1418 Self: 'static + Debug + Sized,
1419 {
1420 let actor_id = self.core().actor_id().inner();
1421 let handler = ShareableMessageHandler::from_typed(move |data: &CustomData| {
1422 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1423 actor.handle_data(data);
1424 } else {
1425 log::error!("Actor {actor_id} not found for data handling");
1426 }
1427 });
1428
1429 DataActorCore::subscribe_data(self.core_mut(), handler, data_type, client_id, params);
1430 }
1431
1432 fn subscribe_signal(&mut self, name: &str, priority: Option<u32>)
1447 where
1448 Self: DataActorNative,
1449 Self: 'static + Debug + Sized,
1450 {
1451 let actor_id = self.core().actor_id().inner();
1452 let handler = ShareableMessageHandler::from_typed(move |data: &CustomData| {
1455 if let Some(signal) = data.data.as_any().downcast_ref::<Signal>() {
1456 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1457 actor.handle_signal(signal);
1458 } else {
1459 log::error!("Actor {actor_id} not found for signal handling");
1460 }
1461 }
1462 });
1463
1464 DataActorCore::subscribe_signal(self.core_mut(), handler, name, priority);
1465 }
1466
1467 fn subscribe_queue_state(&mut self, priority: Option<u32>)
1473 where
1474 Self: DataActorNative,
1475 Self: 'static + Debug + Sized,
1476 {
1477 let actor_id = self.core().actor_id().inner();
1478 let handler = ShareableMessageHandler::from_typed(move |event: &QueueStateChanged| {
1479 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1480 actor.handle_queue_state(event);
1481 } else {
1482 log::error!("Actor {actor_id} not found for queue state change handling");
1483 }
1484 });
1485
1486 DataActorCore::subscribe_queue_state(self.core_mut(), handler, priority);
1487 }
1488
1489 fn subscribe_socket_state(&mut self, priority: Option<u32>)
1495 where
1496 Self: DataActorNative,
1497 Self: 'static + Debug + Sized,
1498 {
1499 let actor_id = self.core().actor_id().inner();
1500 let handler = ShareableMessageHandler::from_typed(move |event: &SocketStateChanged| {
1501 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1502 actor.handle_socket_state(event);
1503 } else {
1504 log::error!("Actor {actor_id} not found for socket state change handling");
1505 }
1506 });
1507
1508 DataActorCore::subscribe_socket_state(self.core_mut(), handler, priority);
1509 }
1510
1511 fn subscribe_quotes(
1513 &mut self,
1514 instrument_id: InstrumentId,
1515 client_id: Option<ClientId>,
1516 params: Option<Params>,
1517 ) where
1518 Self: DataActorNative,
1519 Self: 'static + Debug + Sized,
1520 {
1521 let actor_id = self.core().actor_id().inner();
1522 let topic = get_quotes_topic(instrument_id);
1523
1524 let handler = TypedHandler::from(move |quote: &QuoteTick| {
1525 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1526 actor.handle_quote(quote);
1527 } else {
1528 log::error!("Actor {actor_id} not found for quote handling");
1529 }
1530 });
1531
1532 DataActorCore::subscribe_quotes(
1533 self.core_mut(),
1534 topic,
1535 handler,
1536 instrument_id,
1537 client_id,
1538 params,
1539 );
1540 }
1541
1542 fn subscribe_instruments(
1544 &mut self,
1545 venue: Venue,
1546 client_id: Option<ClientId>,
1547 params: Option<Params>,
1548 ) where
1549 Self: DataActorNative,
1550 Self: 'static + Debug + Sized,
1551 {
1552 let actor_id = self.core().actor_id().inner();
1553 let pattern = get_instruments_pattern(venue);
1554
1555 let handler = TypedHandler::from(move |instrument: &InstrumentAny| {
1556 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1557 actor.handle_instrument(instrument);
1558 } else {
1559 log::error!("Actor {actor_id} not found for instruments handling");
1560 }
1561 });
1562
1563 DataActorCore::subscribe_instruments(
1564 self.core_mut(),
1565 pattern,
1566 handler,
1567 venue,
1568 client_id,
1569 params,
1570 );
1571 }
1572
1573 fn subscribe_instrument(
1575 &mut self,
1576 instrument_id: InstrumentId,
1577 client_id: Option<ClientId>,
1578 params: Option<Params>,
1579 ) where
1580 Self: DataActorNative,
1581 Self: 'static + Debug + Sized,
1582 {
1583 let actor_id = self.core().actor_id().inner();
1584 let topic = get_instrument_topic(instrument_id);
1585
1586 let handler = TypedHandler::from(move |instrument: &InstrumentAny| {
1587 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1588 actor.handle_instrument(instrument);
1589 } else {
1590 log::error!("Actor {actor_id} not found for instrument handling");
1591 }
1592 });
1593
1594 DataActorCore::subscribe_instrument(
1595 self.core_mut(),
1596 topic,
1597 handler,
1598 instrument_id,
1599 client_id,
1600 params,
1601 );
1602 }
1603
1604 fn subscribe_book_deltas(
1610 &mut self,
1611 instrument_id: InstrumentId,
1612 book_type: BookType,
1613 depth: Option<NonZeroUsize>,
1614 client_id: Option<ClientId>,
1615 managed: bool,
1616 params: Option<Params>,
1617 ) where
1618 Self: DataActorNative,
1619 Self: 'static + Debug + Sized,
1620 {
1621 let actor_id = self.core().actor_id().inner();
1622 let is_parent = is_parent_subscription(params.as_ref());
1623 let pattern = if is_parent {
1624 get_book_deltas_pattern(instrument_id)
1625 } else {
1626 get_book_deltas_topic(instrument_id).into()
1627 };
1628
1629 let handler = TypedHandler::from(move |deltas: &OrderBookDeltas| {
1630 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1631 actor.handle_book_deltas(deltas);
1632 } else {
1633 log::error!("Actor {actor_id} not found for book deltas handling");
1634 }
1635 });
1636
1637 DataActorCore::subscribe_book_deltas(
1638 self.core_mut(),
1639 pattern,
1640 handler,
1641 instrument_id,
1642 book_type,
1643 depth,
1644 client_id,
1645 managed,
1646 params,
1647 );
1648 }
1649
1650 fn subscribe_book_depth10(
1656 &mut self,
1657 instrument_id: InstrumentId,
1658 book_type: BookType,
1659 client_id: Option<ClientId>,
1660 managed: bool,
1661 params: Option<Params>,
1662 ) where
1663 Self: DataActorNative,
1664 Self: 'static + Debug + Sized,
1665 {
1666 let actor_id = self.core().actor_id().inner();
1667 let pattern = if is_parent_subscription(params.as_ref()) {
1668 get_book_depth10_pattern(instrument_id)
1669 } else {
1670 get_book_depth10_topic(instrument_id).into()
1671 };
1672
1673 let handler = TypedHandler::from(move |depth: &OrderBookDepth10| {
1674 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1675 actor.handle_book_depth(depth);
1676 } else {
1677 log::error!("Actor {actor_id} not found for book depth handling");
1678 }
1679 });
1680
1681 DataActorCore::subscribe_book_depth10(
1682 self.core_mut(),
1683 pattern,
1684 handler,
1685 instrument_id,
1686 book_type,
1687 client_id,
1688 managed,
1689 params,
1690 );
1691 }
1692
1693 fn subscribe_book_at_interval(
1695 &mut self,
1696 instrument_id: InstrumentId,
1697 book_type: BookType,
1698 depth: Option<NonZeroUsize>,
1699 interval_ms: NonZeroUsize,
1700 client_id: Option<ClientId>,
1701 params: Option<Params>,
1702 ) where
1703 Self: DataActorNative,
1704 Self: 'static + Debug + Sized,
1705 {
1706 let actor_id = self.core().actor_id().inner();
1707 let topic = get_book_snapshots_topic(instrument_id, interval_ms);
1708
1709 let handler = TypedHandler::from(move |book: &OrderBook| {
1710 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1711 actor.handle_book(book);
1712 } else {
1713 log::error!("Actor {actor_id} not found for book handling");
1714 }
1715 });
1716
1717 DataActorCore::subscribe_book_at_interval(
1718 self.core_mut(),
1719 topic,
1720 handler,
1721 instrument_id,
1722 book_type,
1723 depth,
1724 interval_ms,
1725 client_id,
1726 params,
1727 );
1728 }
1729
1730 fn subscribe_trades(
1732 &mut self,
1733 instrument_id: InstrumentId,
1734 client_id: Option<ClientId>,
1735 params: Option<Params>,
1736 ) where
1737 Self: DataActorNative,
1738 Self: 'static + Debug + Sized,
1739 {
1740 let actor_id = self.core().actor_id().inner();
1741 let topic = get_trades_topic(instrument_id);
1742
1743 let handler = TypedHandler::from(move |trade: &TradeTick| {
1744 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1745 actor.handle_trade(trade);
1746 } else {
1747 log::error!("Actor {actor_id} not found for trade handling");
1748 }
1749 });
1750
1751 DataActorCore::subscribe_trades(
1752 self.core_mut(),
1753 topic,
1754 handler,
1755 instrument_id,
1756 client_id,
1757 params,
1758 );
1759 }
1760
1761 fn subscribe_bars(
1763 &mut self,
1764 bar_type: BarType,
1765 client_id: Option<ClientId>,
1766 params: Option<Params>,
1767 ) where
1768 Self: DataActorNative,
1769 Self: 'static + Debug + Sized,
1770 {
1771 let actor_id = self.core().actor_id().inner();
1772 let topic = get_bars_topic(bar_type.standard());
1774
1775 let handler = TypedHandler::from(move |bar: &Bar| {
1776 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1777 actor.handle_bar(bar);
1778 } else {
1779 log::error!("Actor {actor_id} not found for bar handling");
1780 }
1781 });
1782
1783 DataActorCore::subscribe_bars(self.core_mut(), topic, handler, bar_type, client_id, params);
1784 }
1785
1786 fn subscribe_mark_prices(
1788 &mut self,
1789 instrument_id: InstrumentId,
1790 client_id: Option<ClientId>,
1791 params: Option<Params>,
1792 ) where
1793 Self: DataActorNative,
1794 Self: 'static + Debug + Sized,
1795 {
1796 let actor_id = self.core().actor_id().inner();
1797 let topic = get_mark_price_topic(instrument_id);
1798
1799 let handler = TypedHandler::from(move |mark_price: &MarkPriceUpdate| {
1800 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1801 actor.handle_mark_price(mark_price);
1802 } else {
1803 log::error!("Actor {actor_id} not found for mark price handling");
1804 }
1805 });
1806
1807 DataActorCore::subscribe_mark_prices(
1808 self.core_mut(),
1809 topic,
1810 handler,
1811 instrument_id,
1812 client_id,
1813 params,
1814 );
1815 }
1816
1817 fn subscribe_index_prices(
1819 &mut self,
1820 instrument_id: InstrumentId,
1821 client_id: Option<ClientId>,
1822 params: Option<Params>,
1823 ) where
1824 Self: DataActorNative,
1825 Self: 'static + Debug + Sized,
1826 {
1827 let actor_id = self.core().actor_id().inner();
1828 let topic = get_index_price_topic(instrument_id);
1829
1830 let handler = TypedHandler::from(move |index_price: &IndexPriceUpdate| {
1831 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1832 actor.handle_index_price(index_price);
1833 } else {
1834 log::error!("Actor {actor_id} not found for index price handling");
1835 }
1836 });
1837
1838 DataActorCore::subscribe_index_prices(
1839 self.core_mut(),
1840 topic,
1841 handler,
1842 instrument_id,
1843 client_id,
1844 params,
1845 );
1846 }
1847
1848 fn subscribe_funding_rates(
1850 &mut self,
1851 instrument_id: InstrumentId,
1852 client_id: Option<ClientId>,
1853 params: Option<Params>,
1854 ) where
1855 Self: DataActorNative,
1856 Self: 'static + Debug + Sized,
1857 {
1858 let actor_id = self.core().actor_id().inner();
1859 let topic = get_funding_rate_topic(instrument_id);
1860
1861 let handler = TypedHandler::from(move |funding_rate: &FundingRateUpdate| {
1862 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1863 actor.handle_funding_rate(funding_rate);
1864 } else {
1865 log::error!("Actor {actor_id} not found for funding rate handling");
1866 }
1867 });
1868
1869 DataActorCore::subscribe_funding_rates(
1870 self.core_mut(),
1871 topic,
1872 handler,
1873 instrument_id,
1874 client_id,
1875 params,
1876 );
1877 }
1878
1879 fn subscribe_option_greeks(
1881 &mut self,
1882 instrument_id: InstrumentId,
1883 client_id: Option<ClientId>,
1884 params: Option<Params>,
1885 ) where
1886 Self: DataActorNative,
1887 Self: 'static + Debug + Sized,
1888 {
1889 let actor_id = self.core().actor_id().inner();
1890 let topic = get_option_greeks_topic(instrument_id);
1891
1892 let handler = TypedHandler::from(move |option_greeks: &OptionGreeks| {
1893 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1894 actor.handle_option_greeks(option_greeks);
1895 } else {
1896 log::error!("Actor {actor_id} not found for option greeks handling");
1897 }
1898 });
1899
1900 DataActorCore::subscribe_option_greeks(
1901 self.core_mut(),
1902 topic,
1903 handler,
1904 instrument_id,
1905 client_id,
1906 params,
1907 );
1908 }
1909
1910 fn subscribe_instrument_status(
1912 &mut self,
1913 instrument_id: InstrumentId,
1914 client_id: Option<ClientId>,
1915 params: Option<Params>,
1916 ) where
1917 Self: DataActorNative,
1918 Self: 'static + Debug + Sized,
1919 {
1920 let actor_id = self.core().actor_id().inner();
1921 let topic = get_instrument_status_topic(instrument_id);
1922
1923 let handler = ShareableMessageHandler::from_typed(move |status: &InstrumentStatus| {
1924 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1925 actor.handle_instrument_status(status);
1926 } else {
1927 log::error!("Actor {actor_id} not found for instrument status handling");
1928 }
1929 });
1930
1931 DataActorCore::subscribe_instrument_status(
1932 self.core_mut(),
1933 topic,
1934 handler,
1935 instrument_id,
1936 client_id,
1937 params,
1938 );
1939 }
1940
1941 fn subscribe_instrument_close(
1943 &mut self,
1944 instrument_id: InstrumentId,
1945 client_id: Option<ClientId>,
1946 params: Option<Params>,
1947 ) where
1948 Self: DataActorNative,
1949 Self: 'static + Debug + Sized,
1950 {
1951 let actor_id = self.core().actor_id().inner();
1952 let topic = get_instrument_close_topic(instrument_id);
1953
1954 let handler = ShareableMessageHandler::from_typed(move |close: &InstrumentClose| {
1955 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1956 actor.handle_instrument_close(close);
1957 } else {
1958 log::error!("Actor {actor_id} not found for instrument close handling");
1959 }
1960 });
1961
1962 DataActorCore::subscribe_instrument_close(
1963 self.core_mut(),
1964 topic,
1965 handler,
1966 instrument_id,
1967 client_id,
1968 params,
1969 );
1970 }
1971
1972 fn subscribe_option_chain(
1977 &mut self,
1978 series_id: OptionSeriesId,
1979 strike_range: StrikeRange,
1980 snapshot_interval_ms: Option<u64>,
1981 client_id: Option<ClientId>,
1982 params: Option<Params>,
1983 ) where
1984 Self: DataActorNative,
1985 Self: 'static + Debug + Sized,
1986 {
1987 let actor_id = self.core().actor_id().inner();
1988 let topic = get_option_chain_topic(series_id);
1989
1990 let handler = TypedHandler::from(move |slice: &OptionChainSlice| {
1991 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
1992 actor.handle_option_chain(slice);
1993 } else {
1994 log::error!("Actor {actor_id} not found for option chain handling");
1995 }
1996 });
1997
1998 DataActorCore::subscribe_option_chain(
1999 self.core_mut(),
2000 topic,
2001 handler,
2002 series_id,
2003 strike_range,
2004 snapshot_interval_ms,
2005 client_id,
2006 params,
2007 );
2008 }
2009
2010 #[cfg(feature = "defi")]
2011 fn subscribe_blocks(
2013 &mut self,
2014 chain: Blockchain,
2015 client_id: Option<ClientId>,
2016 params: Option<Params>,
2017 ) where
2018 Self: DataActorNative,
2019 Self: 'static + Debug + Sized,
2020 {
2021 let actor_id = self.core().actor_id().inner();
2022 let topic = defi::switchboard::get_defi_blocks_topic(chain);
2023
2024 let handler = TypedHandler::from(move |block: &Block| {
2025 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2026 actor.handle_block(block);
2027 } else {
2028 log::error!("Actor {actor_id} not found for block handling");
2029 }
2030 });
2031
2032 DataActorCore::subscribe_blocks(self.core_mut(), topic, handler, chain, client_id, params);
2033 }
2034
2035 #[cfg(feature = "defi")]
2036 fn subscribe_pool(
2038 &mut self,
2039 instrument_id: InstrumentId,
2040 client_id: Option<ClientId>,
2041 params: Option<Params>,
2042 ) where
2043 Self: DataActorNative,
2044 Self: 'static + Debug + Sized,
2045 {
2046 let actor_id = self.core().actor_id().inner();
2047 let topic = defi::switchboard::get_defi_pool_topic(instrument_id);
2048
2049 let handler = TypedHandler::from(move |pool: &Pool| {
2050 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2051 actor.handle_pool(pool);
2052 } else {
2053 log::error!("Actor {actor_id} not found for pool handling");
2054 }
2055 });
2056
2057 DataActorCore::subscribe_pool(
2058 self.core_mut(),
2059 topic,
2060 handler,
2061 instrument_id,
2062 client_id,
2063 params,
2064 );
2065 }
2066
2067 #[cfg(feature = "defi")]
2068 fn subscribe_pool_swaps(
2070 &mut self,
2071 instrument_id: InstrumentId,
2072 client_id: Option<ClientId>,
2073 params: Option<Params>,
2074 ) where
2075 Self: DataActorNative,
2076 Self: 'static + Debug + Sized,
2077 {
2078 let actor_id = self.core().actor_id().inner();
2079 let topic = defi::switchboard::get_defi_pool_swaps_topic(instrument_id);
2080
2081 let handler = TypedHandler::from(move |swap: &PoolSwap| {
2082 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2083 actor.handle_pool_swap(swap);
2084 } else {
2085 log::error!("Actor {actor_id} not found for pool swap handling");
2086 }
2087 });
2088
2089 DataActorCore::subscribe_pool_swaps(
2090 self.core_mut(),
2091 topic,
2092 handler,
2093 instrument_id,
2094 client_id,
2095 params,
2096 );
2097 }
2098
2099 #[cfg(feature = "defi")]
2100 fn subscribe_pool_liquidity_updates(
2102 &mut self,
2103 instrument_id: InstrumentId,
2104 client_id: Option<ClientId>,
2105 params: Option<Params>,
2106 ) where
2107 Self: DataActorNative,
2108 Self: 'static + Debug + Sized,
2109 {
2110 let actor_id = self.core().actor_id().inner();
2111 let topic = defi::switchboard::get_defi_liquidity_topic(instrument_id);
2112
2113 let handler = TypedHandler::from(move |update: &PoolLiquidityUpdate| {
2114 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2115 actor.handle_pool_liquidity_update(update);
2116 } else {
2117 log::error!("Actor {actor_id} not found for pool liquidity update handling");
2118 }
2119 });
2120
2121 DataActorCore::subscribe_pool_liquidity_updates(
2122 self.core_mut(),
2123 topic,
2124 handler,
2125 instrument_id,
2126 client_id,
2127 params,
2128 );
2129 }
2130
2131 #[cfg(feature = "defi")]
2132 fn subscribe_pool_fee_collects(
2134 &mut self,
2135 instrument_id: InstrumentId,
2136 client_id: Option<ClientId>,
2137 params: Option<Params>,
2138 ) where
2139 Self: DataActorNative,
2140 Self: 'static + Debug + Sized,
2141 {
2142 let actor_id = self.core().actor_id().inner();
2143 let topic = defi::switchboard::get_defi_collect_topic(instrument_id);
2144
2145 let handler = TypedHandler::from(move |collect: &PoolFeeCollect| {
2146 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2147 actor.handle_pool_fee_collect(collect);
2148 } else {
2149 log::error!("Actor {actor_id} not found for pool fee collect handling");
2150 }
2151 });
2152
2153 DataActorCore::subscribe_pool_fee_collects(
2154 self.core_mut(),
2155 topic,
2156 handler,
2157 instrument_id,
2158 client_id,
2159 params,
2160 );
2161 }
2162
2163 #[cfg(feature = "defi")]
2164 fn subscribe_pool_flash_events(
2166 &mut self,
2167 instrument_id: InstrumentId,
2168 client_id: Option<ClientId>,
2169 params: Option<Params>,
2170 ) where
2171 Self: DataActorNative,
2172 Self: 'static + Debug + Sized,
2173 {
2174 let actor_id = self.core().actor_id().inner();
2175 let topic = defi::switchboard::get_defi_flash_topic(instrument_id);
2176
2177 let handler = TypedHandler::from(move |flash: &PoolFlash| {
2178 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2179 actor.handle_pool_flash(flash);
2180 } else {
2181 log::error!("Actor {actor_id} not found for pool flash handling");
2182 }
2183 });
2184
2185 DataActorCore::subscribe_pool_flash_events(
2186 self.core_mut(),
2187 topic,
2188 handler,
2189 instrument_id,
2190 client_id,
2191 params,
2192 );
2193 }
2194
2195 fn unsubscribe_data(
2197 &mut self,
2198 data_type: DataType,
2199 client_id: Option<ClientId>,
2200 params: Option<Params>,
2201 ) where
2202 Self: DataActorNative,
2203 Self: 'static + Debug + Sized,
2204 {
2205 DataActorCore::unsubscribe_data(self.core_mut(), data_type, client_id, params);
2206 }
2207
2208 fn unsubscribe_signal(&mut self, name: &str)
2210 where
2211 Self: DataActorNative,
2212 Self: 'static + Debug + Sized,
2213 {
2214 DataActorCore::unsubscribe_signal(self.core_mut(), name);
2215 }
2216
2217 fn unsubscribe_queue_state(&mut self)
2219 where
2220 Self: DataActorNative,
2221 Self: 'static + Debug + Sized,
2222 {
2223 DataActorCore::unsubscribe_queue_state(self.core_mut());
2224 }
2225
2226 fn unsubscribe_socket_state(&mut self)
2228 where
2229 Self: DataActorNative,
2230 Self: 'static + Debug + Sized,
2231 {
2232 DataActorCore::unsubscribe_socket_state(self.core_mut());
2233 }
2234
2235 fn unsubscribe_instruments(
2237 &mut self,
2238 venue: Venue,
2239 client_id: Option<ClientId>,
2240 params: Option<Params>,
2241 ) where
2242 Self: DataActorNative,
2243 Self: 'static + Debug + Sized,
2244 {
2245 DataActorCore::unsubscribe_instruments(self.core_mut(), venue, client_id, params);
2246 }
2247
2248 fn unsubscribe_instrument(
2250 &mut self,
2251 instrument_id: InstrumentId,
2252 client_id: Option<ClientId>,
2253 params: Option<Params>,
2254 ) where
2255 Self: DataActorNative,
2256 Self: 'static + Debug + Sized,
2257 {
2258 DataActorCore::unsubscribe_instrument(self.core_mut(), instrument_id, client_id, params);
2259 }
2260
2261 fn unsubscribe_book_deltas(
2263 &mut self,
2264 instrument_id: InstrumentId,
2265 client_id: Option<ClientId>,
2266 params: Option<Params>,
2267 ) where
2268 Self: DataActorNative,
2269 Self: 'static + Debug + Sized,
2270 {
2271 DataActorCore::unsubscribe_book_deltas(self.core_mut(), instrument_id, client_id, params);
2272 }
2273
2274 fn unsubscribe_book_depth10(
2276 &mut self,
2277 instrument_id: InstrumentId,
2278 client_id: Option<ClientId>,
2279 params: Option<Params>,
2280 ) where
2281 Self: DataActorNative,
2282 Self: 'static + Debug + Sized,
2283 {
2284 DataActorCore::unsubscribe_book_depth10(self.core_mut(), instrument_id, client_id, params);
2285 }
2286
2287 fn unsubscribe_book_at_interval(
2289 &mut self,
2290 instrument_id: InstrumentId,
2291 interval_ms: NonZeroUsize,
2292 client_id: Option<ClientId>,
2293 params: Option<Params>,
2294 ) where
2295 Self: DataActorNative,
2296 Self: 'static + Debug + Sized,
2297 {
2298 DataActorCore::unsubscribe_book_at_interval(
2299 self.core_mut(),
2300 instrument_id,
2301 interval_ms,
2302 client_id,
2303 params,
2304 );
2305 }
2306
2307 fn unsubscribe_quotes(
2309 &mut self,
2310 instrument_id: InstrumentId,
2311 client_id: Option<ClientId>,
2312 params: Option<Params>,
2313 ) where
2314 Self: DataActorNative,
2315 Self: 'static + Debug + Sized,
2316 {
2317 DataActorCore::unsubscribe_quotes(self.core_mut(), instrument_id, client_id, params);
2318 }
2319
2320 fn unsubscribe_trades(
2322 &mut self,
2323 instrument_id: InstrumentId,
2324 client_id: Option<ClientId>,
2325 params: Option<Params>,
2326 ) where
2327 Self: DataActorNative,
2328 Self: 'static + Debug + Sized,
2329 {
2330 DataActorCore::unsubscribe_trades(self.core_mut(), instrument_id, client_id, params);
2331 }
2332
2333 fn unsubscribe_bars(
2335 &mut self,
2336 bar_type: BarType,
2337 client_id: Option<ClientId>,
2338 params: Option<Params>,
2339 ) where
2340 Self: DataActorNative,
2341 Self: 'static + Debug + Sized,
2342 {
2343 DataActorCore::unsubscribe_bars(self.core_mut(), bar_type, client_id, params);
2344 }
2345
2346 fn unsubscribe_mark_prices(
2348 &mut self,
2349 instrument_id: InstrumentId,
2350 client_id: Option<ClientId>,
2351 params: Option<Params>,
2352 ) where
2353 Self: DataActorNative,
2354 Self: 'static + Debug + Sized,
2355 {
2356 DataActorCore::unsubscribe_mark_prices(self.core_mut(), instrument_id, client_id, params);
2357 }
2358
2359 fn unsubscribe_index_prices(
2361 &mut self,
2362 instrument_id: InstrumentId,
2363 client_id: Option<ClientId>,
2364 params: Option<Params>,
2365 ) where
2366 Self: DataActorNative,
2367 Self: 'static + Debug + Sized,
2368 {
2369 DataActorCore::unsubscribe_index_prices(self.core_mut(), instrument_id, client_id, params);
2370 }
2371
2372 fn unsubscribe_funding_rates(
2374 &mut self,
2375 instrument_id: InstrumentId,
2376 client_id: Option<ClientId>,
2377 params: Option<Params>,
2378 ) where
2379 Self: DataActorNative,
2380 Self: 'static + Debug + Sized,
2381 {
2382 DataActorCore::unsubscribe_funding_rates(self.core_mut(), instrument_id, client_id, params);
2383 }
2384
2385 fn unsubscribe_option_greeks(
2387 &mut self,
2388 instrument_id: InstrumentId,
2389 client_id: Option<ClientId>,
2390 params: Option<Params>,
2391 ) where
2392 Self: DataActorNative,
2393 Self: 'static + Debug + Sized,
2394 {
2395 DataActorCore::unsubscribe_option_greeks(self.core_mut(), instrument_id, client_id, params);
2396 }
2397
2398 fn unsubscribe_instrument_status(
2400 &mut self,
2401 instrument_id: InstrumentId,
2402 client_id: Option<ClientId>,
2403 params: Option<Params>,
2404 ) where
2405 Self: DataActorNative,
2406 Self: 'static + Debug + Sized,
2407 {
2408 DataActorCore::unsubscribe_instrument_status(
2409 self.core_mut(),
2410 instrument_id,
2411 client_id,
2412 params,
2413 );
2414 }
2415
2416 fn unsubscribe_instrument_close(
2418 &mut self,
2419 instrument_id: InstrumentId,
2420 client_id: Option<ClientId>,
2421 params: Option<Params>,
2422 ) where
2423 Self: DataActorNative,
2424 Self: 'static + Debug + Sized,
2425 {
2426 DataActorCore::unsubscribe_instrument_close(
2427 self.core_mut(),
2428 instrument_id,
2429 client_id,
2430 params,
2431 );
2432 }
2433
2434 fn unsubscribe_option_chain(&mut self, series_id: OptionSeriesId, client_id: Option<ClientId>)
2436 where
2437 Self: DataActorNative,
2438 Self: 'static + Debug + Sized,
2439 {
2440 DataActorCore::unsubscribe_option_chain(self.core_mut(), series_id, client_id);
2441 }
2442
2443 #[cfg(feature = "defi")]
2444 fn unsubscribe_blocks(
2446 &mut self,
2447 chain: Blockchain,
2448 client_id: Option<ClientId>,
2449 params: Option<Params>,
2450 ) where
2451 Self: DataActorNative,
2452 Self: 'static + Debug + Sized,
2453 {
2454 DataActorCore::unsubscribe_blocks(self.core_mut(), chain, client_id, params);
2455 }
2456
2457 #[cfg(feature = "defi")]
2458 fn unsubscribe_pool(
2460 &mut self,
2461 instrument_id: InstrumentId,
2462 client_id: Option<ClientId>,
2463 params: Option<Params>,
2464 ) where
2465 Self: DataActorNative,
2466 Self: 'static + Debug + Sized,
2467 {
2468 DataActorCore::unsubscribe_pool(self.core_mut(), instrument_id, client_id, params);
2469 }
2470
2471 #[cfg(feature = "defi")]
2472 fn unsubscribe_pool_swaps(
2474 &mut self,
2475 instrument_id: InstrumentId,
2476 client_id: Option<ClientId>,
2477 params: Option<Params>,
2478 ) where
2479 Self: DataActorNative,
2480 Self: 'static + Debug + Sized,
2481 {
2482 DataActorCore::unsubscribe_pool_swaps(self.core_mut(), instrument_id, client_id, params);
2483 }
2484
2485 #[cfg(feature = "defi")]
2486 fn unsubscribe_pool_liquidity_updates(
2488 &mut self,
2489 instrument_id: InstrumentId,
2490 client_id: Option<ClientId>,
2491 params: Option<Params>,
2492 ) where
2493 Self: DataActorNative,
2494 Self: 'static + Debug + Sized,
2495 {
2496 DataActorCore::unsubscribe_pool_liquidity_updates(
2497 self.core_mut(),
2498 instrument_id,
2499 client_id,
2500 params,
2501 );
2502 }
2503
2504 #[cfg(feature = "defi")]
2505 fn unsubscribe_pool_fee_collects(
2507 &mut self,
2508 instrument_id: InstrumentId,
2509 client_id: Option<ClientId>,
2510 params: Option<Params>,
2511 ) where
2512 Self: DataActorNative,
2513 Self: 'static + Debug + Sized,
2514 {
2515 DataActorCore::unsubscribe_pool_fee_collects(
2516 self.core_mut(),
2517 instrument_id,
2518 client_id,
2519 params,
2520 );
2521 }
2522
2523 #[cfg(feature = "defi")]
2524 fn unsubscribe_pool_flash_events(
2526 &mut self,
2527 instrument_id: InstrumentId,
2528 client_id: Option<ClientId>,
2529 params: Option<Params>,
2530 ) where
2531 Self: DataActorNative,
2532 Self: 'static + Debug + Sized,
2533 {
2534 DataActorCore::unsubscribe_pool_flash_events(
2535 self.core_mut(),
2536 instrument_id,
2537 client_id,
2538 params,
2539 );
2540 }
2541
2542 fn request_data(
2548 &mut self,
2549 data_type: DataType,
2550 client_id: ClientId,
2551 start: Option<Timestamp>,
2552 end: Option<Timestamp>,
2553 limit: Option<NonZeroUsize>,
2554 params: Option<Params>,
2555 ) -> anyhow::Result<UUID4>
2556 where
2557 Self: DataActorNative,
2558 Self: 'static + Debug + Sized,
2559 {
2560 let actor_id = self.core().actor_id().inner();
2561 let handler = ShareableMessageHandler::from_typed(move |resp: &CustomDataResponse| {
2562 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2563 actor.handle_data_response(resp);
2564 } else {
2565 log::error!("Actor {actor_id} not found for data response handling");
2566 }
2567 });
2568
2569 DataActorCore::request_data(
2570 self.core_mut(),
2571 data_type,
2572 client_id,
2573 start,
2574 end,
2575 limit,
2576 params,
2577 handler,
2578 )
2579 }
2580
2581 fn request_instrument(
2587 &mut self,
2588 instrument_id: InstrumentId,
2589 start: Option<Timestamp>,
2590 end: Option<Timestamp>,
2591 client_id: Option<ClientId>,
2592 params: Option<Params>,
2593 ) -> anyhow::Result<UUID4>
2594 where
2595 Self: DataActorNative,
2596 Self: 'static + Debug + Sized,
2597 {
2598 let actor_id = self.core().actor_id().inner();
2599 let handler = ShareableMessageHandler::from_typed(move |resp: &InstrumentResponse| {
2600 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2601 actor.handle_instrument_response(resp);
2602 } else {
2603 log::error!("Actor {actor_id} not found for instrument response handling");
2604 }
2605 });
2606
2607 DataActorCore::request_instrument(
2608 self.core_mut(),
2609 instrument_id,
2610 start,
2611 end,
2612 client_id,
2613 params,
2614 handler,
2615 )
2616 }
2617
2618 fn request_instruments(
2624 &mut self,
2625 venue: Option<Venue>,
2626 start: Option<Timestamp>,
2627 end: Option<Timestamp>,
2628 client_id: Option<ClientId>,
2629 params: Option<Params>,
2630 ) -> anyhow::Result<UUID4>
2631 where
2632 Self: DataActorNative,
2633 Self: 'static + Debug + Sized,
2634 {
2635 let actor_id = self.core().actor_id().inner();
2636 let handler = ShareableMessageHandler::from_typed(move |resp: &InstrumentsResponse| {
2637 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2638 actor.handle_instruments_response(resp);
2639 } else {
2640 log::error!("Actor {actor_id} not found for instruments response handling");
2641 }
2642 });
2643
2644 DataActorCore::request_instruments(
2645 self.core_mut(),
2646 venue,
2647 start,
2648 end,
2649 client_id,
2650 params,
2651 handler,
2652 )
2653 }
2654
2655 fn request_book_snapshot(
2661 &mut self,
2662 instrument_id: InstrumentId,
2663 depth: Option<NonZeroUsize>,
2664 client_id: Option<ClientId>,
2665 params: Option<Params>,
2666 ) -> anyhow::Result<UUID4>
2667 where
2668 Self: DataActorNative,
2669 Self: 'static + Debug + Sized,
2670 {
2671 let actor_id = self.core().actor_id().inner();
2672 let handler = ShareableMessageHandler::from_typed(move |resp: &BookResponse| {
2673 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2674 actor.handle_book_response(resp);
2675 } else {
2676 log::error!("Actor {actor_id} not found for book response handling");
2677 }
2678 });
2679
2680 DataActorCore::request_book_snapshot(
2681 self.core_mut(),
2682 instrument_id,
2683 depth,
2684 client_id,
2685 params,
2686 handler,
2687 )
2688 }
2689
2690 fn request_book_deltas(
2696 &mut self,
2697 instrument_id: InstrumentId,
2698 start: Option<Timestamp>,
2699 end: Option<Timestamp>,
2700 limit: Option<NonZeroUsize>,
2701 client_id: Option<ClientId>,
2702 params: Option<Params>,
2703 ) -> anyhow::Result<UUID4>
2704 where
2705 Self: DataActorNative,
2706 Self: 'static + Debug + Sized,
2707 {
2708 let actor_id = self.core().actor_id().inner();
2709 let handler = ShareableMessageHandler::from_typed(move |resp: &BookDeltasResponse| {
2710 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2711 actor.handle_book_deltas_response(resp);
2712 } else {
2713 log::error!("Actor {actor_id} not found for book deltas response handling");
2714 }
2715 });
2716
2717 DataActorCore::request_book_deltas(
2718 self.core_mut(),
2719 instrument_id,
2720 start,
2721 end,
2722 limit,
2723 client_id,
2724 params,
2725 handler,
2726 )
2727 }
2728
2729 #[expect(clippy::too_many_arguments)]
2735 fn request_book_depth(
2736 &mut self,
2737 instrument_id: InstrumentId,
2738 start: Option<Timestamp>,
2739 end: Option<Timestamp>,
2740 limit: Option<NonZeroUsize>,
2741 depth: Option<NonZeroUsize>,
2742 client_id: Option<ClientId>,
2743 params: Option<Params>,
2744 ) -> anyhow::Result<UUID4>
2745 where
2746 Self: DataActorNative,
2747 Self: 'static + Debug + Sized,
2748 {
2749 let actor_id = self.core().actor_id().inner();
2750 let handler = ShareableMessageHandler::from_typed(move |resp: &BookDepthResponse| {
2751 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2752 actor.handle_book_depth_response(resp);
2753 } else {
2754 log::error!("Actor {actor_id} not found for book depth response handling");
2755 }
2756 });
2757
2758 DataActorCore::request_book_depth(
2759 self.core_mut(),
2760 instrument_id,
2761 start,
2762 end,
2763 limit,
2764 depth,
2765 client_id,
2766 params,
2767 handler,
2768 )
2769 }
2770
2771 fn request_quotes(
2777 &mut self,
2778 instrument_id: InstrumentId,
2779 start: Option<Timestamp>,
2780 end: Option<Timestamp>,
2781 limit: Option<NonZeroUsize>,
2782 client_id: Option<ClientId>,
2783 params: Option<Params>,
2784 ) -> anyhow::Result<UUID4>
2785 where
2786 Self: DataActorNative,
2787 Self: 'static + Debug + Sized,
2788 {
2789 let actor_id = self.core().actor_id().inner();
2790 let handler = ShareableMessageHandler::from_typed(move |resp: &QuotesResponse| {
2791 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2792 actor.handle_quotes_response(resp);
2793 } else {
2794 log::error!("Actor {actor_id} not found for quotes response handling");
2795 }
2796 });
2797
2798 DataActorCore::request_quotes(
2799 self.core_mut(),
2800 instrument_id,
2801 start,
2802 end,
2803 limit,
2804 client_id,
2805 params,
2806 handler,
2807 )
2808 }
2809
2810 fn request_trades(
2816 &mut self,
2817 instrument_id: InstrumentId,
2818 start: Option<Timestamp>,
2819 end: Option<Timestamp>,
2820 limit: Option<NonZeroUsize>,
2821 client_id: Option<ClientId>,
2822 params: Option<Params>,
2823 ) -> anyhow::Result<UUID4>
2824 where
2825 Self: DataActorNative,
2826 Self: 'static + Debug + Sized,
2827 {
2828 let actor_id = self.core().actor_id().inner();
2829 let handler = ShareableMessageHandler::from_typed(move |resp: &TradesResponse| {
2830 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2831 actor.handle_trades_response(resp);
2832 } else {
2833 log::error!("Actor {actor_id} not found for trades response handling");
2834 }
2835 });
2836
2837 DataActorCore::request_trades(
2838 self.core_mut(),
2839 instrument_id,
2840 start,
2841 end,
2842 limit,
2843 client_id,
2844 params,
2845 handler,
2846 )
2847 }
2848
2849 fn request_bars(
2855 &mut self,
2856 bar_type: BarType,
2857 start: Option<Timestamp>,
2858 end: Option<Timestamp>,
2859 limit: Option<NonZeroUsize>,
2860 client_id: Option<ClientId>,
2861 params: Option<Params>,
2862 ) -> anyhow::Result<UUID4>
2863 where
2864 Self: DataActorNative,
2865 Self: 'static + Debug + Sized,
2866 {
2867 let actor_id = self.core().actor_id().inner();
2868 let handler = ShareableMessageHandler::from_typed(move |resp: &BarsResponse| {
2869 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2870 actor.handle_bars_response(resp);
2871 } else {
2872 log::error!("Actor {actor_id} not found for bars response handling");
2873 }
2874 });
2875
2876 DataActorCore::request_bars(
2877 self.core_mut(),
2878 bar_type,
2879 start,
2880 end,
2881 limit,
2882 client_id,
2883 params,
2884 handler,
2885 )
2886 }
2887
2888 fn request_funding_rates(
2894 &mut self,
2895 instrument_id: InstrumentId,
2896 start: Option<Timestamp>,
2897 end: Option<Timestamp>,
2898 limit: Option<NonZeroUsize>,
2899 client_id: Option<ClientId>,
2900 params: Option<Params>,
2901 ) -> anyhow::Result<UUID4>
2902 where
2903 Self: DataActorNative,
2904 Self: 'static + Debug + Sized,
2905 {
2906 let actor_id = self.core().actor_id().inner();
2907 let handler = ShareableMessageHandler::from_typed(move |resp: &FundingRatesResponse| {
2908 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
2909 actor.handle_funding_rates_response(resp);
2910 } else {
2911 log::error!("Actor {actor_id} not found for funding rates response handling");
2912 }
2913 });
2914
2915 DataActorCore::request_funding_rates(
2916 self.core_mut(),
2917 instrument_id,
2918 start,
2919 end,
2920 limit,
2921 client_id,
2922 params,
2923 handler,
2924 )
2925 }
2926
2927 #[cfg(feature = "live")]
2938 fn reconnect_socket(&self, client_id: ClientId, endpoint: &str) -> anyhow::Result<()>
2939 where
2940 Self: DataActorNative,
2941 {
2942 DataActorCore::reconnect_socket(self.core(), client_id, endpoint)
2943 }
2944}
2945
2946impl<T> Actor for T
2948where
2949 T: DataActor + DataActorNative + Debug + 'static,
2950{
2951 fn id(&self) -> Ustr {
2952 self.core().actor_id.inner()
2953 }
2954
2955 #[allow(unused_variables)]
2956 fn handle(&mut self, msg: &dyn Any) {
2957 }
2959
2960 fn as_any(&self) -> &dyn Any {
2961 self
2962 }
2963}
2964
2965impl<T> Component for T
2966where
2967 T: DataActor + DataActorNative + Debug + 'static,
2968{
2969 fn component_id(&self) -> ComponentId {
2970 ComponentId::from(self.core().actor_id)
2971 }
2972
2973 fn release_subscriptions(&mut self) {
2974 self.core_mut().unsubscribe_all();
2975 }
2976
2977 fn state(&self) -> ComponentState {
2978 self.core().state
2979 }
2980
2981 fn transition_state(&mut self, trigger: ComponentTrigger) -> anyhow::Result<()> {
2982 let core = self.core_mut();
2983 core.state = core.state.transition(&trigger)?;
2984 log::info!(
2985 component = core.actor_id.inner().as_str();
2986 "{}",
2987 core.state.variant_name()
2988 );
2989 Ok(())
2990 }
2991
2992 fn register(
2993 &mut self,
2994 trader_id: TraderId,
2995 clock: Rc<RefCell<dyn Clock>>,
2996 cache: Rc<RefCell<Cache>>,
2997 ) -> anyhow::Result<()> {
2998 DataActorCore::register(self.core_mut(), trader_id, clock.clone(), cache)?;
2999
3000 let actor_id = self.core().actor_id().inner();
3002 let callback = TimeEventCallback::from(move |event: TimeEvent| {
3003 if let Some(mut actor) = try_get_actor_unchecked::<Self>(&actor_id) {
3004 actor.handle_time_event(&event);
3005 } else {
3006 log::error!("Actor {actor_id} not found for time event handling");
3007 }
3008 });
3009
3010 clock.borrow_mut().register_default_handler(callback);
3011
3012 self.initialize()
3013 }
3014
3015 fn on_start(&mut self) -> anyhow::Result<()> {
3016 DataActor::on_start(self)
3017 }
3018
3019 fn on_stop(&mut self) -> anyhow::Result<()> {
3020 DataActor::on_stop(self)
3021 }
3022
3023 fn on_resume(&mut self) -> anyhow::Result<()> {
3024 DataActor::on_resume(self)
3025 }
3026
3027 fn on_degrade(&mut self) -> anyhow::Result<()> {
3028 DataActor::on_degrade(self)
3029 }
3030
3031 fn on_fault(&mut self) -> anyhow::Result<()> {
3032 DataActor::on_fault(self)
3033 }
3034
3035 fn on_reset(&mut self) -> anyhow::Result<()> {
3036 DataActor::on_reset(self)
3037 }
3038
3039 fn on_dispose(&mut self) -> anyhow::Result<()> {
3040 DataActor::on_dispose(self)
3041 }
3042}
3043
3044#[derive(Clone)]
3046#[allow(
3047 dead_code,
3048 reason = "TODO: Under development (pending_requests, signal_classes)"
3049)]
3050pub struct DataActorCore {
3051 pub actor_id: ActorId,
3053 pub config: DataActorConfig,
3055 trader_id: Option<TraderId>,
3056 clock: Option<Rc<RefCell<dyn Clock>>>, cache: Option<Rc<RefCell<Cache>>>, state: ComponentState,
3059 topic_handlers: AHashMap<MStr<Pattern>, ShareableMessageHandler>,
3060 instrument_handlers: AHashMap<MStr<Pattern>, TypedHandler<InstrumentAny>>,
3061 deltas_handlers: AHashMap<MStr<Pattern>, TypedHandler<OrderBookDeltas>>,
3062 depth10_handlers: AHashMap<MStr<Pattern>, TypedHandler<OrderBookDepth10>>,
3063 book_handlers: AHashMap<MStr<Topic>, TypedHandler<OrderBook>>,
3064 quote_handlers: AHashMap<MStr<Topic>, TypedHandler<QuoteTick>>,
3065 trade_handlers: AHashMap<MStr<Topic>, TypedHandler<TradeTick>>,
3066 bar_handlers: AHashMap<MStr<Topic>, TypedHandler<Bar>>,
3067 mark_price_handlers: AHashMap<MStr<Topic>, TypedHandler<MarkPriceUpdate>>,
3068 index_price_handlers: AHashMap<MStr<Topic>, TypedHandler<IndexPriceUpdate>>,
3069 funding_rate_handlers: AHashMap<MStr<Topic>, TypedHandler<FundingRateUpdate>>,
3070 option_greeks_handlers: AHashMap<MStr<Topic>, TypedHandler<OptionGreeks>>,
3071 option_chain_handlers: AHashMap<MStr<Topic>, TypedHandler<OptionChainSlice>>,
3072 #[cfg(feature = "defi")]
3073 block_handlers: AHashMap<MStr<Topic>, TypedHandler<Block>>,
3074 #[cfg(feature = "defi")]
3075 pool_handlers: AHashMap<MStr<Topic>, TypedHandler<Pool>>,
3076 #[cfg(feature = "defi")]
3077 pool_swap_handlers: AHashMap<MStr<Topic>, TypedHandler<PoolSwap>>,
3078 #[cfg(feature = "defi")]
3079 pool_liquidity_handlers: AHashMap<MStr<Topic>, TypedHandler<PoolLiquidityUpdate>>,
3080 #[cfg(feature = "defi")]
3081 pool_collect_handlers: AHashMap<MStr<Topic>, TypedHandler<PoolFeeCollect>>,
3082 #[cfg(feature = "defi")]
3083 pool_flash_handlers: AHashMap<MStr<Topic>, TypedHandler<PoolFlash>>,
3084 warning_events: AHashSet<String>, pending_requests: AHashMap<UUID4, Option<RequestCallback>>,
3086 signal_classes: AHashMap<String, String>,
3087 indicators: Indicators,
3088}
3089
3090impl Debug for DataActorCore {
3091 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3092 f.debug_struct(stringify!(DataActorCore))
3093 .field("actor_id", &self.actor_id)
3094 .field("config", &self.config)
3095 .field("state", &self.state)
3096 .field("trader_id", &self.trader_id)
3097 .finish()
3098 }
3099}
3100
3101impl DataActorCore {
3102 pub(crate) fn add_subscription_any(
3105 &mut self,
3106 topic: MStr<Topic>,
3107 handler: ShareableMessageHandler,
3108 priority: Option<u32>,
3109 ) {
3110 let pattern: MStr<Pattern> = topic.into();
3111 if self.topic_handlers.contains_key(&pattern) {
3112 log::warn!(
3113 "Actor {} attempted duplicate subscription to topic '{topic}'",
3114 self.actor_id,
3115 );
3116 return;
3117 }
3118
3119 self.topic_handlers.insert(pattern, handler.clone());
3120 msgbus::subscribe_any(pattern, handler, priority);
3121 }
3122
3123 pub(crate) fn remove_subscription_any(&mut self, topic: MStr<Topic>) {
3127 let pattern: MStr<Pattern> = topic.into();
3128 if let Some(handler) = self.topic_handlers.remove(&pattern) {
3129 msgbus::unsubscribe_any(pattern, &handler);
3130 } else {
3131 log::warn!(
3132 "Actor {} attempted to unsubscribe from topic '{topic}' when not subscribed",
3133 self.actor_id,
3134 );
3135 }
3136 }
3137
3138 pub(crate) fn add_quote_subscription(
3139 &mut self,
3140 topic: MStr<Topic>,
3141 handler: TypedHandler<QuoteTick>,
3142 ) {
3143 if self.quote_handlers.contains_key(&topic) {
3144 log::warn!(
3145 "Actor {} attempted duplicate quote subscription to '{topic}'",
3146 self.actor_id
3147 );
3148 return;
3149 }
3150 self.quote_handlers.insert(topic, handler.clone());
3151 msgbus::subscribe_quotes(topic.into(), handler, None);
3152 }
3153
3154 #[allow(dead_code)]
3155 pub(crate) fn remove_quote_subscription(&mut self, topic: MStr<Topic>) {
3156 if let Some(handler) = self.quote_handlers.remove(&topic) {
3157 msgbus::unsubscribe_quotes(topic.into(), &handler);
3158 }
3159 }
3160
3161 pub(crate) fn add_trade_subscription(
3162 &mut self,
3163 topic: MStr<Topic>,
3164 handler: TypedHandler<TradeTick>,
3165 ) {
3166 if self.trade_handlers.contains_key(&topic) {
3167 log::warn!(
3168 "Actor {} attempted duplicate trade subscription to '{topic}'",
3169 self.actor_id
3170 );
3171 return;
3172 }
3173 self.trade_handlers.insert(topic, handler.clone());
3174 msgbus::subscribe_trades(topic.into(), handler, None);
3175 }
3176
3177 #[allow(dead_code)]
3178 pub(crate) fn remove_trade_subscription(&mut self, topic: MStr<Topic>) {
3179 if let Some(handler) = self.trade_handlers.remove(&topic) {
3180 msgbus::unsubscribe_trades(topic.into(), &handler);
3181 }
3182 }
3183
3184 pub(crate) fn add_bar_subscription(&mut self, topic: MStr<Topic>, handler: TypedHandler<Bar>) {
3185 if self.bar_handlers.contains_key(&topic) {
3186 log::warn!(
3187 "Actor {} attempted duplicate bar subscription to '{topic}'",
3188 self.actor_id
3189 );
3190 return;
3191 }
3192 self.bar_handlers.insert(topic, handler.clone());
3193 msgbus::subscribe_bars(topic.into(), handler, None);
3194 }
3195
3196 #[allow(dead_code)]
3197 pub(crate) fn remove_bar_subscription(&mut self, topic: MStr<Topic>) {
3198 if let Some(handler) = self.bar_handlers.remove(&topic) {
3199 msgbus::unsubscribe_bars(topic.into(), &handler);
3200 }
3201 }
3202
3203 pub(crate) fn add_deltas_subscription(
3204 &mut self,
3205 pattern: MStr<Pattern>,
3206 handler: TypedHandler<OrderBookDeltas>,
3207 ) {
3208 if self.deltas_handlers.contains_key(&pattern) {
3209 log::warn!(
3210 "Actor {} attempted duplicate deltas subscription to '{pattern}'",
3211 self.actor_id
3212 );
3213 return;
3214 }
3215 self.deltas_handlers.insert(pattern, handler.clone());
3216 msgbus::subscribe_book_deltas(pattern, handler, None);
3217 }
3218
3219 #[allow(dead_code)]
3220 pub(crate) fn remove_deltas_subscription(&mut self, pattern: MStr<Pattern>) {
3221 if let Some(handler) = self.deltas_handlers.remove(&pattern) {
3222 msgbus::unsubscribe_book_deltas(pattern, &handler);
3223 }
3224 }
3225
3226 pub(crate) fn add_depth10_subscription(
3227 &mut self,
3228 pattern: MStr<Pattern>,
3229 handler: TypedHandler<OrderBookDepth10>,
3230 ) {
3231 if self.depth10_handlers.contains_key(&pattern) {
3232 log::warn!(
3233 "Actor {} attempted duplicate depth10 subscription to '{pattern}'",
3234 self.actor_id
3235 );
3236 return;
3237 }
3238 self.depth10_handlers.insert(pattern, handler.clone());
3239 msgbus::subscribe_book_depth10(pattern, handler, None);
3240 }
3241
3242 pub(crate) fn remove_depth10_subscription(&mut self, pattern: MStr<Pattern>) {
3243 if let Some(handler) = self.depth10_handlers.remove(&pattern) {
3244 msgbus::unsubscribe_book_depth10(pattern, &handler);
3245 }
3246 }
3247
3248 pub(crate) fn add_instrument_subscription(
3249 &mut self,
3250 pattern: MStr<Pattern>,
3251 handler: TypedHandler<InstrumentAny>,
3252 ) {
3253 if self.instrument_handlers.contains_key(&pattern) {
3254 log::warn!(
3255 "Actor {} attempted duplicate instrument subscription to '{pattern}'",
3256 self.actor_id
3257 );
3258 return;
3259 }
3260 self.instrument_handlers.insert(pattern, handler.clone());
3261 msgbus::subscribe_instruments(pattern, handler, None);
3262 }
3263
3264 #[allow(dead_code)]
3265 pub(crate) fn remove_instrument_subscription(&mut self, pattern: MStr<Pattern>) {
3266 if let Some(handler) = self.instrument_handlers.remove(&pattern) {
3267 msgbus::unsubscribe_instruments(pattern, &handler);
3268 }
3269 }
3270
3271 pub(crate) fn add_instrument_close_subscription(
3272 &mut self,
3273 topic: MStr<Topic>,
3274 handler: ShareableMessageHandler,
3275 ) {
3276 let pattern: MStr<Pattern> = topic.into();
3277 if self.topic_handlers.contains_key(&pattern) {
3278 log::warn!(
3279 "Actor {} attempted duplicate instrument close subscription to '{topic}'",
3280 self.actor_id
3281 );
3282 return;
3283 }
3284 self.topic_handlers.insert(pattern, handler.clone());
3285 msgbus::subscribe_any(pattern, handler, None);
3286 }
3287
3288 #[allow(dead_code)]
3289 pub(crate) fn remove_instrument_close_subscription(&mut self, topic: MStr<Topic>) {
3290 let pattern: MStr<Pattern> = topic.into();
3291 if let Some(handler) = self.topic_handlers.remove(&pattern) {
3292 msgbus::unsubscribe_any(pattern, &handler);
3293 }
3294 }
3295
3296 pub(crate) fn add_book_snapshot_subscription(
3297 &mut self,
3298 topic: MStr<Topic>,
3299 handler: TypedHandler<OrderBook>,
3300 ) {
3301 if self.book_handlers.contains_key(&topic) {
3302 log::warn!(
3303 "Actor {} attempted duplicate book snapshot subscription to '{topic}'",
3304 self.actor_id
3305 );
3306 return;
3307 }
3308 self.book_handlers.insert(topic, handler.clone());
3309 msgbus::subscribe_book_snapshots(topic.into(), handler, None);
3310 }
3311
3312 #[allow(dead_code)]
3313 pub(crate) fn remove_book_snapshot_subscription(&mut self, topic: MStr<Topic>) {
3314 if let Some(handler) = self.book_handlers.remove(&topic) {
3315 msgbus::unsubscribe_book_snapshots(topic.into(), &handler);
3316 }
3317 }
3318
3319 pub(crate) fn add_mark_price_subscription(
3320 &mut self,
3321 topic: MStr<Topic>,
3322 handler: TypedHandler<MarkPriceUpdate>,
3323 ) {
3324 if self.mark_price_handlers.contains_key(&topic) {
3325 log::warn!(
3326 "Actor {} attempted duplicate mark price subscription to '{topic}'",
3327 self.actor_id
3328 );
3329 return;
3330 }
3331 self.mark_price_handlers.insert(topic, handler.clone());
3332 msgbus::subscribe_mark_prices(topic.into(), handler, None);
3333 }
3334
3335 #[allow(dead_code)]
3336 pub(crate) fn remove_mark_price_subscription(&mut self, topic: MStr<Topic>) {
3337 if let Some(handler) = self.mark_price_handlers.remove(&topic) {
3338 msgbus::unsubscribe_mark_prices(topic.into(), &handler);
3339 }
3340 }
3341
3342 pub(crate) fn add_index_price_subscription(
3343 &mut self,
3344 topic: MStr<Topic>,
3345 handler: TypedHandler<IndexPriceUpdate>,
3346 ) {
3347 if self.index_price_handlers.contains_key(&topic) {
3348 log::warn!(
3349 "Actor {} attempted duplicate index price subscription to '{topic}'",
3350 self.actor_id
3351 );
3352 return;
3353 }
3354 self.index_price_handlers.insert(topic, handler.clone());
3355 msgbus::subscribe_index_prices(topic.into(), handler, None);
3356 }
3357
3358 #[allow(dead_code)]
3359 pub(crate) fn remove_index_price_subscription(&mut self, topic: MStr<Topic>) {
3360 if let Some(handler) = self.index_price_handlers.remove(&topic) {
3361 msgbus::unsubscribe_index_prices(topic.into(), &handler);
3362 }
3363 }
3364
3365 pub(crate) fn add_funding_rate_subscription(
3366 &mut self,
3367 topic: MStr<Topic>,
3368 handler: TypedHandler<FundingRateUpdate>,
3369 ) {
3370 if self.funding_rate_handlers.contains_key(&topic) {
3371 log::warn!(
3372 "Actor {} attempted duplicate funding rate subscription to '{topic}'",
3373 self.actor_id
3374 );
3375 return;
3376 }
3377 self.funding_rate_handlers.insert(topic, handler.clone());
3378 msgbus::subscribe_funding_rates(topic.into(), handler, None);
3379 }
3380
3381 #[allow(dead_code)]
3382 pub(crate) fn remove_funding_rate_subscription(&mut self, topic: MStr<Topic>) {
3383 if let Some(handler) = self.funding_rate_handlers.remove(&topic) {
3384 msgbus::unsubscribe_funding_rates(topic.into(), &handler);
3385 }
3386 }
3387
3388 pub(crate) fn add_option_greeks_subscription(
3389 &mut self,
3390 topic: MStr<Topic>,
3391 handler: TypedHandler<OptionGreeks>,
3392 ) {
3393 if self.option_greeks_handlers.contains_key(&topic) {
3394 log::warn!(
3395 "Actor {} attempted duplicate option greeks subscription to '{topic}'",
3396 self.actor_id
3397 );
3398 return;
3399 }
3400 self.option_greeks_handlers.insert(topic, handler.clone());
3401 msgbus::subscribe_option_greeks(topic.into(), handler, None);
3402 }
3403
3404 #[allow(dead_code)]
3405 pub(crate) fn remove_option_greeks_subscription(&mut self, topic: MStr<Topic>) {
3406 if let Some(handler) = self.option_greeks_handlers.remove(&topic) {
3407 msgbus::unsubscribe_option_greeks(topic.into(), &handler);
3408 }
3409 }
3410
3411 pub(crate) fn add_option_chain_subscription(
3412 &mut self,
3413 topic: MStr<Topic>,
3414 handler: TypedHandler<OptionChainSlice>,
3415 ) {
3416 if self.option_chain_handlers.contains_key(&topic) {
3417 log::warn!(
3418 "Actor {} attempted duplicate option chain subscription to '{topic}'",
3419 self.actor_id
3420 );
3421 return;
3422 }
3423 self.option_chain_handlers.insert(topic, handler.clone());
3424 msgbus::subscribe_option_chain(topic.into(), handler, None);
3425 }
3426
3427 pub(crate) fn remove_option_chain_subscription(&mut self, topic: MStr<Topic>) {
3428 if let Some(handler) = self.option_chain_handlers.remove(&topic) {
3429 msgbus::unsubscribe_option_chain(topic.into(), &handler);
3430 }
3431 }
3432
3433 #[cfg(feature = "defi")]
3434 pub(crate) fn add_block_subscription(
3435 &mut self,
3436 topic: MStr<Topic>,
3437 handler: TypedHandler<Block>,
3438 ) {
3439 if self.block_handlers.contains_key(&topic) {
3440 log::warn!(
3441 "Actor {} attempted duplicate block subscription to '{topic}'",
3442 self.actor_id
3443 );
3444 return;
3445 }
3446 self.block_handlers.insert(topic, handler.clone());
3447 msgbus::subscribe_defi_blocks(topic.into(), handler, None);
3448 }
3449
3450 #[cfg(feature = "defi")]
3451 #[allow(dead_code)]
3452 pub(crate) fn remove_block_subscription(&mut self, topic: MStr<Topic>) {
3453 if let Some(handler) = self.block_handlers.remove(&topic) {
3454 msgbus::unsubscribe_defi_blocks(topic.into(), &handler);
3455 }
3456 }
3457
3458 #[cfg(feature = "defi")]
3459 pub(crate) fn add_pool_subscription(
3460 &mut self,
3461 topic: MStr<Topic>,
3462 handler: TypedHandler<Pool>,
3463 ) {
3464 if self.pool_handlers.contains_key(&topic) {
3465 log::warn!(
3466 "Actor {} attempted duplicate pool subscription to '{topic}'",
3467 self.actor_id
3468 );
3469 return;
3470 }
3471 self.pool_handlers.insert(topic, handler.clone());
3472 msgbus::subscribe_defi_pools(topic.into(), handler, None);
3473 }
3474
3475 #[cfg(feature = "defi")]
3476 #[allow(dead_code)]
3477 pub(crate) fn remove_pool_subscription(&mut self, topic: MStr<Topic>) {
3478 if let Some(handler) = self.pool_handlers.remove(&topic) {
3479 msgbus::unsubscribe_defi_pools(topic.into(), &handler);
3480 }
3481 }
3482
3483 #[cfg(feature = "defi")]
3484 pub(crate) fn add_pool_swap_subscription(
3485 &mut self,
3486 topic: MStr<Topic>,
3487 handler: TypedHandler<PoolSwap>,
3488 ) {
3489 if self.pool_swap_handlers.contains_key(&topic) {
3490 log::warn!(
3491 "Actor {} attempted duplicate pool swap subscription to '{topic}'",
3492 self.actor_id
3493 );
3494 return;
3495 }
3496 self.pool_swap_handlers.insert(topic, handler.clone());
3497 msgbus::subscribe_defi_swaps(topic.into(), handler, None);
3498 }
3499
3500 #[cfg(feature = "defi")]
3501 #[allow(dead_code)]
3502 pub(crate) fn remove_pool_swap_subscription(&mut self, topic: MStr<Topic>) {
3503 if let Some(handler) = self.pool_swap_handlers.remove(&topic) {
3504 msgbus::unsubscribe_defi_swaps(topic.into(), &handler);
3505 }
3506 }
3507
3508 #[cfg(feature = "defi")]
3509 pub(crate) fn add_pool_liquidity_subscription(
3510 &mut self,
3511 topic: MStr<Topic>,
3512 handler: TypedHandler<PoolLiquidityUpdate>,
3513 ) {
3514 if self.pool_liquidity_handlers.contains_key(&topic) {
3515 log::warn!(
3516 "Actor {} attempted duplicate pool liquidity subscription to '{topic}'",
3517 self.actor_id
3518 );
3519 return;
3520 }
3521 self.pool_liquidity_handlers.insert(topic, handler.clone());
3522 msgbus::subscribe_defi_liquidity(topic.into(), handler, None);
3523 }
3524
3525 #[cfg(feature = "defi")]
3526 #[allow(dead_code)]
3527 pub(crate) fn remove_pool_liquidity_subscription(&mut self, topic: MStr<Topic>) {
3528 if let Some(handler) = self.pool_liquidity_handlers.remove(&topic) {
3529 msgbus::unsubscribe_defi_liquidity(topic.into(), &handler);
3530 }
3531 }
3532
3533 #[cfg(feature = "defi")]
3534 pub(crate) fn add_pool_collect_subscription(
3535 &mut self,
3536 topic: MStr<Topic>,
3537 handler: TypedHandler<PoolFeeCollect>,
3538 ) {
3539 if self.pool_collect_handlers.contains_key(&topic) {
3540 log::warn!(
3541 "Actor {} attempted duplicate pool collect subscription to '{topic}'",
3542 self.actor_id
3543 );
3544 return;
3545 }
3546 self.pool_collect_handlers.insert(topic, handler.clone());
3547 msgbus::subscribe_defi_collects(topic.into(), handler, None);
3548 }
3549
3550 #[cfg(feature = "defi")]
3551 #[allow(dead_code)]
3552 pub(crate) fn remove_pool_collect_subscription(&mut self, topic: MStr<Topic>) {
3553 if let Some(handler) = self.pool_collect_handlers.remove(&topic) {
3554 msgbus::unsubscribe_defi_collects(topic.into(), &handler);
3555 }
3556 }
3557
3558 #[cfg(feature = "defi")]
3559 pub(crate) fn add_pool_flash_subscription(
3560 &mut self,
3561 topic: MStr<Topic>,
3562 handler: TypedHandler<PoolFlash>,
3563 ) {
3564 if self.pool_flash_handlers.contains_key(&topic) {
3565 log::warn!(
3566 "Actor {} attempted duplicate pool flash subscription to '{topic}'",
3567 self.actor_id
3568 );
3569 return;
3570 }
3571 self.pool_flash_handlers.insert(topic, handler.clone());
3572 msgbus::subscribe_defi_flash(topic.into(), handler, None);
3573 }
3574
3575 #[cfg(feature = "defi")]
3576 #[allow(dead_code)]
3577 pub(crate) fn remove_pool_flash_subscription(&mut self, topic: MStr<Topic>) {
3578 if let Some(handler) = self.pool_flash_handlers.remove(&topic) {
3579 msgbus::unsubscribe_defi_flash(topic.into(), &handler);
3580 }
3581 }
3582
3583 pub(crate) fn unsubscribe_all(&mut self) {
3588 for (pattern, handler) in std::mem::take(&mut self.topic_handlers) {
3589 msgbus::unsubscribe_any(pattern, &handler);
3590 }
3591
3592 for (pattern, handler) in std::mem::take(&mut self.instrument_handlers) {
3593 msgbus::unsubscribe_instruments(pattern, &handler);
3594 }
3595
3596 for (pattern, handler) in std::mem::take(&mut self.deltas_handlers) {
3597 msgbus::unsubscribe_book_deltas(pattern, &handler);
3598 }
3599
3600 for (pattern, handler) in std::mem::take(&mut self.depth10_handlers) {
3601 msgbus::unsubscribe_book_depth10(pattern, &handler);
3602 }
3603
3604 for (topic, handler) in std::mem::take(&mut self.book_handlers) {
3605 msgbus::unsubscribe_book_snapshots(topic.into(), &handler);
3606 }
3607
3608 for (topic, handler) in std::mem::take(&mut self.quote_handlers) {
3609 msgbus::unsubscribe_quotes(topic.into(), &handler);
3610 }
3611
3612 for (topic, handler) in std::mem::take(&mut self.trade_handlers) {
3613 msgbus::unsubscribe_trades(topic.into(), &handler);
3614 }
3615
3616 for (topic, handler) in std::mem::take(&mut self.bar_handlers) {
3617 msgbus::unsubscribe_bars(topic.into(), &handler);
3618 }
3619
3620 for (topic, handler) in std::mem::take(&mut self.mark_price_handlers) {
3621 msgbus::unsubscribe_mark_prices(topic.into(), &handler);
3622 }
3623
3624 for (topic, handler) in std::mem::take(&mut self.index_price_handlers) {
3625 msgbus::unsubscribe_index_prices(topic.into(), &handler);
3626 }
3627
3628 for (topic, handler) in std::mem::take(&mut self.funding_rate_handlers) {
3629 msgbus::unsubscribe_funding_rates(topic.into(), &handler);
3630 }
3631
3632 for (topic, handler) in std::mem::take(&mut self.option_greeks_handlers) {
3633 msgbus::unsubscribe_option_greeks(topic.into(), &handler);
3634 }
3635
3636 for (topic, handler) in std::mem::take(&mut self.option_chain_handlers) {
3637 msgbus::unsubscribe_option_chain(topic.into(), &handler);
3638 }
3639
3640 #[cfg(feature = "defi")]
3641 self.unsubscribe_all_defi();
3642 }
3643
3644 #[cfg(feature = "defi")]
3645 fn unsubscribe_all_defi(&mut self) {
3646 for (topic, handler) in std::mem::take(&mut self.block_handlers) {
3647 msgbus::unsubscribe_defi_blocks(topic.into(), &handler);
3648 }
3649
3650 for (topic, handler) in std::mem::take(&mut self.pool_handlers) {
3651 msgbus::unsubscribe_defi_pools(topic.into(), &handler);
3652 }
3653
3654 for (topic, handler) in std::mem::take(&mut self.pool_swap_handlers) {
3655 msgbus::unsubscribe_defi_swaps(topic.into(), &handler);
3656 }
3657
3658 for (topic, handler) in std::mem::take(&mut self.pool_liquidity_handlers) {
3659 msgbus::unsubscribe_defi_liquidity(topic.into(), &handler);
3660 }
3661
3662 for (topic, handler) in std::mem::take(&mut self.pool_collect_handlers) {
3663 msgbus::unsubscribe_defi_collects(topic.into(), &handler);
3664 }
3665
3666 for (topic, handler) in std::mem::take(&mut self.pool_flash_handlers) {
3667 msgbus::unsubscribe_defi_flash(topic.into(), &handler);
3668 }
3669 }
3670
3671 pub fn new(config: DataActorConfig) -> Self {
3673 let actor_id = config.actor_id.unwrap_or_else(Self::default_actor_id);
3674
3675 Self {
3676 actor_id,
3677 config,
3678 trader_id: None, clock: None, cache: None, state: ComponentState::default(),
3682 topic_handlers: AHashMap::new(),
3683 instrument_handlers: AHashMap::new(),
3684 deltas_handlers: AHashMap::new(),
3685 depth10_handlers: AHashMap::new(),
3686 book_handlers: AHashMap::new(),
3687 quote_handlers: AHashMap::new(),
3688 trade_handlers: AHashMap::new(),
3689 bar_handlers: AHashMap::new(),
3690 mark_price_handlers: AHashMap::new(),
3691 index_price_handlers: AHashMap::new(),
3692 funding_rate_handlers: AHashMap::new(),
3693 option_greeks_handlers: AHashMap::new(),
3694 option_chain_handlers: AHashMap::new(),
3695 #[cfg(feature = "defi")]
3696 block_handlers: AHashMap::new(),
3697 #[cfg(feature = "defi")]
3698 pool_handlers: AHashMap::new(),
3699 #[cfg(feature = "defi")]
3700 pool_swap_handlers: AHashMap::new(),
3701 #[cfg(feature = "defi")]
3702 pool_liquidity_handlers: AHashMap::new(),
3703 #[cfg(feature = "defi")]
3704 pool_collect_handlers: AHashMap::new(),
3705 #[cfg(feature = "defi")]
3706 pool_flash_handlers: AHashMap::new(),
3707 warning_events: AHashSet::new(),
3708 pending_requests: AHashMap::new(),
3709 signal_classes: AHashMap::new(),
3710 indicators: Indicators::default(),
3711 }
3712 }
3713
3714 #[must_use]
3716 pub fn registered_indicators(&self) -> Vec<SharedActorIndicator> {
3717 self.indicators.registered_indicators()
3718 }
3719
3720 pub fn indicators_initialized(&self) -> anyhow::Result<bool> {
3726 self.indicators.initialized()
3727 }
3728
3729 pub fn register_indicator_for_quote_ticks(
3731 &mut self,
3732 instrument_id: InstrumentId,
3733 indicator: SharedActorIndicator,
3734 ) {
3735 self.indicators
3736 .register_indicator_for_quote_ticks(instrument_id, indicator);
3737 }
3738
3739 pub fn register_indicator_for_trade_ticks(
3741 &mut self,
3742 instrument_id: InstrumentId,
3743 indicator: SharedActorIndicator,
3744 ) {
3745 self.indicators
3746 .register_indicator_for_trade_ticks(instrument_id, indicator);
3747 }
3748
3749 pub fn register_indicator_for_bars(
3751 &mut self,
3752 bar_type: BarType,
3753 indicator: SharedActorIndicator,
3754 ) {
3755 self.indicators
3756 .register_indicator_for_bars(bar_type, indicator);
3757 }
3758
3759 pub(crate) fn handle_indicators_for_quote(&self, quote: &QuoteTick) -> anyhow::Result<()> {
3760 self.indicators.handle_quote(quote)
3761 }
3762
3763 pub(crate) fn handle_indicators_for_quotes(&self, quotes: &[QuoteTick]) -> anyhow::Result<()> {
3764 self.indicators.handle_quotes(quotes)
3765 }
3766
3767 pub(crate) fn handle_indicators_for_trade(&self, trade: &TradeTick) -> anyhow::Result<()> {
3768 self.indicators.handle_trade(trade)
3769 }
3770
3771 pub(crate) fn handle_indicators_for_trades(&self, trades: &[TradeTick]) -> anyhow::Result<()> {
3772 self.indicators.handle_trades(trades)
3773 }
3774
3775 pub(crate) fn handle_indicators_for_bar(&self, bar: &Bar) -> anyhow::Result<()> {
3776 self.indicators.handle_bar(bar)
3777 }
3778
3779 pub(crate) fn handle_indicators_for_bars(&self, bars: &[Bar]) -> anyhow::Result<()> {
3780 self.indicators.handle_bars(bars)
3781 }
3782
3783 #[must_use]
3785 pub fn mem_address(&self) -> String {
3786 format!("{self:p}")
3787 }
3788
3789 pub fn state(&self) -> ComponentState {
3791 self.state
3792 }
3793
3794 pub fn trader_id(&self) -> Option<TraderId> {
3796 self.trader_id
3797 }
3798
3799 pub fn actor_id(&self) -> ActorId {
3801 self.actor_id
3802 }
3803
3804 fn default_actor_id() -> ActorId {
3805 ActorId::from(stringify!(DataActor))
3806 }
3807
3808 pub fn timestamp_ns(&self) -> UnixNanos {
3810 self.clock_ref().timestamp_ns()
3811 }
3812
3813 fn clock_api(&self) -> ClockApi<'_> {
3814 let clock = self.clock.as_ref().unwrap_or_else(|| {
3815 panic!(
3816 "DataActor {} must be registered before calling `clock()` - trader_id: {:?}",
3817 self.actor_id, self.trader_id
3818 )
3819 });
3820 ClockApi::new(clock.as_ref())
3821 }
3822
3823 fn clock_ref(&self) -> Ref<'_, dyn Clock> {
3824 self.clock
3825 .as_ref()
3826 .unwrap_or_else(|| {
3827 panic!(
3828 "DataActor {} must be registered before calling `clock_ref()` - trader_id: {:?}",
3829 self.actor_id, self.trader_id
3830 )
3831 })
3832 .borrow()
3833 }
3834
3835 fn cache_api(&self) -> CacheApi<'_> {
3836 let cache = self.cache.as_ref().unwrap_or_else(|| {
3837 panic!(
3838 "DataActor {} must be registered before calling `cache()` - trader_id: {:?}",
3839 self.actor_id, self.trader_id
3840 )
3841 });
3842 CacheApi::new(cache.as_ref())
3843 }
3844
3845 pub fn register(
3852 &mut self,
3853 trader_id: TraderId,
3854 clock: Rc<RefCell<dyn Clock>>,
3855 cache: Rc<RefCell<Cache>>,
3856 ) -> anyhow::Result<()> {
3857 if let Some(existing_trader_id) = self.trader_id {
3858 anyhow::bail!(
3859 "DataActor {} already registered with trader {existing_trader_id}",
3860 self.actor_id
3861 );
3862 }
3863
3864 {
3866 let _timestamp = clock.borrow().timestamp_ns();
3867 }
3868
3869 {
3871 let _cache_borrow = cache.borrow();
3872 }
3873
3874 self.trader_id = Some(trader_id);
3875 self.clock = Some(clock);
3876 self.cache = Some(cache);
3877
3878 if !self.is_properly_registered() {
3880 anyhow::bail!(
3881 "DataActor {} registration incomplete - validation failed",
3882 self.actor_id
3883 );
3884 }
3885
3886 log::debug!("Registered {} with trader {trader_id}", self.actor_id);
3887 Ok(())
3888 }
3889
3890 pub fn register_warning_event(&mut self, event_type: &str) {
3892 self.warning_events.insert(event_type.to_string());
3893 log::debug!("Registered event type '{event_type}' for warning logs");
3894 }
3895
3896 pub fn deregister_warning_event(&mut self, event_type: &str) {
3898 self.warning_events.remove(event_type);
3899 log::debug!("Deregistered event type '{event_type}' from warning logs");
3900 }
3901
3902 pub fn is_registered(&self) -> bool {
3903 self.trader_id.is_some()
3904 }
3905
3906 pub(crate) fn check_registered(&self) {
3907 assert!(
3908 self.is_registered(),
3909 "Actor has not been registered with a Trader"
3910 );
3911 }
3912
3913 fn is_properly_registered(&self) -> bool {
3915 self.trader_id.is_some() && self.clock.is_some() && self.cache.is_some()
3916 }
3917
3918 pub(crate) fn send_data_cmd(&self, command: DataCommand) {
3919 if self.config.log_commands {
3920 log::info!("{CMD}{SEND} {command:?}");
3921 }
3922
3923 let endpoint = MessagingSwitchboard::data_engine_queue_execute();
3924 msgbus::send_data_command(endpoint, command);
3925 }
3926
3927 #[allow(dead_code)]
3928 fn send_data_req(&self, request: &RequestCommand) {
3929 if self.config.log_commands {
3930 log::info!("{REQ}{SEND} {request:?}");
3931 }
3932
3933 let endpoint = MessagingSwitchboard::data_engine_queue_execute();
3936 msgbus::send_any(endpoint, request.as_any());
3937 }
3938
3939 pub fn shutdown_system(&self, reason: Option<String>) {
3945 self.check_registered();
3946
3947 let command = ShutdownSystem::new(
3949 self.trader_id().unwrap(),
3950 self.actor_id.inner(),
3951 reason,
3952 UUID4::new(),
3953 self.timestamp_ns(),
3954 None, );
3956
3957 let topic = MessagingSwitchboard::shutdown_system_topic();
3958 msgbus::publish_any(topic, command.as_any());
3959 }
3960
3961 pub fn publish_data(&self, data_type: &DataType, data: &CustomData) {
3971 self.check_registered();
3972
3973 let topic = get_custom_topic(data_type);
3974 msgbus::publish_any(topic, data);
3975 }
3976
3977 pub fn publish_signal(&self, name: &str, value: String, ts_event: UnixNanos) {
3989 self.check_registered();
3990
3991 let now = self.timestamp_ns();
3992 let ts_event = if ts_event.as_u64() == 0 {
3993 now
3994 } else {
3995 ts_event
3996 };
3997 let signal = Signal::new(Ustr::from(name), value, ts_event, now);
3998
3999 let data_type = DataType::new(
4000 &format!(
4001 "Signal{}",
4002 nautilus_core::string::conversions::title_case(name)
4003 ),
4004 None,
4005 None,
4006 );
4007 let data = CustomData::new(Arc::new(signal), data_type);
4008 let topic = get_custom_topic(&data.data_type);
4009 msgbus::publish_any(topic, &data);
4010 }
4011
4012 pub fn add_synthetic(&self, synthetic: SyntheticInstrument) -> anyhow::Result<()> {
4020 self.check_registered();
4021
4022 let cache = self.cache_rc();
4023 if cache.borrow().synthetic(&synthetic.id).is_some() {
4024 anyhow::bail!("`synthetic` {} already exists", synthetic.id);
4025 }
4026 cache.borrow_mut().add_synthetic(synthetic)
4027 }
4028
4029 pub fn update_synthetic(&self, synthetic: SyntheticInstrument) -> anyhow::Result<()> {
4037 self.check_registered();
4038
4039 let cache = self.cache_rc();
4040 if cache.borrow().synthetic(&synthetic.id).is_none() {
4041 anyhow::bail!("`synthetic` {} does not exist", synthetic.id);
4042 }
4043 cache.borrow_mut().add_synthetic(synthetic)
4044 }
4045
4046 pub fn subscribe_data(
4052 &mut self,
4053 handler: ShareableMessageHandler,
4054 data_type: DataType,
4055 client_id: Option<ClientId>,
4056 params: Option<Params>,
4057 ) {
4058 assert!(
4059 self.is_properly_registered(),
4060 "DataActor {} is not properly registered - trader_id: {:?}, clock: {}, cache: {}",
4061 self.actor_id,
4062 self.trader_id,
4063 self.clock.is_some(),
4064 self.cache.is_some()
4065 );
4066
4067 let topic = get_custom_topic(&data_type);
4068 self.add_subscription_any(topic, handler, None);
4069
4070 if client_id.is_none() {
4072 return;
4073 }
4074
4075 let command = SubscribeCommand::Data(SubscribeCustomData {
4076 data_type,
4077 client_id,
4078 venue: None,
4079 command_id: UUID4::new(),
4080 ts_init: self.timestamp_ns(),
4081 correlation_id: None,
4082 params,
4083 });
4084
4085 self.send_data_cmd(DataCommand::Subscribe(command));
4086 }
4087
4088 pub fn subscribe_signal(
4096 &mut self,
4097 handler: ShareableMessageHandler,
4098 name: &str,
4099 priority: Option<u32>,
4100 ) {
4101 self.check_registered();
4102
4103 let pattern = get_signal_pattern(name);
4104 if self.topic_handlers.contains_key(&pattern) {
4105 log::warn!(
4106 "Actor {} attempted duplicate signal subscription to '{pattern}'",
4107 self.actor_id,
4108 );
4109 return;
4110 }
4111 self.topic_handlers.insert(pattern, handler.clone());
4112 msgbus::subscribe_any(pattern, handler, priority);
4113 }
4114
4115 pub fn subscribe_queue_state(
4121 &mut self,
4122 handler: ShareableMessageHandler,
4123 priority: Option<u32>,
4124 ) {
4125 self.check_registered();
4126
4127 let topic = MessagingSwitchboard::queue_state_changed_topic();
4128 self.add_subscription_any(topic, handler, priority);
4129 }
4130
4131 pub fn subscribe_socket_state(
4137 &mut self,
4138 handler: ShareableMessageHandler,
4139 priority: Option<u32>,
4140 ) {
4141 self.check_registered();
4142
4143 let topic = MessagingSwitchboard::socket_state_changed_topic();
4144 self.add_subscription_any(topic, handler, priority);
4145 }
4146
4147 pub fn subscribe_quotes(
4149 &mut self,
4150 topic: MStr<Topic>,
4151 handler: TypedHandler<QuoteTick>,
4152 instrument_id: InstrumentId,
4153 client_id: Option<ClientId>,
4154 params: Option<Params>,
4155 ) {
4156 self.check_registered();
4157
4158 self.add_quote_subscription(topic, handler);
4159
4160 let command = SubscribeCommand::Quotes(SubscribeQuotes {
4161 instrument_id,
4162 client_id,
4163 venue: Some(instrument_id.venue),
4164 command_id: UUID4::new(),
4165 ts_init: self.timestamp_ns(),
4166 correlation_id: None,
4167 params,
4168 });
4169
4170 self.send_data_cmd(DataCommand::Subscribe(command));
4171 }
4172
4173 pub fn subscribe_instruments(
4175 &mut self,
4176 pattern: MStr<Pattern>,
4177 handler: TypedHandler<InstrumentAny>,
4178 venue: Venue,
4179 client_id: Option<ClientId>,
4180 params: Option<Params>,
4181 ) {
4182 self.check_registered();
4183
4184 self.add_instrument_subscription(pattern, handler);
4185
4186 let command = SubscribeCommand::Instruments(SubscribeInstruments {
4187 client_id,
4188 venue,
4189 command_id: UUID4::new(),
4190 ts_init: self.timestamp_ns(),
4191 correlation_id: None,
4192 params,
4193 });
4194
4195 self.send_data_cmd(DataCommand::Subscribe(command));
4196 }
4197
4198 pub fn subscribe_instrument(
4200 &mut self,
4201 topic: MStr<Topic>,
4202 handler: TypedHandler<InstrumentAny>,
4203 instrument_id: InstrumentId,
4204 client_id: Option<ClientId>,
4205 params: Option<Params>,
4206 ) {
4207 self.check_registered();
4208
4209 self.add_instrument_subscription(topic.into(), handler);
4210
4211 let command = SubscribeCommand::Instrument(SubscribeInstrument {
4212 instrument_id,
4213 client_id,
4214 venue: Some(instrument_id.venue),
4215 command_id: UUID4::new(),
4216 ts_init: self.timestamp_ns(),
4217 correlation_id: None,
4218 params,
4219 });
4220
4221 self.send_data_cmd(DataCommand::Subscribe(command));
4222 }
4223
4224 #[expect(clippy::too_many_arguments)]
4226 pub fn subscribe_book_deltas(
4227 &mut self,
4228 pattern: MStr<Pattern>,
4229 handler: TypedHandler<OrderBookDeltas>,
4230 instrument_id: InstrumentId,
4231 book_type: BookType,
4232 depth: Option<NonZeroUsize>,
4233 client_id: Option<ClientId>,
4234 managed: bool,
4235 params: Option<Params>,
4236 ) {
4237 self.check_registered();
4238
4239 self.add_deltas_subscription(pattern, handler);
4240
4241 let command = SubscribeCommand::BookDeltas(SubscribeBookDeltas {
4242 instrument_id,
4243 book_type,
4244 client_id,
4245 venue: Some(instrument_id.venue),
4246 command_id: UUID4::new(),
4247 ts_init: self.timestamp_ns(),
4248 depth,
4249 managed,
4250 correlation_id: None,
4251 params,
4252 });
4253
4254 self.send_data_cmd(DataCommand::Subscribe(command));
4255 }
4256
4257 #[expect(clippy::too_many_arguments)]
4259 pub fn subscribe_book_depth10(
4260 &mut self,
4261 pattern: MStr<Pattern>,
4262 handler: TypedHandler<OrderBookDepth10>,
4263 instrument_id: InstrumentId,
4264 book_type: BookType,
4265 client_id: Option<ClientId>,
4266 managed: bool,
4267 params: Option<Params>,
4268 ) {
4269 self.check_registered();
4270
4271 self.add_depth10_subscription(pattern, handler);
4272
4273 let command = SubscribeCommand::BookDepth10(SubscribeBookDepth10 {
4274 instrument_id,
4275 book_type,
4276 client_id,
4277 venue: Some(instrument_id.venue),
4278 command_id: UUID4::new(),
4279 ts_init: self.timestamp_ns(),
4280 depth: NonZeroUsize::new(10),
4281 managed,
4282 correlation_id: None,
4283 params,
4284 });
4285
4286 self.send_data_cmd(DataCommand::Subscribe(command));
4287 }
4288
4289 #[expect(clippy::too_many_arguments)]
4291 pub fn subscribe_book_at_interval(
4292 &mut self,
4293 topic: MStr<Topic>,
4294 handler: TypedHandler<OrderBook>,
4295 instrument_id: InstrumentId,
4296 book_type: BookType,
4297 depth: Option<NonZeroUsize>,
4298 interval_ms: NonZeroUsize,
4299 client_id: Option<ClientId>,
4300 params: Option<Params>,
4301 ) {
4302 self.check_registered();
4303
4304 self.add_book_snapshot_subscription(topic, handler);
4305
4306 let command = SubscribeCommand::BookSnapshots(SubscribeBookSnapshots {
4307 instrument_id,
4308 book_type,
4309 client_id,
4310 venue: Some(instrument_id.venue),
4311 command_id: UUID4::new(),
4312 ts_init: self.timestamp_ns(),
4313 depth,
4314 interval_ms,
4315 correlation_id: None,
4316 params,
4317 });
4318
4319 self.send_data_cmd(DataCommand::Subscribe(command));
4320 }
4321
4322 pub fn subscribe_trades(
4324 &mut self,
4325 topic: MStr<Topic>,
4326 handler: TypedHandler<TradeTick>,
4327 instrument_id: InstrumentId,
4328 client_id: Option<ClientId>,
4329 params: Option<Params>,
4330 ) {
4331 self.check_registered();
4332
4333 self.add_trade_subscription(topic, handler);
4334
4335 let command = SubscribeCommand::Trades(SubscribeTrades {
4336 instrument_id,
4337 client_id,
4338 venue: Some(instrument_id.venue),
4339 command_id: UUID4::new(),
4340 ts_init: self.timestamp_ns(),
4341 correlation_id: None,
4342 params,
4343 });
4344
4345 self.send_data_cmd(DataCommand::Subscribe(command));
4346 }
4347
4348 pub fn subscribe_bars(
4350 &mut self,
4351 topic: MStr<Topic>,
4352 handler: TypedHandler<Bar>,
4353 bar_type: BarType,
4354 client_id: Option<ClientId>,
4355 params: Option<Params>,
4356 ) {
4357 self.check_registered();
4358
4359 self.add_bar_subscription(topic, handler);
4360
4361 let command = SubscribeCommand::Bars(SubscribeBars {
4362 bar_type,
4363 client_id,
4364 venue: Some(bar_type.instrument_id().venue),
4365 command_id: UUID4::new(),
4366 ts_init: self.timestamp_ns(),
4367 correlation_id: None,
4368 params,
4369 });
4370
4371 self.send_data_cmd(DataCommand::Subscribe(command));
4372 }
4373
4374 pub fn subscribe_mark_prices(
4376 &mut self,
4377 topic: MStr<Topic>,
4378 handler: TypedHandler<MarkPriceUpdate>,
4379 instrument_id: InstrumentId,
4380 client_id: Option<ClientId>,
4381 params: Option<Params>,
4382 ) {
4383 self.check_registered();
4384
4385 self.add_mark_price_subscription(topic, handler);
4386
4387 let command = SubscribeCommand::MarkPrices(SubscribeMarkPrices {
4388 instrument_id,
4389 client_id,
4390 venue: Some(instrument_id.venue),
4391 command_id: UUID4::new(),
4392 ts_init: self.timestamp_ns(),
4393 correlation_id: None,
4394 params,
4395 });
4396
4397 self.send_data_cmd(DataCommand::Subscribe(command));
4398 }
4399
4400 pub fn subscribe_index_prices(
4402 &mut self,
4403 topic: MStr<Topic>,
4404 handler: TypedHandler<IndexPriceUpdate>,
4405 instrument_id: InstrumentId,
4406 client_id: Option<ClientId>,
4407 params: Option<Params>,
4408 ) {
4409 self.check_registered();
4410
4411 self.add_index_price_subscription(topic, handler);
4412
4413 let command = SubscribeCommand::IndexPrices(SubscribeIndexPrices {
4414 instrument_id,
4415 client_id,
4416 venue: Some(instrument_id.venue),
4417 command_id: UUID4::new(),
4418 ts_init: self.timestamp_ns(),
4419 correlation_id: None,
4420 params,
4421 });
4422
4423 self.send_data_cmd(DataCommand::Subscribe(command));
4424 }
4425
4426 pub fn subscribe_funding_rates(
4428 &mut self,
4429 topic: MStr<Topic>,
4430 handler: TypedHandler<FundingRateUpdate>,
4431 instrument_id: InstrumentId,
4432 client_id: Option<ClientId>,
4433 params: Option<Params>,
4434 ) {
4435 self.check_registered();
4436
4437 self.add_funding_rate_subscription(topic, handler);
4438
4439 let command = SubscribeCommand::FundingRates(SubscribeFundingRates {
4440 instrument_id,
4441 client_id,
4442 venue: Some(instrument_id.venue),
4443 command_id: UUID4::new(),
4444 ts_init: self.timestamp_ns(),
4445 correlation_id: None,
4446 params,
4447 });
4448
4449 self.send_data_cmd(DataCommand::Subscribe(command));
4450 }
4451
4452 pub fn subscribe_option_greeks(
4454 &mut self,
4455 topic: MStr<Topic>,
4456 handler: TypedHandler<OptionGreeks>,
4457 instrument_id: InstrumentId,
4458 client_id: Option<ClientId>,
4459 params: Option<Params>,
4460 ) {
4461 self.check_registered();
4462
4463 self.add_option_greeks_subscription(topic, handler);
4464
4465 let command = SubscribeCommand::OptionGreeks(SubscribeOptionGreeks {
4466 instrument_id,
4467 client_id,
4468 venue: Some(instrument_id.venue),
4469 command_id: UUID4::new(),
4470 ts_init: self.timestamp_ns(),
4471 correlation_id: None,
4472 params,
4473 });
4474
4475 self.send_data_cmd(DataCommand::Subscribe(command));
4476 }
4477
4478 pub fn subscribe_instrument_status(
4480 &mut self,
4481 topic: MStr<Topic>,
4482 handler: ShareableMessageHandler,
4483 instrument_id: InstrumentId,
4484 client_id: Option<ClientId>,
4485 params: Option<Params>,
4486 ) {
4487 self.check_registered();
4488
4489 self.add_subscription_any(topic, handler, None);
4490
4491 let command = SubscribeCommand::InstrumentStatus(SubscribeInstrumentStatus {
4492 instrument_id,
4493 client_id,
4494 venue: Some(instrument_id.venue),
4495 command_id: UUID4::new(),
4496 ts_init: self.timestamp_ns(),
4497 correlation_id: None,
4498 params,
4499 });
4500
4501 self.send_data_cmd(DataCommand::Subscribe(command));
4502 }
4503
4504 pub fn subscribe_instrument_close(
4506 &mut self,
4507 topic: MStr<Topic>,
4508 handler: ShareableMessageHandler,
4509 instrument_id: InstrumentId,
4510 client_id: Option<ClientId>,
4511 params: Option<Params>,
4512 ) {
4513 self.check_registered();
4514
4515 self.add_instrument_close_subscription(topic, handler);
4516
4517 let command = SubscribeCommand::InstrumentClose(SubscribeInstrumentClose {
4518 instrument_id,
4519 client_id,
4520 venue: Some(instrument_id.venue),
4521 command_id: UUID4::new(),
4522 ts_init: self.timestamp_ns(),
4523 correlation_id: None,
4524 params,
4525 });
4526
4527 self.send_data_cmd(DataCommand::Subscribe(command));
4528 }
4529
4530 #[expect(
4532 clippy::too_many_arguments,
4533 reason = "subscription command mirrors the option chain request fields"
4534 )]
4535 pub fn subscribe_option_chain(
4536 &mut self,
4537 topic: MStr<Topic>,
4538 handler: TypedHandler<OptionChainSlice>,
4539 series_id: OptionSeriesId,
4540 strike_range: StrikeRange,
4541 snapshot_interval_ms: Option<u64>,
4542 client_id: Option<ClientId>,
4543 params: Option<Params>,
4544 ) {
4545 self.check_registered();
4546
4547 self.add_option_chain_subscription(topic, handler);
4548
4549 let command = SubscribeCommand::OptionChain(SubscribeOptionChain::new(
4550 series_id,
4551 strike_range,
4552 snapshot_interval_ms,
4553 UUID4::new(),
4554 self.timestamp_ns(),
4555 client_id,
4556 Some(series_id.venue),
4557 params,
4558 ));
4559
4560 self.send_data_cmd(DataCommand::Subscribe(command));
4561 }
4562
4563 pub fn unsubscribe_data(
4565 &mut self,
4566 data_type: DataType,
4567 client_id: Option<ClientId>,
4568 params: Option<Params>,
4569 ) {
4570 self.check_registered();
4571
4572 let topic = get_custom_topic(&data_type);
4573 self.remove_subscription_any(topic);
4574
4575 if client_id.is_none() {
4576 return;
4577 }
4578
4579 let command = UnsubscribeCommand::Data(UnsubscribeCustomData {
4580 data_type,
4581 client_id,
4582 venue: None,
4583 command_id: UUID4::new(),
4584 ts_init: self.timestamp_ns(),
4585 correlation_id: None,
4586 params,
4587 });
4588
4589 self.send_data_cmd(DataCommand::Unsubscribe(command));
4590 }
4591
4592 pub fn unsubscribe_signal(&mut self, name: &str) {
4598 self.check_registered();
4599
4600 let pattern = get_signal_pattern(name);
4601 if let Some(handler) = self.topic_handlers.remove(&pattern) {
4602 msgbus::unsubscribe_any(pattern, &handler);
4603 } else {
4604 log::warn!(
4605 "Actor {} attempted to unsubscribe from signal pattern '{pattern}' when not subscribed",
4606 self.actor_id,
4607 );
4608 }
4609 }
4610
4611 pub fn unsubscribe_queue_state(&mut self) {
4617 self.check_registered();
4618
4619 let topic = MessagingSwitchboard::queue_state_changed_topic();
4620 self.remove_subscription_any(topic);
4621 }
4622
4623 pub fn unsubscribe_socket_state(&mut self) {
4629 self.check_registered();
4630
4631 let topic = MessagingSwitchboard::socket_state_changed_topic();
4632 self.remove_subscription_any(topic);
4633 }
4634
4635 pub fn unsubscribe_instruments(
4637 &mut self,
4638 venue: Venue,
4639 client_id: Option<ClientId>,
4640 params: Option<Params>,
4641 ) {
4642 self.check_registered();
4643
4644 let pattern = get_instruments_pattern(venue);
4645 self.remove_instrument_subscription(pattern);
4646
4647 let command = UnsubscribeCommand::Instruments(UnsubscribeInstruments {
4648 client_id,
4649 venue,
4650 command_id: UUID4::new(),
4651 ts_init: self.timestamp_ns(),
4652 correlation_id: None,
4653 params,
4654 });
4655
4656 self.send_data_cmd(DataCommand::Unsubscribe(command));
4657 }
4658
4659 pub fn unsubscribe_instrument(
4661 &mut self,
4662 instrument_id: InstrumentId,
4663 client_id: Option<ClientId>,
4664 params: Option<Params>,
4665 ) {
4666 self.check_registered();
4667
4668 let topic = get_instrument_topic(instrument_id);
4669 self.remove_instrument_subscription(topic.into());
4670
4671 let command = UnsubscribeCommand::Instrument(UnsubscribeInstrument {
4672 instrument_id,
4673 client_id,
4674 venue: Some(instrument_id.venue),
4675 command_id: UUID4::new(),
4676 ts_init: self.timestamp_ns(),
4677 correlation_id: None,
4678 params,
4679 });
4680
4681 self.send_data_cmd(DataCommand::Unsubscribe(command));
4682 }
4683
4684 pub fn unsubscribe_book_deltas(
4686 &mut self,
4687 instrument_id: InstrumentId,
4688 client_id: Option<ClientId>,
4689 params: Option<Params>,
4690 ) {
4691 self.check_registered();
4692
4693 let pattern = if is_parent_subscription(params.as_ref()) {
4694 get_book_deltas_pattern(instrument_id)
4695 } else {
4696 get_book_deltas_topic(instrument_id).into()
4697 };
4698 self.remove_deltas_subscription(pattern);
4699
4700 let command = UnsubscribeCommand::BookDeltas(UnsubscribeBookDeltas {
4701 instrument_id,
4702 client_id,
4703 venue: Some(instrument_id.venue),
4704 command_id: UUID4::new(),
4705 ts_init: self.timestamp_ns(),
4706 correlation_id: None,
4707 params,
4708 });
4709
4710 self.send_data_cmd(DataCommand::Unsubscribe(command));
4711 }
4712
4713 pub fn unsubscribe_book_depth10(
4715 &mut self,
4716 instrument_id: InstrumentId,
4717 client_id: Option<ClientId>,
4718 params: Option<Params>,
4719 ) {
4720 self.check_registered();
4721
4722 let pattern = if is_parent_subscription(params.as_ref()) {
4723 get_book_depth10_pattern(instrument_id)
4724 } else {
4725 get_book_depth10_topic(instrument_id).into()
4726 };
4727 self.remove_depth10_subscription(pattern);
4728
4729 let command = UnsubscribeCommand::BookDepth10(UnsubscribeBookDepth10 {
4730 instrument_id,
4731 client_id,
4732 venue: Some(instrument_id.venue),
4733 command_id: UUID4::new(),
4734 ts_init: self.timestamp_ns(),
4735 correlation_id: None,
4736 params,
4737 });
4738
4739 self.send_data_cmd(DataCommand::Unsubscribe(command));
4740 }
4741
4742 pub fn unsubscribe_book_at_interval(
4744 &mut self,
4745 instrument_id: InstrumentId,
4746 interval_ms: NonZeroUsize,
4747 client_id: Option<ClientId>,
4748 params: Option<Params>,
4749 ) {
4750 self.check_registered();
4751
4752 let topic = get_book_snapshots_topic(instrument_id, interval_ms);
4753 self.remove_book_snapshot_subscription(topic);
4754
4755 let command = UnsubscribeCommand::BookSnapshots(UnsubscribeBookSnapshots {
4756 instrument_id,
4757 interval_ms,
4758 client_id,
4759 venue: Some(instrument_id.venue),
4760 command_id: UUID4::new(),
4761 ts_init: self.timestamp_ns(),
4762 correlation_id: None,
4763 params,
4764 });
4765
4766 self.send_data_cmd(DataCommand::Unsubscribe(command));
4767 }
4768
4769 pub fn unsubscribe_quotes(
4771 &mut self,
4772 instrument_id: InstrumentId,
4773 client_id: Option<ClientId>,
4774 params: Option<Params>,
4775 ) {
4776 self.check_registered();
4777
4778 let topic = get_quotes_topic(instrument_id);
4779 self.remove_quote_subscription(topic);
4780
4781 let command = UnsubscribeCommand::Quotes(UnsubscribeQuotes {
4782 instrument_id,
4783 client_id,
4784 venue: Some(instrument_id.venue),
4785 command_id: UUID4::new(),
4786 ts_init: self.timestamp_ns(),
4787 correlation_id: None,
4788 params,
4789 });
4790
4791 self.send_data_cmd(DataCommand::Unsubscribe(command));
4792 }
4793
4794 pub fn unsubscribe_trades(
4796 &mut self,
4797 instrument_id: InstrumentId,
4798 client_id: Option<ClientId>,
4799 params: Option<Params>,
4800 ) {
4801 self.check_registered();
4802
4803 let topic = get_trades_topic(instrument_id);
4804 self.remove_trade_subscription(topic);
4805
4806 let command = UnsubscribeCommand::Trades(UnsubscribeTrades {
4807 instrument_id,
4808 client_id,
4809 venue: Some(instrument_id.venue),
4810 command_id: UUID4::new(),
4811 ts_init: self.timestamp_ns(),
4812 correlation_id: None,
4813 params,
4814 });
4815
4816 self.send_data_cmd(DataCommand::Unsubscribe(command));
4817 }
4818
4819 pub fn unsubscribe_bars(
4821 &mut self,
4822 bar_type: BarType,
4823 client_id: Option<ClientId>,
4824 params: Option<Params>,
4825 ) {
4826 self.check_registered();
4827
4828 let topic = get_bars_topic(bar_type.standard());
4830 self.remove_bar_subscription(topic);
4831
4832 let command = UnsubscribeCommand::Bars(UnsubscribeBars {
4833 bar_type,
4834 client_id,
4835 venue: Some(bar_type.instrument_id().venue),
4836 command_id: UUID4::new(),
4837 ts_init: self.timestamp_ns(),
4838 correlation_id: None,
4839 params,
4840 });
4841
4842 self.send_data_cmd(DataCommand::Unsubscribe(command));
4843 }
4844
4845 pub fn unsubscribe_mark_prices(
4847 &mut self,
4848 instrument_id: InstrumentId,
4849 client_id: Option<ClientId>,
4850 params: Option<Params>,
4851 ) {
4852 self.check_registered();
4853
4854 let topic = get_mark_price_topic(instrument_id);
4855 self.remove_mark_price_subscription(topic);
4856
4857 let command = UnsubscribeCommand::MarkPrices(UnsubscribeMarkPrices {
4858 instrument_id,
4859 client_id,
4860 venue: Some(instrument_id.venue),
4861 command_id: UUID4::new(),
4862 ts_init: self.timestamp_ns(),
4863 correlation_id: None,
4864 params,
4865 });
4866
4867 self.send_data_cmd(DataCommand::Unsubscribe(command));
4868 }
4869
4870 pub fn unsubscribe_index_prices(
4872 &mut self,
4873 instrument_id: InstrumentId,
4874 client_id: Option<ClientId>,
4875 params: Option<Params>,
4876 ) {
4877 self.check_registered();
4878
4879 let topic = get_index_price_topic(instrument_id);
4880 self.remove_index_price_subscription(topic);
4881
4882 let command = UnsubscribeCommand::IndexPrices(UnsubscribeIndexPrices {
4883 instrument_id,
4884 client_id,
4885 venue: Some(instrument_id.venue),
4886 command_id: UUID4::new(),
4887 ts_init: self.timestamp_ns(),
4888 correlation_id: None,
4889 params,
4890 });
4891
4892 self.send_data_cmd(DataCommand::Unsubscribe(command));
4893 }
4894
4895 pub fn unsubscribe_funding_rates(
4897 &mut self,
4898 instrument_id: InstrumentId,
4899 client_id: Option<ClientId>,
4900 params: Option<Params>,
4901 ) {
4902 self.check_registered();
4903
4904 let topic = get_funding_rate_topic(instrument_id);
4905 self.remove_funding_rate_subscription(topic);
4906
4907 let command = UnsubscribeCommand::FundingRates(UnsubscribeFundingRates {
4908 instrument_id,
4909 client_id,
4910 venue: Some(instrument_id.venue),
4911 command_id: UUID4::new(),
4912 ts_init: self.timestamp_ns(),
4913 correlation_id: None,
4914 params,
4915 });
4916
4917 self.send_data_cmd(DataCommand::Unsubscribe(command));
4918 }
4919
4920 pub fn unsubscribe_option_greeks(
4922 &mut self,
4923 instrument_id: InstrumentId,
4924 client_id: Option<ClientId>,
4925 params: Option<Params>,
4926 ) {
4927 self.check_registered();
4928
4929 let topic = get_option_greeks_topic(instrument_id);
4930 self.remove_option_greeks_subscription(topic);
4931
4932 let command = UnsubscribeCommand::OptionGreeks(UnsubscribeOptionGreeks {
4933 instrument_id,
4934 client_id,
4935 venue: Some(instrument_id.venue),
4936 command_id: UUID4::new(),
4937 ts_init: self.timestamp_ns(),
4938 correlation_id: None,
4939 params,
4940 });
4941
4942 self.send_data_cmd(DataCommand::Unsubscribe(command));
4943 }
4944
4945 pub fn unsubscribe_instrument_status(
4947 &mut self,
4948 instrument_id: InstrumentId,
4949 client_id: Option<ClientId>,
4950 params: Option<Params>,
4951 ) {
4952 self.check_registered();
4953
4954 let topic = get_instrument_status_topic(instrument_id);
4955 self.remove_subscription_any(topic);
4956
4957 let command = UnsubscribeCommand::InstrumentStatus(UnsubscribeInstrumentStatus {
4958 instrument_id,
4959 client_id,
4960 venue: Some(instrument_id.venue),
4961 command_id: UUID4::new(),
4962 ts_init: self.timestamp_ns(),
4963 correlation_id: None,
4964 params,
4965 });
4966
4967 self.send_data_cmd(DataCommand::Unsubscribe(command));
4968 }
4969
4970 pub fn unsubscribe_instrument_close(
4972 &mut self,
4973 instrument_id: InstrumentId,
4974 client_id: Option<ClientId>,
4975 params: Option<Params>,
4976 ) {
4977 self.check_registered();
4978
4979 let topic = get_instrument_close_topic(instrument_id);
4980 self.remove_instrument_close_subscription(topic);
4981
4982 let command = UnsubscribeCommand::InstrumentClose(UnsubscribeInstrumentClose {
4983 instrument_id,
4984 client_id,
4985 venue: Some(instrument_id.venue),
4986 command_id: UUID4::new(),
4987 ts_init: self.timestamp_ns(),
4988 correlation_id: None,
4989 params,
4990 });
4991
4992 self.send_data_cmd(DataCommand::Unsubscribe(command));
4993 }
4994
4995 pub fn unsubscribe_option_chain(
4997 &mut self,
4998 series_id: OptionSeriesId,
4999 client_id: Option<ClientId>,
5000 ) {
5001 self.check_registered();
5002
5003 let topic = get_option_chain_topic(series_id);
5004 self.remove_option_chain_subscription(topic);
5005
5006 let command = UnsubscribeCommand::OptionChain(UnsubscribeOptionChain::new(
5007 series_id,
5008 UUID4::new(),
5009 self.timestamp_ns(),
5010 client_id,
5011 Some(series_id.venue),
5012 ));
5013
5014 self.send_data_cmd(DataCommand::Unsubscribe(command));
5015 }
5016
5017 #[expect(clippy::too_many_arguments)]
5023 pub fn request_data(
5024 &self,
5025 data_type: DataType,
5026 client_id: ClientId,
5027 start: Option<Timestamp>,
5028 end: Option<Timestamp>,
5029 limit: Option<NonZeroUsize>,
5030 params: Option<Params>,
5031 handler: ShareableMessageHandler,
5032 ) -> anyhow::Result<UUID4> {
5033 self.check_registered();
5034
5035 let now = self.clock_ref().utc_now();
5036 check_timestamps(now, start, end)?;
5037
5038 let request_id = UUID4::new();
5039 let command = RequestCommand::Data(RequestCustomData {
5040 client_id,
5041 data_type,
5042 start,
5043 end,
5044 limit,
5045 request_id,
5046 ts_init: self.timestamp_ns(),
5047 params,
5048 });
5049
5050 get_message_bus()
5051 .borrow_mut()
5052 .register_response_handler(command.request_id(), handler)?;
5053
5054 self.send_data_cmd(DataCommand::Request(command));
5055
5056 Ok(request_id)
5057 }
5058
5059 pub fn request_instrument(
5065 &self,
5066 instrument_id: InstrumentId,
5067 start: Option<Timestamp>,
5068 end: Option<Timestamp>,
5069 client_id: Option<ClientId>,
5070 params: Option<Params>,
5071 handler: ShareableMessageHandler,
5072 ) -> anyhow::Result<UUID4> {
5073 self.check_registered();
5074
5075 let now = self.clock_ref().utc_now();
5076 check_timestamps(now, start, end)?;
5077
5078 let request_id = UUID4::new();
5079 let command = RequestCommand::Instrument(RequestInstrument {
5080 instrument_id,
5081 start,
5082 end,
5083 client_id,
5084 request_id,
5085 ts_init: now.into(),
5086 params,
5087 });
5088
5089 get_message_bus()
5090 .borrow_mut()
5091 .register_response_handler(command.request_id(), handler)?;
5092
5093 self.send_data_cmd(DataCommand::Request(command));
5094
5095 Ok(request_id)
5096 }
5097
5098 pub fn request_instruments(
5104 &self,
5105 venue: Option<Venue>,
5106 start: Option<Timestamp>,
5107 end: Option<Timestamp>,
5108 client_id: Option<ClientId>,
5109 params: Option<Params>,
5110 handler: ShareableMessageHandler,
5111 ) -> anyhow::Result<UUID4> {
5112 self.check_registered();
5113
5114 let now = self.clock_ref().utc_now();
5115 check_timestamps(now, start, end)?;
5116
5117 let request_id = UUID4::new();
5118 let command = RequestCommand::Instruments(RequestInstruments {
5119 venue,
5120 start,
5121 end,
5122 client_id,
5123 request_id,
5124 ts_init: now.into(),
5125 params,
5126 });
5127
5128 get_message_bus()
5129 .borrow_mut()
5130 .register_response_handler(command.request_id(), handler)?;
5131
5132 self.send_data_cmd(DataCommand::Request(command));
5133
5134 Ok(request_id)
5135 }
5136
5137 pub fn request_book_snapshot(
5143 &self,
5144 instrument_id: InstrumentId,
5145 depth: Option<NonZeroUsize>,
5146 client_id: Option<ClientId>,
5147 params: Option<Params>,
5148 handler: ShareableMessageHandler,
5149 ) -> anyhow::Result<UUID4> {
5150 self.check_registered();
5151
5152 let request_id = UUID4::new();
5153 let command = RequestCommand::BookSnapshot(RequestBookSnapshot {
5154 instrument_id,
5155 depth,
5156 client_id,
5157 request_id,
5158 ts_init: self.timestamp_ns(),
5159 params,
5160 });
5161
5162 get_message_bus()
5163 .borrow_mut()
5164 .register_response_handler(command.request_id(), handler)?;
5165
5166 self.send_data_cmd(DataCommand::Request(command));
5167
5168 Ok(request_id)
5169 }
5170
5171 #[expect(clippy::too_many_arguments)]
5177 pub fn request_book_deltas(
5178 &self,
5179 instrument_id: InstrumentId,
5180 start: Option<Timestamp>,
5181 end: Option<Timestamp>,
5182 limit: Option<NonZeroUsize>,
5183 client_id: Option<ClientId>,
5184 params: Option<Params>,
5185 handler: ShareableMessageHandler,
5186 ) -> anyhow::Result<UUID4> {
5187 self.check_registered();
5188
5189 let now = self.clock_ref().utc_now();
5190 check_timestamps(now, start, end)?;
5191
5192 let request_id = UUID4::new();
5193 let command = RequestCommand::BookDeltas(RequestBookDeltas {
5194 instrument_id,
5195 start,
5196 end,
5197 limit,
5198 client_id,
5199 request_id,
5200 ts_init: now.into(),
5201 params,
5202 });
5203
5204 get_message_bus()
5205 .borrow_mut()
5206 .register_response_handler(command.request_id(), handler)?;
5207
5208 self.send_data_cmd(DataCommand::Request(command));
5209
5210 Ok(request_id)
5211 }
5212
5213 #[expect(clippy::too_many_arguments)]
5219 pub fn request_book_depth(
5220 &self,
5221 instrument_id: InstrumentId,
5222 start: Option<Timestamp>,
5223 end: Option<Timestamp>,
5224 limit: Option<NonZeroUsize>,
5225 depth: Option<NonZeroUsize>,
5226 client_id: Option<ClientId>,
5227 params: Option<Params>,
5228 handler: ShareableMessageHandler,
5229 ) -> anyhow::Result<UUID4> {
5230 self.check_registered();
5231
5232 let now = self.clock_ref().utc_now();
5233 check_timestamps(now, start, end)?;
5234
5235 let request_id = UUID4::new();
5236 let command = RequestCommand::BookDepth(RequestBookDepth {
5237 instrument_id,
5238 start,
5239 end,
5240 limit,
5241 depth,
5242 client_id,
5243 request_id,
5244 ts_init: now.into(),
5245 params,
5246 });
5247
5248 get_message_bus()
5249 .borrow_mut()
5250 .register_response_handler(command.request_id(), handler)?;
5251
5252 self.send_data_cmd(DataCommand::Request(command));
5253
5254 Ok(request_id)
5255 }
5256
5257 #[expect(clippy::too_many_arguments)]
5263 pub fn request_quotes(
5264 &self,
5265 instrument_id: InstrumentId,
5266 start: Option<Timestamp>,
5267 end: Option<Timestamp>,
5268 limit: Option<NonZeroUsize>,
5269 client_id: Option<ClientId>,
5270 params: Option<Params>,
5271 handler: ShareableMessageHandler,
5272 ) -> anyhow::Result<UUID4> {
5273 self.check_registered();
5274
5275 let now = self.clock_ref().utc_now();
5276 check_timestamps(now, start, end)?;
5277
5278 let request_id = UUID4::new();
5279 let command = RequestCommand::Quotes(RequestQuotes {
5280 instrument_id,
5281 start,
5282 end,
5283 limit,
5284 client_id,
5285 request_id,
5286 ts_init: now.into(),
5287 params,
5288 });
5289
5290 get_message_bus()
5291 .borrow_mut()
5292 .register_response_handler(command.request_id(), handler)?;
5293
5294 self.send_data_cmd(DataCommand::Request(command));
5295
5296 Ok(request_id)
5297 }
5298
5299 #[expect(clippy::too_many_arguments)]
5305 pub fn request_trades(
5306 &self,
5307 instrument_id: InstrumentId,
5308 start: Option<Timestamp>,
5309 end: Option<Timestamp>,
5310 limit: Option<NonZeroUsize>,
5311 client_id: Option<ClientId>,
5312 params: Option<Params>,
5313 handler: ShareableMessageHandler,
5314 ) -> anyhow::Result<UUID4> {
5315 self.check_registered();
5316
5317 let now = self.clock_ref().utc_now();
5318 check_timestamps(now, start, end)?;
5319
5320 let request_id = UUID4::new();
5321 let command = RequestCommand::Trades(RequestTrades {
5322 instrument_id,
5323 start,
5324 end,
5325 limit,
5326 client_id,
5327 request_id,
5328 ts_init: now.into(),
5329 params,
5330 });
5331
5332 get_message_bus()
5333 .borrow_mut()
5334 .register_response_handler(command.request_id(), handler)?;
5335
5336 self.send_data_cmd(DataCommand::Request(command));
5337
5338 Ok(request_id)
5339 }
5340
5341 #[expect(clippy::too_many_arguments)]
5347 pub fn request_bars(
5348 &self,
5349 bar_type: BarType,
5350 start: Option<Timestamp>,
5351 end: Option<Timestamp>,
5352 limit: Option<NonZeroUsize>,
5353 client_id: Option<ClientId>,
5354 params: Option<Params>,
5355 handler: ShareableMessageHandler,
5356 ) -> anyhow::Result<UUID4> {
5357 self.check_registered();
5358
5359 anyhow::ensure!(
5360 bar_type.is_standard(),
5361 "Composite bar types are not supported for `request_bars`, was {bar_type}; \
5362 request aggregation via the `bar_types` params instead",
5363 );
5364
5365 let now = self.clock_ref().utc_now();
5366 check_timestamps(now, start, end)?;
5367
5368 let request_id = UUID4::new();
5369 let command = RequestCommand::Bars(RequestBars {
5370 bar_type,
5371 start,
5372 end,
5373 limit,
5374 client_id,
5375 request_id,
5376 ts_init: now.into(),
5377 params,
5378 });
5379
5380 get_message_bus()
5381 .borrow_mut()
5382 .register_response_handler(command.request_id(), handler)?;
5383
5384 self.send_data_cmd(DataCommand::Request(command));
5385
5386 Ok(request_id)
5387 }
5388
5389 #[expect(clippy::too_many_arguments)]
5395 pub fn request_funding_rates(
5396 &self,
5397 instrument_id: InstrumentId,
5398 start: Option<Timestamp>,
5399 end: Option<Timestamp>,
5400 limit: Option<NonZeroUsize>,
5401 client_id: Option<ClientId>,
5402 params: Option<Params>,
5403 handler: ShareableMessageHandler,
5404 ) -> anyhow::Result<UUID4> {
5405 self.check_registered();
5406
5407 let now = self.clock_ref().utc_now();
5408 check_timestamps(now, start, end)?;
5409
5410 let request_id = UUID4::new();
5411 let command = RequestCommand::FundingRates(RequestFundingRates {
5412 instrument_id,
5413 start,
5414 end,
5415 limit,
5416 client_id,
5417 request_id,
5418 ts_init: now.into(),
5419 params,
5420 });
5421
5422 get_message_bus()
5423 .borrow_mut()
5424 .register_response_handler(command.request_id(), handler)?;
5425
5426 self.send_data_cmd(DataCommand::Request(command));
5427
5428 Ok(request_id)
5429 }
5430
5431 #[cfg(feature = "live")]
5438 pub fn reconnect_socket(&self, client_id: ClientId, endpoint: &str) -> anyhow::Result<()> {
5439 let endpoint = socket_endpoint(endpoint)?;
5440
5441 if !self.is_properly_registered() {
5442 anyhow::bail!(
5443 "Actor {} has not been registered with a Trader",
5444 self.actor_id
5445 );
5446 }
5447
5448 let sender = try_get_system_command_sender()
5449 .ok_or_else(|| anyhow::anyhow!("Live runner system command channel is unavailable"))?;
5450 let trader_id = self
5451 .trader_id
5452 .ok_or_else(|| anyhow::anyhow!("Actor {} has no trader ID", self.actor_id))?;
5453 let command = ReconnectSocket::new(trader_id, client_id, endpoint, self.timestamp_ns());
5454 sender
5455 .send(SystemCommand::ReconnectSocket(command))
5456 .map_err(|_| anyhow::anyhow!("Live runner system command channel is closed"))?;
5457 Ok(())
5458 }
5459
5460 #[cfg(test)]
5461 pub fn quote_handler_count(&self) -> usize {
5462 self.quote_handlers.len()
5463 }
5464
5465 #[cfg(test)]
5466 pub fn trade_handler_count(&self) -> usize {
5467 self.trade_handlers.len()
5468 }
5469
5470 #[cfg(test)]
5471 pub fn bar_handler_count(&self) -> usize {
5472 self.bar_handlers.len()
5473 }
5474
5475 #[cfg(test)]
5476 pub fn deltas_handler_count(&self) -> usize {
5477 self.deltas_handlers.len()
5478 }
5479
5480 #[cfg(test)]
5481 pub fn depth10_handler_count(&self) -> usize {
5482 self.depth10_handlers.len()
5483 }
5484
5485 #[cfg(test)]
5486 pub fn has_quote_handler(&self, topic: &str) -> bool {
5487 self.quote_handlers
5488 .contains_key(&MStr::<Topic>::from(topic))
5489 }
5490
5491 #[cfg(test)]
5492 pub fn has_trade_handler(&self, topic: &str) -> bool {
5493 self.trade_handlers
5494 .contains_key(&MStr::<Topic>::from(topic))
5495 }
5496
5497 #[cfg(test)]
5498 pub fn has_bar_handler(&self, topic: &str) -> bool {
5499 self.bar_handlers.contains_key(&MStr::<Topic>::from(topic))
5500 }
5501
5502 #[cfg(test)]
5503 pub fn has_deltas_handler(&self, pattern: &str) -> bool {
5504 self.deltas_handlers
5505 .contains_key(&MStr::<Pattern>::from(pattern))
5506 }
5507
5508 #[cfg(test)]
5509 pub fn has_depth10_handler(&self, pattern: &str) -> bool {
5510 self.depth10_handlers
5511 .contains_key(&MStr::<Pattern>::from(pattern))
5512 }
5513}
5514
5515impl DataActorNative for DataActorCore {
5516 fn core(&self) -> &DataActorCore {
5517 self
5518 }
5519
5520 fn core_mut(&mut self) -> &mut DataActorCore {
5521 self
5522 }
5523}
5524
5525fn check_timestamps(
5526 now: Timestamp,
5527 start: Option<Timestamp>,
5528 end: Option<Timestamp>,
5529) -> anyhow::Result<()> {
5530 if let Some(start) = start {
5531 check_predicate_true(start <= now, "start was > now")?;
5532 }
5533
5534 if let Some(end) = end {
5535 check_predicate_true(end <= now, "end was > now")?;
5536 }
5537
5538 if let (Some(start), Some(end)) = (start, end) {
5539 check_predicate_true(start <= end, "start was > end")?;
5540 }
5541
5542 Ok(())
5543}
5544
5545fn log_error(e: &anyhow::Error) {
5546 log::error!("{e}");
5547}
5548
5549fn log_not_running<T>(msg: &T)
5550where
5551 T: Debug,
5552{
5553 log::trace!("Received message when not running - skipping {msg:?}");
5554}
5555
5556fn log_received<T>(msg: &T)
5557where
5558 T: Debug,
5559{
5560 log::debug!("{RECV} {msg:?}");
5561}
5562
5563fn log_received_bulk(kind: &str, correlation_id: &UUID4, records: usize) {
5564 log::debug!("{RECV} {kind} correlation_id={correlation_id} records={records}");
5565}