1#![allow(dead_code)]
24#![allow(unused_variables)]
25
26use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
27
28use nautilus_common::{
29 clock::{Clock, TestClock},
30 component::Component,
31 enums::{ComponentState, ComponentTrigger, Environment},
32 timer::TimeEvent,
33};
34use nautilus_core::{UUID4, UnixNanos};
35use nautilus_model::identifiers::{ComponentId, ExecAlgorithmId, StrategyId, TraderId};
36
37#[derive(Debug)]
43pub struct Trader {
44 pub trader_id: TraderId,
46 pub instance_id: UUID4,
48 pub environment: Environment,
50 state: ComponentState,
52 clock: Rc<RefCell<dyn Clock>>,
54 actors: HashMap<ComponentId, Box<dyn Component>>, strategies: HashMap<StrategyId, Box<dyn Component>>,
58 exec_algorithms: HashMap<ExecAlgorithmId, Box<dyn Component>>, component_clocks: HashMap<ComponentId, Rc<RefCell<dyn Clock>>>, ts_created: UnixNanos,
64 ts_started: Option<UnixNanos>,
66 ts_stopped: Option<UnixNanos>,
68}
69
70impl Trader {
71 #[must_use]
73 pub fn new(
74 trader_id: TraderId,
75 instance_id: UUID4,
76 environment: Environment,
77 clock: Rc<RefCell<dyn Clock>>,
78 ) -> Self {
79 let ts_created = clock.borrow().timestamp_ns();
80
81 Self {
82 trader_id,
83 instance_id,
84 environment,
85 state: ComponentState::PreInitialized,
86 clock,
87 actors: HashMap::new(),
88 strategies: HashMap::new(),
89 exec_algorithms: HashMap::new(),
90 component_clocks: HashMap::new(),
91 ts_created,
92 ts_started: None,
93 ts_stopped: None,
94 }
95 }
96
97 #[must_use]
99 pub const fn trader_id(&self) -> TraderId {
100 self.trader_id
101 }
102
103 #[must_use]
105 pub const fn instance_id(&self) -> UUID4 {
106 self.instance_id
107 }
108
109 #[must_use]
111 pub const fn environment(&self) -> Environment {
112 self.environment
113 }
114
115 #[must_use]
117 pub const fn state(&self) -> ComponentState {
118 self.state
119 }
120
121 #[must_use]
123 pub const fn ts_created(&self) -> UnixNanos {
124 self.ts_created
125 }
126
127 #[must_use]
129 pub const fn ts_started(&self) -> Option<UnixNanos> {
130 self.ts_started
131 }
132
133 #[must_use]
135 pub const fn ts_stopped(&self) -> Option<UnixNanos> {
136 self.ts_stopped
137 }
138
139 #[must_use]
141 pub const fn is_running(&self) -> bool {
142 matches!(self.state, ComponentState::Running)
143 }
144
145 #[must_use]
147 pub const fn is_stopped(&self) -> bool {
148 matches!(self.state, ComponentState::Stopped)
149 }
150
151 #[must_use]
153 pub const fn is_disposed(&self) -> bool {
154 matches!(self.state, ComponentState::Disposed)
155 }
156
157 #[must_use]
159 pub fn actor_count(&self) -> usize {
160 self.actors.len()
161 }
162
163 #[must_use]
165 pub fn strategy_count(&self) -> usize {
166 self.strategies.len()
167 }
168
169 #[must_use]
171 pub fn exec_algorithm_count(&self) -> usize {
172 self.exec_algorithms.len()
173 }
174
175 #[must_use]
177 pub fn component_count(&self) -> usize {
178 self.actors.len() + self.strategies.len() + self.exec_algorithms.len()
179 }
180
181 #[must_use]
183 pub fn actor_ids(&self) -> Vec<ComponentId> {
184 self.actors.keys().copied().collect()
185 }
186
187 #[must_use]
189 pub fn strategy_ids(&self) -> Vec<StrategyId> {
190 self.strategies.keys().copied().collect()
191 }
192
193 #[must_use]
195 pub fn exec_algorithm_ids(&self) -> Vec<ExecAlgorithmId> {
196 self.exec_algorithms.keys().copied().collect()
197 }
198
199 fn create_component_clock(&self) -> Rc<RefCell<dyn Clock>> {
204 match self.environment {
205 Environment::Backtest => {
206 Rc::new(RefCell::new(TestClock::new()))
208 }
209 Environment::Live | Environment::Sandbox => {
210 self.clock.clone()
212 }
213 }
214 }
215
216 pub fn add_actor(&mut self, mut actor: Box<dyn Component>) -> anyhow::Result<()> {
224 self.validate_component_registration()?;
225
226 let component_id = actor.id();
227
228 if self.actors.contains_key(&component_id) {
230 anyhow::bail!("Actor '{component_id}' is already registered");
231 }
232
233 let component_clock = self.create_component_clock();
234 self.component_clocks
235 .insert(component_id, component_clock.clone());
236
237 self.register_component(&mut actor, component_clock)?;
238
239 log::info!("Registered actor '{component_id}'");
240 self.actors.insert(component_id, actor);
241
242 Ok(())
243 }
244
245 pub fn add_strategy(&mut self, mut strategy: Box<dyn Component>) -> anyhow::Result<()> {
253 self.validate_component_registration()?;
254
255 let strategy_id = StrategyId::from(strategy.id().to_string().as_str());
256
257 if self.strategies.contains_key(&strategy_id) {
259 anyhow::bail!("Strategy '{strategy_id}' is already registered");
260 }
261
262 let component_clock = self.create_component_clock();
263 let component_id = strategy.id();
264 self.component_clocks
265 .insert(component_id, component_clock.clone());
266
267 self.register_component(&mut strategy, component_clock)?;
268
269 log::info!("Registered strategy '{strategy_id}'");
272 self.strategies.insert(strategy_id, strategy);
273
274 Ok(())
275 }
276
277 pub fn add_exec_algorithm(
285 &mut self,
286 mut exec_algorithm: Box<dyn Component>,
287 ) -> anyhow::Result<()> {
288 self.validate_component_registration()?;
289
290 let exec_algorithm_id = ExecAlgorithmId::from(exec_algorithm.id().to_string().as_str());
291
292 if self.exec_algorithms.contains_key(&exec_algorithm_id) {
294 anyhow::bail!("Execution algorithm '{exec_algorithm_id}' is already registered");
295 }
296
297 let component_clock = self.create_component_clock();
298 let component_id = exec_algorithm.id();
299 self.component_clocks
300 .insert(component_id, component_clock.clone());
301
302 self.register_component(&mut exec_algorithm, component_clock)?;
303
304 log::info!("Registered execution algorithm '{exec_algorithm_id}'");
305 self.exec_algorithms
306 .insert(exec_algorithm_id, exec_algorithm);
307
308 Ok(())
309 }
310
311 fn validate_component_registration(&self) -> anyhow::Result<()> {
313 match self.state {
314 ComponentState::PreInitialized | ComponentState::Ready | ComponentState::Stopped => {
315 Ok(())
316 }
317 ComponentState::Running => {
318 anyhow::bail!("Cannot add components while trader is running")
319 }
320 ComponentState::Disposed => {
321 anyhow::bail!("Cannot add components to disposed trader")
322 }
323 _ => anyhow::bail!("Cannot add components in current state: {}", self.state),
324 }
325 }
326
327 fn register_component(
329 &self,
330 component: &mut Box<dyn Component>,
331 _component_clock: Rc<RefCell<dyn Clock>>,
332 ) -> anyhow::Result<()> {
333 log::debug!(
339 "Registering component '{}' with system resources",
340 component.id()
341 );
342
343 Ok(())
350 }
351
352 pub fn start_components(&mut self) -> anyhow::Result<()> {
358 log::info!("Starting {} components", self.component_count());
359
360 for (id, actor) in &mut self.actors {
362 log::debug!("Starting actor '{id}'");
363 actor.start()?;
364 }
365
366 for (id, strategy) in &mut self.strategies {
368 log::debug!("Starting strategy '{id}'");
369 strategy.start()?;
370 }
371
372 for (id, exec_algorithm) in &mut self.exec_algorithms {
374 log::debug!("Starting execution algorithm '{id}'");
375 exec_algorithm.start()?;
376 }
377
378 log::info!("All components started successfully");
379 Ok(())
380 }
381
382 pub fn stop_components(&mut self) -> anyhow::Result<()> {
388 log::info!("Stopping {} components", self.component_count());
389
390 for (id, exec_algorithm) in &mut self.exec_algorithms {
392 log::debug!("Stopping execution algorithm '{id}'");
393 exec_algorithm.stop()?;
394 }
395
396 for (id, strategy) in &mut self.strategies {
398 log::debug!("Stopping strategy '{id}'");
399 strategy.stop()?;
400 }
401
402 for (id, actor) in &mut self.actors {
404 log::debug!("Stopping actor '{id}'");
405 actor.stop()?;
406 }
407
408 log::info!("All components stopped successfully");
409 Ok(())
410 }
411
412 pub fn reset_components(&mut self) -> anyhow::Result<()> {
418 log::info!("Resetting {} components", self.component_count());
419
420 for (id, actor) in &mut self.actors {
422 log::debug!("Resetting actor '{id}'");
423 actor.reset()?;
424 }
425
426 for (id, strategy) in &mut self.strategies {
427 log::debug!("Resetting strategy '{id}'");
428 strategy.reset()?;
429 }
430
431 for (id, exec_algorithm) in &mut self.exec_algorithms {
432 log::debug!("Resetting execution algorithm '{id}'");
433 exec_algorithm.reset()?;
434 }
435
436 log::info!("All components reset successfully");
437 Ok(())
438 }
439
440 pub fn dispose_components(&mut self) -> anyhow::Result<()> {
446 log::info!("Disposing {} components", self.component_count());
447
448 for (id, actor) in &mut self.actors {
450 log::debug!("Disposing actor '{id}'");
451 actor.dispose()?;
452 }
453
454 for (id, strategy) in &mut self.strategies {
455 log::debug!("Disposing strategy '{id}'");
456 strategy.dispose()?;
457 }
458
459 for (id, exec_algorithm) in &mut self.exec_algorithms {
460 log::debug!("Disposing execution algorithm '{id}'");
461 exec_algorithm.dispose()?;
462 }
463
464 self.actors.clear();
466 self.strategies.clear();
467 self.exec_algorithms.clear();
468 self.component_clocks.clear();
469
470 log::info!("All components disposed successfully");
471 Ok(())
472 }
473
474 pub fn initialize(&mut self) -> anyhow::Result<()> {
482 log::info!("Initializing trader {}", self.trader_id);
483
484 let new_state = self.state.transition(&ComponentTrigger::Initialize)?;
485 self.state = new_state;
486
487 log::info!("Trader {} initialized successfully", self.trader_id);
488 Ok(())
489 }
490}
491
492impl Component for Trader {
493 fn id(&self) -> ComponentId {
494 ComponentId::from(format!("Trader-{}", self.trader_id).as_str())
495 }
496
497 fn state(&self) -> ComponentState {
498 self.state
499 }
500
501 fn trigger(&self) -> ComponentTrigger {
502 ComponentTrigger::Initialize
503 }
504
505 fn is_running(&self) -> bool {
506 self.is_running()
507 }
508
509 fn is_stopped(&self) -> bool {
510 self.is_stopped()
511 }
512
513 fn is_disposed(&self) -> bool {
514 self.is_disposed()
515 }
516
517 fn start(&mut self) -> anyhow::Result<()> {
518 if self.state == ComponentState::Running {
519 log::warn!("Trader is already running");
520 return Ok(());
521 }
522
523 if !matches!(self.state, ComponentState::Ready | ComponentState::Stopped) {
525 anyhow::bail!("Cannot start trader from {} state", self.state);
526 }
527
528 log::info!("Starting trader {}", self.trader_id);
529
530 self.start_components()?;
531
532 self.state = ComponentState::Running;
534 self.ts_started = Some(self.clock.borrow().timestamp_ns());
535
536 log::info!("Trader {} started successfully", self.trader_id);
537 Ok(())
538 }
539
540 fn stop(&mut self) -> anyhow::Result<()> {
541 if !self.is_running() {
542 log::warn!("Trader is not running");
543 return Ok(());
544 }
545
546 log::info!("Stopping trader {}", self.trader_id);
547
548 self.stop_components()?;
550
551 self.state = ComponentState::Stopped;
552 self.ts_stopped = Some(self.clock.borrow().timestamp_ns());
553
554 log::info!("Trader {} stopped successfully", self.trader_id);
555 Ok(())
556 }
557
558 fn reset(&mut self) -> anyhow::Result<()> {
559 if self.is_running() {
560 anyhow::bail!("Cannot reset trader while running. Stop first.");
561 }
562
563 log::info!("Resetting trader {}", self.trader_id);
564
565 self.reset_components()?;
567
568 self.state = ComponentState::Ready;
569 self.ts_started = None;
570 self.ts_stopped = None;
571
572 log::info!("Trader {} reset successfully", self.trader_id);
573 Ok(())
574 }
575
576 fn dispose(&mut self) -> anyhow::Result<()> {
577 if self.is_running() {
578 self.stop()?;
579 }
580
581 log::info!("Disposing trader {}", self.trader_id);
582
583 self.dispose_components()?;
585
586 self.state = ComponentState::Disposed;
587
588 log::info!("Trader {} disposed successfully", self.trader_id);
589 Ok(())
590 }
591
592 fn handle_event(&mut self, _event: TimeEvent) {
593 }
596}
597
598#[cfg(test)]
603mod tests {
604 use std::{cell::RefCell, rc::Rc};
605
606 use nautilus_common::{
607 cache::Cache,
608 clock::TestClock,
609 enums::{ComponentState, ComponentTrigger, Environment},
610 msgbus::MessageBus,
611 timer::TimeEvent,
612 };
613 use nautilus_core::UUID4;
614 use posei_trader::engine::{DataEngine, config::DataEngineConfig};
615 use nautilus_execution::engine::{ExecutionEngine, config::ExecutionEngineConfig};
616 use nautilus_model::identifiers::{ComponentId, TraderId};
617 use nautilus_portfolio::portfolio::Portfolio;
618 use nautilus_risk::engine::{RiskEngine, config::RiskEngineConfig};
619
620 use super::*;
621
622 #[derive(Debug)]
624 struct MockComponent {
625 id: ComponentId,
626 state: ComponentState,
627 }
628
629 impl MockComponent {
630 fn new(id: &str) -> Self {
631 Self {
632 id: ComponentId::from(id),
633 state: ComponentState::PreInitialized,
634 }
635 }
636 }
637
638 impl Component for MockComponent {
639 fn id(&self) -> ComponentId {
640 self.id
641 }
642
643 fn state(&self) -> ComponentState {
644 self.state
645 }
646
647 fn trigger(&self) -> ComponentTrigger {
648 ComponentTrigger::Initialize
649 }
650
651 fn is_running(&self) -> bool {
652 matches!(self.state, ComponentState::Running)
653 }
654
655 fn is_stopped(&self) -> bool {
656 matches!(self.state, ComponentState::Stopped)
657 }
658
659 fn is_disposed(&self) -> bool {
660 matches!(self.state, ComponentState::Disposed)
661 }
662
663 fn start(&mut self) -> anyhow::Result<()> {
664 self.state = ComponentState::Running;
665 Ok(())
666 }
667
668 fn stop(&mut self) -> anyhow::Result<()> {
669 self.state = ComponentState::Stopped;
670 Ok(())
671 }
672
673 fn reset(&mut self) -> anyhow::Result<()> {
674 self.state = ComponentState::Ready;
675 Ok(())
676 }
677
678 fn dispose(&mut self) -> anyhow::Result<()> {
679 self.state = ComponentState::Disposed;
680 Ok(())
681 }
682
683 fn handle_event(&mut self, _event: TimeEvent) {
684 }
686 }
687
688 fn create_trader_components() -> (
689 Rc<RefCell<MessageBus>>,
690 Rc<RefCell<Cache>>,
691 Rc<RefCell<Portfolio>>,
692 Rc<RefCell<DataEngine>>,
693 Rc<RefCell<RiskEngine>>,
694 Rc<RefCell<ExecutionEngine>>,
695 Rc<RefCell<TestClock>>,
696 ) {
697 let trader_id = TraderId::default();
698 let instance_id = UUID4::new();
699 let clock = Rc::new(RefCell::new(TestClock::new()));
700 clock.borrow_mut().set_time(1_000_000_000u64.into());
702 let msgbus = Rc::new(RefCell::new(MessageBus::new(
703 trader_id,
704 instance_id,
705 Some("test".to_string()),
706 None,
707 )));
708 let cache = Rc::new(RefCell::new(Cache::new(None, None)));
709 let portfolio = Rc::new(RefCell::new(Portfolio::new(
710 cache.clone(),
711 clock.clone() as Rc<RefCell<dyn Clock>>,
712 None,
713 )));
714 let data_engine = Rc::new(RefCell::new(DataEngine::new(
715 clock.clone(),
716 cache.clone(),
717 Some(DataEngineConfig::default()),
718 )));
719
720 let risk_cache = Rc::new(RefCell::new(Cache::new(None, None)));
722 let risk_clock = Rc::new(RefCell::new(TestClock::new()));
723 let risk_portfolio = Portfolio::new(
724 risk_cache.clone(),
725 risk_clock.clone() as Rc<RefCell<dyn Clock>>,
726 None,
727 );
728 let risk_engine = Rc::new(RefCell::new(RiskEngine::new(
729 RiskEngineConfig::default(),
730 risk_portfolio,
731 risk_clock as Rc<RefCell<dyn Clock>>,
732 risk_cache,
733 )));
734 let exec_engine = Rc::new(RefCell::new(ExecutionEngine::new(
735 clock.clone(),
736 cache.clone(),
737 Some(ExecutionEngineConfig::default()),
738 )));
739
740 (
741 msgbus,
742 cache,
743 portfolio,
744 data_engine,
745 risk_engine,
746 exec_engine,
747 clock,
748 )
749 }
750
751 #[test]
752 fn test_trader_creation() {
753 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
754 create_trader_components();
755 let trader_id = TraderId::default();
756 let instance_id = UUID4::new();
757
758 let trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock);
759
760 assert_eq!(trader.trader_id(), trader_id);
761 assert_eq!(trader.instance_id(), instance_id);
762 assert_eq!(trader.environment(), Environment::Backtest);
763 assert_eq!(trader.state(), ComponentState::PreInitialized);
764 assert_eq!(trader.actor_count(), 0);
765 assert_eq!(trader.strategy_count(), 0);
766 assert_eq!(trader.exec_algorithm_count(), 0);
767 assert_eq!(trader.component_count(), 0);
768 assert!(!trader.is_running());
769 assert!(!trader.is_stopped());
770 assert!(!trader.is_disposed());
771 assert!(trader.ts_created() > 0);
772 assert!(trader.ts_started().is_none());
773 assert!(trader.ts_stopped().is_none());
774 }
775
776 #[test]
777 fn test_trader_component_id() {
778 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
779 create_trader_components();
780 let trader_id = TraderId::from("TRADER-001");
781 let instance_id = UUID4::new();
782
783 let trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock);
784
785 assert_eq!(trader.id(), ComponentId::from("Trader-TRADER-001"));
786 }
787
788 #[test]
789 fn test_add_actor_success() {
790 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
791 create_trader_components();
792 let trader_id = TraderId::default();
793 let instance_id = UUID4::new();
794
795 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock);
796
797 let actor = Box::new(MockComponent::new("TestActor"));
798 let actor_id = actor.id();
799
800 let result = trader.add_actor(actor);
801 assert!(result.is_ok());
802 assert_eq!(trader.actor_count(), 1);
803 assert_eq!(trader.component_count(), 1);
804 assert!(trader.actor_ids().contains(&actor_id));
805 }
806
807 #[test]
808 fn test_add_duplicate_actor_fails() {
809 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
810 create_trader_components();
811 let trader_id = TraderId::default();
812 let instance_id = UUID4::new();
813
814 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock);
815
816 let actor1 = Box::new(MockComponent::new("TestActor"));
817 let actor2 = Box::new(MockComponent::new("TestActor"));
818
819 assert!(trader.add_actor(actor1).is_ok());
821 assert_eq!(trader.actor_count(), 1);
822
823 let result = trader.add_actor(actor2);
825 assert!(result.is_err());
826 assert!(
827 result
828 .unwrap_err()
829 .to_string()
830 .contains("already registered")
831 );
832 assert_eq!(trader.actor_count(), 1);
833 }
834
835 #[test]
836 fn test_add_strategy_success() {
837 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
838 create_trader_components();
839 let trader_id = TraderId::default();
840 let instance_id = UUID4::new();
841
842 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock);
843
844 let strategy = Box::new(MockComponent::new("Test-Strategy"));
845 let strategy_id = StrategyId::from(strategy.id().to_string().as_str());
846
847 let result = trader.add_strategy(strategy);
848 assert!(result.is_ok());
849 assert_eq!(trader.strategy_count(), 1);
850 assert_eq!(trader.component_count(), 1);
851 assert!(trader.strategy_ids().contains(&strategy_id));
852 }
853
854 #[test]
855 fn test_add_exec_algorithm_success() {
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);
862
863 let exec_algorithm = Box::new(MockComponent::new("TestExecAlgorithm"));
864 let exec_algorithm_id = ExecAlgorithmId::from(exec_algorithm.id().to_string().as_str());
865
866 let result = trader.add_exec_algorithm(exec_algorithm);
867 assert!(result.is_ok());
868 assert_eq!(trader.exec_algorithm_count(), 1);
869 assert_eq!(trader.component_count(), 1);
870 assert!(trader.exec_algorithm_ids().contains(&exec_algorithm_id));
871 }
872
873 #[test]
874 fn test_component_lifecycle() {
875 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
876 create_trader_components();
877 let trader_id = TraderId::default();
878 let instance_id = UUID4::new();
879
880 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock);
881
882 let actor = Box::new(MockComponent::new("TestActor"));
884 let strategy = Box::new(MockComponent::new("Test-Strategy"));
885 let exec_algorithm = Box::new(MockComponent::new("TestExecAlgorithm"));
886
887 assert!(trader.add_actor(actor).is_ok());
888 assert!(trader.add_strategy(strategy).is_ok());
889 assert!(trader.add_exec_algorithm(exec_algorithm).is_ok());
890 assert_eq!(trader.component_count(), 3);
891
892 assert!(trader.start_components().is_ok());
894
895 assert!(trader.stop_components().is_ok());
897
898 assert!(trader.reset_components().is_ok());
900
901 assert!(trader.dispose_components().is_ok());
903 assert_eq!(trader.component_count(), 0);
904 }
905
906 #[test]
907 fn test_trader_component_lifecycle() {
908 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
909 create_trader_components();
910 let trader_id = TraderId::default();
911 let instance_id = UUID4::new();
912
913 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock);
914
915 assert_eq!(trader.state(), ComponentState::PreInitialized);
917 assert!(!trader.is_running());
918 assert!(!trader.is_stopped());
919 assert!(!trader.is_disposed());
920
921 assert!(trader.start().is_err());
923
924 trader.state = ComponentState::Ready;
926
927 assert!(trader.start().is_ok());
929 assert_eq!(trader.state(), ComponentState::Running);
930 assert!(trader.is_running());
931 assert!(trader.ts_started().is_some());
932
933 assert!(trader.stop().is_ok());
935 assert_eq!(trader.state(), ComponentState::Stopped);
936 assert!(trader.is_stopped());
937 assert!(trader.ts_stopped().is_some());
938
939 assert!(trader.reset().is_ok());
941 assert_eq!(trader.state(), ComponentState::Ready);
942 assert!(trader.ts_started().is_none());
943 assert!(trader.ts_stopped().is_none());
944
945 assert!(trader.dispose().is_ok());
947 assert_eq!(trader.state(), ComponentState::Disposed);
948 assert!(trader.is_disposed());
949 }
950
951 #[test]
952 fn test_cannot_add_components_while_running() {
953 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
954 create_trader_components();
955 let trader_id = TraderId::default();
956 let instance_id = UUID4::new();
957
958 let mut trader = Trader::new(trader_id, instance_id, Environment::Backtest, clock);
959
960 trader.state = ComponentState::Running;
962
963 let actor = Box::new(MockComponent::new("TestActor"));
964 let result = trader.add_actor(actor);
965 assert!(result.is_err());
966 assert!(
967 result
968 .unwrap_err()
969 .to_string()
970 .contains("while trader is running")
971 );
972 }
973
974 #[test]
975 fn test_create_component_clock_backtest_vs_live() {
976 let (msgbus, cache, portfolio, data_engine, risk_engine, exec_engine, clock) =
977 create_trader_components();
978 let trader_id = TraderId::default();
979 let instance_id = UUID4::new();
980
981 let trader_backtest =
983 Trader::new(trader_id, instance_id, Environment::Backtest, clock.clone());
984
985 let backtest_clock = trader_backtest.create_component_clock();
986 assert_ne!(
988 backtest_clock.as_ptr() as *const _,
989 clock.as_ptr() as *const _
990 );
991
992 let trader_live = Trader::new(trader_id, instance_id, Environment::Live, clock.clone());
994
995 let live_clock = trader_live.create_component_clock();
996 assert_eq!(live_clock.as_ptr() as *const _, clock.as_ptr() as *const _);
998 }
999}