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