1use std::{collections::HashMap, time::Duration};
19
20use nautilus_common::{
21 cache::CacheConfig, enums::Environment, logging::logger::LoggerConfig,
22 msgbus::database::MessageBusConfig,
23};
24use nautilus_core::UUID4;
25use nautilus_data::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::NautilusKernelConfig;
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_startup_delay_secs: Option<f64>,
79 pub reconciliation_lookback_mins: Option<u32>,
81 pub reconciliation_instrument_ids: Option<Vec<String>>,
83 pub filtered_client_order_ids: Option<Vec<String>>,
85 pub filter_unclaimed_external_orders: bool,
87 pub filter_position_reports: bool,
89 pub generate_missing_orders: bool,
91 pub inflight_check_interval_ms: u32,
93 pub inflight_check_threshold_ms: u32,
95 pub inflight_check_retries: u32,
97 pub own_books_audit_interval_secs: Option<f64>,
99 pub open_check_interval_secs: Option<f64>,
101 pub open_check_lookback_mins: Option<u32>,
103 pub open_check_missing_retries: Option<u32>,
105 pub open_check_open_only: bool,
107 pub purge_closed_orders_interval_mins: Option<u32>,
109 pub purge_closed_orders_buffer_mins: Option<u32>,
111 pub purge_closed_positions_interval_mins: Option<u32>,
113 pub purge_closed_positions_buffer_mins: Option<u32>,
115 pub purge_account_events_interval_mins: Option<u32>,
117 pub purge_account_events_lookback_mins: Option<u32>,
119 pub qsize: u32,
121}
122
123impl Default for LiveExecEngineConfig {
124 fn default() -> Self {
125 Self {
126 reconciliation: true,
127 reconciliation_startup_delay_secs: Some(10.0),
128 reconciliation_lookback_mins: None,
129 reconciliation_instrument_ids: None,
130 filtered_client_order_ids: None,
131 filter_unclaimed_external_orders: false,
132 filter_position_reports: false,
133 generate_missing_orders: true,
134 inflight_check_interval_ms: 2_000,
135 inflight_check_threshold_ms: 5_000,
136 inflight_check_retries: 5,
137 own_books_audit_interval_secs: None,
138 open_check_interval_secs: None,
139 open_check_lookback_mins: None,
140 open_check_missing_retries: None,
141 open_check_open_only: true,
142 purge_closed_orders_interval_mins: None,
143 purge_closed_orders_buffer_mins: None,
144 purge_closed_positions_interval_mins: None,
145 purge_closed_positions_buffer_mins: None,
146 purge_account_events_interval_mins: None,
147 purge_account_events_lookback_mins: None,
148 qsize: 100_000,
149 }
150 }
151}
152
153impl From<LiveExecEngineConfig> for ExecutionEngineConfig {
154 fn from(_config: LiveExecEngineConfig) -> Self {
155 Self::default()
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
161pub struct RoutingConfig {
162 pub default: bool,
164 pub venues: Option<Vec<String>>,
166}
167
168#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
170pub struct InstrumentProviderConfig {
171 pub load_all: bool,
173 pub load_ids: bool,
175 pub filters: HashMap<String, String>,
177}
178
179impl Default for InstrumentProviderConfig {
180 fn default() -> Self {
181 Self {
182 load_all: false,
183 load_ids: true,
184 filters: HashMap::new(),
185 }
186 }
187}
188
189#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
191pub struct LiveDataClientConfig {
192 pub handle_revised_bars: bool,
194 pub instrument_provider: InstrumentProviderConfig,
196 pub routing: RoutingConfig,
198}
199
200#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
202pub struct LiveExecClientConfig {
203 pub instrument_provider: InstrumentProviderConfig,
205 pub routing: RoutingConfig,
207}
208
209#[derive(Debug, Clone)]
211pub struct LiveNodeConfig {
212 pub environment: Environment,
214 pub trader_id: TraderId,
216 pub load_state: bool,
218 pub save_state: bool,
220 pub logging: LoggerConfig,
222 pub instance_id: Option<UUID4>,
224 pub timeout_connection: Duration,
226 pub timeout_reconciliation: Duration,
228 pub timeout_portfolio: Duration,
230 pub timeout_disconnection: Duration,
232 pub delay_post_stop: Duration,
234 pub timeout_shutdown: Duration,
236 pub cache: Option<CacheConfig>,
238 pub msgbus: Option<MessageBusConfig>,
240 pub portfolio: Option<PortfolioConfig>,
242 pub streaming: Option<StreamingConfig>,
244 pub data_engine: LiveDataEngineConfig,
246 pub risk_engine: LiveRiskEngineConfig,
248 pub exec_engine: LiveExecEngineConfig,
250 pub data_clients: HashMap<String, LiveDataClientConfig>,
252 pub exec_clients: HashMap<String, LiveExecClientConfig>,
254}
255
256impl Default for LiveNodeConfig {
257 fn default() -> Self {
258 Self {
259 environment: Environment::Live,
260 trader_id: TraderId::from("TRADER-001"),
261 load_state: false,
262 save_state: false,
263 logging: LoggerConfig::default(),
264 instance_id: None,
265 timeout_connection: Duration::from_secs(60),
266 timeout_reconciliation: Duration::from_secs(30),
267 timeout_portfolio: Duration::from_secs(10),
268 timeout_disconnection: Duration::from_secs(10),
269 delay_post_stop: Duration::from_secs(10),
270 timeout_shutdown: Duration::from_secs(5),
271 cache: None,
272 msgbus: None,
273 portfolio: None,
274 streaming: None,
275 data_engine: LiveDataEngineConfig::default(),
276 risk_engine: LiveRiskEngineConfig::default(),
277 exec_engine: LiveExecEngineConfig::default(),
278 data_clients: HashMap::new(),
279 exec_clients: HashMap::new(),
280 }
281 }
282}
283
284impl NautilusKernelConfig for LiveNodeConfig {
285 fn environment(&self) -> Environment {
286 self.environment
287 }
288
289 fn trader_id(&self) -> TraderId {
290 self.trader_id
291 }
292
293 fn load_state(&self) -> bool {
294 self.load_state
295 }
296
297 fn save_state(&self) -> bool {
298 self.save_state
299 }
300
301 fn logging(&self) -> LoggerConfig {
302 self.logging.clone()
303 }
304
305 fn instance_id(&self) -> Option<UUID4> {
306 self.instance_id
307 }
308
309 fn timeout_connection(&self) -> Duration {
310 self.timeout_connection
311 }
312
313 fn timeout_reconciliation(&self) -> Duration {
314 self.timeout_reconciliation
315 }
316
317 fn timeout_portfolio(&self) -> Duration {
318 self.timeout_portfolio
319 }
320
321 fn timeout_disconnection(&self) -> Duration {
322 self.timeout_disconnection
323 }
324
325 fn delay_post_stop(&self) -> Duration {
326 self.delay_post_stop
327 }
328
329 fn timeout_shutdown(&self) -> Duration {
330 self.timeout_shutdown
331 }
332
333 fn cache(&self) -> Option<CacheConfig> {
334 self.cache.clone()
335 }
336
337 fn msgbus(&self) -> Option<MessageBusConfig> {
338 self.msgbus.clone()
339 }
340
341 fn data_engine(&self) -> Option<DataEngineConfig> {
342 Some(self.data_engine.clone().into())
343 }
344
345 fn risk_engine(&self) -> Option<RiskEngineConfig> {
346 Some(self.risk_engine.clone().into())
347 }
348
349 fn exec_engine(&self) -> Option<ExecutionEngineConfig> {
350 Some(self.exec_engine.clone().into())
351 }
352
353 fn portfolio(&self) -> Option<PortfolioConfig> {
354 self.portfolio.clone()
355 }
356
357 fn streaming(&self) -> Option<nautilus_persistence::config::StreamingConfig> {
358 self.streaming.clone()
359 }
360}
361
362#[cfg(test)]
367mod tests {
368 use rstest::rstest;
369
370 use super::*;
371
372 #[rstest]
373 fn test_trading_node_config_default() {
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_eq!(config.data_engine.qsize, 100_000);
379 assert_eq!(config.risk_engine.qsize, 100_000);
380 assert_eq!(config.exec_engine.qsize, 100_000);
381 assert!(config.exec_engine.reconciliation);
382 assert!(!config.exec_engine.filter_unclaimed_external_orders);
383 assert!(config.data_clients.is_empty());
384 assert!(config.exec_clients.is_empty());
385 }
386
387 #[rstest]
388 fn test_trading_node_config_as_kernel_config() {
389 let config = LiveNodeConfig::default();
390
391 assert_eq!(config.environment(), Environment::Live);
392 assert_eq!(config.trader_id(), TraderId::from("TRADER-001"));
393 assert!(config.data_engine().is_some());
394 assert!(config.risk_engine().is_some());
395 assert!(config.exec_engine().is_some());
396 assert!(!config.load_state());
397 assert!(!config.save_state());
398 }
399
400 #[rstest]
401 fn test_live_exec_engine_config_defaults() {
402 let config = LiveExecEngineConfig::default();
403
404 assert!(config.reconciliation);
405 assert_eq!(config.reconciliation_startup_delay_secs, Some(10.0));
406 assert_eq!(config.reconciliation_lookback_mins, None);
407 assert_eq!(config.reconciliation_instrument_ids, None);
408 assert_eq!(config.filtered_client_order_ids, None);
409 assert!(!config.filter_unclaimed_external_orders);
410 assert!(!config.filter_position_reports);
411 assert!(config.generate_missing_orders);
412 assert_eq!(config.inflight_check_interval_ms, 2_000);
413 assert_eq!(config.inflight_check_threshold_ms, 5_000);
414 assert_eq!(config.inflight_check_retries, 5);
415 assert_eq!(config.open_check_lookback_mins, None);
416 assert_eq!(config.open_check_missing_retries, None);
417 assert!(config.open_check_open_only);
418 assert_eq!(config.qsize, 100_000);
419 }
420
421 #[rstest]
422 fn test_routing_config_default() {
423 let config = RoutingConfig::default();
424
425 assert!(!config.default);
426 assert_eq!(config.venues, None);
427 }
428
429 #[rstest]
430 fn test_live_data_client_config_default() {
431 let config = LiveDataClientConfig::default();
432
433 assert!(!config.handle_revised_bars);
434 assert!(!config.instrument_provider.load_all);
435 assert!(config.instrument_provider.load_ids);
436 assert!(!config.routing.default);
437 }
438}