nautilus_model/orders/
stubs.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 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::{UnixNanos, UUID4};
19
20use super::any::OrderAny;
21use crate::{
22    enums::LiquiditySide,
23    events::{OrderAccepted, OrderEventAny, OrderFilled, OrderSubmitted},
24    identifiers::{AccountId, PositionId, TradeId, VenueOrderId},
25    instruments::InstrumentAny,
26    types::{Money, Price, Quantity},
27};
28
29// Test Event Stubs
30pub struct TestOrderEventStubs;
31
32impl TestOrderEventStubs {
33    pub fn order_submitted(order: &OrderAny, account_id: AccountId) -> OrderEventAny {
34        let event = OrderSubmitted::new(
35            order.trader_id(),
36            order.strategy_id(),
37            order.instrument_id(),
38            order.client_order_id(),
39            account_id,
40            UUID4::new(),
41            UnixNanos::default(),
42            UnixNanos::default(),
43        );
44        OrderEventAny::Submitted(event)
45    }
46
47    pub fn order_accepted(
48        order: &OrderAny,
49        account_id: AccountId,
50        venue_order_id: VenueOrderId,
51    ) -> OrderEventAny {
52        let event = OrderAccepted::new(
53            order.trader_id(),
54            order.strategy_id(),
55            order.instrument_id(),
56            order.client_order_id(),
57            venue_order_id,
58            account_id,
59            UUID4::new(),
60            UnixNanos::default(),
61            UnixNanos::default(),
62            false,
63        );
64        OrderEventAny::Accepted(event)
65    }
66
67    #[allow(clippy::too_many_arguments)]
68    pub fn order_filled(
69        order: &OrderAny,
70        instrument: &InstrumentAny,
71        trade_id: Option<TradeId>,
72        position_id: Option<PositionId>,
73        last_px: Option<Price>,
74        last_qty: Option<Quantity>,
75        liquidity_side: Option<LiquiditySide>,
76        commission: Option<Money>,
77        ts_filled_ns: Option<UnixNanos>,
78        account_id: Option<AccountId>,
79    ) -> OrderEventAny {
80        let venue_order_id = order.venue_order_id().unwrap_or_default();
81        let account_id = account_id
82            .or(order.account_id())
83            .unwrap_or(AccountId::from("SIM-001"));
84        let trade_id = trade_id.unwrap_or(TradeId::new(
85            order.client_order_id().as_str().replace('O', "E").as_str(),
86        ));
87        let liquidity_side = liquidity_side.unwrap_or(LiquiditySide::Maker);
88        let event = UUID4::new();
89        let position_id = position_id
90            .or_else(|| order.position_id())
91            .unwrap_or(PositionId::new("1"));
92        let commission = commission.unwrap_or(Money::from("2 USD"));
93        let last_px = last_px.unwrap_or(Price::from_str("1.0").unwrap());
94        let last_qty = last_qty.unwrap_or(order.quantity());
95        let event = OrderFilled::new(
96            order.trader_id(),
97            order.strategy_id(),
98            instrument.id(),
99            order.client_order_id(),
100            venue_order_id,
101            account_id,
102            trade_id,
103            order.order_side(),
104            order.order_type(),
105            last_qty,
106            last_px,
107            instrument.quote_currency(),
108            liquidity_side,
109            event,
110            ts_filled_ns.unwrap_or_default(),
111            UnixNanos::default(),
112            false,
113            Some(position_id),
114            Some(commission),
115        );
116        OrderEventAny::Filled(event)
117    }
118}
119
120pub struct TestOrderStubs;
121
122impl TestOrderStubs {
123    pub fn make_accepted_order(order: &OrderAny) -> OrderAny {
124        let mut new_order = order.clone();
125        let submitted_event =
126            TestOrderEventStubs::order_submitted(&new_order, AccountId::from("SIM-001"));
127        let accepted_event = TestOrderEventStubs::order_accepted(
128            &new_order,
129            AccountId::from("SIM-001"),
130            VenueOrderId::from("V-001"),
131        );
132        new_order.apply(submitted_event).unwrap();
133        new_order.apply(accepted_event).unwrap();
134        new_order
135    }
136
137    pub fn make_filled_order(
138        order: &OrderAny,
139        instrument: &InstrumentAny,
140        liquidity_side: LiquiditySide,
141    ) -> OrderAny {
142        let mut accepted_order = TestOrderStubs::make_accepted_order(order);
143        let fill = TestOrderEventStubs::order_filled(
144            &accepted_order,
145            instrument,
146            None,
147            None,
148            None,
149            None,
150            Some(liquidity_side),
151            None,
152            None,
153            None,
154        );
155        accepted_order.apply(fill).unwrap();
156        accepted_order
157    }
158}