1use std::fmt::{Debug, Display};
17
18use derive_builder::Builder;
19use indexmap::IndexMap;
20use nautilus_core::{UUID4, UnixNanos};
21use rust_decimal::Decimal;
22use serde::{Deserialize, Serialize};
23use ustr::Ustr;
24
25use crate::{
26 enums::{
27 ContingencyType, LiquiditySide, OrderSide, OrderType, TimeInForce, TrailingOffsetType,
28 TriggerType,
29 },
30 events::OrderEvent,
31 identifiers::{
32 AccountId, ClientOrderId, ExecAlgorithmId, InstrumentId, OrderListId, PositionId,
33 StrategyId, TradeId, TraderId, VenueOrderId,
34 },
35 orders::OrderAny,
36 types::{Currency, Money, Price, Quantity},
37};
38
39#[repr(C)]
46#[derive(Clone, PartialEq, Eq, Builder, Serialize, Deserialize)]
47#[serde(tag = "type")]
48#[cfg_attr(any(test, feature = "stubs"), builder(default))]
49#[cfg_attr(
50 feature = "python",
51 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model")
52)]
53pub struct OrderInitialized {
54 pub trader_id: TraderId,
56 pub strategy_id: StrategyId,
58 pub instrument_id: InstrumentId,
60 pub client_order_id: ClientOrderId,
62 pub order_side: OrderSide,
64 pub order_type: OrderType,
66 pub quantity: Quantity,
68 pub time_in_force: TimeInForce,
70 pub post_only: bool,
72 pub reduce_only: bool,
74 pub quote_quantity: bool,
76 pub reconciliation: bool,
78 pub event_id: UUID4,
80 pub ts_event: UnixNanos,
82 pub ts_init: UnixNanos,
84 pub price: Option<Price>,
86 pub trigger_price: Option<Price>,
88 pub trigger_type: Option<TriggerType>,
90 pub limit_offset: Option<Decimal>,
92 pub trailing_offset: Option<Decimal>,
94 pub trailing_offset_type: Option<TrailingOffsetType>,
96 pub expire_time: Option<UnixNanos>,
98 pub display_qty: Option<Quantity>,
100 pub emulation_trigger: Option<TriggerType>,
102 pub trigger_instrument_id: Option<InstrumentId>,
104 pub contingency_type: Option<ContingencyType>,
106 pub order_list_id: Option<OrderListId>,
108 pub linked_order_ids: Option<Vec<ClientOrderId>>,
110 pub parent_order_id: Option<ClientOrderId>,
112 pub exec_algorithm_id: Option<ExecAlgorithmId>,
114 pub exec_algorithm_params: Option<IndexMap<Ustr, Ustr>>,
116 pub exec_spawn_id: Option<ClientOrderId>,
118 pub tags: Option<Vec<Ustr>>,
120}
121
122impl OrderInitialized {
123 #[allow(clippy::too_many_arguments)]
125 pub fn new(
126 trader_id: TraderId,
127 strategy_id: StrategyId,
128 instrument_id: InstrumentId,
129 client_order_id: ClientOrderId,
130 order_side: OrderSide,
131 order_type: OrderType,
132 quantity: Quantity,
133 time_in_force: TimeInForce,
134 post_only: bool,
135 reduce_only: bool,
136 quote_quantity: bool,
137 reconciliation: bool,
138 event_id: UUID4,
139 ts_event: UnixNanos,
140 ts_init: UnixNanos,
141 price: Option<Price>,
142 trigger_price: Option<Price>,
143 trigger_type: Option<TriggerType>,
144 limit_offset: Option<Decimal>,
145 trailing_offset: Option<Decimal>,
146 trailing_offset_type: Option<TrailingOffsetType>,
147 expire_time: Option<UnixNanos>,
148 display_qty: Option<Quantity>,
149 emulation_trigger: Option<TriggerType>,
150 trigger_instrument_id: Option<InstrumentId>,
151 contingency_type: Option<ContingencyType>,
152 order_list_id: Option<OrderListId>,
153 linked_order_ids: Option<Vec<ClientOrderId>>,
154 parent_order_id: Option<ClientOrderId>,
155 exec_algorithm_id: Option<ExecAlgorithmId>,
156 exec_algorithm_params: Option<IndexMap<Ustr, Ustr>>,
157 exec_spawn_id: Option<ClientOrderId>,
158 tags: Option<Vec<Ustr>>,
159 ) -> Self {
160 Self {
161 trader_id,
162 strategy_id,
163 instrument_id,
164 client_order_id,
165 order_side,
166 order_type,
167 quantity,
168 time_in_force,
169 post_only,
170 reduce_only,
171 quote_quantity,
172 reconciliation,
173 event_id,
174 ts_event,
175 ts_init,
176 price,
177 trigger_price,
178 trigger_type,
179 limit_offset,
180 trailing_offset,
181 trailing_offset_type,
182 expire_time,
183 display_qty,
184 emulation_trigger,
185 trigger_instrument_id,
186 contingency_type,
187 order_list_id,
188 linked_order_ids,
189 parent_order_id,
190 exec_algorithm_id,
191 exec_algorithm_params,
192 exec_spawn_id,
193 tags,
194 }
195 }
196}
197
198impl Debug for OrderInitialized {
199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200 write!(
201 f,
202 "{}(\
203 trader_id={}, \
204 strategy_id={}, \
205 instrument_id={}, \
206 client_order_id={}, \
207 side={}, \
208 type={}, \
209 quantity={}, \
210 time_in_force={}, \
211 post_only={}, \
212 reduce_only={}, \
213 quote_quantity={}, \
214 price={}, \
215 emulation_trigger={}, \
216 trigger_instrument_id={}, \
217 contingency_type={}, \
218 order_list_id={}, \
219 linked_order_ids=[{}], \
220 parent_order_id={}, \
221 exec_algorithm_id={}, \
222 exec_algorithm_params={}, \
223 exec_spawn_id={}, \
224 tags={}, \
225 event_id={}, \
226 ts_init={})",
227 stringify!(OrderInitialized),
228 self.trader_id,
229 self.strategy_id,
230 self.instrument_id,
231 self.client_order_id,
232 self.order_side,
233 self.order_type,
234 self.quantity,
235 self.time_in_force,
236 self.post_only,
237 self.reduce_only,
238 self.quote_quantity,
239 self.price
240 .map_or("None".to_string(), |price| format!("{price}")),
241 self.emulation_trigger
242 .map_or("None".to_string(), |trigger| format!("{trigger}")),
243 self.trigger_instrument_id
244 .map_or("None".to_string(), |instrument_id| format!(
245 "{instrument_id}"
246 )),
247 self.contingency_type
248 .map_or("None".to_string(), |contingency_type| format!(
249 "{contingency_type}"
250 )),
251 self.order_list_id
252 .map_or("None".to_string(), |order_list_id| format!(
253 "{order_list_id}"
254 )),
255 self.linked_order_ids
256 .as_ref()
257 .map_or("None".to_string(), |linked_order_ids| linked_order_ids
258 .iter()
259 .map(ToString::to_string)
260 .collect::<Vec<_>>()
261 .join(", ")),
262 self.parent_order_id
263 .map_or("None".to_string(), |parent_order_id| format!(
264 "{parent_order_id}"
265 )),
266 self.exec_algorithm_id
267 .map_or("None".to_string(), |exec_algorithm_id| format!(
268 "{exec_algorithm_id}"
269 )),
270 self.exec_algorithm_params
271 .as_ref()
272 .map_or("None".to_string(), |exec_algorithm_params| format!(
273 "{exec_algorithm_params:?}"
274 )),
275 self.exec_spawn_id
276 .map_or("None".to_string(), |exec_spawn_id| format!(
277 "{exec_spawn_id}"
278 )),
279 self.tags.as_ref().map_or("None".to_string(), |tags| tags
280 .iter()
281 .map(|x| x.to_string())
282 .collect::<Vec<String>>()
283 .join(", ")),
284 self.event_id,
285 self.ts_init
286 )
287 }
288}
289
290impl Display for OrderInitialized {
291 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
292 write!(
293 f,
294 "{}(\
295 instrument_id={}, \
296 client_order_id={}, \
297 side={}, \
298 type={}, \
299 quantity={}, \
300 time_in_force={}, \
301 post_only={}, \
302 reduce_only={}, \
303 quote_quantity={}, \
304 price={}, \
305 emulation_trigger={}, \
306 trigger_instrument_id={}, \
307 contingency_type={}, \
308 order_list_id={}, \
309 linked_order_ids=[{}], \
310 parent_order_id={}, \
311 exec_algorithm_id={}, \
312 exec_algorithm_params={}, \
313 exec_spawn_id={}, \
314 tags={})",
315 stringify!(OrderInitialized),
316 self.instrument_id,
317 self.client_order_id,
318 self.order_side,
319 self.order_type,
320 self.quantity,
321 self.time_in_force,
322 self.post_only,
323 self.reduce_only,
324 self.quote_quantity,
325 self.price
326 .map_or("None".to_string(), |price| format!("{price}")),
327 self.emulation_trigger
328 .map_or("None".to_string(), |trigger| format!("{trigger}")),
329 self.trigger_instrument_id
330 .map_or("None".to_string(), |instrument_id| format!(
331 "{instrument_id}"
332 )),
333 self.contingency_type
334 .map_or("None".to_string(), |contingency_type| format!(
335 "{contingency_type}"
336 )),
337 self.order_list_id
338 .map_or("None".to_string(), |order_list_id| format!(
339 "{order_list_id}"
340 )),
341 self.linked_order_ids
342 .as_ref()
343 .map_or("None".to_string(), |linked_order_ids| linked_order_ids
344 .iter()
345 .map(ToString::to_string)
346 .collect::<Vec<_>>()
347 .join(", ")),
348 self.parent_order_id
349 .map_or("None".to_string(), |parent_order_id| format!(
350 "{parent_order_id}"
351 )),
352 self.exec_algorithm_id
353 .map_or("None".to_string(), |exec_algorithm_id| format!(
354 "{exec_algorithm_id}"
355 )),
356 self.exec_algorithm_params
357 .as_ref()
358 .map_or("None".to_string(), |exec_algorithm_params| format!(
359 "{exec_algorithm_params:?}"
360 )),
361 self.exec_spawn_id
362 .map_or("None".to_string(), |exec_spawn_id| format!(
363 "{exec_spawn_id}"
364 )),
365 self.tags.as_ref().map_or("None".to_string(), |tags| tags
366 .iter()
367 .map(|s| s.to_string())
368 .collect::<Vec<String>>()
369 .join(", ")),
370 )
371 }
372}
373
374impl OrderEvent for OrderInitialized {
375 fn id(&self) -> UUID4 {
376 self.event_id
377 }
378
379 fn kind(&self) -> &str {
380 stringify!(OrderInitialized)
381 }
382
383 fn order_type(&self) -> Option<OrderType> {
384 Some(self.order_type)
385 }
386
387 fn order_side(&self) -> Option<OrderSide> {
388 Some(self.order_side)
389 }
390
391 fn trader_id(&self) -> TraderId {
392 self.trader_id
393 }
394
395 fn strategy_id(&self) -> StrategyId {
396 self.strategy_id
397 }
398
399 fn instrument_id(&self) -> InstrumentId {
400 self.instrument_id
401 }
402
403 fn trade_id(&self) -> Option<TradeId> {
404 None
405 }
406
407 fn currency(&self) -> Option<Currency> {
408 None
409 }
410
411 fn client_order_id(&self) -> ClientOrderId {
412 self.client_order_id
413 }
414
415 fn reason(&self) -> Option<Ustr> {
416 None
417 }
418
419 fn quantity(&self) -> Option<Quantity> {
420 Some(self.quantity)
421 }
422
423 fn time_in_force(&self) -> Option<TimeInForce> {
424 Some(self.time_in_force)
425 }
426
427 fn liquidity_side(&self) -> Option<LiquiditySide> {
428 None
429 }
430
431 fn post_only(&self) -> Option<bool> {
432 Some(self.post_only)
433 }
434
435 fn reduce_only(&self) -> Option<bool> {
436 Some(self.reduce_only)
437 }
438
439 fn quote_quantity(&self) -> Option<bool> {
440 Some(self.quote_quantity)
441 }
442
443 fn reconciliation(&self) -> bool {
444 false
445 }
446
447 fn price(&self) -> Option<Price> {
448 self.price
449 }
450
451 fn last_px(&self) -> Option<Price> {
452 None
453 }
454
455 fn last_qty(&self) -> Option<Quantity> {
456 None
457 }
458
459 fn trigger_price(&self) -> Option<Price> {
460 self.trigger_price
461 }
462
463 fn trigger_type(&self) -> Option<TriggerType> {
464 self.trigger_type
465 }
466
467 fn limit_offset(&self) -> Option<Decimal> {
468 self.limit_offset
469 }
470
471 fn trailing_offset(&self) -> Option<Decimal> {
472 self.trailing_offset
473 }
474
475 fn trailing_offset_type(&self) -> Option<TrailingOffsetType> {
476 self.trailing_offset_type
477 }
478
479 fn expire_time(&self) -> Option<UnixNanos> {
480 self.expire_time
481 }
482
483 fn display_qty(&self) -> Option<Quantity> {
484 self.display_qty
485 }
486
487 fn emulation_trigger(&self) -> Option<TriggerType> {
488 self.emulation_trigger
489 }
490
491 fn trigger_instrument_id(&self) -> Option<InstrumentId> {
492 self.trigger_instrument_id
493 }
494
495 fn contingency_type(&self) -> Option<ContingencyType> {
496 self.contingency_type
497 }
498
499 fn order_list_id(&self) -> Option<OrderListId> {
500 self.order_list_id
501 }
502
503 fn linked_order_ids(&self) -> Option<Vec<ClientOrderId>> {
504 self.linked_order_ids.clone()
505 }
506
507 fn parent_order_id(&self) -> Option<ClientOrderId> {
508 self.parent_order_id
509 }
510
511 fn exec_algorithm_id(&self) -> Option<ExecAlgorithmId> {
512 self.exec_algorithm_id
513 }
514
515 fn exec_spawn_id(&self) -> Option<ClientOrderId> {
516 self.exec_spawn_id
517 }
518
519 fn venue_order_id(&self) -> Option<VenueOrderId> {
520 None
521 }
522
523 fn account_id(&self) -> Option<AccountId> {
524 None
525 }
526
527 fn position_id(&self) -> Option<PositionId> {
528 None
529 }
530
531 fn commission(&self) -> Option<Money> {
532 None
533 }
534
535 fn ts_event(&self) -> UnixNanos {
536 self.ts_event
537 }
538
539 fn ts_init(&self) -> UnixNanos {
540 self.ts_init
541 }
542}
543
544impl From<OrderInitialized> for OrderAny {
545 fn from(order: OrderInitialized) -> Self {
546 match order.order_type {
547 OrderType::Limit => Self::Limit(order.into()),
548 OrderType::Market => Self::Market(order.into()),
549 OrderType::StopMarket => Self::StopMarket(order.into()),
550 OrderType::StopLimit => Self::StopLimit(order.into()),
551 OrderType::LimitIfTouched => Self::LimitIfTouched(order.into()),
552 OrderType::TrailingStopLimit => Self::TrailingStopLimit(order.into()),
553 OrderType::TrailingStopMarket => Self::TrailingStopMarket(order.into()),
554 OrderType::MarketToLimit => Self::MarketToLimit(order.into()),
555 OrderType::MarketIfTouched => Self::MarketIfTouched(order.into()),
556 }
557 }
558}
559
560#[cfg(test)]
561mod test {
562 use rstest::rstest;
563
564 use crate::events::order::{initialized::OrderInitialized, stubs::*};
565 #[rstest]
566 fn test_order_initialized(order_initialized_buy_limit: OrderInitialized) {
567 let display = format!("{order_initialized_buy_limit}");
568 assert_eq!(
569 display,
570 "OrderInitialized(instrument_id=BTCUSDT.COINBASE, client_order_id=O-19700101-000000-001-001-1, \
571 side=BUY, type=LIMIT, quantity=0.561, time_in_force=DAY, post_only=true, reduce_only=true, \
572 quote_quantity=false, price=22000, emulation_trigger=BID_ASK, trigger_instrument_id=BTCUSDT.COINBASE, \
573 contingency_type=OTO, order_list_id=1, linked_order_ids=[O-2020872378424], parent_order_id=None, \
574 exec_algorithm_id=None, exec_algorithm_params=None, exec_spawn_id=None, tags=None)"
575 );
576 }
577}