nautilus_trading/strategy/
core.rs1use std::{
17 cell::RefCell,
18 fmt::Debug,
19 ops::{Deref, DerefMut},
20 rc::Rc,
21};
22
23use ahash::AHashMap;
24use nautilus_common::{
25 actor::{DataActorConfig, DataActorCore},
26 cache::Cache,
27 clock::Clock,
28 factories::OrderFactory,
29};
30use nautilus_core::time::get_atomic_clock_static;
31use nautilus_execution::order_manager::manager::OrderManager;
32use nautilus_model::identifiers::{ActorId, ClientOrderId, StrategyId, TraderId};
33use nautilus_portfolio::portfolio::Portfolio;
34use ustr::Ustr;
35
36use super::config::StrategyConfig;
37
38pub struct StrategyCore {
45 pub actor: DataActorCore,
47 pub config: StrategyConfig,
49 pub order_manager: Option<OrderManager>,
51 pub order_factory: Option<OrderFactory>,
53 pub portfolio: Option<Rc<RefCell<Portfolio>>>,
55 pub gtd_timers: AHashMap<ClientOrderId, Ustr>,
57}
58
59impl Debug for StrategyCore {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 f.debug_struct("StrategyCore")
62 .field("actor", &self.actor)
63 .field("config", &self.config)
64 .field("order_manager", &self.order_manager)
65 .field("order_factory", &self.order_factory)
66 .finish()
67 }
68}
69
70impl StrategyCore {
71 pub fn new(config: StrategyConfig) -> Self {
73 let actor_config = DataActorConfig {
74 actor_id: config
75 .strategy_id
76 .map(|id| ActorId::from(id.inner().as_str())),
77 log_events: config.log_events,
78 log_commands: config.log_commands,
79 };
80
81 Self {
82 actor: DataActorCore::new(actor_config),
83 config,
84 order_manager: None,
85 order_factory: None,
86 portfolio: None,
87 gtd_timers: AHashMap::new(),
88 }
89 }
90
91 pub fn register(
99 &mut self,
100 trader_id: TraderId,
101 clock: Rc<RefCell<dyn Clock>>,
102 cache: Rc<RefCell<Cache>>,
103 portfolio: Rc<RefCell<Portfolio>>,
104 ) -> anyhow::Result<()> {
105 self.actor
106 .register(trader_id, clock.clone(), cache.clone())?;
107
108 let strategy_id = StrategyId::from(self.actor.actor_id.inner().as_str());
109
110 self.order_factory = Some(OrderFactory::new(
111 trader_id,
112 strategy_id,
113 None,
114 None,
115 get_atomic_clock_static(),
116 self.config.use_uuid_client_order_ids,
117 self.config.use_hyphens_in_client_order_ids,
118 ));
119
120 self.order_manager = Some(OrderManager::new(
121 clock, cache, false, ));
123
124 self.portfolio = Some(portfolio);
125
126 Ok(())
127 }
128}
129
130impl Deref for StrategyCore {
131 type Target = DataActorCore;
132 fn deref(&self) -> &Self::Target {
133 &self.actor
134 }
135}
136
137impl DerefMut for StrategyCore {
138 fn deref_mut(&mut self) -> &mut Self::Target {
139 &mut self.actor
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use std::{cell::RefCell, rc::Rc};
146
147 use nautilus_common::{cache::Cache, clock::TestClock};
148 use nautilus_model::identifiers::{StrategyId, TraderId};
149 use nautilus_portfolio::portfolio::Portfolio;
150 use rstest::rstest;
151
152 use super::*;
153
154 fn create_test_config() -> StrategyConfig {
155 StrategyConfig {
156 strategy_id: Some(StrategyId::from("TEST-001")),
157 order_id_tag: Some("001".to_string()),
158 ..Default::default()
159 }
160 }
161
162 #[rstest]
163 fn test_strategy_core_new() {
164 let config = create_test_config();
165 let core = StrategyCore::new(config.clone());
166
167 assert_eq!(core.config.strategy_id, config.strategy_id);
168 assert_eq!(core.config.order_id_tag, config.order_id_tag);
169 assert!(core.order_manager.is_none());
170 assert!(core.order_factory.is_none());
171 assert!(core.portfolio.is_none());
172 }
173
174 #[rstest]
175 fn test_strategy_core_register() {
176 let config = create_test_config();
177 let mut core = StrategyCore::new(config);
178
179 let trader_id = TraderId::from("TRADER-001");
180 let clock = Rc::new(RefCell::new(TestClock::new()));
181 let cache = Rc::new(RefCell::new(Cache::default()));
182 let portfolio = Rc::new(RefCell::new(Portfolio::new(
183 cache.clone(),
184 clock.clone(),
185 None,
186 )));
187
188 let result = core.register(trader_id, clock, cache, portfolio);
189 assert!(result.is_ok());
190
191 assert!(core.order_manager.is_some());
192 assert!(core.order_factory.is_some());
193 assert!(core.portfolio.is_some());
194 assert_eq!(core.trader_id(), Some(trader_id));
195 }
196
197 #[rstest]
198 fn test_strategy_core_deref() {
199 let config = create_test_config();
200 let core = StrategyCore::new(config);
201
202 assert!(core.trader_id().is_none());
203 }
204
205 #[rstest]
206 fn test_strategy_core_debug() {
207 let config = create_test_config();
208 let core = StrategyCore::new(config);
209
210 let debug_str = format!("{core:?}");
211 assert!(debug_str.contains("StrategyCore"));
212 }
213}