1use std::fmt::Display;
17
18use derive_builder::Builder;
19use nautilus_core::{Params, UUID4, UnixNanos};
20use nautilus_model::{
21 enums::OrderSide,
22 identifiers::{ClientId, ClientOrderId, InstrumentId, StrategyId, TraderId, VenueOrderId},
23};
24use serde::{Deserialize, Serialize};
25
26#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Builder)]
27#[serde(tag = "type")]
28#[cfg_attr(
29 feature = "python",
30 pyo3::pyclass(module = "nautilus_trader.live", frozen, from_py_object)
31)]
32#[cfg_attr(
33 feature = "python",
34 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.live")
35)]
36pub struct CancelOrder {
37 pub trader_id: TraderId,
38 pub client_id: Option<ClientId>,
39 pub strategy_id: StrategyId,
40 pub instrument_id: InstrumentId,
41 pub client_order_id: ClientOrderId,
42 pub venue_order_id: Option<VenueOrderId>,
43 pub command_id: UUID4,
44 pub ts_init: UnixNanos,
45 pub params: Option<Params>,
46 #[builder(default)]
47 pub correlation_id: Option<UUID4>,
48 #[builder(default)]
49 #[serde(default, skip_serializing_if = "Option::is_none")]
50 pub causation_id: Option<UUID4>,
51}
52
53impl CancelOrder {
54 #[expect(clippy::too_many_arguments)]
56 #[must_use]
57 pub fn new(
58 trader_id: TraderId,
59 client_id: Option<ClientId>,
60 strategy_id: StrategyId,
61 instrument_id: InstrumentId,
62 client_order_id: ClientOrderId,
63 venue_order_id: Option<VenueOrderId>,
64 command_id: UUID4,
65 ts_init: UnixNanos,
66 params: Option<Params>,
67 correlation_id: Option<UUID4>,
68 ) -> Self {
69 Self {
70 trader_id,
71 client_id,
72 strategy_id,
73 instrument_id,
74 client_order_id,
75 venue_order_id,
76 command_id,
77 ts_init,
78 params,
79 correlation_id,
80 causation_id: None,
81 }
82 }
83}
84
85impl Display for CancelOrder {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 write!(
88 f,
89 "CancelOrder(instrument_id={}, client_order_id={}, venue_order_id={:?})",
90 self.instrument_id, self.client_order_id, self.venue_order_id,
91 )
92 }
93}
94
95#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Builder)]
96#[serde(tag = "type")]
97#[cfg_attr(
98 feature = "python",
99 pyo3::pyclass(module = "nautilus_trader.live", frozen, from_py_object)
100)]
101#[cfg_attr(
102 feature = "python",
103 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.live")
104)]
105pub struct CancelAllOrders {
106 pub trader_id: TraderId,
107 pub client_id: Option<ClientId>,
108 pub strategy_id: StrategyId,
109 pub instrument_id: InstrumentId,
110 #[serde(with = "nautilus_model::enums::serde_option_order_side")]
111 pub order_side: Option<OrderSide>,
112 pub command_id: UUID4,
113 pub ts_init: UnixNanos,
114 pub params: Option<Params>,
115 #[builder(default)]
116 pub correlation_id: Option<UUID4>,
117 #[builder(default)]
118 #[serde(default, skip_serializing_if = "Option::is_none")]
119 pub causation_id: Option<UUID4>,
120}
121
122impl CancelAllOrders {
123 #[expect(clippy::too_many_arguments)]
125 #[must_use]
126 pub fn new(
127 trader_id: TraderId,
128 client_id: Option<ClientId>,
129 strategy_id: StrategyId,
130 instrument_id: InstrumentId,
131 order_side: Option<OrderSide>,
132 command_id: UUID4,
133 ts_init: UnixNanos,
134 params: Option<Params>,
135 correlation_id: Option<UUID4>,
136 ) -> Self {
137 Self {
138 trader_id,
139 client_id,
140 strategy_id,
141 instrument_id,
142 order_side,
143 command_id,
144 ts_init,
145 params,
146 correlation_id,
147 causation_id: None,
148 }
149 }
150}
151
152impl Display for CancelAllOrders {
153 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154 let order_side = self
155 .order_side
156 .as_ref()
157 .map_or("NO_ORDER_SIDE", AsRef::as_ref);
158 write!(
159 f,
160 "CancelAllOrders(instrument_id={}, order_side={})",
161 self.instrument_id, order_side,
162 )
163 }
164}
165
166#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Builder)]
167#[serde(tag = "type")]
168#[cfg_attr(
169 feature = "python",
170 pyo3::pyclass(module = "nautilus_trader.live", frozen, from_py_object)
171)]
172#[cfg_attr(
173 feature = "python",
174 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.live")
175)]
176pub struct BatchCancelOrders {
177 pub trader_id: TraderId,
178 pub client_id: Option<ClientId>,
179 pub strategy_id: StrategyId,
180 pub instrument_id: InstrumentId,
181 pub cancels: Vec<CancelOrder>,
182 pub command_id: UUID4,
183 pub ts_init: UnixNanos,
184 pub params: Option<Params>,
185 #[builder(default)]
186 pub correlation_id: Option<UUID4>,
187 #[builder(default)]
188 #[serde(default, skip_serializing_if = "Option::is_none")]
189 pub causation_id: Option<UUID4>,
190}
191
192impl BatchCancelOrders {
193 #[expect(clippy::too_many_arguments)]
195 #[must_use]
196 pub fn new(
197 trader_id: TraderId,
198 client_id: Option<ClientId>,
199 strategy_id: StrategyId,
200 instrument_id: InstrumentId,
201 cancels: Vec<CancelOrder>,
202 command_id: UUID4,
203 ts_init: UnixNanos,
204 params: Option<Params>,
205 correlation_id: Option<UUID4>,
206 ) -> Self {
207 Self {
208 trader_id,
209 client_id,
210 strategy_id,
211 instrument_id,
212 cancels,
213 command_id,
214 ts_init,
215 params,
216 correlation_id,
217 causation_id: None,
218 }
219 }
220}
221
222impl Display for BatchCancelOrders {
223 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224 write!(
225 f,
226 "BatchCancelOrders(instrument_id={}, cancels={})",
227 self.instrument_id,
228 self.cancels.len(),
229 )
230 }
231}
232
233#[cfg(test)]
234mod tests {
235 use rstest::rstest;
236
237 use super::*;
238
239 #[rstest]
240 #[case(Some(OrderSide::Buy), "BUY")]
241 #[case(None, "NO_ORDER_SIDE")]
242 fn test_cancel_all_orders_display(
243 #[case] order_side: Option<OrderSide>,
244 #[case] expected_order_side: &str,
245 ) {
246 let command = CancelAllOrders::new(
247 TraderId::from("TRADER-001"),
248 None,
249 StrategyId::from("S-001"),
250 InstrumentId::from("AUD/USD.SIM"),
251 order_side,
252 UUID4::new(),
253 UnixNanos::default(),
254 None,
255 None,
256 );
257
258 assert_eq!(
259 command.to_string(),
260 format!("CancelAllOrders(instrument_id=AUD/USD.SIM, order_side={expected_order_side})")
261 );
262 }
263
264 #[rstest]
265 fn test_batch_cancel_orders_display() {
266 let cancel = CancelOrder::new(
267 TraderId::from("TRADER-001"),
268 None,
269 StrategyId::from("S-001"),
270 InstrumentId::from("AUD/USD.SIM"),
271 ClientOrderId::from("O-001"),
272 None,
273 UUID4::new(),
274 UnixNanos::default(),
275 None,
276 None,
277 );
278 let command = BatchCancelOrders::new(
279 TraderId::from("TRADER-001"),
280 None,
281 StrategyId::from("S-001"),
282 InstrumentId::from("AUD/USD.SIM"),
283 vec![cancel.clone(), cancel],
284 UUID4::new(),
285 UnixNanos::default(),
286 None,
287 None,
288 );
289
290 assert_eq!(
291 command.to_string(),
292 "BatchCancelOrders(instrument_id=AUD/USD.SIM, cancels=2)"
293 );
294 }
295}