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