nautilus_model/events/order/spec/
rejected.rs1use nautilus_core::{UUID4, UnixNanos};
17use ustr::Ustr;
18
19use crate::{
20 events::OrderRejected,
21 identifiers::{AccountId, ClientOrderId, InstrumentId, StrategyId, TraderId},
22 stubs::{TestDefault, test_uuid},
23};
24
25#[derive(Debug, Clone, bon::Builder)]
31#[builder(finish_fn = into_spec)]
32pub struct OrderRejectedSpec {
33 #[builder(default = TraderId::test_default())]
34 pub trader_id: TraderId,
35 #[builder(default = StrategyId::test_default())]
36 pub strategy_id: StrategyId,
37 #[builder(default = InstrumentId::test_default())]
38 pub instrument_id: InstrumentId,
39 #[builder(default = ClientOrderId::test_default())]
40 pub client_order_id: ClientOrderId,
41 #[builder(default = AccountId::test_default())]
42 pub account_id: AccountId,
43 #[builder(default = Ustr::from("TEST"))]
44 pub reason: Ustr,
45 #[builder(default = test_uuid())]
46 pub event_id: UUID4,
47 #[builder(default = UnixNanos::default())]
48 pub ts_event: UnixNanos,
49 #[builder(default = UnixNanos::default())]
50 pub ts_init: UnixNanos,
51 #[builder(default = false)]
52 pub reconciliation: bool,
53 #[builder(default = false)]
54 pub due_post_only: bool,
55}
56
57impl<S: order_rejected_spec_builder::IsComplete> OrderRejectedSpecBuilder<S> {
58 #[must_use]
60 pub fn build(self) -> OrderRejected {
61 let spec = self.into_spec();
62 OrderRejected::new(
63 spec.trader_id,
64 spec.strategy_id,
65 spec.instrument_id,
66 spec.client_order_id,
67 spec.account_id,
68 spec.reason,
69 spec.event_id,
70 spec.ts_event,
71 spec.ts_init,
72 spec.reconciliation,
73 spec.due_post_only,
74 )
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use rstest::rstest;
81
82 use super::*;
83 use crate::stubs::reset_test_uuid_rng;
84
85 #[rstest]
86 fn defaults_are_sensible() {
87 let event = OrderRejectedSpec::builder().build();
90 assert_eq!(event.trader_id, TraderId::test_default());
91 assert_eq!(event.strategy_id, StrategyId::test_default());
92 assert_eq!(event.instrument_id, InstrumentId::test_default());
93 assert_eq!(event.client_order_id, ClientOrderId::test_default());
94 assert_eq!(event.account_id, AccountId::test_default());
95 assert_eq!(event.reason, Ustr::from("TEST"));
96 assert_eq!(event.ts_event, UnixNanos::default());
97 assert_eq!(event.ts_init, UnixNanos::default());
98 assert_eq!(event.reconciliation, 0);
99 assert_eq!(event.due_post_only, 0);
100 }
101
102 #[rstest]
103 fn overrides_apply_through_constructor() {
104 let event = OrderRejectedSpec::builder()
105 .reason(Ustr::from("INSUFFICIENT_MARGIN"))
106 .reconciliation(true)
107 .due_post_only(true)
108 .build();
109
110 assert_eq!(event.reason, Ustr::from("INSUFFICIENT_MARGIN"));
111 assert_eq!(event.reconciliation, 1);
113 assert_eq!(event.due_post_only, 1);
114 assert_eq!(event.trader_id, TraderId::test_default());
115 }
116
117 #[rstest]
118 fn event_ids_are_unique_within_a_run() {
119 reset_test_uuid_rng();
120 let a = OrderRejectedSpec::builder().build();
121 let b = OrderRejectedSpec::builder().build();
122 let c = OrderRejectedSpec::builder().build();
123 assert_ne!(a.event_id, b.event_id);
124 assert_ne!(b.event_id, c.event_id);
125 assert_ne!(a.event_id, c.event_id);
126 }
127
128 #[rstest]
129 fn event_id_sequence_is_reproducible() {
130 reset_test_uuid_rng();
132 let first_run: Vec<_> = (0..3)
133 .map(|_| OrderRejectedSpec::builder().build().event_id)
134 .collect();
135
136 reset_test_uuid_rng();
137 let second_run: Vec<_> = (0..3)
138 .map(|_| OrderRejectedSpec::builder().build().event_id)
139 .collect();
140
141 assert_eq!(first_run, second_run);
142 }
143}