Skip to main content

nautilus_model/data/
deltas.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//! An `OrderBookDeltas` container type to carry a bulk of `OrderBookDelta` records.
17
18use std::{
19    fmt::Display,
20    hash::{Hash, Hasher},
21    ops::{Deref, DerefMut},
22};
23
24use nautilus_core::{
25    UnixNanos,
26    correctness::{FAILED, check_predicate_true},
27};
28use serde::{Deserialize, Serialize};
29
30use super::{HasTsInit, OrderBookDelta};
31use crate::identifiers::InstrumentId;
32
33/// Represents a grouped batch of `OrderBookDelta` updates for an `OrderBook`.
34///
35/// This type cannot be `repr(C)` due to the `deltas` vec.
36#[derive(Clone, Debug, Serialize, Deserialize)]
37#[cfg_attr(
38    feature = "python",
39    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model", from_py_object)
40)]
41pub struct OrderBookDeltas {
42    /// The instrument ID for the book.
43    pub instrument_id: InstrumentId,
44    /// The order book deltas.
45    pub deltas: Vec<OrderBookDelta>,
46    /// The record flags bit field, indicating event end and data information.
47    pub flags: u8,
48    /// The message sequence number assigned at the venue.
49    pub sequence: u64,
50    /// UNIX timestamp (nanoseconds) when the book event occurred.
51    pub ts_event: UnixNanos,
52    /// UNIX timestamp (nanoseconds) when the instance was created.
53    pub ts_init: UnixNanos,
54}
55
56impl OrderBookDeltas {
57    /// Creates a new [`OrderBookDeltas`] instance.
58    ///
59    /// # Panics
60    ///
61    /// Panics if `deltas` is empty and correctness check fails.
62    #[must_use]
63    #[allow(clippy::too_many_arguments)]
64    pub fn new(instrument_id: InstrumentId, deltas: Vec<OrderBookDelta>) -> Self {
65        Self::new_checked(instrument_id, deltas).expect(FAILED)
66    }
67
68    /// Creates a new [`OrderBookDeltas`] instance with correctness checking.
69    ///
70    /// # Notes
71    ///
72    /// PyO3 requires a `Result` type for proper error handling and stacktrace printing in Python.
73    #[allow(clippy::too_many_arguments)]
74    /// Creates a new [`OrderBookDeltas`] instance with correctness checking.
75    ///
76    /// # Errors
77    ///
78    /// Returns an error if `deltas` is empty.
79    #[allow(clippy::missing_panics_doc)] // Guarded by predicate check above
80    pub fn new_checked(
81        instrument_id: InstrumentId,
82        deltas: Vec<OrderBookDelta>,
83    ) -> anyhow::Result<Self> {
84        check_predicate_true(!deltas.is_empty(), "`deltas` cannot be empty")?;
85        let last = deltas.last().expect("deltas not empty");
86        let flags = last.flags;
87        let sequence = last.sequence;
88        let ts_event = last.ts_event;
89        let ts_init = last.ts_init;
90        Ok(Self {
91            instrument_id,
92            deltas,
93            flags,
94            sequence,
95            ts_event,
96            ts_init,
97        })
98    }
99}
100
101impl PartialEq<Self> for OrderBookDeltas {
102    fn eq(&self, other: &Self) -> bool {
103        self.instrument_id == other.instrument_id && self.sequence == other.sequence
104    }
105}
106
107impl Eq for OrderBookDeltas {}
108
109impl Hash for OrderBookDeltas {
110    fn hash<H: Hasher>(&self, state: &mut H) {
111        self.instrument_id.hash(state);
112        self.sequence.hash(state);
113    }
114}
115
116// TODO: Implement
117// impl Serializable for OrderBookDeltas {}
118
119// TODO: Exact format for Debug and Display TBD
120impl Display for OrderBookDeltas {
121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        write!(
123            f,
124            "{},len={},flags={},sequence={},ts_event={},ts_init={}",
125            self.instrument_id,
126            self.deltas.len(),
127            self.flags,
128            self.sequence,
129            self.ts_event,
130            self.ts_init
131        )
132    }
133}
134
135impl HasTsInit for OrderBookDeltas {
136    fn ts_init(&self) -> UnixNanos {
137        self.ts_init
138    }
139}
140
141/// C compatible Foreign Function Interface (FFI) for an underlying [`OrderBookDeltas`].
142///
143/// This struct wraps `OrderBookDeltas` in a way that makes it compatible with C function
144/// calls, enabling interaction with `OrderBookDeltas` in a C environment.
145///
146/// It implements the `Deref` trait, allowing instances of `OrderBookDeltas_API` to be
147/// dereferenced to `OrderBookDeltas`, providing access to `OrderBookDeltas`'s methods without
148/// having to manually access the underlying `OrderBookDeltas` instance.
149#[repr(C)]
150#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
151#[allow(non_camel_case_types)]
152pub struct OrderBookDeltas_API(Box<OrderBookDeltas>);
153
154// TODO: This wrapper will go along with Cython
155impl OrderBookDeltas_API {
156    #[must_use]
157    pub fn new(deltas: OrderBookDeltas) -> Self {
158        Self(Box::new(deltas))
159    }
160
161    /// Consumes the wrapper and returns the inner `OrderBookDeltas`.
162    #[must_use]
163    pub fn into_inner(self) -> OrderBookDeltas {
164        *self.0
165    }
166}
167
168impl Deref for OrderBookDeltas_API {
169    type Target = OrderBookDeltas;
170
171    fn deref(&self) -> &Self::Target {
172        &self.0
173    }
174}
175
176impl DerefMut for OrderBookDeltas_API {
177    fn deref_mut(&mut self) -> &mut Self::Target {
178        &mut self.0
179    }
180}
181
182#[cfg(test)]
183mod tests {
184    use std::{
185        collections::hash_map::DefaultHasher,
186        hash::{Hash, Hasher},
187    };
188
189    use rstest::rstest;
190    use serde_json;
191
192    use super::*;
193    use crate::{
194        data::{order::BookOrder, stubs::stub_deltas},
195        enums::{BookAction, OrderSide},
196        types::{Price, Quantity},
197    };
198
199    fn create_test_delta() -> OrderBookDelta {
200        let instrument_id = InstrumentId::from("EURUSD.SIM");
201        OrderBookDelta::new(
202            instrument_id,
203            BookAction::Add,
204            BookOrder::new(
205                OrderSide::Buy,
206                Price::from("1.0500"),
207                Quantity::from("100000"),
208                1,
209            ),
210            0,
211            123,
212            UnixNanos::from(1_000_000_000),
213            UnixNanos::from(2_000_000_000),
214        )
215    }
216
217    fn create_test_deltas() -> OrderBookDeltas {
218        let instrument_id = InstrumentId::from("EURUSD.SIM");
219        let flags = 32;
220        let sequence = 123;
221        let ts_event = UnixNanos::from(1_000_000_000);
222        let ts_init = UnixNanos::from(2_000_000_000);
223
224        let delta1 = OrderBookDelta::new(
225            instrument_id,
226            BookAction::Add,
227            BookOrder::new(
228                OrderSide::Sell,
229                Price::from("1.0520"),
230                Quantity::from("50000"),
231                1,
232            ),
233            flags,
234            sequence,
235            ts_event,
236            ts_init,
237        );
238        let delta2 = OrderBookDelta::new(
239            instrument_id,
240            BookAction::Add,
241            BookOrder::new(
242                OrderSide::Buy,
243                Price::from("1.0500"),
244                Quantity::from("75000"),
245                2,
246            ),
247            flags,
248            sequence,
249            ts_event,
250            ts_init,
251        );
252
253        OrderBookDeltas::new(instrument_id, vec![delta1, delta2])
254    }
255
256    fn create_test_deltas_multiple() -> OrderBookDeltas {
257        let instrument_id = InstrumentId::from("GBPUSD.SIM");
258        let flags = 16;
259        let sequence = 456;
260        let ts_event = UnixNanos::from(3_000_000_000);
261        let ts_init = UnixNanos::from(4_000_000_000);
262
263        let deltas = vec![
264            OrderBookDelta::clear(instrument_id, sequence, ts_event, ts_init),
265            OrderBookDelta::new(
266                instrument_id,
267                BookAction::Add,
268                BookOrder::new(
269                    OrderSide::Sell,
270                    Price::from("1.2550"),
271                    Quantity::from("100000"),
272                    1,
273                ),
274                flags,
275                sequence,
276                ts_event,
277                ts_init,
278            ),
279            OrderBookDelta::new(
280                instrument_id,
281                BookAction::Update,
282                BookOrder::new(
283                    OrderSide::Buy,
284                    Price::from("1.2530"),
285                    Quantity::from("200000"),
286                    2,
287                ),
288                flags,
289                sequence,
290                ts_event,
291                ts_init,
292            ),
293            OrderBookDelta::new(
294                instrument_id,
295                BookAction::Delete,
296                BookOrder::new(
297                    OrderSide::Sell,
298                    Price::from("1.2560"),
299                    Quantity::from("0"),
300                    3,
301                ),
302                flags,
303                sequence,
304                ts_event,
305                ts_init,
306            ),
307        ];
308
309        OrderBookDeltas::new(instrument_id, deltas)
310    }
311
312    #[rstest]
313    fn test_order_book_deltas_new() {
314        let deltas = create_test_deltas();
315
316        assert_eq!(deltas.instrument_id, InstrumentId::from("EURUSD.SIM"));
317        assert_eq!(deltas.deltas.len(), 2);
318        assert_eq!(deltas.flags, 32);
319        assert_eq!(deltas.sequence, 123);
320        assert_eq!(deltas.ts_event, UnixNanos::from(1_000_000_000));
321        assert_eq!(deltas.ts_init, UnixNanos::from(2_000_000_000));
322    }
323
324    #[rstest]
325    fn test_order_book_deltas_new_checked_valid() {
326        let instrument_id = InstrumentId::from("EURUSD.SIM");
327        let delta = create_test_delta();
328
329        let result = OrderBookDeltas::new_checked(instrument_id, vec![delta]);
330
331        assert!(result.is_ok());
332        let deltas = result.unwrap();
333        assert_eq!(deltas.instrument_id, instrument_id);
334        assert_eq!(deltas.deltas.len(), 1);
335    }
336
337    #[rstest]
338    fn test_order_book_deltas_new_checked_empty_deltas() {
339        let instrument_id = InstrumentId::from("EURUSD.SIM");
340
341        let result = OrderBookDeltas::new_checked(instrument_id, vec![]);
342
343        assert!(result.is_err());
344        assert!(
345            result
346                .unwrap_err()
347                .to_string()
348                .contains("`deltas` cannot be empty")
349        );
350    }
351
352    #[rstest]
353    #[should_panic(expected = "Condition failed")]
354    fn test_order_book_deltas_new_empty_deltas_panics() {
355        let instrument_id = InstrumentId::from("EURUSD.SIM");
356        let _ = OrderBookDeltas::new(instrument_id, vec![]);
357    }
358
359    #[rstest]
360    fn test_order_book_deltas_uses_last_delta_properties() {
361        let instrument_id = InstrumentId::from("EURUSD.SIM");
362
363        let delta1 = OrderBookDelta::new(
364            instrument_id,
365            BookAction::Add,
366            BookOrder::new(
367                OrderSide::Buy,
368                Price::from("1.0500"),
369                Quantity::from("100000"),
370                1,
371            ),
372            16,                             // Different flags
373            100,                            // Different sequence
374            UnixNanos::from(500_000_000),   // Different ts_event
375            UnixNanos::from(1_000_000_000), // Different ts_init
376        );
377
378        let delta2 = OrderBookDelta::new(
379            instrument_id,
380            BookAction::Add,
381            BookOrder::new(
382                OrderSide::Sell,
383                Price::from("1.0520"),
384                Quantity::from("50000"),
385                2,
386            ),
387            32,                             // Final flags
388            200,                            // Final sequence
389            UnixNanos::from(1_500_000_000), // Final ts_event
390            UnixNanos::from(2_000_000_000), // Final ts_init
391        );
392
393        let deltas = OrderBookDeltas::new(instrument_id, vec![delta1, delta2]);
394
395        // Should use properties from the last delta
396        assert_eq!(deltas.flags, 32);
397        assert_eq!(deltas.sequence, 200);
398        assert_eq!(deltas.ts_event, UnixNanos::from(1_500_000_000));
399        assert_eq!(deltas.ts_init, UnixNanos::from(2_000_000_000));
400    }
401
402    #[rstest]
403    fn test_order_book_deltas_hash_different_objects() {
404        let deltas1 = create_test_deltas();
405        let deltas2 = create_test_deltas_multiple();
406
407        let mut hasher1 = DefaultHasher::new();
408        let mut hasher2 = DefaultHasher::new();
409
410        deltas1.hash(&mut hasher1);
411        deltas2.hash(&mut hasher2);
412
413        assert_ne!(hasher1.finish(), hasher2.finish()); // Different objects should have different hashes
414    }
415
416    #[rstest]
417    fn test_order_book_deltas_hash_uses_instrument_id_and_sequence() {
418        let instrument_id = InstrumentId::from("EURUSD.SIM");
419        let sequence = 123u64;
420
421        // Create separate hasher to verify what's being hashed
422        let mut expected_hasher = DefaultHasher::new();
423        instrument_id.hash(&mut expected_hasher);
424        sequence.hash(&mut expected_hasher);
425        let expected_hash = expected_hasher.finish();
426
427        let delta = OrderBookDelta::new(
428            instrument_id,
429            BookAction::Add,
430            BookOrder::new(
431                OrderSide::Buy,
432                Price::from("1.0500"),
433                Quantity::from("100000"),
434                1,
435            ),
436            0,
437            sequence,
438            UnixNanos::from(1_000_000_000),
439            UnixNanos::from(2_000_000_000),
440        );
441
442        let deltas = OrderBookDeltas::new(instrument_id, vec![delta]);
443
444        let mut deltas_hasher = DefaultHasher::new();
445        deltas.hash(&mut deltas_hasher);
446
447        assert_eq!(deltas_hasher.finish(), expected_hash);
448    }
449
450    #[rstest]
451    fn test_order_book_deltas_display() {
452        let deltas = create_test_deltas();
453        let display_str = format!("{deltas}");
454
455        assert!(display_str.contains("EURUSD.SIM"));
456        assert!(display_str.contains("len=2"));
457        assert!(display_str.contains("flags=32"));
458        assert!(display_str.contains("sequence=123"));
459        assert!(display_str.contains("ts_event=1000000000"));
460        assert!(display_str.contains("ts_init=2000000000"));
461    }
462
463    #[rstest]
464    fn test_order_book_deltas_display_format() {
465        let deltas = create_test_deltas();
466        let expected =
467            "EURUSD.SIM,len=2,flags=32,sequence=123,ts_event=1000000000,ts_init=2000000000";
468
469        assert_eq!(format!("{deltas}"), expected);
470    }
471
472    #[rstest]
473    fn test_order_book_deltas_has_ts_init() {
474        let deltas = create_test_deltas();
475
476        assert_eq!(deltas.ts_init(), UnixNanos::from(2_000_000_000));
477    }
478
479    #[rstest]
480    fn test_order_book_deltas_clone() {
481        let deltas1 = create_test_deltas();
482        let deltas2 = deltas1.clone();
483
484        assert_eq!(deltas1.instrument_id, deltas2.instrument_id);
485        assert_eq!(deltas1.deltas.len(), deltas2.deltas.len());
486        assert_eq!(deltas1.flags, deltas2.flags);
487        assert_eq!(deltas1.sequence, deltas2.sequence);
488        assert_eq!(deltas1.ts_event, deltas2.ts_event);
489        assert_eq!(deltas1.ts_init, deltas2.ts_init);
490        assert_eq!(deltas1, deltas2);
491    }
492
493    #[rstest]
494    fn test_order_book_deltas_debug() {
495        let deltas = create_test_deltas();
496        let debug_str = format!("{deltas:?}");
497
498        assert!(debug_str.contains("OrderBookDeltas"));
499        assert!(debug_str.contains("EURUSD.SIM"));
500        assert!(debug_str.contains("flags: 32"));
501        assert!(debug_str.contains("sequence: 123"));
502    }
503
504    #[rstest]
505    fn test_order_book_deltas_serialization() {
506        let deltas = create_test_deltas();
507
508        // Test JSON serialization
509        let json = serde_json::to_string(&deltas).unwrap();
510        let deserialized: OrderBookDeltas = serde_json::from_str(&json).unwrap();
511
512        assert_eq!(deltas.instrument_id, deserialized.instrument_id);
513        assert_eq!(deltas.deltas.len(), deserialized.deltas.len());
514        assert_eq!(deltas.flags, deserialized.flags);
515        assert_eq!(deltas.sequence, deserialized.sequence);
516        assert_eq!(deltas.ts_event, deserialized.ts_event);
517        assert_eq!(deltas.ts_init, deserialized.ts_init);
518    }
519
520    #[rstest]
521    fn test_order_book_deltas_single_delta() {
522        let instrument_id = InstrumentId::from("BTCUSD.CRYPTO");
523        let delta = create_test_delta();
524
525        let deltas = OrderBookDeltas::new(instrument_id, vec![delta]);
526
527        assert_eq!(deltas.instrument_id, instrument_id);
528        assert_eq!(deltas.deltas.len(), 1);
529        assert_eq!(deltas.flags, delta.flags);
530        assert_eq!(deltas.sequence, delta.sequence);
531        assert_eq!(deltas.ts_event, delta.ts_event);
532        assert_eq!(deltas.ts_init, delta.ts_init);
533    }
534
535    #[rstest]
536    fn test_order_book_deltas_large_number_of_deltas() {
537        let instrument_id = InstrumentId::from("ETHUSD.CRYPTO");
538        let mut delta_vec = Vec::new();
539
540        // Create 100 deltas
541        for i in 0..100 {
542            let delta = OrderBookDelta::new(
543                instrument_id,
544                BookAction::Add,
545                BookOrder::new(
546                    OrderSide::Buy,
547                    Price::from(&format!("1000.{i:02}")),
548                    Quantity::from("1000"),
549                    i as u64,
550                ),
551                0,
552                i as u64,
553                UnixNanos::from(1_000_000_000 + i as u64),
554                UnixNanos::from(2_000_000_000 + i as u64),
555            );
556            delta_vec.push(delta);
557        }
558
559        let deltas = OrderBookDeltas::new(instrument_id, delta_vec);
560
561        assert_eq!(deltas.deltas.len(), 100);
562        assert_eq!(deltas.sequence, 99); // Last delta's sequence
563        assert_eq!(deltas.ts_event, UnixNanos::from(1_000_000_000 + 99));
564        assert_eq!(deltas.ts_init, UnixNanos::from(2_000_000_000 + 99));
565    }
566
567    #[rstest]
568    fn test_order_book_deltas_different_action_types() {
569        let deltas = create_test_deltas_multiple();
570
571        assert_eq!(deltas.deltas.len(), 4);
572
573        // Verify different action types are preserved
574        assert_eq!(deltas.deltas[0].action, BookAction::Clear);
575        assert_eq!(deltas.deltas[1].action, BookAction::Add);
576        assert_eq!(deltas.deltas[2].action, BookAction::Update);
577        assert_eq!(deltas.deltas[3].action, BookAction::Delete);
578    }
579
580    #[rstest]
581    fn test_order_book_deltas_api_new() {
582        let deltas = create_test_deltas();
583        let api_wrapper = OrderBookDeltas_API::new(deltas.clone());
584
585        assert_eq!(api_wrapper.instrument_id, deltas.instrument_id);
586        assert_eq!(api_wrapper.deltas.len(), deltas.deltas.len());
587        assert_eq!(api_wrapper.flags, deltas.flags);
588        assert_eq!(api_wrapper.sequence, deltas.sequence);
589    }
590
591    #[rstest]
592    fn test_order_book_deltas_api_into_inner() {
593        let deltas = create_test_deltas();
594        let api_wrapper = OrderBookDeltas_API::new(deltas.clone());
595        let inner_deltas = api_wrapper.into_inner();
596
597        assert_eq!(inner_deltas, deltas);
598    }
599
600    #[rstest]
601    fn test_order_book_deltas_api_deref() {
602        let deltas = create_test_deltas();
603        let api_wrapper = OrderBookDeltas_API::new(deltas.clone());
604
605        // Test Deref functionality
606        assert_eq!(api_wrapper.instrument_id, deltas.instrument_id);
607        assert_eq!(api_wrapper.ts_init(), deltas.ts_init());
608
609        // Test accessing methods through Deref
610        let display_str = format!("{}", &*api_wrapper);
611        assert!(display_str.contains("EURUSD.SIM"));
612    }
613
614    #[rstest]
615    fn test_order_book_deltas_api_deref_mut() {
616        let deltas = create_test_deltas();
617        let mut api_wrapper = OrderBookDeltas_API::new(deltas);
618
619        // Test DerefMut functionality by modifying through the wrapper
620        let original_flags = api_wrapper.flags;
621        api_wrapper.flags = 64;
622
623        assert_ne!(api_wrapper.flags, original_flags);
624        assert_eq!(api_wrapper.flags, 64);
625    }
626
627    #[rstest]
628    fn test_order_book_deltas_api_clone() {
629        let deltas = create_test_deltas();
630        let api_wrapper1 = OrderBookDeltas_API::new(deltas);
631        let api_wrapper2 = api_wrapper1.clone();
632
633        assert_eq!(api_wrapper1.instrument_id, api_wrapper2.instrument_id);
634        assert_eq!(api_wrapper1.sequence, api_wrapper2.sequence);
635        assert_eq!(api_wrapper1, api_wrapper2);
636    }
637
638    #[rstest]
639    fn test_order_book_deltas_api_debug() {
640        let deltas = create_test_deltas();
641        let api_wrapper = OrderBookDeltas_API::new(deltas);
642        let debug_str = format!("{api_wrapper:?}");
643
644        assert!(debug_str.contains("OrderBookDeltas_API"));
645        assert!(debug_str.contains("EURUSD.SIM"));
646    }
647
648    #[rstest]
649    fn test_order_book_deltas_api_serialization() {
650        let deltas = create_test_deltas();
651        let api_wrapper = OrderBookDeltas_API::new(deltas);
652
653        // Test JSON serialization
654        let json = serde_json::to_string(&api_wrapper).unwrap();
655        let deserialized: OrderBookDeltas_API = serde_json::from_str(&json).unwrap();
656
657        assert_eq!(api_wrapper.instrument_id, deserialized.instrument_id);
658        assert_eq!(api_wrapper.sequence, deserialized.sequence);
659        assert_eq!(api_wrapper, deserialized);
660    }
661
662    #[rstest]
663    fn test_order_book_deltas_with_stub(stub_deltas: OrderBookDeltas) {
664        let deltas = stub_deltas;
665
666        assert_eq!(deltas.instrument_id, InstrumentId::from("AAPL.XNAS"));
667        assert_eq!(deltas.deltas.len(), 7);
668        assert_eq!(deltas.flags, 32);
669        assert_eq!(deltas.sequence, 0);
670        assert_eq!(deltas.ts_event, UnixNanos::from(1));
671        assert_eq!(deltas.ts_init, UnixNanos::from(2));
672    }
673
674    #[rstest]
675    fn test_display_with_stub(stub_deltas: OrderBookDeltas) {
676        let deltas = stub_deltas;
677        assert_eq!(
678            format!("{deltas}"),
679            "AAPL.XNAS,len=7,flags=32,sequence=0,ts_event=1,ts_init=2".to_string()
680        );
681    }
682
683    #[rstest]
684    fn test_order_book_deltas_zero_sequence() {
685        let instrument_id = InstrumentId::from("ZERO.TEST");
686        let delta = OrderBookDelta::new(
687            instrument_id,
688            BookAction::Add,
689            BookOrder::new(
690                OrderSide::Buy,
691                Price::from("100.0"),
692                Quantity::from("1000"),
693                1,
694            ),
695            0,
696            0,                  // Zero sequence
697            UnixNanos::from(0), // Zero timestamp
698            UnixNanos::from(0),
699        );
700
701        let deltas = OrderBookDeltas::new(instrument_id, vec![delta]);
702
703        assert_eq!(deltas.sequence, 0);
704        assert_eq!(deltas.ts_event, UnixNanos::from(0));
705        assert_eq!(deltas.ts_init, UnixNanos::from(0));
706    }
707
708    #[rstest]
709    fn test_order_book_deltas_max_values() {
710        let instrument_id = InstrumentId::from("MAX.TEST");
711        let delta = OrderBookDelta::new(
712            instrument_id,
713            BookAction::Add,
714            BookOrder::new(
715                OrderSide::Buy,
716                Price::from("999999.99"),
717                Quantity::from("999999999"),
718                u64::MAX,
719            ),
720            u8::MAX,
721            u64::MAX,
722            UnixNanos::from(u64::MAX),
723            UnixNanos::from(u64::MAX),
724        );
725
726        let deltas = OrderBookDeltas::new(instrument_id, vec![delta]);
727
728        assert_eq!(deltas.flags, u8::MAX);
729        assert_eq!(deltas.sequence, u64::MAX);
730        assert_eq!(deltas.ts_event, UnixNanos::from(u64::MAX));
731        assert_eq!(deltas.ts_init, UnixNanos::from(u64::MAX));
732    }
733
734    #[rstest]
735    fn test_new() {
736        let instrument_id = InstrumentId::from("AAPL.XNAS");
737        let flags = 32; // Snapshot flag
738        let sequence = 0;
739        let ts_event = 1;
740        let ts_init = 2;
741
742        let delta0 =
743            OrderBookDelta::clear(instrument_id, sequence, ts_event.into(), ts_init.into());
744        let delta1 = OrderBookDelta::new(
745            instrument_id,
746            BookAction::Add,
747            BookOrder::new(
748                OrderSide::Sell,
749                Price::from("102.00"),
750                Quantity::from("300"),
751                1,
752            ),
753            flags,
754            sequence,
755            ts_event.into(),
756            ts_init.into(),
757        );
758        let delta2 = OrderBookDelta::new(
759            instrument_id,
760            BookAction::Add,
761            BookOrder::new(
762                OrderSide::Sell,
763                Price::from("101.00"),
764                Quantity::from("200"),
765                2,
766            ),
767            flags,
768            sequence,
769            ts_event.into(),
770            ts_init.into(),
771        );
772        let delta3 = OrderBookDelta::new(
773            instrument_id,
774            BookAction::Add,
775            BookOrder::new(
776                OrderSide::Sell,
777                Price::from("100.00"),
778                Quantity::from("100"),
779                3,
780            ),
781            flags,
782            sequence,
783            ts_event.into(),
784            ts_init.into(),
785        );
786        let delta4 = OrderBookDelta::new(
787            instrument_id,
788            BookAction::Add,
789            BookOrder::new(
790                OrderSide::Buy,
791                Price::from("99.00"),
792                Quantity::from("100"),
793                4,
794            ),
795            flags,
796            sequence,
797            ts_event.into(),
798            ts_init.into(),
799        );
800        let delta5 = OrderBookDelta::new(
801            instrument_id,
802            BookAction::Add,
803            BookOrder::new(
804                OrderSide::Buy,
805                Price::from("98.00"),
806                Quantity::from("200"),
807                5,
808            ),
809            flags,
810            sequence,
811            ts_event.into(),
812            ts_init.into(),
813        );
814        let delta6 = OrderBookDelta::new(
815            instrument_id,
816            BookAction::Add,
817            BookOrder::new(
818                OrderSide::Buy,
819                Price::from("97.00"),
820                Quantity::from("300"),
821                6,
822            ),
823            flags,
824            sequence,
825            ts_event.into(),
826            ts_init.into(),
827        );
828
829        let deltas = OrderBookDeltas::new(
830            instrument_id,
831            vec![delta0, delta1, delta2, delta3, delta4, delta5, delta6],
832        );
833
834        assert_eq!(deltas.instrument_id, instrument_id);
835        assert_eq!(deltas.deltas.len(), 7);
836        assert_eq!(deltas.flags, flags);
837        assert_eq!(deltas.sequence, sequence);
838        assert_eq!(deltas.ts_event, ts_event);
839        assert_eq!(deltas.ts_init, ts_init);
840    }
841}