nautilus_live/execution/config.rs
1// -------------------------------------------------------------------------------------------------
2// Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3// https://nautechsystems.io
4//
5// Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6// You may not use this file except in compliance with the License.
7// You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Configuration for execution reconciliation decisions and cache retention.
17//!
18//! Thresholds, retry limits, filters, and lookbacks govern manager decisions. Startup enablement
19//! and polling intervals belong to the live node's execution-engine configuration.
20
21use indexmap::IndexSet;
22use nautilus_common::config::{ConfigError, ConfigErrorCollector, ConfigResult};
23use nautilus_core::{DurationNanos, datetime::checked_mins_to_secs};
24use nautilus_model::identifiers::{ClientOrderId, InstrumentId, TraderId};
25
26use super::submission::SubmissionRecoveryPolicy;
27
28/// Configuration for execution manager.
29#[expect(
30 clippy::struct_excessive_bools,
31 reason = "config flags mirror the live execution engine configuration surface"
32)]
33#[derive(Debug, Clone)]
34pub struct ExecutionManagerConfig {
35 /// The trader ID for generated orders.
36 pub trader_id: TraderId,
37 /// Number of minutes to look back during reconciliation.
38 pub lookback_mins: Option<u64>,
39 /// Instrument IDs to include during reconciliation (empty => all).
40 pub reconciliation_instrument_ids: IndexSet<InstrumentId>,
41 /// Whether to filter unclaimed external orders.
42 pub filter_unclaimed_external: bool,
43 /// Whether to filter position status reports during reconciliation.
44 pub filter_position_reports: bool,
45 /// Client order IDs excluded from reconciliation.
46 pub filtered_client_order_ids: IndexSet<ClientOrderId>,
47 /// Whether to generate missing orders from reports.
48 pub generate_missing_orders: bool,
49 /// Threshold in milliseconds for inflight order checks.
50 pub inflight_threshold_ms: u64,
51 /// Maximum number of retries for inflight checks.
52 pub inflight_max_retries: u32,
53 /// Policy when a submitted order exhausts automatic recovery.
54 pub submission_recovery_policy: SubmissionRecoveryPolicy,
55 /// The lookback minutes for open order checks.
56 pub open_check_lookback_mins: Option<u64>,
57 /// Threshold before acting on venue discrepancies for open orders.
58 pub open_check_threshold_ns: DurationNanos,
59 /// Maximum retries before resolving an open order missing at the venue.
60 pub open_check_missing_retries: u32,
61 /// Whether open-order polling should only request open orders from the venue.
62 pub open_check_open_only: bool,
63 /// The maximum number of single-order queries per consistency check cycle.
64 pub max_single_order_queries_per_cycle: u32,
65 /// The delay (milliseconds) between consecutive single-order queries.
66 pub single_order_query_delay_ms: u32,
67 /// The lookback minutes for position consistency checks.
68 pub position_check_lookback_mins: u64,
69 /// Threshold before acting on venue discrepancies for positions.
70 pub position_check_threshold_ns: DurationNanos,
71 /// Maximum retries before stopping position discrepancy reconciliation.
72 pub position_check_retries: u32,
73 /// The time buffer (minutes) before closed orders can be purged.
74 pub purge_closed_orders_buffer_mins: Option<u32>,
75 /// The time buffer (minutes) before closed positions can be purged.
76 pub purge_closed_positions_buffer_mins: Option<u32>,
77 /// The time buffer (minutes) before account events can be purged.
78 pub purge_account_events_lookback_mins: Option<u32>,
79 /// If purge operations should also delete from the backing database.
80 pub purge_from_database: bool,
81}
82
83impl Default for ExecutionManagerConfig {
84 fn default() -> Self {
85 Self {
86 trader_id: TraderId::default(),
87 lookback_mins: Some(60),
88 reconciliation_instrument_ids: IndexSet::new(),
89 filter_unclaimed_external: false,
90 filter_position_reports: false,
91 filtered_client_order_ids: IndexSet::new(),
92 generate_missing_orders: true,
93 inflight_threshold_ms: 5_000,
94 inflight_max_retries: 5,
95 submission_recovery_policy: SubmissionRecoveryPolicy::default(),
96 open_check_lookback_mins: Some(60),
97 open_check_threshold_ns: DurationNanos::from_secs(5),
98 open_check_missing_retries: 5,
99 open_check_open_only: true,
100 max_single_order_queries_per_cycle: 5,
101 single_order_query_delay_ms: 100,
102 position_check_lookback_mins: 60,
103 position_check_threshold_ns: DurationNanos::from_mins(1),
104 position_check_retries: 3,
105 purge_closed_orders_buffer_mins: None,
106 purge_closed_positions_buffer_mins: None,
107 purge_account_events_lookback_mins: None,
108 purge_from_database: false,
109 }
110 }
111}
112
113impl ExecutionManagerConfig {
114 /// Validates the execution manager configuration, collecting every field violation.
115 ///
116 /// # Errors
117 ///
118 /// Returns an error if any field fails validation. Multiple validation failures are collected
119 /// into one error.
120 pub fn validate(&self) -> ConfigResult<()> {
121 let mut errors = ConfigErrorCollector::with_capacity(3);
122
123 if let Some(mins) = self.lookback_mins {
124 errors.check(
125 checked_mins_to_secs(mins).is_some(),
126 ConfigError::range(
127 "ExecutionManagerConfig.lookback_mins",
128 format!("{mins} minutes (must fit in `u64` seconds)"),
129 ),
130 );
131 }
132
133 if let Some(mins) = self.open_check_lookback_mins {
134 errors.check(
135 DurationNanos::try_from_mins(mins).is_ok(),
136 ConfigError::range(
137 "ExecutionManagerConfig.open_check_lookback_mins",
138 format!("{mins} minutes (must fit in `u64` nanoseconds)"),
139 ),
140 );
141 }
142
143 errors.check(
144 DurationNanos::try_from_mins(self.position_check_lookback_mins).is_ok(),
145 ConfigError::range(
146 "ExecutionManagerConfig.position_check_lookback_mins",
147 format!(
148 "{} minutes (must fit in `u64` nanoseconds)",
149 self.position_check_lookback_mins
150 ),
151 ),
152 );
153
154 errors.into_result()
155 }
156
157 /// Sets the trader ID on the configuration.
158 #[must_use]
159 pub fn with_trader_id(mut self, trader_id: TraderId) -> Self {
160 self.trader_id = trader_id;
161 self
162 }
163}