Skip to main content

nautilus_trading/algorithm/
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 algorithms.
17
18use std::collections::HashMap;
19
20use nautilus_core::serialization::default_true;
21use nautilus_model::identifiers::ExecAlgorithmId;
22use serde::{Deserialize, Serialize};
23
24/// Configuration for an execution algorithm.
25#[cfg_attr(
26    feature = "python",
27    expect(
28        clippy::unsafe_derive_deserialize,
29        reason = "config deserializes plain fields; unsafe methods come from generated PyO3 integration"
30    )
31)]
32#[derive(Clone, Debug, Deserialize, Serialize, bon::Builder)]
33#[serde(deny_unknown_fields)]
34#[cfg_attr(
35    feature = "python",
36    pyo3::pyclass(
37        module = "nautilus_trader.core.nautilus_pyo3.trading",
38        subclass,
39        from_py_object
40    )
41)]
42#[cfg_attr(
43    feature = "python",
44    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.trading")
45)]
46pub struct ExecutionAlgorithmConfig {
47    /// The unique ID for the execution algorithm.
48    pub exec_algorithm_id: Option<ExecAlgorithmId>,
49    /// If events should be logged by the algorithm.
50    #[serde(default = "default_true")]
51    #[builder(default = true)]
52    pub log_events: bool,
53    /// If commands should be logged by the algorithm.
54    #[serde(default = "default_true")]
55    #[builder(default = true)]
56    pub log_commands: bool,
57}
58
59impl Default for ExecutionAlgorithmConfig {
60    fn default() -> Self {
61        Self::builder().build()
62    }
63}
64
65/// Configuration for creating execution algorithms from importable paths.
66#[cfg_attr(
67    feature = "python",
68    expect(
69        clippy::unsafe_derive_deserialize,
70        reason = "config deserializes plain fields; unsafe methods come from generated PyO3 integration"
71    )
72)]
73#[derive(Debug, Clone, Deserialize, Serialize)]
74#[serde(deny_unknown_fields)]
75#[cfg_attr(
76    feature = "python",
77    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.trading", from_py_object)
78)]
79#[cfg_attr(
80    feature = "python",
81    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.trading")
82)]
83pub struct ImportableExecAlgorithmConfig {
84    /// The fully qualified name of the execution algorithm class.
85    pub exec_algorithm_path: String,
86    /// The fully qualified name of the execution algorithm config class.
87    pub config_path: String,
88    /// The execution algorithm configuration as a dictionary.
89    pub config: HashMap<String, serde_json::Value>,
90}
91
92#[cfg(test)]
93mod tests {
94    use rstest::rstest;
95
96    use super::*;
97
98    #[rstest]
99    fn test_config_default() {
100        let config = ExecutionAlgorithmConfig::default();
101
102        assert!(config.exec_algorithm_id.is_none());
103        assert!(config.log_events);
104        assert!(config.log_commands);
105    }
106
107    #[rstest]
108    fn test_config_with_id() {
109        let exec_algorithm_id = ExecAlgorithmId::new("TWAP");
110        let config = ExecutionAlgorithmConfig {
111            exec_algorithm_id: Some(exec_algorithm_id),
112            ..Default::default()
113        };
114
115        assert_eq!(config.exec_algorithm_id, Some(exec_algorithm_id));
116    }
117
118    #[rstest]
119    fn test_config_serialization() {
120        let config = ExecutionAlgorithmConfig {
121            exec_algorithm_id: Some(ExecAlgorithmId::new("TWAP")),
122            log_events: false,
123            log_commands: true,
124        };
125
126        let json = serde_json::to_string(&config).unwrap();
127        let deserialized: ExecutionAlgorithmConfig = serde_json::from_str(&json).unwrap();
128
129        assert_eq!(config.exec_algorithm_id, deserialized.exec_algorithm_id);
130        assert_eq!(config.log_events, deserialized.log_events);
131        assert_eq!(config.log_commands, deserialized.log_commands);
132    }
133}