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