Skip to main content

nautilus_common/messages/execution/
submit.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 std::fmt::Display;
17
18use nautilus_core::{Params, UUID4, UnixNanos, correctness::check_equal};
19use nautilus_model::{
20    events::OrderInitialized,
21    identifiers::{
22        ClientId, ClientOrderId, ExecAlgorithmId, InstrumentId, PositionId, StrategyId, TraderId,
23    },
24    orders::{Order, OrderAny, OrderList},
25};
26use serde::{Deserialize, Serialize};
27
28#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
29#[serde(tag = "type")]
30pub struct SubmitOrder {
31    pub trader_id: TraderId,
32    pub client_id: Option<ClientId>,
33    pub strategy_id: StrategyId,
34    pub instrument_id: InstrumentId,
35    pub client_order_id: ClientOrderId,
36    pub order_init: OrderInitialized,
37    pub exec_algorithm_id: Option<ExecAlgorithmId>,
38    pub position_id: Option<PositionId>,
39    pub params: Option<Params>,
40    pub command_id: UUID4,
41    pub ts_init: UnixNanos,
42    pub correlation_id: Option<UUID4>,
43    #[serde(default, skip_serializing_if = "Option::is_none")]
44    pub causation_id: Option<UUID4>,
45}
46
47impl SubmitOrder {
48    /// Creates a new [`SubmitOrder`] instance.
49    #[expect(clippy::too_many_arguments)]
50    #[must_use]
51    pub const fn new(
52        trader_id: TraderId,
53        client_id: Option<ClientId>,
54        strategy_id: StrategyId,
55        instrument_id: InstrumentId,
56        client_order_id: ClientOrderId,
57        order_init: OrderInitialized,
58        exec_algorithm_id: Option<ExecAlgorithmId>,
59        position_id: Option<PositionId>,
60        params: Option<Params>,
61        command_id: UUID4,
62        ts_init: UnixNanos,
63        correlation_id: Option<UUID4>,
64    ) -> Self {
65        Self {
66            trader_id,
67            client_id,
68            strategy_id,
69            instrument_id,
70            client_order_id,
71            order_init,
72            exec_algorithm_id,
73            position_id,
74            params,
75            command_id,
76            ts_init,
77            correlation_id,
78            causation_id: None,
79        }
80    }
81
82    /// Creates a new [`SubmitOrder`] from an existing order.
83    #[must_use]
84    pub fn from_order(
85        order: &OrderAny,
86        trader_id: TraderId,
87        client_id: Option<ClientId>,
88        position_id: Option<PositionId>,
89        command_id: UUID4,
90        ts_init: UnixNanos,
91    ) -> Self {
92        Self {
93            trader_id,
94            client_id,
95            strategy_id: order.strategy_id(),
96            instrument_id: order.instrument_id(),
97            client_order_id: order.client_order_id(),
98            order_init: OrderInitialized::from(order),
99            exec_algorithm_id: order.exec_algorithm_id(),
100            position_id,
101            params: None,
102            command_id,
103            ts_init,
104            correlation_id: None,
105            causation_id: None,
106        }
107    }
108}
109
110impl Display for SubmitOrder {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        write!(
113            f,
114            "SubmitOrder(instrument_id={}, client_order_id={}, position_id={})",
115            self.instrument_id,
116            self.client_order_id,
117            self.position_id
118                .map_or("None".to_string(), |position_id| format!("{position_id}")),
119        )
120    }
121}
122
123#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
124#[serde(tag = "type")]
125pub struct SubmitOrderList {
126    pub trader_id: TraderId,
127    pub client_id: Option<ClientId>,
128    pub strategy_id: StrategyId,
129    pub instrument_id: InstrumentId,
130    pub order_list: OrderList,
131    pub order_inits: Vec<OrderInitialized>,
132    pub exec_algorithm_id: Option<ExecAlgorithmId>,
133    pub position_id: Option<PositionId>,
134    pub params: Option<Params>,
135    pub command_id: UUID4,
136    pub ts_init: UnixNanos,
137    pub correlation_id: Option<UUID4>,
138    #[serde(default, skip_serializing_if = "Option::is_none")]
139    pub causation_id: Option<UUID4>,
140}
141
142impl SubmitOrderList {
143    /// Creates a new [`SubmitOrderList`] instance.
144    ///
145    /// # Panics
146    ///
147    /// Panics if `order_inits` length doesn't match `order_list.client_order_ids`, or if
148    /// the client order IDs don't match in order.
149    #[expect(clippy::too_many_arguments)]
150    #[must_use]
151    pub fn new(
152        trader_id: TraderId,
153        client_id: Option<ClientId>,
154        strategy_id: StrategyId,
155        order_list: OrderList,
156        order_inits: Vec<OrderInitialized>,
157        exec_algorithm_id: Option<ExecAlgorithmId>,
158        position_id: Option<PositionId>,
159        params: Option<Params>,
160        command_id: UUID4,
161        ts_init: UnixNanos,
162        correlation_id: Option<UUID4>,
163    ) -> Self {
164        check_equal(
165            &order_inits.len(),
166            &order_list.client_order_ids.len(),
167            "order_inits.len()",
168            "order_list.client_order_ids.len()",
169        )
170        .unwrap();
171
172        for (init, id) in order_inits.iter().zip(order_list.client_order_ids.iter()) {
173            check_equal(
174                &init.client_order_id,
175                id,
176                "order_init.client_order_id",
177                "order_list.client_order_ids id",
178            )
179            .unwrap();
180        }
181
182        Self {
183            trader_id,
184            client_id,
185            strategy_id,
186            instrument_id: order_list.instrument_id,
187            order_list,
188            order_inits,
189            exec_algorithm_id,
190            position_id,
191            params,
192            command_id,
193            ts_init,
194            correlation_id,
195            causation_id: None,
196        }
197    }
198}
199
200impl Display for SubmitOrderList {
201    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202        write!(
203            f,
204            "SubmitOrderList(instrument_id={}, order_list={}, position_id={})",
205            self.instrument_id,
206            self.order_list.id,
207            self.position_id
208                .map_or("None".to_string(), |position_id| format!("{position_id}")),
209        )
210    }
211}