Skip to main content

nautilus_model/data/
delta.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 `OrderBookDelta` data type intended to carry book state information.
17
18use std::{collections::HashMap, fmt::Display, hash::Hash};
19
20use indexmap::IndexMap;
21use nautilus_core::{UnixNanos, correctness::FAILED, serialization::Serializable};
22use serde::{Deserialize, Serialize};
23
24use super::{
25    HasTsInit,
26    order::{BookOrder, NULL_ORDER},
27};
28use crate::{
29    enums::{BookAction, RecordFlag},
30    identifiers::InstrumentId,
31    types::{fixed::FIXED_SIZE_BINARY, quantity::check_positive_quantity},
32};
33
34/// Represents a single change/delta in an order book.
35#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
36#[serde(tag = "type")]
37#[cfg_attr(
38    feature = "python",
39    pyo3::pyclass(module = "nautilus_trader.model", from_py_object)
40)]
41#[cfg_attr(
42    feature = "python",
43    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.model")
44)]
45pub struct OrderBookDelta {
46    /// The instrument ID for the book.
47    pub instrument_id: InstrumentId,
48    /// The order book delta action.
49    pub action: BookAction,
50    /// The order to apply.
51    pub order: BookOrder,
52    /// The record flags bit field indicating event end and data information.
53    pub flags: u8,
54    /// The message sequence number assigned at the venue.
55    pub sequence: u64,
56    /// UNIX timestamp (nanoseconds) when the book event occurred.
57    pub ts_event: UnixNanos,
58    /// UNIX timestamp (nanoseconds) when the instance was created.
59    pub ts_init: UnixNanos,
60}
61
62impl OrderBookDelta {
63    /// Creates a new [`OrderBookDelta`] instance with correctness checking.
64    ///
65    /// # Errors
66    ///
67    /// Returns an error if `action` is [`BookAction::Add`] or [`BookAction::Update`] and `size` is not positive (> 0).
68    ///
69    /// # Notes
70    ///
71    /// PyO3 requires a `Result` type for proper error handling and stacktrace printing in Python.
72    pub fn new_checked(
73        instrument_id: InstrumentId,
74        action: BookAction,
75        order: BookOrder,
76        flags: u8,
77        sequence: u64,
78        ts_event: UnixNanos,
79        ts_init: UnixNanos,
80    ) -> anyhow::Result<Self> {
81        if matches!(action, BookAction::Add | BookAction::Update) {
82            check_positive_quantity(order.size, stringify!(order.size))?;
83        }
84
85        Ok(Self {
86            instrument_id,
87            action,
88            order,
89            flags,
90            sequence,
91            ts_event,
92            ts_init,
93        })
94    }
95
96    /// Creates a new [`OrderBookDelta`] instance.
97    ///
98    /// # Panics
99    ///
100    /// Panics if `action` is [`BookAction::Add`] or [`BookAction::Update`] and `size` is not positive (> 0).
101    #[must_use]
102    pub fn new(
103        instrument_id: InstrumentId,
104        action: BookAction,
105        order: BookOrder,
106        flags: u8,
107        sequence: u64,
108        ts_event: UnixNanos,
109        ts_init: UnixNanos,
110    ) -> Self {
111        Self::new_checked(
112            instrument_id,
113            action,
114            order,
115            flags,
116            sequence,
117            ts_event,
118            ts_init,
119        )
120        .expect(FAILED)
121    }
122
123    /// Creates a new [`OrderBookDelta`] instance with a `Clear` action and NULL order.
124    #[must_use]
125    pub fn clear(
126        instrument_id: InstrumentId,
127        sequence: u64,
128        ts_event: UnixNanos,
129        ts_init: UnixNanos,
130    ) -> Self {
131        Self {
132            instrument_id,
133            action: BookAction::Clear,
134            order: NULL_ORDER,
135            flags: RecordFlag::F_SNAPSHOT as u8,
136            sequence,
137            ts_event,
138            ts_init,
139        }
140    }
141
142    /// Returns the metadata for the type, for use with serialization formats.
143    #[must_use]
144    pub fn get_metadata(
145        instrument_id: &InstrumentId,
146        price_precision: u8,
147        size_precision: u8,
148    ) -> HashMap<String, String> {
149        let mut metadata = HashMap::new();
150        metadata.insert("instrument_id".to_string(), instrument_id.to_string());
151        metadata.insert("price_precision".to_string(), price_precision.to_string());
152        metadata.insert("size_precision".to_string(), size_precision.to_string());
153        metadata
154    }
155
156    /// Returns the field map for the type, for use with Arrow schemas.
157    #[must_use]
158    pub fn get_fields() -> IndexMap<String, String> {
159        let mut metadata = IndexMap::new();
160        metadata.insert("action".to_string(), "UInt8".to_string());
161        metadata.insert("side".to_string(), "UInt8".to_string());
162        metadata.insert("price".to_string(), FIXED_SIZE_BINARY.to_string());
163        metadata.insert("size".to_string(), FIXED_SIZE_BINARY.to_string());
164        metadata.insert("order_id".to_string(), "UInt64".to_string());
165        metadata.insert("flags".to_string(), "UInt8".to_string());
166        metadata.insert("sequence".to_string(), "UInt64".to_string());
167        metadata.insert("ts_event".to_string(), "UInt64".to_string());
168        metadata.insert("ts_init".to_string(), "UInt64".to_string());
169        metadata
170    }
171}
172
173impl Display for OrderBookDelta {
174    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175        write!(
176            f,
177            "{},{},{},{},{},{},{}",
178            self.instrument_id,
179            self.action,
180            self.order,
181            self.flags,
182            self.sequence,
183            self.ts_event,
184            self.ts_init
185        )
186    }
187}
188
189impl Serializable for OrderBookDelta {}
190
191impl HasTsInit for OrderBookDelta {
192    fn ts_init(&self) -> UnixNanos {
193        self.ts_init
194    }
195}
196
197#[cfg(test)]
198mod tests {
199    use std::{
200        collections::hash_map::DefaultHasher,
201        hash::{Hash, Hasher},
202    };
203
204    use nautilus_core::{
205        UnixNanos,
206        serialization::{
207            Serializable,
208            msgpack::{FromMsgPack, ToMsgPack},
209        },
210    };
211    use rstest::rstest;
212
213    use crate::{
214        data::{BookOrder, HasTsInit, OrderBookDelta, stubs::*},
215        enums::{BookAction, OrderSide, RecordFlag},
216        identifiers::InstrumentId,
217        types::{Price, Quantity},
218    };
219
220    fn create_test_delta() -> OrderBookDelta {
221        let order = BookOrder::new(
222            OrderSide::Buy,
223            Price::from("1.0500"),
224            Quantity::from("100000"),
225            12345,
226        );
227        OrderBookDelta::new(
228            InstrumentId::from("EURUSD.SIM"),
229            BookAction::Add,
230            order,
231            0,
232            123,
233            UnixNanos::from(1_000_000_000),
234            UnixNanos::from(2_000_000_000),
235        )
236    }
237
238    #[rstest]
239    fn test_order_book_delta_new() {
240        let delta = create_test_delta();
241
242        assert_eq!(delta.instrument_id, InstrumentId::from("EURUSD.SIM"));
243        assert_eq!(delta.action, BookAction::Add);
244        assert_eq!(delta.order.side, OrderSide::Buy.into());
245        assert_eq!(delta.order.price, Price::from("1.0500"));
246        assert_eq!(delta.order.size, Quantity::from("100000"));
247        assert_eq!(delta.order.order_id, 12345);
248        assert_eq!(delta.flags, 0);
249        assert_eq!(delta.sequence, 123);
250        assert_eq!(delta.ts_event, UnixNanos::from(1_000_000_000));
251        assert_eq!(delta.ts_init, UnixNanos::from(2_000_000_000));
252    }
253
254    #[rstest]
255    fn test_order_book_delta_new_checked_valid() {
256        let order = BookOrder::new(
257            OrderSide::Sell,
258            Price::from("1.0505"),
259            Quantity::from("50000"),
260            67890,
261        );
262        let result = OrderBookDelta::new_checked(
263            InstrumentId::from("GBPUSD.SIM"),
264            BookAction::Update,
265            order,
266            16,
267            456,
268            UnixNanos::from(500_000_000),
269            UnixNanos::from(1_500_000_000),
270        );
271
272        assert!(result.is_ok());
273        let delta = result.unwrap();
274        assert_eq!(delta.instrument_id, InstrumentId::from("GBPUSD.SIM"));
275        assert_eq!(delta.action, BookAction::Update);
276        assert_eq!(delta.order.side, OrderSide::Sell.into());
277        assert_eq!(delta.flags, 16);
278    }
279
280    #[rstest]
281    #[should_panic(expected = "invalid `Quantity` for 'order.size' not positive, was 0")]
282    fn test_order_book_delta_new_with_zero_size_panics() {
283        let instrument_id = InstrumentId::from("AAPL.XNAS");
284        let action = BookAction::Add;
285        let price = Price::from("100.00");
286        let zero_size = Quantity::from(0);
287        let side = OrderSide::Buy;
288        let order_id = 123_456;
289        let flags = 0;
290        let sequence = 1;
291        let ts_event = UnixNanos::from(0);
292        let ts_init = UnixNanos::from(1);
293
294        let order = BookOrder::new(side, price, zero_size, order_id);
295
296        let _ = OrderBookDelta::new(
297            instrument_id,
298            action,
299            order,
300            flags,
301            sequence,
302            ts_event,
303            ts_init,
304        );
305    }
306
307    #[rstest]
308    fn test_order_book_delta_new_checked_with_zero_size_error() {
309        let instrument_id = InstrumentId::from("AAPL.XNAS");
310        let action = BookAction::Add;
311        let price = Price::from("100.00");
312        let zero_size = Quantity::from(0);
313        let side = OrderSide::Buy;
314        let order_id = 123_456;
315        let flags = 0;
316        let sequence = 1;
317        let ts_event = UnixNanos::from(0);
318        let ts_init = UnixNanos::from(1);
319
320        let order = BookOrder::new(side, price, zero_size, order_id);
321
322        let result = OrderBookDelta::new_checked(
323            instrument_id,
324            action,
325            order,
326            flags,
327            sequence,
328            ts_event,
329            ts_init,
330        );
331
332        assert!(result.is_err());
333        assert!(
334            result
335                .unwrap_err()
336                .to_string()
337                .contains("invalid `Quantity` for 'order.size' not positive")
338        );
339    }
340
341    #[rstest]
342    fn test_order_book_delta_new_checked_delete_with_zero_size_ok() {
343        let order = BookOrder::new(
344            OrderSide::Buy,
345            Price::from("100.00"),
346            Quantity::from(0),
347            123_456,
348        );
349        let result = OrderBookDelta::new_checked(
350            InstrumentId::from("TEST.SIM"),
351            BookAction::Delete,
352            order,
353            0,
354            1,
355            UnixNanos::from(0),
356            UnixNanos::from(1),
357        );
358
359        assert!(result.is_ok());
360    }
361
362    #[rstest]
363    fn test_order_book_delta_clear() {
364        let instrument_id = InstrumentId::from("BTCUSD.CRYPTO");
365        let sequence = 999;
366        let ts_event = UnixNanos::from(3_000_000_000);
367        let ts_init = UnixNanos::from(4_000_000_000);
368
369        let delta = OrderBookDelta::clear(instrument_id, sequence, ts_event, ts_init);
370
371        assert_eq!(delta.instrument_id, instrument_id);
372        assert_eq!(delta.action, BookAction::Clear);
373        assert!(delta.order.price.is_zero());
374        assert!(delta.order.size.is_zero());
375        assert_eq!(delta.order.side, None);
376        assert_eq!(delta.order.order_id, 0);
377        assert_eq!(delta.flags, RecordFlag::F_SNAPSHOT as u8);
378        assert_eq!(delta.sequence, sequence);
379        assert_eq!(delta.ts_event, ts_event);
380        assert_eq!(delta.ts_init, ts_init);
381    }
382
383    #[rstest]
384    fn test_get_metadata() {
385        let instrument_id = InstrumentId::from("EURUSD.SIM");
386        let metadata = OrderBookDelta::get_metadata(&instrument_id, 5, 8);
387
388        assert_eq!(metadata.len(), 3);
389        assert_eq!(
390            metadata.get("instrument_id"),
391            Some(&"EURUSD.SIM".to_string())
392        );
393        assert_eq!(metadata.get("price_precision"), Some(&"5".to_string()));
394        assert_eq!(metadata.get("size_precision"), Some(&"8".to_string()));
395    }
396
397    #[rstest]
398    fn test_get_fields() {
399        let fields = OrderBookDelta::get_fields();
400
401        assert_eq!(fields.len(), 9);
402        assert_eq!(fields.get("action"), Some(&"UInt8".to_string()));
403        assert_eq!(fields.get("side"), Some(&"UInt8".to_string()));
404
405        #[cfg(feature = "high-precision")]
406        {
407            assert_eq!(
408                fields.get("price"),
409                Some(&"FixedSizeBinary(16)".to_string())
410            );
411            assert_eq!(fields.get("size"), Some(&"FixedSizeBinary(16)".to_string()));
412        }
413        #[cfg(not(feature = "high-precision"))]
414        {
415            assert_eq!(fields.get("price"), Some(&"FixedSizeBinary(8)".to_string()));
416            assert_eq!(fields.get("size"), Some(&"FixedSizeBinary(8)".to_string()));
417        }
418
419        assert_eq!(fields.get("order_id"), Some(&"UInt64".to_string()));
420        assert_eq!(fields.get("flags"), Some(&"UInt8".to_string()));
421        assert_eq!(fields.get("sequence"), Some(&"UInt64".to_string()));
422        assert_eq!(fields.get("ts_event"), Some(&"UInt64".to_string()));
423        assert_eq!(fields.get("ts_init"), Some(&"UInt64".to_string()));
424    }
425
426    #[rstest]
427    #[case(BookAction::Add)]
428    #[case(BookAction::Update)]
429    #[case(BookAction::Delete)]
430    #[case(BookAction::Clear)]
431    fn test_order_book_delta_with_different_actions(#[case] action: BookAction) {
432        let order = BookOrder::new(
433            OrderSide::Buy,
434            Price::from("100.00"),
435            if matches!(action, BookAction::Delete | BookAction::Clear) {
436                Quantity::from(0)
437            } else {
438                Quantity::from("1000")
439            },
440            123_456,
441        );
442
443        let result = if matches!(action, BookAction::Clear) {
444            Ok(OrderBookDelta::clear(
445                InstrumentId::from("TEST.SIM"),
446                1,
447                UnixNanos::from(1_000_000_000),
448                UnixNanos::from(2_000_000_000),
449            ))
450        } else {
451            OrderBookDelta::new_checked(
452                InstrumentId::from("TEST.SIM"),
453                action,
454                order,
455                0,
456                1,
457                UnixNanos::from(1_000_000_000),
458                UnixNanos::from(2_000_000_000),
459            )
460        };
461
462        assert!(result.is_ok());
463        let delta = result.unwrap();
464        assert_eq!(delta.action, action);
465    }
466
467    #[rstest]
468    #[case(OrderSide::Buy)]
469    #[case(OrderSide::Sell)]
470    fn test_order_book_delta_with_different_sides(#[case] side: OrderSide) {
471        let order = BookOrder::new(side, Price::from("100.00"), Quantity::from("1000"), 123_456);
472
473        let delta = OrderBookDelta::new(
474            InstrumentId::from("TEST.SIM"),
475            BookAction::Add,
476            order,
477            0,
478            1,
479            UnixNanos::from(1_000_000_000),
480            UnixNanos::from(2_000_000_000),
481        );
482
483        assert_eq!(delta.order.side, side.into());
484    }
485
486    #[rstest]
487    fn test_order_book_delta_has_ts_init() {
488        let delta = create_test_delta();
489        assert_eq!(delta.ts_init(), UnixNanos::from(2_000_000_000));
490    }
491
492    #[rstest]
493    fn test_order_book_delta_display() {
494        let delta = create_test_delta();
495        let display_str = format!("{delta}");
496
497        assert!(display_str.contains("EURUSD.SIM"));
498        assert!(display_str.contains("ADD"));
499        assert!(display_str.contains("BUY"));
500        assert!(display_str.contains("1.0500"));
501        assert!(display_str.contains("100000"));
502        assert!(display_str.contains("12345"));
503        assert!(display_str.contains("123"));
504    }
505
506    #[rstest]
507    fn test_order_book_delta_with_zero_timestamps() {
508        let order = BookOrder::new(
509            OrderSide::Buy,
510            Price::from("100.00"),
511            Quantity::from("1000"),
512            123_456,
513        );
514        let delta = OrderBookDelta::new(
515            InstrumentId::from("TEST.SIM"),
516            BookAction::Add,
517            order,
518            0,
519            0,
520            UnixNanos::from(0),
521            UnixNanos::from(0),
522        );
523
524        assert_eq!(delta.sequence, 0);
525        assert_eq!(delta.ts_event, UnixNanos::from(0));
526        assert_eq!(delta.ts_init, UnixNanos::from(0));
527    }
528
529    #[rstest]
530    fn test_order_book_delta_with_max_values() {
531        let order = BookOrder::new(
532            OrderSide::Sell,
533            Price::from("999999.9999"),
534            Quantity::from("999999999.9999"),
535            u64::MAX,
536        );
537        let delta = OrderBookDelta::new(
538            InstrumentId::from("TEST.SIM"),
539            BookAction::Update,
540            order,
541            u8::MAX,
542            u64::MAX,
543            UnixNanos::from(u64::MAX),
544            UnixNanos::from(u64::MAX),
545        );
546
547        assert_eq!(delta.flags, u8::MAX);
548        assert_eq!(delta.sequence, u64::MAX);
549        assert_eq!(delta.order.order_id, u64::MAX);
550        assert_eq!(delta.ts_event, UnixNanos::from(u64::MAX));
551        assert_eq!(delta.ts_init, UnixNanos::from(u64::MAX));
552    }
553
554    #[rstest]
555    fn test_new() {
556        let instrument_id = InstrumentId::from("AAPL.XNAS");
557        let action = BookAction::Add;
558        let price = Price::from("100.00");
559        let size = Quantity::from("10");
560        let side = OrderSide::Buy;
561        let order_id = 123_456;
562        let flags = 0;
563        let sequence = 1;
564        let ts_event = 1;
565        let ts_init = 2;
566
567        let order = BookOrder::new(side, price, size, order_id);
568
569        let delta = OrderBookDelta::new(
570            instrument_id,
571            action,
572            order,
573            flags,
574            sequence,
575            ts_event.into(),
576            ts_init.into(),
577        );
578
579        assert_eq!(delta.instrument_id, instrument_id);
580        assert_eq!(delta.action, action);
581        assert_eq!(delta.order.price, price);
582        assert_eq!(delta.order.size, size);
583        assert_eq!(delta.order.side, side.into());
584        assert_eq!(delta.order.order_id, order_id);
585        assert_eq!(delta.flags, flags);
586        assert_eq!(delta.sequence, sequence);
587        assert_eq!(delta.ts_event, ts_event);
588        assert_eq!(delta.ts_init, ts_init);
589    }
590
591    #[rstest]
592    fn test_clear() {
593        let instrument_id = InstrumentId::from("AAPL.XNAS");
594        let sequence = 1;
595        let ts_event = 2;
596        let ts_init = 3;
597
598        let delta = OrderBookDelta::clear(instrument_id, sequence, ts_event.into(), ts_init.into());
599
600        assert_eq!(delta.instrument_id, instrument_id);
601        assert_eq!(delta.action, BookAction::Clear);
602        assert!(delta.order.price.is_zero());
603        assert!(delta.order.size.is_zero());
604        assert_eq!(delta.order.side, None);
605        assert_eq!(delta.order.order_id, 0);
606        assert_eq!(delta.flags, 32);
607        assert_eq!(delta.sequence, sequence);
608        assert_eq!(delta.ts_event, ts_event);
609        assert_eq!(delta.ts_init, ts_init);
610    }
611
612    #[rstest]
613    fn test_order_book_delta_hash() {
614        let delta1 = create_test_delta();
615        let delta2 = create_test_delta();
616
617        let mut hasher1 = DefaultHasher::new();
618        let mut hasher2 = DefaultHasher::new();
619
620        delta1.hash(&mut hasher1);
621        delta2.hash(&mut hasher2);
622
623        assert_eq!(hasher1.finish(), hasher2.finish());
624    }
625
626    #[rstest]
627    fn test_order_book_delta_hash_different_deltas() {
628        let delta1 = create_test_delta();
629        let order2 = BookOrder::new(
630            OrderSide::Sell,
631            Price::from("1.0505"),
632            Quantity::from("50000"),
633            67890,
634        );
635        let delta2 = OrderBookDelta::new(
636            InstrumentId::from("EURUSD.SIM"),
637            BookAction::Add,
638            order2,
639            0,
640            123,
641            UnixNanos::from(1_000_000_000),
642            UnixNanos::from(2_000_000_000),
643        );
644
645        let mut hasher1 = DefaultHasher::new();
646        let mut hasher2 = DefaultHasher::new();
647
648        delta1.hash(&mut hasher1);
649        delta2.hash(&mut hasher2);
650
651        assert_ne!(hasher1.finish(), hasher2.finish());
652    }
653
654    #[rstest]
655    fn test_order_book_delta_partial_eq() {
656        let delta1 = create_test_delta();
657        let delta2 = create_test_delta();
658
659        // Test equality
660        assert_eq!(delta1, delta2);
661
662        // Test inequality with different instrument
663        let order3 = BookOrder::new(
664            OrderSide::Buy,
665            Price::from("1.0500"),
666            Quantity::from("100000"),
667            12345,
668        );
669        let delta3 = OrderBookDelta::new(
670            InstrumentId::from("GBPUSD.SIM"),
671            BookAction::Add,
672            order3,
673            0,
674            123,
675            UnixNanos::from(1_000_000_000),
676            UnixNanos::from(2_000_000_000),
677        );
678
679        assert_ne!(delta1, delta3);
680    }
681
682    #[rstest]
683    fn test_order_book_delta_clone() {
684        let delta1 = create_test_delta();
685        let delta2 = delta1;
686
687        assert_eq!(delta1, delta2);
688        assert_eq!(delta1.instrument_id, delta2.instrument_id);
689        assert_eq!(delta1.action, delta2.action);
690        assert_eq!(delta1.order, delta2.order);
691        assert_eq!(delta1.flags, delta2.flags);
692        assert_eq!(delta1.sequence, delta2.sequence);
693        assert_eq!(delta1.ts_event, delta2.ts_event);
694        assert_eq!(delta1.ts_init, delta2.ts_init);
695    }
696
697    #[rstest]
698    fn test_order_book_delta_debug() {
699        let delta = create_test_delta();
700        let debug_str = format!("{delta:?}");
701
702        assert!(debug_str.contains("OrderBookDelta"));
703        assert!(debug_str.contains("EURUSD.SIM"));
704        assert!(debug_str.contains("Add"));
705        assert!(debug_str.contains("BUY"));
706        assert!(debug_str.contains("1.0500"));
707    }
708
709    #[rstest]
710    fn test_order_book_delta_serialization() {
711        let delta = create_test_delta();
712
713        let json = serde_json::to_string(&delta).unwrap();
714        let deserialized: OrderBookDelta = serde_json::from_str(&json).unwrap();
715
716        assert_eq!(delta, deserialized);
717    }
718
719    #[rstest]
720    fn test_json_serialization(stub_delta: OrderBookDelta) {
721        let delta = stub_delta;
722        let serialized = delta.to_json_bytes().unwrap();
723        let deserialized = OrderBookDelta::from_json_bytes(serialized.as_ref()).unwrap();
724        assert_eq!(deserialized, delta);
725    }
726
727    #[rstest]
728    fn test_msgpack_serialization(stub_delta: OrderBookDelta) {
729        let delta = stub_delta;
730        let serialized = delta.to_msgpack_bytes().unwrap();
731        let deserialized = OrderBookDelta::from_msgpack_bytes(serialized.as_ref()).unwrap();
732        assert_eq!(deserialized, delta);
733    }
734}