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<()>
264 where
265 T: DataActor + Component + Debug + 'static,
266 {
267 let actor_id = actor.actor_id();
268 let mem_addr = actor.mem_address();
269
270 register_component_actor(actor);
272
273 self.actor_ids.push(actor_id);
275
276 log::info!(
277 "Registered '{actor_id}' at mem_addr {mem_addr} with trader {}",
278 self.trader_id
279 );
280
281 Ok(())
282 }
283
284 pub fn add_actor_id_for_lifecycle(&mut self, actor_id: ActorId) -> anyhow::Result<()> {
294 if self.actor_ids.contains(&actor_id) {
296 anyhow::bail!("Actor '{actor_id}' is already tracked by trader");
297 }
298
299 self.actor_ids.push(actor_id);
301
302 log::debug!(
303 "Added actor ID '{actor_id}' to trader {} for lifecycle management",
304 self.trader_id
305 );
306
307 Ok(())
308 }
309
310 pub fn add_strategy(&mut self, mut strategy: Box<dyn Component>) -> anyhow::Result<()> {
318 self.validate_component_registration()?;
319
320 let strategy_id = StrategyId::from(strategy.component_id().inner().as_str());
321
322 if self.strategies.contains_key(&strategy_id) {
324 anyhow::bail!("Strategy '{strategy_id}' is already registered");
325 }
326
327 let clock = self.create_component_clock();
328 let component_id = strategy.component_id();
329 self.clocks.insert(component_id, clock.clone());
330
331 strategy.register(self.trader_id, clock, self.cache.clone())?;
332
333 self.strategies.insert(strategy_id, strategy);
334 log::info!(
335 "Registered strategy '{strategy_id}' with trader {}",
336 self.trader_id
337 );
338
339 Ok(())
340 }
341
342 pub fn add_exec_algorithm(
350 &mut self,
351 mut exec_algorithm: Box<dyn Component>,
352 ) -> anyhow::Result<()> {
353 self.validate_component_registration()?;
354
355 let exec_algorithm_id =
356 ExecAlgorithmId::from(exec_algorithm.component_id().inner().as_str());
357
358 if self.exec_algorithms.contains_key(&exec_algorithm_id) {
360 anyhow::bail!("Execution algorithm '{exec_algorithm_id}' is already registered");
361 }
362
363 let clock = self.create_component_clock();
364 let component_id = exec_algorithm.component_id();
365 self.clocks.insert(component_id, clock.clone());
366
367 exec_algorithm.register(self.trader_id, clock, self.cache.clone())?;
368
369 self.exec_algorithms
370 .insert(exec_algorithm_id, exec_algorithm);
371 log::info!(
372 "Registered execution algorithm '{exec_algorithm_id}' with trader {}",
373 self.trader_id
374 );
375
376 Ok(())
377 }
378
379 fn validate_component_registration(&self) -> anyhow::Result<()> {
381 match self.state {
382 ComponentState::PreInitialized | ComponentState::Ready | ComponentState::Stopped => {
383 Ok(())
384 }
385 ComponentState::Running => {
386 anyhow::bail!("Cannot add components while trader is running")
387 }
388 ComponentState::Disposed => {
389 anyhow::bail!("Cannot add components to disposed trader")
390 }
391 _ => anyhow::bail!("Cannot add components in current state: {}", self.state),
392 }
393 }
394
395 pub fn start_components(&mut self) -> anyhow::Result<()> {
401 for actor_id in &self.actor_ids {
403 log::debug!("Starting actor '{actor_id}'");
404 start_component(&actor_id.inner())?;
405 }
406
407 for strategy_id in &mut self.strategies.keys() {
408 log::debug!("Starting strategy '{strategy_id}'");
409 }
411
412 for exec_algorithm_id in &mut self.exec_algorithms.keys() {
413 log::debug!("Starting execution algorithm '{exec_algorithm_id}'");
414 }
416
417 Ok(())
418 }
419
420 pub fn stop_components(&mut self) -> anyhow::Result<()> {
426 for actor_id in &self.actor_ids {
427 log::debug!("Stopping actor '{actor_id}'");
428 stop_component(&actor_id.inner())?;
429 }
430
431 for exec_algorithm_id in &mut self.exec_algorithms.keys() {
432 log::debug!("Stopping execution algorithm '{exec_algorithm_id}'");
433 }
435
436 for strategy_id in &mut self.strategies.keys() {
437 log::debug!("Stopping strategy '{strategy_id}'");
438 }
440
441 Ok(())
442 }
443
444 pub fn reset_components(&mut self) -> anyhow::Result<()> {
450 for actor_id in &self.actor_ids {
452 log::debug!("Resetting actor '{actor_id}'");
453 reset_component(&actor_id.inner())?;
454 }
455
456 for strategy_id in &mut self.strategies.keys() {
457 log::debug!("Resetting strategy '{strategy_id}'");
458 }
460
461 for exec_algorithm_id in &mut self.exec_algorithms.keys() {
462 log::debug!("Resetting execution algorithm '{exec_algorithm_id}'");
463 }
465
466 Ok(())
467 }
468
469 pub fn dispose_components(&mut self) -> anyhow::Result<()> {
475 for actor_id in &self.actor_ids {
477 log::debug!("Disposing actor '{actor_id}'");
478 dispose_component(&actor_id.inner())?;
479 }
480
481 for strategy_id in &mut self.strategies.keys() {
482 log::debug!("Disposing strategy '{strategy_id}'");
483 }
485
486 for exec_algorithm_id in &mut self.exec_algorithms.keys() {
487 log::debug!("Disposing execution algorithm '{exec_algorithm_id}'");
488 }
490
491 self.actor_ids.clear();
492 self.strategies.clear();
493 self.exec_algorithms.clear();
494 self.clocks.clear();
495
496 Ok(())
497 }
498
499 pub fn initialize(&mut self) -> anyhow::Result<()> {
507 let new_state = self.state.transition(&ComponentTrigger::Initialize)?;
508 self.state = new_state;
509
510 Ok(())
511 }
512
513 fn on_start(&mut self) -> anyhow::Result<()> {
514 self.start_components()?;
515
516 self.ts_started = Some(self.clock.borrow().timestamp_ns());
518
519 Ok(())
520 }
521
522 fn on_stop(&mut self) -> anyhow::Result<()> {
523 self.stop_components()?;
524
525 self.ts_stopped = Some(self.clock.borrow().timestamp_ns());
526
527 Ok(())
528 }
529
530 fn on_reset(&mut self) -> anyhow::Result<()> {
531 self.reset_components()?;
532
533 self.ts_started = None;
534 self.ts_stopped = None;
535
536 Ok(())
537 }
538
539 fn on_dispose(&mut self) -> anyhow::Result<()> {
540 if self.is_running() {
541 self.stop()?;
542 }
543
544 self.dispose_components()?;
545
546 Ok(())
547 }
548}
549
550impl Component for Trader {
551 fn component_id(&self) -> ComponentId {
552 ComponentId::new(format!("Trader-{}", self.trader_id))
553 }
554
555 fn state(&self) -> ComponentState {
556 self.state
557 }
558
559 fn transition_state(&mut self, trigger: ComponentTrigger) -> anyhow::Result<()> {
560 self.state = self.state.transition(&trigger)?;
561 log::info!("{}", self.state.variant_name());
562 Ok(())
563 }
564
565 fn register(
566 &mut self,
567 _trader_id: TraderId,
568 _clock: Rc<RefCell<dyn Clock>>,
569 _cache: Rc<RefCell<Cache>>,
570 ) -> anyhow::Result<()> {
571 anyhow::bail!("Trader cannot register with itself")
572 }
573
574 fn on_start(&mut self) -> anyhow::Result<()> {
575 Self::on_start(self)
576 }
577
578 fn on_stop(&mut self) -> anyhow::Result<()> {
579 Self::on_stop(self)
580 }
581
582 fn on_reset(&mut self) -> anyhow::Result<()> {
583 Self::on_reset(self)
584 }
585
586 fn on_dispose(&mut self) -> anyhow::Result<()> {
587 Self::on_dispose(self)
588 }
589}
590
591#[cfg(test)]
596mod tests {
597 use std::{
598 cell::RefCell,
599 ops::{Deref, DerefMut},
600 rc::Rc,
601 };
602
603 use nautilus_common::{
604 actor::{DataActorCore, data_actor::DataActorConfig},
605 cache::Cache,
606 clock::TestClock,
607 enums::{ComponentState, Environment},
608 msgbus::MessageBus,
609 };
610 use nautilus_core::UUID4;
611 use nautilus_data::engine::{DataEngine, config::DataEngineConfig};
612 use nautilus_execution::engine::{ExecutionEngine, config::ExecutionEngineConfig};
613 use nautilus_model::identifiers::{ActorId, ComponentId, TraderId};
614 use nautilus_portfolio::portfolio::Portfolio;
615 use nautilus_risk::engine::{RiskEngine, config::RiskEngineConfig};
616 use rstest::rstest;
617
618 use super::*;
619
620 #[derive(Debug)]
622 struct TestDataActor {
623 core: DataActorCore,
624 }
625
626 impl TestDataActor {
627 fn new(config: DataActorConfig) -> Self {
628 Self {
629 core: DataActorCore::new(config),
630 }
631 }
632 }
633
634 impl DataActor for TestDataActor {}
635
636 impl Deref for TestDataActor {
637 type Target = DataActorCore;
638 fn deref(&self) -> &Self::Target {
639 &self.core
640 }
641 }
642
643 impl DerefMut for TestDataActor {
644 fn deref_mut(&mut self) -> &mut Self::Target {
645 &mut self.core
646 }
647 }
648
649 #[derive(Debug)]
651 struct MockComponent {
652 id: ComponentId,
653 state: ComponentState,
654 }
655
656 impl MockComponent {
657 fn new(id: &str) -> Self {
658 Self {
659 id: ComponentId::from(id),
660 state: ComponentState::PreInitialized,
661 }
662 }
663 }
664
665 impl Component for MockComponent {
666 fn component_id(&self) -> ComponentId {
667 self.id
668 }
669
670 fn state(&self) -> ComponentState {
671 self.state
672 }
673
674 fn transition_state(&mut self, trigger: ComponentTrigger) -> anyhow::Result<()> {
675 self.state = self.state.transition(&trigger)?;
676 log::info!("{}", self.state.variant_name());
677 Ok(())
678 }
679
680 fn register(
681 &mut self,
682 _trader_id: TraderId,
683 _clock: Rc<RefCell<dyn Clock>>,
684 _cache: Rc<RefCell<Cache>>,
685 ) -> anyhow::Result<()> {
686 Ok(())
688 }
689
690 fn on_start(&mut self) -> anyhow::Result<()> {
691 Ok(())
692 }
693 }
694
695 #[allow(clippy::type_complexity)]
696 fn create_trader_components() -> (
697 Rc<RefCell<MessageBus>>,
698 Rc<RefCell<Cache>>,
699 Rc<RefCell<Portfolio>>,
700 Rc<RefCell<DataEngine>>,
701 Rc<RefCell<RiskEngine>>,
702 Rc<RefCell<ExecutionEngine>>,
703 Rc<RefCell<TestClock>>,
704 ) {
705 let trader_id = TraderId::default();
706 let instance_id = UUID4::new();
707 let clock = Rc::new(RefCell::new(TestClock::new()));
708 clock.borrow_mut().set_time(1_000_000_000u64.into());
710 let msgbus = Rc::new(RefCell::new(MessageBus::new(
711 trader_id,
712 instance_id,
713 Some("test".to_string()),
714 None,
715 )));
716 let cache = Rc::new(RefCell::new(Cache::new(None, None)));
717 let portfolio = Rc::new(RefCell::new(Portfolio::new(
718 cache.clone(),
719 clock.clone() as Rc<RefCell<dyn Clock>>,
720 None,
721 )));
722 let data_engine = Rc::new(RefCell::new(DataEngine::new(
723 clock.clone(),
724 cache.clone(),
725 Some(DataEngineConfig::default()),
726 )));
727
728 let risk_cache = Rc::new(RefCell::new(Cache::new(None, None)));
730 let risk_clock = Rc::new(RefCell::new(TestClock::new()));
731 let risk_portfolio = Portfolio::new(
732 risk_cache.clone(),
733 risk_clock.clone() as Rc<RefCell<dyn Clock>>,
734 None,
735 );
736 let risk_engine = Rc::new(RefCell::new(RiskEngine::new(
737 RiskEngineConfig::default(),
738 risk_portfolio,
739 risk_clock as Rc<RefCell<dyn Clock>>,
740 risk_cache,
741 )));
742 let exec_engine = Rc::new(RefCell::new(ExecutionEngine::new(
743 clock.clone(),
744 cache.clone(),
745 Some(ExecutionEngineConfig::default()),
746 )));
747
748 (
749 msgbus,
750 cache,
751 portfolio,
752 data_engine,
753 risk_engine,
754 exec_engine,
755 clock,
756 )
757 }
758
759 #[rstest]
760 fn test_trader_creation() {
761 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
762 create_trader_components();
763 let trader_id = TraderId::default();
764 let instance_id = UUID4::new();
765
766 let trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
767
768 assert_eq!(trader.trader_id(), trader_id);
769 assert_eq!(trader.instance_id(), instance_id);
770 assert_eq!(trader.environment(), Environment::Backtest);
771 assert_eq!(trader.state(), ComponentState::PreInitialized);
772 assert_eq!(trader.actor_count(), 0);
773 assert_eq!(trader.strategy_count(), 0);
774 assert_eq!(trader.exec_algorithm_count(), 0);
775 assert_eq!(trader.component_count(), 0);
776 assert!(!trader.is_running());
777 assert!(!trader.is_stopped());
778 assert!(!trader.is_disposed());
779 assert!(trader.ts_created() > 0);
780 assert!(trader.ts_started().is_none());
781 assert!(trader.ts_stopped().is_none());
782 }
783
784 #[rstest]
785 fn test_trader_component_id() {
786 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
787 create_trader_components();
788 let trader_id = TraderId::from("TRADER-001");
789 let instance_id = UUID4::new();
790
791 let trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
792
793 assert_eq!(
794 trader.component_id(),
795 ComponentId::from("Trader-TRADER-001")
796 );
797 }
798
799 #[rstest]
800 fn test_add_actor_success() {
801 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
802 create_trader_components();
803 let trader_id = TraderId::default();
804 let instance_id = UUID4::new();
805
806 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
807
808 let actor = TestDataActor::new(DataActorConfig::default());
809 let actor_id = actor.actor_id();
810
811 let result = trader.add_actor(actor);
812 assert!(result.is_ok());
813 assert_eq!(trader.actor_count(), 1);
814 assert_eq!(trader.component_count(), 1);
815 assert!(trader.actor_ids().contains(&actor_id));
816 }
817
818 #[rstest]
819 fn test_add_duplicate_actor_fails() {
820 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
821 create_trader_components();
822 let trader_id = TraderId::default();
823 let instance_id = UUID4::new();
824
825 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
826
827 let config = DataActorConfig {
828 actor_id: Some(ActorId::from("TestActor")),
829 ..Default::default()
830 };
831 let actor1 = TestDataActor::new(config.clone());
832 let actor2 = TestDataActor::new(config);
833
834 assert!(trader.add_actor(actor1).is_ok());
836 assert_eq!(trader.actor_count(), 1);
837
838 let result = trader.add_actor(actor2);
840 assert!(result.is_err());
841 assert!(
842 result
843 .unwrap_err()
844 .to_string()
845 .contains("already registered")
846 );
847 assert_eq!(trader.actor_count(), 1);
848 }
849
850 #[rstest]
851 fn test_add_strategy_success() {
852 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
853 create_trader_components();
854 let trader_id = TraderId::default();
855 let instance_id = UUID4::new();
856
857 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
858
859 let strategy = Box::new(MockComponent::new("Test-Strategy"));
860 let strategy_id = StrategyId::from(strategy.component_id().inner().as_str());
861
862 let result = trader.add_strategy(strategy);
863 assert!(result.is_ok());
864 assert_eq!(trader.strategy_count(), 1);
865 assert_eq!(trader.component_count(), 1);
866 assert!(trader.strategy_ids().contains(&strategy_id));
867 }
868
869 #[rstest]
870 fn test_add_exec_algorithm_success() {
871 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
872 create_trader_components();
873 let trader_id = TraderId::default();
874 let instance_id = UUID4::new();
875
876 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
877
878 let exec_algorithm = Box::new(MockComponent::new("TestExecAlgorithm"));
879 let exec_algorithm_id =
880 ExecAlgorithmId::from(exec_algorithm.component_id().inner().as_str());
881
882 let result = trader.add_exec_algorithm(exec_algorithm);
883 assert!(result.is_ok());
884 assert_eq!(trader.exec_algorithm_count(), 1);
885 assert_eq!(trader.component_count(), 1);
886 assert!(trader.exec_algorithm_ids().contains(&exec_algorithm_id));
887 }
888
889 #[rstest]
890 fn test_component_lifecycle() {
891 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
892 create_trader_components();
893 let trader_id = TraderId::default();
894 let instance_id = UUID4::new();
895
896 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
897
898 let actor = TestDataActor::new(DataActorConfig::default());
900 let strategy = Box::new(MockComponent::new("Test-Strategy"));
901 let exec_algorithm = Box::new(MockComponent::new("TestExecAlgorithm"));
902
903 assert!(trader.add_actor(actor).is_ok());
904 assert!(trader.add_strategy(strategy).is_ok());
905 assert!(trader.add_exec_algorithm(exec_algorithm).is_ok());
906 assert_eq!(trader.component_count(), 3);
907
908 assert!(trader.start_components().is_ok());
910
911 assert!(trader.stop_components().is_ok());
913
914 assert!(trader.reset_components().is_ok());
916
917 assert!(trader.dispose_components().is_ok());
919 assert_eq!(trader.component_count(), 0);
920 }
921
922 #[rstest]
923 fn test_trader_component_lifecycle() {
924 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
925 create_trader_components();
926 let trader_id = TraderId::default();
927 let instance_id = UUID4::new();
928
929 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
930
931 assert_eq!(trader.state(), ComponentState::PreInitialized);
933 assert!(!trader.is_running());
934 assert!(!trader.is_stopped());
935 assert!(!trader.is_disposed());
936
937 assert!(trader.start().is_err());
939
940 trader.initialize().unwrap();
942
943 assert!(trader.start().is_ok());
945 assert_eq!(trader.state(), ComponentState::Running);
946 assert!(trader.is_running());
947 assert!(trader.ts_started().is_some());
948
949 assert!(trader.stop().is_ok());
951 assert_eq!(trader.state(), ComponentState::Stopped);
952 assert!(trader.is_stopped());
953 assert!(trader.ts_stopped().is_some());
954
955 assert!(trader.reset().is_ok());
957 assert_eq!(trader.state(), ComponentState::Ready);
958 assert!(trader.ts_started().is_none());
959 assert!(trader.ts_stopped().is_none());
960
961 assert!(trader.dispose().is_ok());
963 assert_eq!(trader.state(), ComponentState::Disposed);
964 assert!(trader.is_disposed());
965 }
966
967 #[rstest]
968 fn test_cannot_add_components_while_running() {
969 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
970 create_trader_components();
971 let trader_id = TraderId::default();
972 let instance_id = UUID4::new();
973
974 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
975
976 trader.state = ComponentState::Running;
978
979 let actor = TestDataActor::new(DataActorConfig::default());
980 let result = trader.add_actor(actor);
981 assert!(result.is_err());
982 assert!(
983 result
984 .unwrap_err()
985 .to_string()
986 .contains("while trader is running")
987 );
988 }
989
990 #[rstest]
991 fn test_create_component_clock_backtest_vs_live() {
992 let (_msgbus, cache, _portfolio, _data_engine, _risk_engine, _exec_engine, clock) =
993 create_trader_components();
994 let trader_id = TraderId::default();
995 let instance_id = UUID4::new();
996
997 let trader_backtest = Trader::new(
999 trader_id,
1000 instance_id,
1001 Environment::Backtest,
1002 clock.clone(),
1003 cache.clone(),
1004 );
1005
1006 let backtest_clock = trader_backtest.create_component_clock();
1007 assert_ne!(
1009 backtest_clock.as_ptr() as *const _,
1010 clock.as_ptr() as *const _
1011 );
1012
1013 let trader_live = Trader::new(
1015 trader_id,
1016 instance_id,
1017 Environment::Live,
1018 clock.clone(),
1019 cache,
1020 );
1021
1022 let live_clock = trader_live.create_component_clock();
1023 assert_eq!(live_clock.as_ptr() as *const _, clock.as_ptr() as *const _);
1025 }
1026}