Skip to main content

nautilus_model/events/order/
stubs.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::str::FromStr;
17
18use nautilus_core::UUID4;
19use rstest::fixture;
20use ustr::Ustr;
21
22use crate::{
23    enums::{ContingencyType, OrderType, TriggerType},
24    events::{
25        OrderAccepted, OrderCancelRejected, OrderCanceled, OrderDenied, OrderEmulated,
26        OrderExpired, OrderFilled, OrderInitialized, OrderModifyRejected, OrderPendingCancel,
27        OrderPendingUpdate, OrderRejected, OrderReleased, OrderSubmitted, OrderTriggered,
28        OrderUpdated,
29        order::spec::{
30            OrderAcceptedSpec, OrderCancelRejectedSpec, OrderCanceledSpec, OrderDeniedSpec,
31            OrderEmulatedSpec, OrderExpiredSpec, OrderFilledSpec, OrderInitializedSpec,
32            OrderModifyRejectedSpec, OrderPendingCancelSpec, OrderPendingUpdateSpec,
33            OrderRejectedSpec, OrderReleasedSpec, OrderSubmittedSpec, OrderTriggeredSpec,
34            OrderUpdatedSpec,
35        },
36    },
37    identifiers::{
38        AccountId, ClientOrderId, InstrumentId, OrderListId, StrategyId, TraderId, VenueOrderId,
39        stubs as id_stubs,
40    },
41    stubs::TestDefault,
42    types::{Currency, Money, Price, Quantity},
43};
44
45// Fixture wrappers for rstest - these are not glob-exported to avoid ambiguity
46#[fixture]
47pub fn trader_id() -> TraderId {
48    id_stubs::trader_id()
49}
50
51#[fixture]
52pub fn strategy_id_ema_cross() -> StrategyId {
53    id_stubs::strategy_id_ema_cross()
54}
55
56#[fixture]
57pub fn instrument_id_btc_usdt() -> InstrumentId {
58    id_stubs::instrument_id_btc_usdt()
59}
60
61#[fixture]
62pub fn client_order_id() -> ClientOrderId {
63    id_stubs::client_order_id()
64}
65
66#[fixture]
67pub fn venue_order_id() -> VenueOrderId {
68    id_stubs::venue_order_id()
69}
70
71#[fixture]
72pub fn account_id() -> AccountId {
73    id_stubs::account_id()
74}
75
76#[fixture]
77pub fn uuid4() -> UUID4 {
78    id_stubs::uuid4()
79}
80
81#[fixture]
82pub fn order_filled(
83    trader_id: TraderId,
84    strategy_id_ema_cross: StrategyId,
85    instrument_id_btc_usdt: InstrumentId,
86    client_order_id: ClientOrderId,
87    uuid4: UUID4,
88) -> OrderFilled {
89    OrderFilledSpec::builder()
90        .trader_id(trader_id)
91        .strategy_id(strategy_id_ema_cross)
92        .instrument_id(instrument_id_btc_usdt)
93        .client_order_id(client_order_id)
94        .venue_order_id(VenueOrderId::new("123456"))
95        .order_type(OrderType::Limit)
96        .last_qty(Quantity::from_str("0.561").unwrap())
97        .last_px(Price::from_str("22000").unwrap())
98        .currency(Currency::from_str("USDT").unwrap())
99        .event_id(uuid4)
100        .commission(Money::from("12.2 USDT"))
101        .build()
102}
103
104#[fixture]
105pub fn order_denied_max_submitted_rate(
106    trader_id: TraderId,
107    strategy_id_ema_cross: StrategyId,
108    instrument_id_btc_usdt: InstrumentId,
109    client_order_id: ClientOrderId,
110    uuid4: UUID4,
111) -> OrderDenied {
112    OrderDeniedSpec::builder()
113        .trader_id(trader_id)
114        .strategy_id(strategy_id_ema_cross)
115        .instrument_id(instrument_id_btc_usdt)
116        .client_order_id(client_order_id)
117        .reason(Ustr::from("RATE_LIMIT_EXCEEDED"))
118        .event_id(uuid4)
119        .build()
120}
121
122#[fixture]
123pub fn order_rejected_insufficient_margin(
124    trader_id: TraderId,
125    account_id: AccountId,
126    strategy_id_ema_cross: StrategyId,
127    instrument_id_btc_usdt: InstrumentId,
128    client_order_id: ClientOrderId,
129    uuid4: UUID4,
130) -> OrderRejected {
131    OrderRejectedSpec::builder()
132        .trader_id(trader_id)
133        .strategy_id(strategy_id_ema_cross)
134        .instrument_id(instrument_id_btc_usdt)
135        .client_order_id(client_order_id)
136        .account_id(account_id)
137        .reason(Ustr::from("INSUFFICIENT_MARGIN"))
138        .event_id(uuid4)
139        .build()
140}
141
142#[fixture]
143pub fn order_initialized_buy_limit(
144    trader_id: TraderId,
145    strategy_id_ema_cross: StrategyId,
146    instrument_id_btc_usdt: InstrumentId,
147    client_order_id: ClientOrderId,
148    uuid4: UUID4,
149) -> OrderInitialized {
150    let order_list_id = OrderListId::new("1");
151    let linked_order_ids = vec![ClientOrderId::new("O-2020872378424")];
152    OrderInitializedSpec::builder()
153        .trader_id(trader_id)
154        .strategy_id(strategy_id_ema_cross)
155        .instrument_id(instrument_id_btc_usdt)
156        .client_order_id(client_order_id)
157        .order_type(OrderType::Limit)
158        .quantity(Quantity::from_str("0.561").unwrap())
159        .post_only(true)
160        .reduce_only(true)
161        .event_id(uuid4)
162        .price(Price::from_str("22000").unwrap())
163        .emulation_trigger(TriggerType::BidAsk)
164        .trigger_instrument_id(instrument_id_btc_usdt)
165        .contingency_type(ContingencyType::Oto)
166        .order_list_id(order_list_id)
167        .linked_order_ids(linked_order_ids)
168        .build()
169}
170
171#[fixture]
172pub fn order_submitted(
173    trader_id: TraderId,
174    strategy_id_ema_cross: StrategyId,
175    instrument_id_btc_usdt: InstrumentId,
176    client_order_id: ClientOrderId,
177    account_id: AccountId,
178    uuid4: UUID4,
179) -> OrderSubmitted {
180    OrderSubmittedSpec::builder()
181        .trader_id(trader_id)
182        .strategy_id(strategy_id_ema_cross)
183        .instrument_id(instrument_id_btc_usdt)
184        .client_order_id(client_order_id)
185        .account_id(account_id)
186        .event_id(uuid4)
187        .build()
188}
189
190#[fixture]
191pub fn order_triggered(
192    trader_id: TraderId,
193    strategy_id_ema_cross: StrategyId,
194    instrument_id_btc_usdt: InstrumentId,
195    client_order_id: ClientOrderId,
196    venue_order_id: VenueOrderId,
197    account_id: AccountId,
198    uuid4: UUID4,
199) -> OrderTriggered {
200    OrderTriggeredSpec::builder()
201        .trader_id(trader_id)
202        .strategy_id(strategy_id_ema_cross)
203        .instrument_id(instrument_id_btc_usdt)
204        .client_order_id(client_order_id)
205        .event_id(uuid4)
206        .venue_order_id(venue_order_id)
207        .account_id(account_id)
208        .build()
209}
210
211#[fixture]
212pub fn order_emulated(
213    trader_id: TraderId,
214    strategy_id_ema_cross: StrategyId,
215    instrument_id_btc_usdt: InstrumentId,
216    client_order_id: ClientOrderId,
217    uuid4: UUID4,
218) -> OrderEmulated {
219    OrderEmulatedSpec::builder()
220        .trader_id(trader_id)
221        .strategy_id(strategy_id_ema_cross)
222        .instrument_id(instrument_id_btc_usdt)
223        .client_order_id(client_order_id)
224        .event_id(uuid4)
225        .build()
226}
227
228#[fixture]
229pub fn order_released(
230    trader_id: TraderId,
231    strategy_id_ema_cross: StrategyId,
232    instrument_id_btc_usdt: InstrumentId,
233    client_order_id: ClientOrderId,
234    uuid4: UUID4,
235) -> OrderReleased {
236    OrderReleasedSpec::builder()
237        .trader_id(trader_id)
238        .strategy_id(strategy_id_ema_cross)
239        .instrument_id(instrument_id_btc_usdt)
240        .client_order_id(client_order_id)
241        .released_price(Price::from_str("22000").unwrap())
242        .event_id(uuid4)
243        .build()
244}
245
246#[fixture]
247pub fn order_updated(
248    trader_id: TraderId,
249    strategy_id_ema_cross: StrategyId,
250    instrument_id_btc_usdt: InstrumentId,
251    client_order_id: ClientOrderId,
252    venue_order_id: VenueOrderId,
253    account_id: AccountId,
254    uuid4: UUID4,
255) -> OrderUpdated {
256    OrderUpdatedSpec::builder()
257        .trader_id(trader_id)
258        .strategy_id(strategy_id_ema_cross)
259        .instrument_id(instrument_id_btc_usdt)
260        .client_order_id(client_order_id)
261        .quantity(Quantity::from(100))
262        .event_id(uuid4)
263        .venue_order_id(venue_order_id)
264        .account_id(account_id)
265        .price(Price::from("22000"))
266        .build()
267}
268
269#[fixture]
270pub fn order_pending_update(
271    trader_id: TraderId,
272    strategy_id_ema_cross: StrategyId,
273    instrument_id_btc_usdt: InstrumentId,
274    client_order_id: ClientOrderId,
275    account_id: AccountId,
276    venue_order_id: VenueOrderId,
277    uuid4: UUID4,
278) -> OrderPendingUpdate {
279    OrderPendingUpdateSpec::builder()
280        .trader_id(trader_id)
281        .strategy_id(strategy_id_ema_cross)
282        .instrument_id(instrument_id_btc_usdt)
283        .client_order_id(client_order_id)
284        .account_id(account_id)
285        .event_id(uuid4)
286        .venue_order_id(venue_order_id)
287        .build()
288}
289
290#[fixture]
291pub fn order_pending_cancel(
292    trader_id: TraderId,
293    strategy_id_ema_cross: StrategyId,
294    instrument_id_btc_usdt: InstrumentId,
295    client_order_id: ClientOrderId,
296    account_id: AccountId,
297    venue_order_id: VenueOrderId,
298    uuid4: UUID4,
299) -> OrderPendingCancel {
300    OrderPendingCancelSpec::builder()
301        .trader_id(trader_id)
302        .strategy_id(strategy_id_ema_cross)
303        .instrument_id(instrument_id_btc_usdt)
304        .client_order_id(client_order_id)
305        .account_id(account_id)
306        .event_id(uuid4)
307        .venue_order_id(venue_order_id)
308        .build()
309}
310
311#[fixture]
312pub fn order_modify_rejected(
313    trader_id: TraderId,
314    strategy_id_ema_cross: StrategyId,
315    instrument_id_btc_usdt: InstrumentId,
316    client_order_id: ClientOrderId,
317    venue_order_id: VenueOrderId,
318    account_id: AccountId,
319    uuid4: UUID4,
320) -> OrderModifyRejected {
321    OrderModifyRejectedSpec::builder()
322        .trader_id(trader_id)
323        .strategy_id(strategy_id_ema_cross)
324        .instrument_id(instrument_id_btc_usdt)
325        .client_order_id(client_order_id)
326        .reason(Ustr::from("ORDER_DOES_NOT_EXIST"))
327        .event_id(uuid4)
328        .venue_order_id(venue_order_id)
329        .account_id(account_id)
330        .build()
331}
332
333#[fixture]
334pub fn order_accepted(
335    trader_id: TraderId,
336    strategy_id_ema_cross: StrategyId,
337    instrument_id_btc_usdt: InstrumentId,
338    client_order_id: ClientOrderId,
339    account_id: AccountId,
340    venue_order_id: VenueOrderId,
341    uuid4: UUID4,
342) -> OrderAccepted {
343    OrderAcceptedSpec::builder()
344        .trader_id(trader_id)
345        .strategy_id(strategy_id_ema_cross)
346        .instrument_id(instrument_id_btc_usdt)
347        .client_order_id(client_order_id)
348        .venue_order_id(venue_order_id)
349        .account_id(account_id)
350        .event_id(uuid4)
351        .build()
352}
353
354#[fixture]
355pub fn order_cancel_rejected(
356    trader_id: TraderId,
357    strategy_id_ema_cross: StrategyId,
358    instrument_id_btc_usdt: InstrumentId,
359    client_order_id: ClientOrderId,
360    venue_order_id: VenueOrderId,
361    account_id: AccountId,
362    uuid4: UUID4,
363) -> OrderCancelRejected {
364    OrderCancelRejectedSpec::builder()
365        .trader_id(trader_id)
366        .strategy_id(strategy_id_ema_cross)
367        .instrument_id(instrument_id_btc_usdt)
368        .client_order_id(client_order_id)
369        .reason(Ustr::from("ORDER_DOES_NOT_EXIST"))
370        .event_id(uuid4)
371        .venue_order_id(venue_order_id)
372        .account_id(account_id)
373        .build()
374}
375
376#[fixture]
377pub fn order_expired(
378    trader_id: TraderId,
379    strategy_id_ema_cross: StrategyId,
380    instrument_id_btc_usdt: InstrumentId,
381    client_order_id: ClientOrderId,
382    venue_order_id: VenueOrderId,
383    account_id: AccountId,
384    uuid4: UUID4,
385) -> OrderExpired {
386    OrderExpiredSpec::builder()
387        .trader_id(trader_id)
388        .strategy_id(strategy_id_ema_cross)
389        .instrument_id(instrument_id_btc_usdt)
390        .client_order_id(client_order_id)
391        .event_id(uuid4)
392        .venue_order_id(venue_order_id)
393        .account_id(account_id)
394        .build()
395}
396
397impl TestDefault for OrderAccepted {
398    fn test_default() -> Self {
399        OrderAcceptedSpec::builder()
400            .event_id(UUID4::default())
401            .build()
402    }
403}
404
405impl Default for OrderAccepted {
406    fn default() -> Self {
407        Self::test_default()
408    }
409}
410
411impl TestDefault for OrderCanceled {
412    fn test_default() -> Self {
413        OrderCanceledSpec::builder()
414            .event_id(UUID4::default())
415            .build()
416    }
417}
418
419impl Default for OrderCanceled {
420    fn default() -> Self {
421        Self::test_default()
422    }
423}
424
425impl TestDefault for OrderCancelRejected {
426    fn test_default() -> Self {
427        OrderCancelRejectedSpec::builder()
428            .event_id(UUID4::default())
429            .build()
430    }
431}
432
433impl Default for OrderCancelRejected {
434    fn default() -> Self {
435        Self::test_default()
436    }
437}
438
439impl TestDefault for OrderDenied {
440    fn test_default() -> Self {
441        OrderDeniedSpec::builder()
442            .event_id(UUID4::default())
443            .build()
444    }
445}
446
447impl Default for OrderDenied {
448    fn default() -> Self {
449        Self::test_default()
450    }
451}
452
453impl TestDefault for OrderEmulated {
454    fn test_default() -> Self {
455        OrderEmulatedSpec::builder()
456            .event_id(UUID4::default())
457            .build()
458    }
459}
460
461impl Default for OrderEmulated {
462    fn default() -> Self {
463        Self::test_default()
464    }
465}
466
467impl TestDefault for OrderExpired {
468    fn test_default() -> Self {
469        OrderExpiredSpec::builder()
470            .event_id(UUID4::default())
471            .build()
472    }
473}
474
475impl Default for OrderExpired {
476    fn default() -> Self {
477        Self::test_default()
478    }
479}
480
481impl TestDefault for OrderInitialized {
482    fn test_default() -> Self {
483        OrderInitializedSpec::builder()
484            .event_id(UUID4::default())
485            .build()
486    }
487}
488
489impl Default for OrderInitialized {
490    fn default() -> Self {
491        Self::test_default()
492    }
493}
494
495impl TestDefault for OrderModifyRejected {
496    fn test_default() -> Self {
497        OrderModifyRejectedSpec::builder()
498            .event_id(UUID4::default())
499            .build()
500    }
501}
502
503impl Default for OrderModifyRejected {
504    fn default() -> Self {
505        Self::test_default()
506    }
507}
508
509impl TestDefault for OrderPendingCancel {
510    fn test_default() -> Self {
511        OrderPendingCancelSpec::builder()
512            .event_id(UUID4::default())
513            .account_id(AccountId::test_default())
514            .build()
515    }
516}
517
518impl Default for OrderPendingCancel {
519    fn default() -> Self {
520        Self::test_default()
521    }
522}
523
524impl TestDefault for OrderPendingUpdate {
525    fn test_default() -> Self {
526        OrderPendingUpdateSpec::builder()
527            .event_id(UUID4::default())
528            .account_id(AccountId::test_default())
529            .build()
530    }
531}
532
533impl Default for OrderPendingUpdate {
534    fn default() -> Self {
535        Self::test_default()
536    }
537}
538
539impl TestDefault for OrderRejected {
540    fn test_default() -> Self {
541        OrderRejectedSpec::builder()
542            .event_id(UUID4::default())
543            .build()
544    }
545}
546
547impl Default for OrderRejected {
548    fn default() -> Self {
549        Self::test_default()
550    }
551}
552
553impl TestDefault for OrderReleased {
554    fn test_default() -> Self {
555        OrderReleasedSpec::builder()
556            .event_id(UUID4::default())
557            .build()
558    }
559}
560
561impl Default for OrderReleased {
562    fn default() -> Self {
563        Self::test_default()
564    }
565}
566
567impl TestDefault for OrderSubmitted {
568    fn test_default() -> Self {
569        OrderSubmittedSpec::builder()
570            .event_id(UUID4::default())
571            .build()
572    }
573}
574
575impl Default for OrderSubmitted {
576    fn default() -> Self {
577        Self::test_default()
578    }
579}
580
581impl TestDefault for OrderTriggered {
582    fn test_default() -> Self {
583        OrderTriggeredSpec::builder()
584            .event_id(UUID4::default())
585            .build()
586    }
587}
588
589impl Default for OrderTriggered {
590    fn default() -> Self {
591        Self::test_default()
592    }
593}
594
595impl TestDefault for OrderUpdated {
596    fn test_default() -> Self {
597        OrderUpdatedSpec::builder()
598            .event_id(UUID4::default())
599            .build()
600    }
601}
602
603impl Default for OrderUpdated {
604    fn default() -> Self {
605        Self::test_default()
606    }
607}