1use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
23
24use nautilus_common::{
25 actor::DataActor,
26 cache::Cache,
27 clock::{Clock, TestClock},
28 component::{
29 Component, dispose_component, register_component_actor, reset_component, start_component,
30 stop_component,
31 },
32 enums::{ComponentState, ComponentTrigger, Environment},
33};
34use nautilus_core::{UUID4, UnixNanos};
35use nautilus_model::identifiers::{ActorId, ComponentId, ExecAlgorithmId, StrategyId, TraderId};
36
37pub struct Trader {
43 pub trader_id: TraderId,
45 pub instance_id: UUID4,
47 pub environment: Environment,
49 state: ComponentState,
51 clock: Rc<RefCell<dyn Clock>>,
53 cache: Rc<RefCell<Cache>>,
55 actor_ids: Vec<ActorId>,
57 strategies: HashMap<StrategyId, Box<dyn Component>>,
59 exec_algorithms: HashMap<ExecAlgorithmId, Box<dyn Component>>,
61 clocks: HashMap<ComponentId, Rc<RefCell<dyn Clock>>>, ts_created: UnixNanos,
65 ts_started: Option<UnixNanos>,
67 ts_stopped: Option<UnixNanos>,
69}
70
71impl Debug for Trader {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 write!(f, "{:?}", stringify!(TraderId)) }
75}
76
77impl Trader {
78 #[must_use]
80 pub fn new(
81 trader_id: TraderId,
82 instance_id: UUID4,
83 environment: Environment,
84 clock: Rc<RefCell<dyn Clock>>,
85 cache: Rc<RefCell<Cache>>,
86 ) -> Self {
87 let ts_created = clock.borrow().timestamp_ns();
88
89 Self {
90 trader_id,
91 instance_id,
92 environment,
93 state: ComponentState::PreInitialized,
94 clock,
95 cache,
96 actor_ids: Vec::new(),
97 strategies: HashMap::new(),
98 exec_algorithms: HashMap::new(),
99 clocks: HashMap::new(),
100 ts_created,
101 ts_started: None,
102 ts_stopped: None,
103 }
104 }
105
106 #[must_use]
108 pub const fn trader_id(&self) -> TraderId {
109 self.trader_id
110 }
111
112 #[must_use]
114 pub const fn instance_id(&self) -> UUID4 {
115 self.instance_id
116 }
117
118 #[must_use]
120 pub const fn environment(&self) -> Environment {
121 self.environment
122 }
123
124 #[must_use]
126 pub const fn state(&self) -> ComponentState {
127 self.state
128 }
129
130 #[must_use]
132 pub const fn ts_created(&self) -> UnixNanos {
133 self.ts_created
134 }
135
136 #[must_use]
138 pub const fn ts_started(&self) -> Option<UnixNanos> {
139 self.ts_started
140 }
141
142 #[must_use]
144 pub const fn ts_stopped(&self) -> Option<UnixNanos> {
145 self.ts_stopped
146 }
147
148 #[must_use]
150 pub const fn actor_count(&self) -> usize {
151 self.actor_ids.len()
152 }
153
154 #[must_use]
156 pub fn strategy_count(&self) -> usize {
157 self.strategies.len()
158 }
159
160 #[must_use]
162 pub fn exec_algorithm_count(&self) -> usize {
163 self.exec_algorithms.len()
164 }
165
166 #[must_use]
168 pub fn component_count(&self) -> usize {
169 self.actor_ids.len() + self.strategies.len() + self.exec_algorithms.len()
170 }
171
172 #[must_use]
174 pub fn actor_ids(&self) -> Vec<ActorId> {
175 self.actor_ids.clone()
176 }
177
178 #[must_use]
180 pub fn strategy_ids(&self) -> Vec<StrategyId> {
181 self.strategies.keys().copied().collect()
182 }
183
184 #[must_use]
186 pub fn exec_algorithm_ids(&self) -> Vec<ExecAlgorithmId> {
187 self.exec_algorithms.keys().copied().collect()
188 }
189
190 fn create_component_clock(&self) -> Rc<RefCell<dyn Clock>> {
195 match self.environment {
196 Environment::Backtest => {
197 Rc::new(RefCell::new(TestClock::new()))
199 }
200 Environment::Live | Environment::Sandbox => {
201 self.clock.clone()
203 }
204 }
205 }
206
207 pub fn add_actor<T>(&mut self, actor: T) -> anyhow::Result<()>
215 where
216 T: DataActor + Component + Debug + 'static,
217 {
218 self.validate_component_registration()?;
219
220 let actor_id = actor.actor_id();
221
222 if self.actor_ids.contains(&actor_id) {
224 anyhow::bail!("Actor '{actor_id}' is already registered");
225 }
226
227 let clock = self.create_component_clock();
228 let component_id = ComponentId::new(actor_id.inner().as_str());
229 self.clocks.insert(component_id, clock.clone());
230
231 let mut actor_mut = actor;
232 actor_mut.register(self.trader_id, clock, self.cache.clone())?;
233
234 self.add_registered_actor(actor_mut)
235 }
236
237 pub fn add_actor_from_factory<F, T>(&mut self, factory: F) -> anyhow::Result<()>
249 where
250 F: FnOnce() -> anyhow::Result<T>,
251 T: DataActor + Component + Debug + 'static,
252 {
253 let actor = factory()?;
254
255 self.add_actor(actor)
256 }
257
258 pub fn add_registered_actor<T>(&mut self, actor: T) -> anyhow::Result<()>
265 where
266 T: DataActor + Component + Debug + 'static,
267 {
268 let actor_id = actor.actor_id();
269 let mem_addr = actor.mem_address();
270
271 register_component_actor(actor);
273
274 self.actor_ids.push(actor_id);
276
277 log::info!(
278 "Registered '{actor_id}' at mem_addr {mem_addr} with trader {}",
279 self.trader_id
280 );
281
282 Ok(())
283 }
284
285 pub fn add_actor_id_for_lifecycle(&mut self, actor_id: ActorId) -> anyhow::Result<()> {
295 if self.actor_ids.contains(&actor_id) {
297 anyhow::bail!("Actor '{actor_id}' is already tracked by trader");
298 }
299
300 self.actor_ids.push(actor_id);
302
303 log::debug!(
304 "Added actor ID '{actor_id}' to trader {} for lifecycle management",
305 self.trader_id
306 );
307
308 Ok(())
309 }
310
311 pub fn add_strategy(&mut self, mut strategy: Box<dyn Component>) -> anyhow::Result<()> {
319 self.validate_component_registration()?;
320
321 let strategy_id = StrategyId::from(strategy.component_id().inner().as_str());
322
323 if self.strategies.contains_key(&strategy_id) {
325 anyhow::bail!("Strategy '{strategy_id}' is already registered");
326 }
327
328 let clock = self.create_component_clock();
329 let component_id = strategy.component_id();
330 self.clocks.insert(component_id, clock.clone());
331
332 strategy.register(self.trader_id, clock, self.cache.clone())?;
333
334 self.strategies.insert(strategy_id, strategy);
335 log::info!(
336 "Registered strategy '{strategy_id}' with trader {}",
337 self.trader_id
338 );
339
340 Ok(())
341 }
342
343 pub fn add_exec_algorithm(
351 &mut self,
352 mut exec_algorithm: Box<dyn Component>,
353 ) -> anyhow::Result<()> {
354 self.validate_component_registration()?;
355
356 let exec_algorithm_id =
357 ExecAlgorithmId::from(exec_algorithm.component_id().inner().as_str());
358
359 if self.exec_algorithms.contains_key(&exec_algorithm_id) {
361 anyhow::bail!("Execution algorithm '{exec_algorithm_id}' is already registered");
362 }
363
364 let clock = self.create_component_clock();
365 let component_id = exec_algorithm.component_id();
366 self.clocks.insert(component_id, clock.clone());
367
368 exec_algorithm.register(self.trader_id, clock, self.cache.clone())?;
369
370 self.exec_algorithms
371 .insert(exec_algorithm_id, exec_algorithm);
372 log::info!(
373 "Registered execution algorithm '{exec_algorithm_id}' with trader {}",
374 self.trader_id
375 );
376
377 Ok(())
378 }
379
380 fn validate_component_registration(&self) -> anyhow::Result<()> {
382 match self.state {
383 ComponentState::PreInitialized | ComponentState::Ready | ComponentState::Stopped => {
384 Ok(())
385 }
386 ComponentState::Running => {
387 anyhow::bail!("Cannot add components while trader is running")
388 }
389 ComponentState::Disposed => {
390 anyhow::bail!("Cannot add components to disposed trader")
391 }
392 _ => anyhow::bail!("Cannot add components in current state: {}", self.state),
393 }
394 }
395
396 pub fn start_components(&mut self) -> anyhow::Result<()> {
402 for actor_id in &self.actor_ids {
404 log::debug!("Starting actor '{actor_id}'");
405 start_component(&actor_id.inner())?;
406 }
407
408 for strategy_id in &mut self.strategies.keys() {
409 log::debug!("Starting strategy '{strategy_id}'");
410 }
412
413 for exec_algorithm_id in &mut self.exec_algorithms.keys() {
414 log::debug!("Starting execution algorithm '{exec_algorithm_id}'");
415 }
417
418 Ok(())
419 }
420
421 pub fn stop_components(&mut self) -> anyhow::Result<()> {
427 for actor_id in &self.actor_ids {
428 log::debug!("Stopping actor '{actor_id}'");
429 stop_component(&actor_id.inner())?;
430 }
431
432 for exec_algorithm_id in &mut self.exec_algorithms.keys() {
433 log::debug!("Stopping execution algorithm '{exec_algorithm_id}'");
434 }
436
437 for strategy_id in &mut self.strategies.keys() {
438 log::debug!("Stopping strategy '{strategy_id}'");
439 }
441
442 Ok(())
443 }
444
445 pub fn reset_components(&mut self) -> anyhow::Result<()> {
451 for actor_id in &self.actor_ids {
453 log::debug!("Resetting actor '{actor_id}'");
454 reset_component(&actor_id.inner())?;
455 }
456
457 for strategy_id in &mut self.strategies.keys() {
458 log::debug!("Resetting strategy '{strategy_id}'");
459 }
461
462 for exec_algorithm_id in &mut self.exec_algorithms.keys() {
463 log::debug!("Resetting execution algorithm '{exec_algorithm_id}'");
464 }
466
467 Ok(())
468 }
469
470 pub fn dispose_components(&mut self) -> anyhow::Result<()> {
476 for actor_id in &self.actor_ids {
478 log::debug!("Disposing actor '{actor_id}'");
479 dispose_component(&actor_id.inner())?;
480 }
481
482 for strategy_id in &mut self.strategies.keys() {
483 log::debug!("Disposing strategy '{strategy_id}'");
484 }
486
487 for exec_algorithm_id in &mut self.exec_algorithms.keys() {
488 log::debug!("Disposing execution algorithm '{exec_algorithm_id}'");
489 }
491
492 self.actor_ids.clear();
493 self.strategies.clear();
494 self.exec_algorithms.clear();
495 self.clocks.clear();
496
497 Ok(())
498 }
499
500 pub fn initialize(&mut self) -> anyhow::Result<()> {
508 let new_state = self.state.transition(&ComponentTrigger::Initialize)?;
509 self.state = new_state;
510
511 Ok(())
512 }
513
514 fn on_start(&mut self) -> anyhow::Result<()> {
515 self.start_components()?;
516
517 self.ts_started = Some(self.clock.borrow().timestamp_ns());
519
520 Ok(())
521 }
522
523 fn on_stop(&mut self) -> anyhow::Result<()> {
524 self.stop_components()?;
525
526 self.ts_stopped = Some(self.clock.borrow().timestamp_ns());
527
528 Ok(())
529 }
530
531 fn on_reset(&mut self) -> anyhow::Result<()> {
532 self.reset_components()?;
533
534 self.ts_started = None;
535 self.ts_stopped = None;
536
537 Ok(())
538 }
539
540 fn on_dispose(&mut self) -> anyhow::Result<()> {
541 if self.is_running() {
542 self.stop()?;
543 }
544
545 self.dispose_components()?;
546
547 Ok(())
548 }
549}
550
551impl Component for Trader {
552 fn component_id(&self) -> ComponentId {
553 ComponentId::new(format!("Trader-{}", self.trader_id))
554 }
555
556 fn state(&self) -> ComponentState {
557 self.state
558 }
559
560 fn transition_state(&mut self, trigger: ComponentTrigger) -> anyhow::Result<()> {
561 self.state = self.state.transition(&trigger)?;
562 log::info!("{}", self.state.variant_name());
563 Ok(())
564 }
565
566 fn register(
567 &mut self,
568 _trader_id: TraderId,
569 _clock: Rc<RefCell<dyn Clock>>,
570 _cache: Rc<RefCell<Cache>>,
571 ) -> anyhow::Result<()> {
572 anyhow::bail!("Trader cannot register with itself")
573 }
574
575 fn on_start(&mut self) -> anyhow::Result<()> {
576 Self::on_start(self)
577 }
578
579 fn on_stop(&mut self) -> anyhow::Result<()> {
580 Self::on_stop(self)
581 }
582
583 fn on_reset(&mut self) -> anyhow::Result<()> {
584 Self::on_reset(self)
585 }
586
587 fn on_dispose(&mut self) -> anyhow::Result<()> {
588 Self::on_dispose(self)
589 }
590}
591
592#[cfg(test)]
597mod tests {
598 use std::{
599 cell::RefCell,
600 ops::{Deref, DerefMut},
601 rc::Rc,
602 };
603
604 use nautilus_common::{
605 actor::{DataActorCore, data_actor::DataActorConfig},
606 cache::Cache,
607 clock::TestClock,
608 enums::{ComponentState, Environment},
609 msgbus::MessageBus,
610 };
611 use nautilus_core::UUID4;
612 use nautilus_data::engine::{DataEngine, config::DataEngineConfig};
613 use nautilus_execution::engine::{ExecutionEngine, config::ExecutionEngineConfig};
614 use nautilus_model::identifiers::{ActorId, ComponentId, TraderId};
615 use nautilus_portfolio::portfolio::Portfolio;
616 use nautilus_risk::engine::{RiskEngine, config::RiskEngineConfig};
617 use rstest::rstest;
618
619 use super::*;
620
621 #[derive(Debug)]
623 struct TestDataActor {
624 core: DataActorCore,
625 }
626
627 impl TestDataActor {
628 fn new(config: DataActorConfig) -> Self {
629 Self {
630 core: DataActorCore::new(config),
631 }
632 }
633 }
634
635 impl DataActor for TestDataActor {}
636
637 impl Deref for TestDataActor {
638 type Target = DataActorCore;
639 fn deref(&self) -> &Self::Target {
640 &self.core
641 }
642 }
643
644 impl DerefMut for TestDataActor {
645 fn deref_mut(&mut self) -> &mut Self::Target {
646 &mut self.core
647 }
648 }
649
650 #[derive(Debug)]
652 struct MockComponent {
653 id: ComponentId,
654 state: ComponentState,
655 }
656
657 impl MockComponent {
658 fn new(id: &str) -> Self {
659 Self {
660 id: ComponentId::from(id),
661 state: ComponentState::PreInitialized,
662 }
663 }
664 }
665
666 impl Component for MockComponent {
667 fn component_id(&self) -> ComponentId {
668 self.id
669 }
670
671 fn state(&self) -> ComponentState {
672 self.state
673 }
674
675 fn transition_state(&mut self, trigger: ComponentTrigger) -> anyhow::Result<()> {
676 self.state = self.state.transition(&trigger)?;
677 log::info!("{}", self.state.variant_name());
678 Ok(())
679 }
680
681 fn register(
682 &mut self,
683 _trader_id: TraderId,
684 _clock: Rc<RefCell<dyn Clock>>,
685 _cache: Rc<RefCell<Cache>>,
686 ) -> anyhow::Result<()> {
687 Ok(())
689 }
690
691 fn on_start(&mut self) -> anyhow::Result<()> {
692 Ok(())
693 }
694 }
695
696 #[allow(clippy::type_complexity)]
697 fn create_trader_components() -> (
698 Rc<RefCell<MessageBus>>,
699 Rc<RefCell<Cache>>,
700 Rc<RefCell<Portfolio>>,
701 Rc<RefCell<DataEngine>>,
702 Rc<RefCell<RiskEngine>>,
703 Rc<RefCell<ExecutionEngine>>,
704 Rc<RefCell<TestClock>>,
705 ) {
706 let trader_id = TraderId::default();
707 let instance_id = UUID4::new();
708 let clock = Rc::new(RefCell::new(TestClock::new()));
709 clock.borrow_mut().set_time(1_000_000_000u64.into());
711 let msgbus = Rc::new(RefCell::new(MessageBus::new(
712 trader_id,
713 instance_id,
714 Some("test".to_string()),
715 None,
716 )));
717 let cache = Rc::new(RefCell::new(Cache::new(None, None)));
718 let portfolio = Rc::new(RefCell::new(Portfolio::new(
719 cache.clone(),
720 clock.clone() as Rc<RefCell<dyn Clock>>,
721 None,
722 )));
723 let data_engine = Rc::new(RefCell::new(DataEngine::new(
724 clock.clone(),
725 cache.clone(),
726 Some(DataEngineConfig::default()),
727 )));
728
729 let risk_cache = Rc::new(RefCell::new(Cache::new(None, None)));
731 let risk_clock = Rc::new(RefCell::new(TestClock::new()));
732 let risk_portfolio = Portfolio::new(
733 risk_cache.clone(),
734 risk_clock.clone() as Rc<RefCell<dyn Clock>>,
735 None,
736 );
737 let risk_engine = Rc::new(RefCell::new(RiskEngine::new(
738 RiskEngineConfig::default(),
739 risk_portfolio,
740 risk_clock as Rc<RefCell<dyn Clock>>,
741 risk_cache,
742 )));
743 let exec_engine = Rc::new(RefCell::new(ExecutionEngine::new(
744 clock.clone(),
745 cache.clone(),
746 Some(ExecutionEngineConfig::default()),
747 )));
748
749 (
750 msgbus,
751 cache,
752 portfolio,
753 data_engine,
754 risk_engine,
755 exec_engine,
756 clock,
757 )
758 }
759
760 #[rstest]
761 fn test_trader_creation() {
762 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
763 create_trader_components();
764 let trader_id = TraderId::default();
765 let instance_id = UUID4::new();
766
767 let trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
768
769 assert_eq!(trader.trader_id(), trader_id);
770 assert_eq!(trader.instance_id(), instance_id);
771 assert_eq!(trader.environment(), Environment::Backtest);
772 assert_eq!(trader.state(), ComponentState::PreInitialized);
773 assert_eq!(trader.actor_count(), 0);
774 assert_eq!(trader.strategy_count(), 0);
775 assert_eq!(trader.exec_algorithm_count(), 0);
776 assert_eq!(trader.component_count(), 0);
777 assert!(!trader.is_running());
778 assert!(!trader.is_stopped());
779 assert!(!trader.is_disposed());
780 assert!(trader.ts_created() > 0);
781 assert!(trader.ts_started().is_none());
782 assert!(trader.ts_stopped().is_none());
783 }
784
785 #[rstest]
786 fn test_trader_component_id() {
787 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
788 create_trader_components();
789 let trader_id = TraderId::from("TRADER-001");
790 let instance_id = UUID4::new();
791
792 let trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
793
794 assert_eq!(
795 trader.component_id(),
796 ComponentId::from("Trader-TRADER-001")
797 );
798 }
799
800 #[rstest]
801 fn test_add_actor_success() {
802 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
803 create_trader_components();
804 let trader_id = TraderId::default();
805 let instance_id = UUID4::new();
806
807 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
808
809 let actor = TestDataActor::new(DataActorConfig::default());
810 let actor_id = actor.actor_id();
811
812 let result = trader.add_actor(actor);
813 assert!(result.is_ok());
814 assert_eq!(trader.actor_count(), 1);
815 assert_eq!(trader.component_count(), 1);
816 assert!(trader.actor_ids().contains(&actor_id));
817 }
818
819 #[rstest]
820 fn test_add_duplicate_actor_fails() {
821 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
822 create_trader_components();
823 let trader_id = TraderId::default();
824 let instance_id = UUID4::new();
825
826 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
827
828 let config = DataActorConfig {
829 actor_id: Some(ActorId::from("TestActor")),
830 ..Default::default()
831 };
832 let actor1 = TestDataActor::new(config.clone());
833 let actor2 = TestDataActor::new(config);
834
835 assert!(trader.add_actor(actor1).is_ok());
837 assert_eq!(trader.actor_count(), 1);
838
839 let result = trader.add_actor(actor2);
841 assert!(result.is_err());
842 assert!(
843 result
844 .unwrap_err()
845 .to_string()
846 .contains("already registered")
847 );
848 assert_eq!(trader.actor_count(), 1);
849 }
850
851 #[rstest]
852 fn test_add_strategy_success() {
853 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
854 create_trader_components();
855 let trader_id = TraderId::default();
856 let instance_id = UUID4::new();
857
858 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
859
860 let strategy = Box::new(MockComponent::new("Test-Strategy"));
861 let strategy_id = StrategyId::from(strategy.component_id().inner().as_str());
862
863 let result = trader.add_strategy(strategy);
864 assert!(result.is_ok());
865 assert_eq!(trader.strategy_count(), 1);
866 assert_eq!(trader.component_count(), 1);
867 assert!(trader.strategy_ids().contains(&strategy_id));
868 }
869
870 #[rstest]
871 fn test_add_exec_algorithm_success() {
872 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
873 create_trader_components();
874 let trader_id = TraderId::default();
875 let instance_id = UUID4::new();
876
877 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
878
879 let exec_algorithm = Box::new(MockComponent::new("TestExecAlgorithm"));
880 let exec_algorithm_id =
881 ExecAlgorithmId::from(exec_algorithm.component_id().inner().as_str());
882
883 let result = trader.add_exec_algorithm(exec_algorithm);
884 assert!(result.is_ok());
885 assert_eq!(trader.exec_algorithm_count(), 1);
886 assert_eq!(trader.component_count(), 1);
887 assert!(trader.exec_algorithm_ids().contains(&exec_algorithm_id));
888 }
889
890 #[rstest]
891 fn test_component_lifecycle() {
892 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
893 create_trader_components();
894 let trader_id = TraderId::default();
895 let instance_id = UUID4::new();
896
897 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
898
899 let actor = TestDataActor::new(DataActorConfig::default());
901 let strategy = Box::new(MockComponent::new("Test-Strategy"));
902 let exec_algorithm = Box::new(MockComponent::new("TestExecAlgorithm"));
903
904 assert!(trader.add_actor(actor).is_ok());
905 assert!(trader.add_strategy(strategy).is_ok());
906 assert!(trader.add_exec_algorithm(exec_algorithm).is_ok());
907 assert_eq!(trader.component_count(), 3);
908
909 assert!(trader.start_components().is_ok());
911
912 assert!(trader.stop_components().is_ok());
914
915 assert!(trader.reset_components().is_ok());
917
918 assert!(trader.dispose_components().is_ok());
920 assert_eq!(trader.component_count(), 0);
921 }
922
923 #[rstest]
924 fn test_trader_component_lifecycle() {
925 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
926 create_trader_components();
927 let trader_id = TraderId::default();
928 let instance_id = UUID4::new();
929
930 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
931
932 assert_eq!(trader.state(), ComponentState::PreInitialized);
934 assert!(!trader.is_running());
935 assert!(!trader.is_stopped());
936 assert!(!trader.is_disposed());
937
938 assert!(trader.start().is_err());
940
941 trader.initialize().unwrap();
943
944 assert!(trader.start().is_ok());
946 assert_eq!(trader.state(), ComponentState::Running);
947 assert!(trader.is_running());
948 assert!(trader.ts_started().is_some());
949
950 assert!(trader.stop().is_ok());
952 assert_eq!(trader.state(), ComponentState::Stopped);
953 assert!(trader.is_stopped());
954 assert!(trader.ts_stopped().is_some());
955
956 assert!(trader.reset().is_ok());
958 assert_eq!(trader.state(), ComponentState::Ready);
959 assert!(trader.ts_started().is_none());
960 assert!(trader.ts_stopped().is_none());
961
962 assert!(trader.dispose().is_ok());
964 assert_eq!(trader.state(), ComponentState::Disposed);
965 assert!(trader.is_disposed());
966 }
967
968 #[rstest]
969 fn test_cannot_add_components_while_running() {
970 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
971 create_trader_components();
972 let trader_id = TraderId::default();
973 let instance_id = UUID4::new();
974
975 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
976
977 trader.state = ComponentState::Running;
979
980 let actor = TestDataActor::new(DataActorConfig::default());
981 let result = trader.add_actor(actor);
982 assert!(result.is_err());
983 assert!(
984 result
985 .unwrap_err()
986 .to_string()
987 .contains("while trader is running")
988 );
989 }
990
991 #[rstest]
992 fn test_create_component_clock_backtest_vs_live() {
993 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
994 create_trader_components();
995 let trader_id = TraderId::default();
996 let instance_id = UUID4::new();
997
998 let trader_backtest = Trader::new(
1000 trader_id,
1001 instance_id,
1002 Environment::Backtest,
1003 clock.clone(),
1004 cache.clone(),
1005 );
1006
1007 let backtest_clock = trader_backtest.create_component_clock();
1008 assert_ne!(
1010 backtest_clock.as_ptr() as *const _,
1011 clock.as_ptr() as *const _
1012 );
1013
1014 let trader_live = Trader::new(
1016 trader_id,
1017 instance_id,
1018 Environment::Live,
1019 clock.clone(),
1020 cache,
1021 );
1022
1023 let live_clock = trader_live.create_component_clock();
1024 assert_eq!(live_clock.as_ptr() as *const _, clock.as_ptr() as *const _);
1026 }
1027}