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