1use std::collections::HashMap;
19
20use nautilus_common::{
21 cache::CacheConfig, enums::Environment, logging::logger::LoggerConfig,
22 msgbus::database::MessageBusConfig,
23};
24use nautilus_core::UUID4;
25use posei_trader::engine::config::DataEngineConfig;
26use nautilus_execution::engine::config::ExecutionEngineConfig;
27use nautilus_model::identifiers::TraderId;
28use nautilus_persistence::config::StreamingConfig;
29use nautilus_portfolio::config::PortfolioConfig;
30use nautilus_risk::engine::config::RiskEngineConfig;
31use nautilus_system::config::PoseiKernelConfig;
32use serde::{Deserialize, Serialize};
33
34#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
36pub struct LiveDataEngineConfig {
37 pub qsize: u32,
39}
40
41impl Default for LiveDataEngineConfig {
42 fn default() -> Self {
43 Self { qsize: 100_000 }
44 }
45}
46
47impl From<LiveDataEngineConfig> for DataEngineConfig {
48 fn from(_config: LiveDataEngineConfig) -> Self {
49 Self::default()
50 }
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
55pub struct LiveRiskEngineConfig {
56 pub qsize: u32,
58}
59
60impl Default for LiveRiskEngineConfig {
61 fn default() -> Self {
62 Self { qsize: 100_000 }
63 }
64}
65
66impl From<LiveRiskEngineConfig> for RiskEngineConfig {
67 fn from(_config: LiveRiskEngineConfig) -> Self {
68 Self::default()
69 }
70}
71
72#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
74pub struct LiveExecEngineConfig {
75 pub reconciliation: bool,
77 pub reconciliation_lookback_mins: Option<u32>,
79 pub filter_unclaimed_external_orders: bool,
81 pub filter_position_reports: bool,
83 pub generate_missing_orders: bool,
85 pub inflight_check_interval_ms: u32,
87 pub inflight_check_threshold_ms: u32,
89 pub inflight_check_retries: u32,
91 pub own_books_audit_interval_secs: Option<f64>,
93 pub open_check_interval_secs: Option<f64>,
95 pub open_check_open_only: bool,
97 pub purge_closed_orders_interval_mins: Option<u32>,
99 pub purge_closed_orders_buffer_mins: Option<u32>,
101 pub purge_closed_positions_interval_mins: Option<u32>,
103 pub purge_closed_positions_buffer_mins: Option<u32>,
105 pub purge_account_events_interval_mins: Option<u32>,
107 pub purge_account_events_lookback_mins: Option<u32>,
109 pub qsize: u32,
111}
112
113impl Default for LiveExecEngineConfig {
114 fn default() -> Self {
115 Self {
116 reconciliation: true,
117 reconciliation_lookback_mins: None,
118 filter_unclaimed_external_orders: false,
119 filter_position_reports: false,
120 generate_missing_orders: true,
121 inflight_check_interval_ms: 2_000,
122 inflight_check_threshold_ms: 5_000,
123 inflight_check_retries: 5,
124 own_books_audit_interval_secs: None,
125 open_check_interval_secs: None,
126 open_check_open_only: true,
127 purge_closed_orders_interval_mins: None,
128 purge_closed_orders_buffer_mins: None,
129 purge_closed_positions_interval_mins: None,
130 purge_closed_positions_buffer_mins: None,
131 purge_account_events_interval_mins: None,
132 purge_account_events_lookback_mins: None,
133 qsize: 100_000,
134 }
135 }
136}
137
138impl From<LiveExecEngineConfig> for ExecutionEngineConfig {
139 fn from(_config: LiveExecEngineConfig) -> Self {
140 Self::default()
141 }
142}
143
144#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
146pub struct RoutingConfig {
147 pub default: bool,
149 pub venues: Option<Vec<String>>,
151}
152
153#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
155pub struct InstrumentProviderConfig {
156 pub load_all: bool,
158 pub load_ids: bool,
160 pub filters: HashMap<String, String>,
162}
163
164impl Default for InstrumentProviderConfig {
165 fn default() -> Self {
166 Self {
167 load_all: false,
168 load_ids: true,
169 filters: HashMap::new(),
170 }
171 }
172}
173
174#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
176pub struct LiveDataClientConfig {
177 pub handle_revised_bars: bool,
179 pub instrument_provider: InstrumentProviderConfig,
181 pub routing: RoutingConfig,
183}
184
185#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
187pub struct LiveExecClientConfig {
188 pub instrument_provider: InstrumentProviderConfig,
190 pub routing: RoutingConfig,
192}
193
194#[derive(Debug, Clone)]
196pub struct LiveNodeConfig {
197 pub environment: Environment,
199 pub trader_id: TraderId,
201 pub load_state: bool,
203 pub save_state: bool,
205 pub logging: LoggerConfig,
207 pub instance_id: Option<UUID4>,
209 pub timeout_connection: u32,
211 pub timeout_reconciliation: u32,
213 pub timeout_portfolio: u32,
215 pub timeout_disconnection: u32,
217 pub timeout_post_stop: u32,
219 pub timeout_shutdown: u32,
221 pub cache: Option<CacheConfig>,
223 pub msgbus: Option<MessageBusConfig>,
225 pub portfolio: Option<PortfolioConfig>,
227 pub streaming: Option<StreamingConfig>,
229 pub data_engine: LiveDataEngineConfig,
231 pub risk_engine: LiveRiskEngineConfig,
233 pub exec_engine: LiveExecEngineConfig,
235 pub data_clients: HashMap<String, LiveDataClientConfig>,
237 pub exec_clients: HashMap<String, LiveExecClientConfig>,
239}
240
241impl Default for LiveNodeConfig {
242 fn default() -> Self {
243 Self {
244 environment: Environment::Live,
245 trader_id: TraderId::from("TRADER-001"),
246 load_state: false,
247 save_state: false,
248 logging: LoggerConfig::default(),
249 instance_id: None,
250 timeout_connection: 60,
251 timeout_reconciliation: 30,
252 timeout_portfolio: 10,
253 timeout_disconnection: 10,
254 timeout_post_stop: 10,
255 timeout_shutdown: 5,
256 cache: None,
257 msgbus: None,
258 portfolio: None,
259 streaming: None,
260 data_engine: LiveDataEngineConfig::default(),
261 risk_engine: LiveRiskEngineConfig::default(),
262 exec_engine: LiveExecEngineConfig::default(),
263 data_clients: HashMap::new(),
264 exec_clients: HashMap::new(),
265 }
266 }
267}
268
269impl PoseiKernelConfig for LiveNodeConfig {
270 fn environment(&self) -> Environment {
271 self.environment
272 }
273
274 fn trader_id(&self) -> TraderId {
275 self.trader_id
276 }
277
278 fn load_state(&self) -> bool {
279 self.load_state
280 }
281
282 fn save_state(&self) -> bool {
283 self.save_state
284 }
285
286 fn logging(&self) -> LoggerConfig {
287 self.logging.clone()
288 }
289
290 fn instance_id(&self) -> Option<UUID4> {
291 self.instance_id
292 }
293
294 fn timeout_connection(&self) -> u32 {
295 self.timeout_connection
296 }
297
298 fn timeout_reconciliation(&self) -> u32 {
299 self.timeout_reconciliation
300 }
301
302 fn timeout_portfolio(&self) -> u32 {
303 self.timeout_portfolio
304 }
305
306 fn timeout_disconnection(&self) -> u32 {
307 self.timeout_disconnection
308 }
309
310 fn timeout_post_stop(&self) -> u32 {
311 self.timeout_post_stop
312 }
313
314 fn timeout_shutdown(&self) -> u32 {
315 self.timeout_shutdown
316 }
317
318 fn cache(&self) -> Option<CacheConfig> {
319 self.cache.clone()
320 }
321
322 fn msgbus(&self) -> Option<MessageBusConfig> {
323 self.msgbus.clone()
324 }
325
326 fn data_engine(&self) -> Option<DataEngineConfig> {
327 Some(self.data_engine.clone().into())
328 }
329
330 fn risk_engine(&self) -> Option<RiskEngineConfig> {
331 Some(self.risk_engine.clone().into())
332 }
333
334 fn exec_engine(&self) -> Option<ExecutionEngineConfig> {
335 Some(self.exec_engine.clone().into())
336 }
337
338 fn portfolio(&self) -> Option<PortfolioConfig> {
339 self.portfolio.clone()
340 }
341
342 fn streaming(&self) -> Option<nautilus_persistence::config::StreamingConfig> {
343 self.streaming.clone()
344 }
345}
346
347#[cfg(test)]
352mod tests {
353 use rstest::rstest;
354
355 use super::*;
356
357 #[rstest]
358 fn test_trading_node_config_default() {
359 let config = LiveNodeConfig::default();
360
361 assert_eq!(config.environment, Environment::Live);
362 assert_eq!(config.trader_id, TraderId::from("TRADER-001"));
363 assert_eq!(config.data_engine.qsize, 100_000);
364 assert_eq!(config.risk_engine.qsize, 100_000);
365 assert_eq!(config.exec_engine.qsize, 100_000);
366 assert!(config.exec_engine.reconciliation);
367 assert!(!config.exec_engine.filter_unclaimed_external_orders);
368 assert!(config.data_clients.is_empty());
369 assert!(config.exec_clients.is_empty());
370 }
371
372 #[rstest]
373 fn test_trading_node_config_as_kernel_config() {
374 let config = LiveNodeConfig::default();
375
376 assert_eq!(config.environment(), Environment::Live);
377 assert_eq!(config.trader_id(), TraderId::from("TRADER-001"));
378 assert!(config.data_engine().is_some());
379 assert!(config.risk_engine().is_some());
380 assert!(config.exec_engine().is_some());
381 assert!(!config.load_state());
382 assert!(!config.save_state());
383 }
384
385 #[rstest]
386 fn test_live_exec_engine_config_defaults() {
387 let config = LiveExecEngineConfig::default();
388
389 assert!(config.reconciliation);
390 assert_eq!(config.reconciliation_lookback_mins, None);
391 assert!(!config.filter_unclaimed_external_orders);
392 assert!(!config.filter_position_reports);
393 assert!(config.generate_missing_orders);
394 assert_eq!(config.inflight_check_interval_ms, 2_000);
395 assert_eq!(config.inflight_check_threshold_ms, 5_000);
396 assert_eq!(config.inflight_check_retries, 5);
397 assert!(config.open_check_open_only);
398 assert_eq!(config.qsize, 100_000);
399 }
400
401 #[rstest]
402 fn test_routing_config_default() {
403 let config = RoutingConfig::default();
404
405 assert!(!config.default);
406 assert_eq!(config.venues, None);
407 }
408
409 #[rstest]
410 fn test_live_data_client_config_default() {
411 let config = LiveDataClientConfig::default();
412
413 assert!(!config.handle_revised_bars);
414 assert!(!config.instrument_provider.load_all);
415 assert!(config.instrument_provider.load_ids);
416 assert!(!config.routing.default);
417 }
418}