1#![allow(dead_code)]
24#![allow(unused_variables)]
25
26use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
27
28use nautilus_common::{
29 actor::DataActor,
30 cache::Cache,
31 clock::{Clock, TestClock},
32 component::{
33 Component, dispose_component, register_component_actor, reset_component, start_component,
34 stop_component,
35 },
36 enums::{ComponentState, ComponentTrigger, Environment},
37};
38use nautilus_core::{UUID4, UnixNanos};
39use nautilus_model::identifiers::{ActorId, ComponentId, ExecAlgorithmId, StrategyId, TraderId};
40
41pub struct Trader {
47 pub trader_id: TraderId,
49 pub instance_id: UUID4,
51 pub environment: Environment,
53 state: ComponentState,
55 clock: Rc<RefCell<dyn Clock>>,
57 cache: Rc<RefCell<Cache>>,
59 actor_ids: Vec<ActorId>,
61 strategies: HashMap<StrategyId, Box<dyn Component>>,
63 exec_algorithms: HashMap<ExecAlgorithmId, Box<dyn Component>>,
65 clocks: HashMap<ComponentId, Rc<RefCell<dyn Clock>>>, ts_created: UnixNanos,
69 ts_started: Option<UnixNanos>,
71 ts_stopped: Option<UnixNanos>,
73}
74
75impl Debug for Trader {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 write!(f, "{:?}", stringify!(TraderId)) }
79}
80
81impl Trader {
82 #[must_use]
84 pub fn new(
85 trader_id: TraderId,
86 instance_id: UUID4,
87 environment: Environment,
88 clock: Rc<RefCell<dyn Clock>>,
89 cache: Rc<RefCell<Cache>>,
90 ) -> Self {
91 let ts_created = clock.borrow().timestamp_ns();
92
93 Self {
94 trader_id,
95 instance_id,
96 environment,
97 state: ComponentState::PreInitialized,
98 clock,
99 cache,
100 actor_ids: Vec::new(),
101 strategies: HashMap::new(),
102 exec_algorithms: HashMap::new(),
103 clocks: HashMap::new(),
104 ts_created,
105 ts_started: None,
106 ts_stopped: None,
107 }
108 }
109
110 #[must_use]
112 pub const fn trader_id(&self) -> TraderId {
113 self.trader_id
114 }
115
116 #[must_use]
118 pub const fn instance_id(&self) -> UUID4 {
119 self.instance_id
120 }
121
122 #[must_use]
124 pub const fn environment(&self) -> Environment {
125 self.environment
126 }
127
128 #[must_use]
130 pub const fn state(&self) -> ComponentState {
131 self.state
132 }
133
134 #[must_use]
136 pub const fn ts_created(&self) -> UnixNanos {
137 self.ts_created
138 }
139
140 #[must_use]
142 pub const fn ts_started(&self) -> Option<UnixNanos> {
143 self.ts_started
144 }
145
146 #[must_use]
148 pub const fn ts_stopped(&self) -> Option<UnixNanos> {
149 self.ts_stopped
150 }
151
152 #[must_use]
154 pub const fn actor_count(&self) -> usize {
155 self.actor_ids.len()
156 }
157
158 #[must_use]
160 pub fn strategy_count(&self) -> usize {
161 self.strategies.len()
162 }
163
164 #[must_use]
166 pub fn exec_algorithm_count(&self) -> usize {
167 self.exec_algorithms.len()
168 }
169
170 #[must_use]
172 pub fn component_count(&self) -> usize {
173 self.actor_ids.len() + self.strategies.len() + self.exec_algorithms.len()
174 }
175
176 #[must_use]
178 pub fn actor_ids(&self) -> Vec<ActorId> {
179 self.actor_ids.clone()
180 }
181
182 #[must_use]
184 pub fn strategy_ids(&self) -> Vec<StrategyId> {
185 self.strategies.keys().copied().collect()
186 }
187
188 #[must_use]
190 pub fn exec_algorithm_ids(&self) -> Vec<ExecAlgorithmId> {
191 self.exec_algorithms.keys().copied().collect()
192 }
193
194 fn create_component_clock(&self) -> Rc<RefCell<dyn Clock>> {
199 match self.environment {
200 Environment::Backtest => {
201 Rc::new(RefCell::new(TestClock::new()))
203 }
204 Environment::Live | Environment::Sandbox => {
205 self.clock.clone()
207 }
208 }
209 }
210
211 pub fn add_actor<T>(&mut self, actor: T) -> anyhow::Result<()>
219 where
220 T: DataActor + Component + Debug + 'static,
221 {
222 self.validate_component_registration()?;
223
224 let actor_id = actor.actor_id();
225
226 if self.actor_ids.contains(&actor_id) {
228 anyhow::bail!("Actor '{actor_id}' is already registered");
229 }
230
231 let clock = self.create_component_clock();
232 let component_id = ComponentId::new(actor_id.inner().as_str());
233 self.clocks.insert(component_id, clock.clone());
234
235 let mut actor_mut = actor;
236 actor_mut.register(self.trader_id, clock, self.cache.clone())?;
237
238 register_component_actor(actor_mut);
240
241 self.actor_ids.push(actor_id);
243 log::info!("Registered '{actor_id}' with trader {}", self.trader_id);
244
245 Ok(())
246 }
247
248 pub fn add_strategy(&mut self, mut strategy: Box<dyn Component>) -> anyhow::Result<()> {
256 self.validate_component_registration()?;
257
258 let strategy_id = StrategyId::from(strategy.component_id().inner().as_str());
259
260 if self.strategies.contains_key(&strategy_id) {
262 anyhow::bail!("Strategy '{strategy_id}' is already registered");
263 }
264
265 let clock = self.create_component_clock();
266 let component_id = strategy.component_id();
267 self.clocks.insert(component_id, clock.clone());
268
269 strategy.register(self.trader_id, clock, self.cache.clone())?;
270
271 self.strategies.insert(strategy_id, strategy);
272 log::info!(
273 "Registered strategy '{strategy_id}' with trader {}",
274 self.trader_id
275 );
276
277 Ok(())
278 }
279
280 pub fn add_exec_algorithm(
288 &mut self,
289 mut exec_algorithm: Box<dyn Component>,
290 ) -> anyhow::Result<()> {
291 self.validate_component_registration()?;
292
293 let exec_algorithm_id =
294 ExecAlgorithmId::from(exec_algorithm.component_id().inner().as_str());
295
296 if self.exec_algorithms.contains_key(&exec_algorithm_id) {
298 anyhow::bail!("Execution algorithm '{exec_algorithm_id}' is already registered");
299 }
300
301 let clock = self.create_component_clock();
302 let component_id = exec_algorithm.component_id();
303 self.clocks.insert(component_id, clock.clone());
304
305 exec_algorithm.register(self.trader_id, clock, self.cache.clone())?;
306
307 self.exec_algorithms
308 .insert(exec_algorithm_id, exec_algorithm);
309 log::info!(
310 "Registered execution algorithm '{exec_algorithm_id}' with trader {}",
311 self.trader_id
312 );
313
314 Ok(())
315 }
316
317 fn validate_component_registration(&self) -> anyhow::Result<()> {
319 match self.state {
320 ComponentState::PreInitialized | ComponentState::Ready | ComponentState::Stopped => {
321 Ok(())
322 }
323 ComponentState::Running => {
324 anyhow::bail!("Cannot add components while trader is running")
325 }
326 ComponentState::Disposed => {
327 anyhow::bail!("Cannot add components to disposed trader")
328 }
329 _ => anyhow::bail!("Cannot add components in current state: {}", self.state),
330 }
331 }
332
333 pub fn start_components(&mut self) -> anyhow::Result<()> {
339 log::info!("Starting {} components", self.component_count());
340
341 for actor_id in &self.actor_ids {
343 log::debug!("Starting actor '{actor_id}'");
344 start_component(&actor_id.inner())?;
345 }
346
347 for (id, strategy) in &mut self.strategies {
348 log::debug!("Starting strategy '{id}'");
349 }
351
352 for (id, exec_algorithm) in &mut self.exec_algorithms {
353 log::debug!("Starting execution algorithm '{id}'");
354 }
356
357 log::info!("All components started successfully");
358 Ok(())
359 }
360
361 pub fn stop_components(&mut self) -> anyhow::Result<()> {
367 log::info!("Stopping {} components", self.component_count());
368
369 for (id, exec_algorithm) in &mut self.exec_algorithms {
370 log::debug!("Stopping execution algorithm '{id}'");
371 }
373
374 for (id, strategy) in &mut self.strategies {
375 log::debug!("Stopping strategy '{id}'");
376 }
378
379 for actor_id in &self.actor_ids {
380 log::debug!("Stopping actor '{actor_id}'");
381 stop_component(&actor_id.inner())?;
382 }
383
384 log::info!("All components stopped successfully");
385 Ok(())
386 }
387
388 pub fn reset_components(&mut self) -> anyhow::Result<()> {
394 log::info!("Resetting {} components", self.component_count());
395
396 for actor_id in &self.actor_ids {
398 log::debug!("Resetting actor '{actor_id}'");
399 reset_component(&actor_id.inner())?;
400 }
401
402 for (id, strategy) in &mut self.strategies {
403 log::debug!("Resetting strategy '{id}'");
404 }
406
407 for (id, exec_algorithm) in &mut self.exec_algorithms {
408 log::debug!("Resetting execution algorithm '{id}'");
409 }
411
412 log::info!("All components reset successfully");
413 Ok(())
414 }
415
416 pub fn dispose_components(&mut self) -> anyhow::Result<()> {
422 log::info!("Disposing {} components", self.component_count());
423
424 for actor_id in &self.actor_ids {
426 log::debug!("Disposing actor '{actor_id}'");
427 dispose_component(&actor_id.inner())?;
428 }
429
430 for (id, strategy) in &mut self.strategies {
431 log::debug!("Disposing strategy '{id}'");
432 }
434
435 for (id, exec_algorithm) in &mut self.exec_algorithms {
436 log::debug!("Disposing execution algorithm '{id}'");
437 }
439
440 self.actor_ids.clear();
441 self.strategies.clear();
442 self.exec_algorithms.clear();
443 self.clocks.clear();
444
445 log::info!("All components disposed successfully");
446 Ok(())
447 }
448
449 pub fn initialize(&mut self) -> anyhow::Result<()> {
457 log::info!("Initializing trader {}", self.trader_id);
458
459 let new_state = self.state.transition(&ComponentTrigger::Initialize)?;
460 self.state = new_state;
461
462 log::info!("Trader {} initialized successfully", self.trader_id);
463 Ok(())
464 }
465
466 fn on_start(&mut self) -> anyhow::Result<()> {
467 log::info!("Starting trader {}", self.trader_id);
468
469 self.start_components()?;
470
471 self.ts_started = Some(self.clock.borrow().timestamp_ns());
473
474 log::info!("Trader {} started successfully", self.trader_id);
475 Ok(())
476 }
477
478 fn on_stop(&mut self) -> anyhow::Result<()> {
479 log::info!("Stopping trader {}", self.trader_id);
480
481 self.stop_components()?;
482
483 self.ts_stopped = Some(self.clock.borrow().timestamp_ns());
484
485 log::info!("Trader {} stopped successfully", self.trader_id);
486 Ok(())
487 }
488
489 fn on_reset(&mut self) -> anyhow::Result<()> {
490 log::info!("Resetting trader {}", self.trader_id);
491
492 self.reset_components()?;
493
494 self.ts_started = None;
495 self.ts_stopped = None;
496
497 log::info!("Trader {} reset successfully", self.trader_id);
498 Ok(())
499 }
500
501 fn on_dispose(&mut self) -> anyhow::Result<()> {
502 if self.is_running() {
503 self.stop()?;
504 }
505
506 log::info!("Disposing trader {}", self.trader_id);
507
508 self.dispose_components()?;
509
510 log::info!("Trader {} disposed successfully", self.trader_id);
511 Ok(())
512 }
513}
514
515impl Component for Trader {
516 fn component_id(&self) -> ComponentId {
517 ComponentId::new(format!("Trader-{}", self.trader_id))
518 }
519
520 fn state(&self) -> ComponentState {
521 self.state
522 }
523
524 fn transition_state(&mut self, trigger: ComponentTrigger) -> anyhow::Result<()> {
525 self.state = self.state.transition(&trigger)?;
526 log::info!("{}", self.state);
527 Ok(())
528 }
529
530 fn register(
531 &mut self,
532 _trader_id: TraderId,
533 _clock: Rc<RefCell<dyn Clock>>,
534 _cache: Rc<RefCell<Cache>>,
535 ) -> anyhow::Result<()> {
536 anyhow::bail!("Trader cannot register with itself")
537 }
538
539 fn on_start(&mut self) -> anyhow::Result<()> {
540 Self::on_start(self)
541 }
542
543 fn on_stop(&mut self) -> anyhow::Result<()> {
544 Self::on_stop(self)
545 }
546
547 fn on_reset(&mut self) -> anyhow::Result<()> {
548 Self::on_reset(self)
549 }
550
551 fn on_dispose(&mut self) -> anyhow::Result<()> {
552 Self::on_dispose(self)
553 }
554}
555
556#[cfg(test)]
561mod tests {
562 use std::{
563 cell::RefCell,
564 ops::{Deref, DerefMut},
565 rc::Rc,
566 };
567
568 use nautilus_common::{
569 actor::{DataActorCore, data_actor::DataActorConfig},
570 cache::Cache,
571 clock::TestClock,
572 enums::{ComponentState, Environment},
573 msgbus::MessageBus,
574 };
575 use nautilus_core::UUID4;
576 use nautilus_data::engine::{DataEngine, config::DataEngineConfig};
577 use nautilus_execution::engine::{ExecutionEngine, config::ExecutionEngineConfig};
578 use nautilus_model::identifiers::{ActorId, ComponentId, TraderId};
579 use nautilus_portfolio::portfolio::Portfolio;
580 use nautilus_risk::engine::{RiskEngine, config::RiskEngineConfig};
581 use rstest::rstest;
582
583 use super::*;
584
585 #[derive(Debug)]
587 struct TestDataActor {
588 core: DataActorCore,
589 }
590
591 impl TestDataActor {
592 fn new(config: DataActorConfig) -> Self {
593 Self {
594 core: DataActorCore::new(config),
595 }
596 }
597 }
598
599 impl DataActor for TestDataActor {}
600
601 impl Deref for TestDataActor {
602 type Target = DataActorCore;
603 fn deref(&self) -> &Self::Target {
604 &self.core
605 }
606 }
607
608 impl DerefMut for TestDataActor {
609 fn deref_mut(&mut self) -> &mut Self::Target {
610 &mut self.core
611 }
612 }
613
614 #[derive(Debug)]
616 struct MockComponent {
617 id: ComponentId,
618 state: ComponentState,
619 }
620
621 impl MockComponent {
622 fn new(id: &str) -> Self {
623 Self {
624 id: ComponentId::from(id),
625 state: ComponentState::PreInitialized,
626 }
627 }
628 }
629
630 impl Component for MockComponent {
631 fn component_id(&self) -> ComponentId {
632 self.id
633 }
634
635 fn state(&self) -> ComponentState {
636 self.state
637 }
638
639 fn transition_state(&mut self, trigger: ComponentTrigger) -> anyhow::Result<()> {
640 self.state = self.state.transition(&trigger)?;
641 log::info!("{}", self.state);
642 Ok(())
643 }
644
645 fn register(
646 &mut self,
647 _trader_id: TraderId,
648 _clock: Rc<RefCell<dyn Clock>>,
649 _cache: Rc<RefCell<Cache>>,
650 ) -> anyhow::Result<()> {
651 Ok(())
653 }
654
655 fn on_start(&mut self) -> anyhow::Result<()> {
656 Ok(())
657 }
658 }
659
660 #[allow(clippy::type_complexity)]
661 fn create_trader_components() -> (
662 Rc<RefCell<MessageBus>>,
663 Rc<RefCell<Cache>>,
664 Rc<RefCell<Portfolio>>,
665 Rc<RefCell<DataEngine>>,
666 Rc<RefCell<RiskEngine>>,
667 Rc<RefCell<ExecutionEngine>>,
668 Rc<RefCell<TestClock>>,
669 ) {
670 let trader_id = TraderId::default();
671 let instance_id = UUID4::new();
672 let clock = Rc::new(RefCell::new(TestClock::new()));
673 clock.borrow_mut().set_time(1_000_000_000u64.into());
675 let msgbus = Rc::new(RefCell::new(MessageBus::new(
676 trader_id,
677 instance_id,
678 Some("test".to_string()),
679 None,
680 )));
681 let cache = Rc::new(RefCell::new(Cache::new(None, None)));
682 let portfolio = Rc::new(RefCell::new(Portfolio::new(
683 cache.clone(),
684 clock.clone() as Rc<RefCell<dyn Clock>>,
685 None,
686 )));
687 let data_engine = Rc::new(RefCell::new(DataEngine::new(
688 clock.clone(),
689 cache.clone(),
690 Some(DataEngineConfig::default()),
691 )));
692
693 let risk_cache = Rc::new(RefCell::new(Cache::new(None, None)));
695 let risk_clock = Rc::new(RefCell::new(TestClock::new()));
696 let risk_portfolio = Portfolio::new(
697 risk_cache.clone(),
698 risk_clock.clone() as Rc<RefCell<dyn Clock>>,
699 None,
700 );
701 let risk_engine = Rc::new(RefCell::new(RiskEngine::new(
702 RiskEngineConfig::default(),
703 risk_portfolio,
704 risk_clock as Rc<RefCell<dyn Clock>>,
705 risk_cache,
706 )));
707 let exec_engine = Rc::new(RefCell::new(ExecutionEngine::new(
708 clock.clone(),
709 cache.clone(),
710 Some(ExecutionEngineConfig::default()),
711 )));
712
713 (
714 msgbus,
715 cache,
716 portfolio,
717 data_engine,
718 risk_engine,
719 exec_engine,
720 clock,
721 )
722 }
723
724 #[rstest]
725 fn test_trader_creation() {
726 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
727 create_trader_components();
728 let trader_id = TraderId::default();
729 let instance_id = UUID4::new();
730
731 let trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
732
733 assert_eq!(trader.trader_id(), trader_id);
734 assert_eq!(trader.instance_id(), instance_id);
735 assert_eq!(trader.environment(), Environment::Backtest);
736 assert_eq!(trader.state(), ComponentState::PreInitialized);
737 assert_eq!(trader.actor_count(), 0);
738 assert_eq!(trader.strategy_count(), 0);
739 assert_eq!(trader.exec_algorithm_count(), 0);
740 assert_eq!(trader.component_count(), 0);
741 assert!(!trader.is_running());
742 assert!(!trader.is_stopped());
743 assert!(!trader.is_disposed());
744 assert!(trader.ts_created() > 0);
745 assert!(trader.ts_started().is_none());
746 assert!(trader.ts_stopped().is_none());
747 }
748
749 #[rstest]
750 fn test_trader_component_id() {
751 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
752 create_trader_components();
753 let trader_id = TraderId::from("TRADER-001");
754 let instance_id = UUID4::new();
755
756 let trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
757
758 assert_eq!(
759 trader.component_id(),
760 ComponentId::from("Trader-TRADER-001")
761 );
762 }
763
764 #[rstest]
765 fn test_add_actor_success() {
766 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
767 create_trader_components();
768 let trader_id = TraderId::default();
769 let instance_id = UUID4::new();
770
771 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
772
773 let actor = TestDataActor::new(DataActorConfig::default());
774 let actor_id = actor.actor_id();
775
776 let result = trader.add_actor(actor);
777 assert!(result.is_ok());
778 assert_eq!(trader.actor_count(), 1);
779 assert_eq!(trader.component_count(), 1);
780 assert!(trader.actor_ids().contains(&actor_id));
781 }
782
783 #[rstest]
784 fn test_add_duplicate_actor_fails() {
785 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
786 create_trader_components();
787 let trader_id = TraderId::default();
788 let instance_id = UUID4::new();
789
790 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
791
792 let config = DataActorConfig {
793 actor_id: Some(ActorId::from("TestActor")),
794 ..Default::default()
795 };
796 let actor1 = TestDataActor::new(config.clone());
797 let actor2 = TestDataActor::new(config);
798
799 assert!(trader.add_actor(actor1).is_ok());
801 assert_eq!(trader.actor_count(), 1);
802
803 let result = trader.add_actor(actor2);
805 assert!(result.is_err());
806 assert!(
807 result
808 .unwrap_err()
809 .to_string()
810 .contains("already registered")
811 );
812 assert_eq!(trader.actor_count(), 1);
813 }
814
815 #[rstest]
816 fn test_add_strategy_success() {
817 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
818 create_trader_components();
819 let trader_id = TraderId::default();
820 let instance_id = UUID4::new();
821
822 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
823
824 let strategy = Box::new(MockComponent::new("Test-Strategy"));
825 let strategy_id = StrategyId::from(strategy.component_id().inner().as_str());
826
827 let result = trader.add_strategy(strategy);
828 assert!(result.is_ok());
829 assert_eq!(trader.strategy_count(), 1);
830 assert_eq!(trader.component_count(), 1);
831 assert!(trader.strategy_ids().contains(&strategy_id));
832 }
833
834 #[rstest]
835 fn test_add_exec_algorithm_success() {
836 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
837 create_trader_components();
838 let trader_id = TraderId::default();
839 let instance_id = UUID4::new();
840
841 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
842
843 let exec_algorithm = Box::new(MockComponent::new("TestExecAlgorithm"));
844 let exec_algorithm_id =
845 ExecAlgorithmId::from(exec_algorithm.component_id().inner().as_str());
846
847 let result = trader.add_exec_algorithm(exec_algorithm);
848 assert!(result.is_ok());
849 assert_eq!(trader.exec_algorithm_count(), 1);
850 assert_eq!(trader.component_count(), 1);
851 assert!(trader.exec_algorithm_ids().contains(&exec_algorithm_id));
852 }
853
854 #[rstest]
855 fn test_component_lifecycle() {
856 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
857 create_trader_components();
858 let trader_id = TraderId::default();
859 let instance_id = UUID4::new();
860
861 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
862
863 let actor = TestDataActor::new(DataActorConfig::default());
865 let strategy = Box::new(MockComponent::new("Test-Strategy"));
866 let exec_algorithm = Box::new(MockComponent::new("TestExecAlgorithm"));
867
868 assert!(trader.add_actor(actor).is_ok());
869 assert!(trader.add_strategy(strategy).is_ok());
870 assert!(trader.add_exec_algorithm(exec_algorithm).is_ok());
871 assert_eq!(trader.component_count(), 3);
872
873 assert!(trader.start_components().is_ok());
875
876 assert!(trader.stop_components().is_ok());
878
879 assert!(trader.reset_components().is_ok());
881
882 assert!(trader.dispose_components().is_ok());
884 assert_eq!(trader.component_count(), 0);
885 }
886
887 #[rstest]
888 fn test_trader_component_lifecycle() {
889 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
890 create_trader_components();
891 let trader_id = TraderId::default();
892 let instance_id = UUID4::new();
893
894 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
895
896 assert_eq!(trader.state(), ComponentState::PreInitialized);
898 assert!(!trader.is_running());
899 assert!(!trader.is_stopped());
900 assert!(!trader.is_disposed());
901
902 assert!(trader.start().is_err());
904
905 trader.initialize().unwrap();
907
908 assert!(trader.start().is_ok());
910 assert_eq!(trader.state(), ComponentState::Running);
911 assert!(trader.is_running());
912 assert!(trader.ts_started().is_some());
913
914 assert!(trader.stop().is_ok());
916 assert_eq!(trader.state(), ComponentState::Stopped);
917 assert!(trader.is_stopped());
918 assert!(trader.ts_stopped().is_some());
919
920 assert!(trader.reset().is_ok());
922 assert_eq!(trader.state(), ComponentState::Ready);
923 assert!(trader.ts_started().is_none());
924 assert!(trader.ts_stopped().is_none());
925
926 assert!(trader.dispose().is_ok());
928 assert_eq!(trader.state(), ComponentState::Disposed);
929 assert!(trader.is_disposed());
930 }
931
932 #[rstest]
933 fn test_cannot_add_components_while_running() {
934 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
935 create_trader_components();
936 let trader_id = TraderId::default();
937 let instance_id = UUID4::new();
938
939 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
940
941 trader.state = ComponentState::Running;
943
944 let actor = TestDataActor::new(DataActorConfig::default());
945 let result = trader.add_actor(actor);
946 assert!(result.is_err());
947 assert!(
948 result
949 .unwrap_err()
950 .to_string()
951 .contains("while trader is running")
952 );
953 }
954
955 #[rstest]
956 fn test_create_component_clock_backtest_vs_live() {
957 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
958 create_trader_components();
959 let trader_id = TraderId::default();
960 let instance_id = UUID4::new();
961
962 let trader_backtest = Trader::new(
964 trader_id,
965 instance_id,
966 Environment::Backtest,
967 clock.clone(),
968 cache.clone(),
969 );
970
971 let backtest_clock = trader_backtest.create_component_clock();
972 assert_ne!(
974 backtest_clock.as_ptr() as *const _,
975 clock.as_ptr() as *const _
976 );
977
978 let trader_live = Trader::new(
980 trader_id,
981 instance_id,
982 Environment::Live,
983 clock.clone(),
984 cache,
985 );
986
987 let live_clock = trader_live.create_component_clock();
988 assert_eq!(live_clock.as_ptr() as *const _, clock.as_ptr() as *const _);
990 }
991}