nautilus_trading/strategy/
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
16use nautilus_core::serialization::{default_false, default_true};
17use nautilus_model::{
18    enums::OmsType,
19    identifiers::{InstrumentId, StrategyId},
20};
21use serde::{Deserialize, Serialize};
22
23/// The base model for all trading strategy configurations.
24#[derive(Clone, Debug, Deserialize, Serialize)]
25#[cfg_attr(
26    feature = "python",
27    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.trading")
28)]
29pub struct StrategyConfig {
30    /// The unique ID for the strategy. Will become the strategy ID if not None.
31    pub strategy_id: Option<StrategyId>,
32    /// The unique order ID tag for the strategy. Must be unique
33    /// amongst all running strategies for a particular trader ID.
34    pub order_id_tag: Option<String>,
35    /// If UUID4's should be used for client order ID values.
36    #[serde(default = "default_false")]
37    pub use_uuid_client_order_ids: bool,
38    /// If hyphens should be used in generated client order ID values.
39    #[serde(default = "default_true")]
40    pub use_hyphens_in_client_order_ids: bool,
41    /// The order management system type for the strategy. This will determine
42    /// how the `ExecutionEngine` handles position IDs.
43    pub oms_type: Option<OmsType>,
44    /// The external order claim instrument IDs.
45    /// External orders for matching instrument IDs will be associated with (claimed by) the strategy.
46    pub external_order_claims: Option<Vec<InstrumentId>>,
47    /// If OUO and OCO **open** contingent orders should be managed automatically by the strategy.
48    /// Any emulated orders which are active local will be managed by the `OrderEmulator` instead.
49    #[serde(default = "default_false")]
50    pub manage_contingent_orders: bool,
51    /// If all order GTD time in force expirations should be managed by the strategy.
52    /// If True, then will ensure open orders have their GTD timers re-activated on start.
53    #[serde(default = "default_false")]
54    pub manage_gtd_expiry: bool,
55    /// If events should be logged by the strategy.
56    /// If False, then only warning events and above are logged.
57    #[serde(default = "default_true")]
58    pub log_events: bool,
59    /// If commands should be logged by the strategy.
60    #[serde(default = "default_true")]
61    pub log_commands: bool,
62    /// If order rejected events where `due_post_only` is True should be logged as warnings.
63    #[serde(default = "default_true")]
64    pub log_rejected_due_post_only_as_warning: bool,
65}
66
67impl Default for StrategyConfig {
68    fn default() -> Self {
69        Self {
70            strategy_id: None,
71            order_id_tag: None,
72            use_uuid_client_order_ids: false,
73            use_hyphens_in_client_order_ids: true,
74            oms_type: None,
75            external_order_claims: None,
76            manage_contingent_orders: false,
77            manage_gtd_expiry: false,
78            log_events: true,
79            log_commands: true,
80            log_rejected_due_post_only_as_warning: true,
81        }
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use rstest::rstest;
88
89    use super::*;
90
91    #[rstest]
92    fn test_strategy_config_default() {
93        let config = StrategyConfig::default();
94
95        assert!(config.strategy_id.is_none());
96        assert!(config.order_id_tag.is_none());
97        assert!(!config.use_uuid_client_order_ids);
98        assert!(config.use_hyphens_in_client_order_ids);
99        assert!(config.oms_type.is_none());
100        assert!(config.external_order_claims.is_none());
101        assert!(!config.manage_contingent_orders);
102        assert!(!config.manage_gtd_expiry);
103        assert!(config.log_events);
104        assert!(config.log_commands);
105        assert!(config.log_rejected_due_post_only_as_warning);
106    }
107
108    #[rstest]
109    fn test_strategy_config_with_strategy_id() {
110        let strategy_id = StrategyId::from("TEST-001");
111        let config = StrategyConfig {
112            strategy_id: Some(strategy_id),
113            ..Default::default()
114        };
115
116        assert_eq!(config.strategy_id, Some(strategy_id));
117    }
118
119    #[rstest]
120    fn test_strategy_config_serialization() {
121        let config = StrategyConfig {
122            strategy_id: Some(StrategyId::from("TEST-001")),
123            order_id_tag: Some("TAG1".to_string()),
124            use_uuid_client_order_ids: true,
125            ..Default::default()
126        };
127
128        let json = serde_json::to_string(&config).unwrap();
129        let deserialized: StrategyConfig = serde_json::from_str(&json).unwrap();
130
131        assert_eq!(config.strategy_id, deserialized.strategy_id);
132        assert_eq!(config.order_id_tag, deserialized.order_id_tag);
133        assert_eq!(
134            config.use_uuid_client_order_ids,
135            deserialized.use_uuid_client_order_ids
136        );
137    }
138}