Skip to main content

nautilus_model/events/
mod.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
16//! Events for the trading domain model.
17
18pub mod account;
19pub mod funding;
20pub mod order;
21pub mod portfolio;
22pub mod position;
23
24use nautilus_core::UnixNanos;
25
26use crate::data::HasTsInit;
27// Re-exports
28pub use crate::events::{
29    account::state::AccountState,
30    funding::settlement::FundingSettlement,
31    order::{
32        OrderEvent, OrderEventType,
33        accepted::OrderAccepted,
34        accepted_batch::OrderAcceptedBatch,
35        any::OrderEventAny,
36        cancel_rejected::OrderCancelRejected,
37        canceled::OrderCanceled,
38        canceled_batch::OrderCanceledBatch,
39        denied::OrderDenied,
40        denied_reason::{OrderDeniedCode, OrderDeniedReason, OrderPriceField},
41        emulated::OrderEmulated,
42        expired::OrderExpired,
43        fill_voided::OrderFillVoided,
44        filled::OrderFilled,
45        initialized::OrderInitialized,
46        modify_rejected::OrderModifyRejected,
47        pending_cancel::OrderPendingCancel,
48        pending_update::OrderPendingUpdate,
49        rejected::OrderRejected,
50        released::OrderReleased,
51        snapshot::OrderSnapshot,
52        submitted::OrderSubmitted,
53        submitted_batch::OrderSubmittedBatch,
54        triggered::OrderTriggered,
55        updated::OrderUpdated,
56    },
57    portfolio::snapshot::PortfolioSnapshot,
58    position::{
59        PositionEvent, adjusted::PositionAdjusted, changed::PositionChanged,
60        closed::PositionClosed, opened::PositionOpened, snapshot::PositionSnapshot,
61    },
62};
63
64impl HasTsInit for AccountState {
65    fn ts_init(&self) -> UnixNanos {
66        self.ts_init
67    }
68}
69
70impl HasTsInit for FundingSettlement {
71    fn ts_init(&self) -> UnixNanos {
72        self.ts_init
73    }
74}
75
76impl HasTsInit for OrderInitialized {
77    fn ts_init(&self) -> UnixNanos {
78        self.ts_init
79    }
80}
81
82impl HasTsInit for OrderDenied {
83    fn ts_init(&self) -> UnixNanos {
84        self.ts_init
85    }
86}
87
88impl HasTsInit for OrderEmulated {
89    fn ts_init(&self) -> UnixNanos {
90        self.ts_init
91    }
92}
93
94impl HasTsInit for OrderSubmitted {
95    fn ts_init(&self) -> UnixNanos {
96        self.ts_init
97    }
98}
99
100impl HasTsInit for OrderAccepted {
101    fn ts_init(&self) -> UnixNanos {
102        self.ts_init
103    }
104}
105
106impl HasTsInit for OrderRejected {
107    fn ts_init(&self) -> UnixNanos {
108        self.ts_init
109    }
110}
111
112impl HasTsInit for OrderPendingCancel {
113    fn ts_init(&self) -> UnixNanos {
114        self.ts_init
115    }
116}
117
118impl HasTsInit for OrderCanceled {
119    fn ts_init(&self) -> UnixNanos {
120        self.ts_init
121    }
122}
123
124impl HasTsInit for OrderCancelRejected {
125    fn ts_init(&self) -> UnixNanos {
126        self.ts_init
127    }
128}
129
130impl HasTsInit for OrderExpired {
131    fn ts_init(&self) -> UnixNanos {
132        self.ts_init
133    }
134}
135
136impl HasTsInit for OrderTriggered {
137    fn ts_init(&self) -> UnixNanos {
138        self.ts_init
139    }
140}
141
142impl HasTsInit for OrderPendingUpdate {
143    fn ts_init(&self) -> UnixNanos {
144        self.ts_init
145    }
146}
147
148impl HasTsInit for OrderReleased {
149    fn ts_init(&self) -> UnixNanos {
150        self.ts_init
151    }
152}
153
154impl HasTsInit for OrderModifyRejected {
155    fn ts_init(&self) -> UnixNanos {
156        self.ts_init
157    }
158}
159
160impl HasTsInit for OrderUpdated {
161    fn ts_init(&self) -> UnixNanos {
162        self.ts_init
163    }
164}
165
166impl HasTsInit for OrderFilled {
167    fn ts_init(&self) -> UnixNanos {
168        self.ts_init
169    }
170}
171
172impl HasTsInit for OrderFillVoided {
173    fn ts_init(&self) -> UnixNanos {
174        self.ts_init
175    }
176}
177
178impl HasTsInit for OrderSnapshot {
179    fn ts_init(&self) -> UnixNanos {
180        self.ts_init
181    }
182}
183
184impl HasTsInit for PositionOpened {
185    fn ts_init(&self) -> UnixNanos {
186        self.ts_init
187    }
188}
189
190impl HasTsInit for PositionChanged {
191    fn ts_init(&self) -> UnixNanos {
192        self.ts_init
193    }
194}
195
196impl HasTsInit for PositionClosed {
197    fn ts_init(&self) -> UnixNanos {
198        self.ts_init
199    }
200}
201
202impl HasTsInit for PositionAdjusted {
203    fn ts_init(&self) -> UnixNanos {
204        self.ts_init
205    }
206}
207
208impl HasTsInit for PositionSnapshot {
209    fn ts_init(&self) -> UnixNanos {
210        self.ts_init
211    }
212}
213
214impl HasTsInit for PortfolioSnapshot {
215    fn ts_init(&self) -> UnixNanos {
216        self.ts_init
217    }
218}
219
220#[cfg(test)]
221mod tests {
222    use nautilus_core::UUID4;
223    use rstest::rstest;
224    use rust_decimal_macros::dec;
225
226    use super::*;
227    use crate::{
228        enums::{AccountType, OrderSide, OrderType, PositionAdjustmentType},
229        events::order::spec::{
230            OrderAcceptedSpec, OrderCancelRejectedSpec, OrderCanceledSpec, OrderDeniedSpec,
231            OrderEmulatedSpec, OrderExpiredSpec, OrderFillVoidedSpec, OrderFilledSpec,
232            OrderInitializedSpec, OrderModifyRejectedSpec, OrderPendingCancelSpec,
233            OrderPendingUpdateSpec, OrderRejectedSpec, OrderReleasedSpec, OrderSubmittedSpec,
234            OrderTriggeredSpec, OrderUpdatedSpec,
235        },
236        identifiers::{AccountId, InstrumentId, PositionId, StrategyId, TraderId},
237        orders::builder::OrderTestBuilder,
238        position::Position,
239        stubs::stub_position_long,
240        types::{Currency, Money, Price, Quantity},
241    };
242
243    #[rstest]
244    fn test_order_lifecycle_event_ts_init() {
245        let ts_init = UnixNanos::from(1);
246
247        assert_eq!(
248            HasTsInit::ts_init(&OrderInitializedSpec::builder().ts_init(ts_init).build()),
249            ts_init
250        );
251        assert_eq!(
252            HasTsInit::ts_init(&OrderDeniedSpec::builder().ts_init(ts_init).build()),
253            ts_init
254        );
255        assert_eq!(
256            HasTsInit::ts_init(&OrderEmulatedSpec::builder().ts_init(ts_init).build()),
257            ts_init
258        );
259        assert_eq!(
260            HasTsInit::ts_init(&OrderReleasedSpec::builder().ts_init(ts_init).build()),
261            ts_init
262        );
263        assert_eq!(
264            HasTsInit::ts_init(&OrderSubmittedSpec::builder().ts_init(ts_init).build()),
265            ts_init
266        );
267        assert_eq!(
268            HasTsInit::ts_init(&OrderAcceptedSpec::builder().ts_init(ts_init).build()),
269            ts_init
270        );
271        assert_eq!(
272            HasTsInit::ts_init(&OrderRejectedSpec::builder().ts_init(ts_init).build()),
273            ts_init
274        );
275        assert_eq!(
276            HasTsInit::ts_init(&OrderTriggeredSpec::builder().ts_init(ts_init).build()),
277            ts_init
278        );
279        assert_eq!(
280            HasTsInit::ts_init(&OrderExpiredSpec::builder().ts_init(ts_init).build()),
281            ts_init
282        );
283        assert_eq!(
284            HasTsInit::ts_init(&OrderCanceledSpec::builder().ts_init(ts_init).build()),
285            ts_init
286        );
287    }
288
289    #[rstest]
290    fn test_order_amendment_event_ts_init() {
291        let ts_init = UnixNanos::from(2);
292
293        assert_eq!(
294            HasTsInit::ts_init(&OrderPendingUpdateSpec::builder().ts_init(ts_init).build()),
295            ts_init
296        );
297        assert_eq!(
298            HasTsInit::ts_init(&OrderPendingCancelSpec::builder().ts_init(ts_init).build()),
299            ts_init
300        );
301        assert_eq!(
302            HasTsInit::ts_init(&OrderModifyRejectedSpec::builder().ts_init(ts_init).build()),
303            ts_init
304        );
305        assert_eq!(
306            HasTsInit::ts_init(&OrderCancelRejectedSpec::builder().ts_init(ts_init).build()),
307            ts_init
308        );
309        assert_eq!(
310            HasTsInit::ts_init(&OrderUpdatedSpec::builder().ts_init(ts_init).build()),
311            ts_init
312        );
313    }
314
315    #[rstest]
316    fn test_order_fill_event_ts_init() {
317        let ts_init = UnixNanos::from(3);
318
319        assert_eq!(
320            HasTsInit::ts_init(&OrderFilledSpec::builder().ts_init(ts_init).build()),
321            ts_init
322        );
323        assert_eq!(
324            HasTsInit::ts_init(&OrderFillVoidedSpec::builder().ts_init(ts_init).build()),
325            ts_init
326        );
327    }
328
329    #[rstest]
330    fn test_order_snapshot_ts_init() {
331        let ts_init = UnixNanos::from(4);
332        let order = OrderTestBuilder::new(OrderType::Market)
333            .instrument_id(InstrumentId::from("AUD/USD.SIM"))
334            .side(OrderSide::Buy)
335            .quantity(Quantity::from(1))
336            .build();
337        let mut snapshot = OrderSnapshot::from(order);
338        snapshot.ts_init = ts_init;
339
340        assert_eq!(HasTsInit::ts_init(&snapshot), ts_init);
341    }
342
343    #[rstest]
344    fn test_position_event_ts_init(mut stub_position_long: Position) {
345        let ts_init = UnixNanos::from(5);
346        let event_id = UUID4::default();
347        let fill = stub_position_long.last_event().unwrap();
348
349        assert_eq!(
350            HasTsInit::ts_init(&PositionOpened::create(
351                &stub_position_long,
352                &fill,
353                event_id,
354                ts_init
355            )),
356            ts_init
357        );
358        assert_eq!(
359            HasTsInit::ts_init(&PositionChanged::create(
360                &stub_position_long,
361                &fill,
362                event_id,
363                ts_init
364            )),
365            ts_init
366        );
367        assert_eq!(
368            HasTsInit::ts_init(&PositionClosed::create(
369                &stub_position_long,
370                &fill,
371                event_id,
372                ts_init
373            )),
374            ts_init
375        );
376
377        stub_position_long.ts_init = ts_init;
378
379        assert_eq!(
380            HasTsInit::ts_init(&PositionSnapshot::from(&stub_position_long, None)),
381            ts_init
382        );
383    }
384
385    #[rstest]
386    fn test_position_adjusted_ts_init() {
387        let ts_init = UnixNanos::from(6);
388
389        let event = PositionAdjusted::new(
390            TraderId::from("TRADER-001"),
391            StrategyId::from("EMA-CROSS"),
392            InstrumentId::from("AUD/USD.SIM"),
393            PositionId::from("P-001"),
394            AccountId::from("SIM-001"),
395            PositionAdjustmentType::Funding,
396            None,
397            Some(Money::new(1.0, Currency::USD())),
398            None,
399            UUID4::default(),
400            UnixNanos::from(5),
401            ts_init,
402        );
403
404        assert_eq!(HasTsInit::ts_init(&event), ts_init);
405    }
406
407    #[rstest]
408    fn test_account_state_ts_init() {
409        let ts_init = UnixNanos::from(7);
410
411        let event = AccountState::new(
412            AccountId::from("SIM-001"),
413            AccountType::Cash,
414            vec![],
415            vec![],
416            true,
417            UUID4::default(),
418            UnixNanos::from(6),
419            ts_init,
420            Some(Currency::USD()),
421        );
422
423        assert_eq!(HasTsInit::ts_init(&event), ts_init);
424    }
425
426    #[rstest]
427    fn test_portfolio_snapshot_ts_init() {
428        let ts_init = UnixNanos::from(8);
429
430        let event = PortfolioSnapshot::new(
431            AccountId::from("SIM-001"),
432            AccountType::Cash,
433            Some(Currency::USD()),
434            vec![],
435            vec![],
436            vec![],
437            vec![],
438            vec![],
439            None,
440            false,
441            vec![],
442            vec![],
443            vec![],
444            UUID4::default(),
445            UnixNanos::from(7),
446            ts_init,
447        );
448
449        assert_eq!(HasTsInit::ts_init(&event), ts_init);
450    }
451
452    #[rstest]
453    fn test_funding_settlement_ts_init() {
454        let ts_init = UnixNanos::from(9);
455
456        let event = FundingSettlement::new(
457            TraderId::from("TRADER-001"),
458            InstrumentId::from("AUD/USD.SIM"),
459            AccountId::from("SIM-001"),
460            dec!(0.0001),
461            Price::from("1.00000"),
462            Currency::USD(),
463            UUID4::default(),
464            UnixNanos::from(8),
465            ts_init,
466        );
467
468        assert_eq!(HasTsInit::ts_init(&event), ts_init);
469    }
470}