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 posei_trader::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 fn create_trader_components() -> (
661 Rc<RefCell<MessageBus>>,
662 Rc<RefCell<Cache>>,
663 Rc<RefCell<Portfolio>>,
664 Rc<RefCell<DataEngine>>,
665 Rc<RefCell<RiskEngine>>,
666 Rc<RefCell<ExecutionEngine>>,
667 Rc<RefCell<TestClock>>,
668 ) {
669 let trader_id = TraderId::default();
670 let instance_id = UUID4::new();
671 let clock = Rc::new(RefCell::new(TestClock::new()));
672 clock.borrow_mut().set_time(1_000_000_000u64.into());
674 let msgbus = Rc::new(RefCell::new(MessageBus::new(
675 trader_id,
676 instance_id,
677 Some("test".to_string()),
678 None,
679 )));
680 let cache = Rc::new(RefCell::new(Cache::new(None, None)));
681 let portfolio = Rc::new(RefCell::new(Portfolio::new(
682 cache.clone(),
683 clock.clone() as Rc<RefCell<dyn Clock>>,
684 None,
685 )));
686 let data_engine = Rc::new(RefCell::new(DataEngine::new(
687 clock.clone(),
688 cache.clone(),
689 Some(DataEngineConfig::default()),
690 )));
691
692 let risk_cache = Rc::new(RefCell::new(Cache::new(None, None)));
694 let risk_clock = Rc::new(RefCell::new(TestClock::new()));
695 let risk_portfolio = Portfolio::new(
696 risk_cache.clone(),
697 risk_clock.clone() as Rc<RefCell<dyn Clock>>,
698 None,
699 );
700 let risk_engine = Rc::new(RefCell::new(RiskEngine::new(
701 RiskEngineConfig::default(),
702 risk_portfolio,
703 risk_clock as Rc<RefCell<dyn Clock>>,
704 risk_cache,
705 )));
706 let exec_engine = Rc::new(RefCell::new(ExecutionEngine::new(
707 clock.clone(),
708 cache.clone(),
709 Some(ExecutionEngineConfig::default()),
710 )));
711
712 (
713 msgbus,
714 cache,
715 portfolio,
716 data_engine,
717 risk_engine,
718 exec_engine,
719 clock,
720 )
721 }
722
723 #[rstest]
724 fn test_trader_creation() {
725 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
726 create_trader_components();
727 let trader_id = TraderId::default();
728 let instance_id = UUID4::new();
729
730 let trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
731
732 assert_eq!(trader.trader_id(), trader_id);
733 assert_eq!(trader.instance_id(), instance_id);
734 assert_eq!(trader.environment(), Environment::Backtest);
735 assert_eq!(trader.state(), ComponentState::PreInitialized);
736 assert_eq!(trader.actor_count(), 0);
737 assert_eq!(trader.strategy_count(), 0);
738 assert_eq!(trader.exec_algorithm_count(), 0);
739 assert_eq!(trader.component_count(), 0);
740 assert!(!trader.is_running());
741 assert!(!trader.is_stopped());
742 assert!(!trader.is_disposed());
743 assert!(trader.ts_created() > 0);
744 assert!(trader.ts_started().is_none());
745 assert!(trader.ts_stopped().is_none());
746 }
747
748 #[rstest]
749 fn test_trader_component_id() {
750 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
751 create_trader_components();
752 let trader_id = TraderId::from("TRADER-001");
753 let instance_id = UUID4::new();
754
755 let trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
756
757 assert_eq!(
758 trader.component_id(),
759 ComponentId::from("Trader-TRADER-001")
760 );
761 }
762
763 #[rstest]
764 fn test_add_actor_success() {
765 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
766 create_trader_components();
767 let trader_id = TraderId::default();
768 let instance_id = UUID4::new();
769
770 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
771
772 let actor = TestDataActor::new(DataActorConfig::default());
773 let actor_id = actor.actor_id();
774
775 let result = trader.add_actor(actor);
776 assert!(result.is_ok());
777 assert_eq!(trader.actor_count(), 1);
778 assert_eq!(trader.component_count(), 1);
779 assert!(trader.actor_ids().contains(&actor_id));
780 }
781
782 #[rstest]
783 fn test_add_duplicate_actor_fails() {
784 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
785 create_trader_components();
786 let trader_id = TraderId::default();
787 let instance_id = UUID4::new();
788
789 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
790
791 let mut config = DataActorConfig::default();
792 config.actor_id = Some(ActorId::from("TestActor"));
793 let actor1 = TestDataActor::new(config.clone());
794 let actor2 = TestDataActor::new(config);
795
796 assert!(trader.add_actor(actor1).is_ok());
798 assert_eq!(trader.actor_count(), 1);
799
800 let result = trader.add_actor(actor2);
802 assert!(result.is_err());
803 assert!(
804 result
805 .unwrap_err()
806 .to_string()
807 .contains("already registered")
808 );
809 assert_eq!(trader.actor_count(), 1);
810 }
811
812 #[rstest]
813 fn test_add_strategy_success() {
814 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
815 create_trader_components();
816 let trader_id = TraderId::default();
817 let instance_id = UUID4::new();
818
819 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
820
821 let strategy = Box::new(MockComponent::new("Test-Strategy"));
822 let strategy_id = StrategyId::from(strategy.component_id().inner().as_str());
823
824 let result = trader.add_strategy(strategy);
825 assert!(result.is_ok());
826 assert_eq!(trader.strategy_count(), 1);
827 assert_eq!(trader.component_count(), 1);
828 assert!(trader.strategy_ids().contains(&strategy_id));
829 }
830
831 #[rstest]
832 fn test_add_exec_algorithm_success() {
833 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
834 create_trader_components();
835 let trader_id = TraderId::default();
836 let instance_id = UUID4::new();
837
838 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
839
840 let exec_algorithm = Box::new(MockComponent::new("TestExecAlgorithm"));
841 let exec_algorithm_id =
842 ExecAlgorithmId::from(exec_algorithm.component_id().inner().as_str());
843
844 let result = trader.add_exec_algorithm(exec_algorithm);
845 assert!(result.is_ok());
846 assert_eq!(trader.exec_algorithm_count(), 1);
847 assert_eq!(trader.component_count(), 1);
848 assert!(trader.exec_algorithm_ids().contains(&exec_algorithm_id));
849 }
850
851 #[rstest]
852 fn test_component_lifecycle() {
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 actor = TestDataActor::new(DataActorConfig::default());
862 let strategy = Box::new(MockComponent::new("Test-Strategy"));
863 let exec_algorithm = Box::new(MockComponent::new("TestExecAlgorithm"));
864
865 assert!(trader.add_actor(actor).is_ok());
866 assert!(trader.add_strategy(strategy).is_ok());
867 assert!(trader.add_exec_algorithm(exec_algorithm).is_ok());
868 assert_eq!(trader.component_count(), 3);
869
870 assert!(trader.start_components().is_ok());
872
873 assert!(trader.stop_components().is_ok());
875
876 assert!(trader.reset_components().is_ok());
878
879 assert!(trader.dispose_components().is_ok());
881 assert_eq!(trader.component_count(), 0);
882 }
883
884 #[rstest]
885 fn test_trader_component_lifecycle() {
886 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
887 create_trader_components();
888 let trader_id = TraderId::default();
889 let instance_id = UUID4::new();
890
891 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
892
893 assert_eq!(trader.state(), ComponentState::PreInitialized);
895 assert!(!trader.is_running());
896 assert!(!trader.is_stopped());
897 assert!(!trader.is_disposed());
898
899 assert!(trader.start().is_err());
901
902 trader.initialize().unwrap();
904
905 assert!(trader.start().is_ok());
907 assert_eq!(trader.state(), ComponentState::Running);
908 assert!(trader.is_running());
909 assert!(trader.ts_started().is_some());
910
911 assert!(trader.stop().is_ok());
913 assert_eq!(trader.state(), ComponentState::Stopped);
914 assert!(trader.is_stopped());
915 assert!(trader.ts_stopped().is_some());
916
917 assert!(trader.reset().is_ok());
919 assert_eq!(trader.state(), ComponentState::Ready);
920 assert!(trader.ts_started().is_none());
921 assert!(trader.ts_stopped().is_none());
922
923 assert!(trader.dispose().is_ok());
925 assert_eq!(trader.state(), ComponentState::Disposed);
926 assert!(trader.is_disposed());
927 }
928
929 #[rstest]
930 fn test_cannot_add_components_while_running() {
931 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
932 create_trader_components();
933 let trader_id = TraderId::default();
934 let instance_id = UUID4::new();
935
936 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock, cache);
937
938 trader.state = ComponentState::Running;
940
941 let actor = TestDataActor::new(DataActorConfig::default());
942 let result = trader.add_actor(actor);
943 assert!(result.is_err());
944 assert!(
945 result
946 .unwrap_err()
947 .to_string()
948 .contains("while trader is running")
949 );
950 }
951
952 #[rstest]
953 fn test_create_component_clock_backtest_vs_live() {
954 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
955 create_trader_components();
956 let trader_id = TraderId::default();
957 let instance_id = UUID4::new();
958
959 let trader_backtest = Trader::new(
961 trader_id,
962 instance_id,
963 Environment::Backtest,
964 clock.clone(),
965 cache.clone(),
966 );
967
968 let backtest_clock = trader_backtest.create_component_clock();
969 assert_ne!(
971 backtest_clock.as_ptr() as *const _,
972 clock.as_ptr() as *const _
973 );
974
975 let trader_live = Trader::new(
977 trader_id,
978 instance_id,
979 Environment::Live,
980 clock.clone(),
981 cache,
982 );
983
984 let live_clock = trader_live.create_component_clock();
985 assert_eq!(live_clock.as_ptr() as *const _, clock.as_ptr() as *const _);
987 }
988}