1use 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 ARROW_ENUM_DICTIONARY, ARROW_TIMESTAMP_NANOSECOND, HasTsInit,
26 order::{BookOrder, NULL_ORDER},
27};
28use crate::{
29 enums::{BookAction, RecordFlag},
30 identifiers::InstrumentId,
31 types::{fixed::FIXED_DECIMAL, quantity::check_positive_quantity},
32};
33
34#[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 pub instrument_id: InstrumentId,
48 pub action: BookAction,
50 pub order: BookOrder,
52 pub flags: u8,
54 pub sequence: u64,
56 pub ts_event: UnixNanos,
58 pub ts_init: UnixNanos,
60}
61
62impl OrderBookDelta {
63 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 #[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 #[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 #[cfg_attr(not(feature = "python"), allow(dead_code))]
144 #[must_use]
145 pub(crate) const fn is_add(&self) -> bool {
146 matches!(self.action, BookAction::Add)
147 }
148
149 #[cfg_attr(not(feature = "python"), allow(dead_code))]
151 #[must_use]
152 pub(crate) const fn is_update(&self) -> bool {
153 matches!(self.action, BookAction::Update)
154 }
155
156 #[cfg_attr(not(feature = "python"), allow(dead_code))]
158 #[must_use]
159 pub(crate) const fn is_delete(&self) -> bool {
160 matches!(self.action, BookAction::Delete)
161 }
162
163 #[cfg_attr(not(feature = "python"), allow(dead_code))]
165 #[must_use]
166 pub(crate) const fn is_clear(&self) -> bool {
167 matches!(self.action, BookAction::Clear)
168 }
169
170 #[must_use]
172 pub fn get_metadata(
173 instrument_id: &InstrumentId,
174 price_precision: u8,
175 size_precision: u8,
176 ) -> HashMap<String, String> {
177 let mut metadata = HashMap::new();
178 metadata.insert("instrument_id".to_string(), instrument_id.to_string());
179 metadata.insert("price_precision".to_string(), price_precision.to_string());
180 metadata.insert("size_precision".to_string(), size_precision.to_string());
181 metadata
182 }
183
184 #[must_use]
186 pub fn get_fields() -> IndexMap<String, String> {
187 let mut metadata = IndexMap::new();
188 metadata.insert("action".to_string(), ARROW_ENUM_DICTIONARY.to_string());
189 metadata.insert("side".to_string(), ARROW_ENUM_DICTIONARY.to_string());
190 metadata.insert("price".to_string(), FIXED_DECIMAL.to_string());
191 metadata.insert("size".to_string(), FIXED_DECIMAL.to_string());
192 metadata.insert("order_id".to_string(), "UInt64".to_string());
193 metadata.insert("flags".to_string(), "UInt8".to_string());
194 metadata.insert("sequence".to_string(), "UInt64".to_string());
195 metadata.insert(
196 "ts_event".to_string(),
197 ARROW_TIMESTAMP_NANOSECOND.to_string(),
198 );
199 metadata.insert(
200 "ts_init".to_string(),
201 ARROW_TIMESTAMP_NANOSECOND.to_string(),
202 );
203 metadata
204 }
205}
206
207impl Display for OrderBookDelta {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 write!(
210 f,
211 "{},{},{},{},{},{},{}",
212 self.instrument_id,
213 self.action,
214 self.order,
215 self.flags,
216 self.sequence,
217 self.ts_event,
218 self.ts_init
219 )
220 }
221}
222
223impl Serializable for OrderBookDelta {}
224
225impl HasTsInit for OrderBookDelta {
226 fn ts_init(&self) -> UnixNanos {
227 self.ts_init
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use std::{
234 collections::hash_map::DefaultHasher,
235 hash::{Hash, Hasher},
236 };
237
238 use nautilus_core::{
239 UnixNanos,
240 serialization::{
241 Serializable,
242 msgpack::{FromMsgPack, ToMsgPack},
243 },
244 };
245 use rstest::rstest;
246
247 use crate::{
248 data::{
249 ARROW_ENUM_DICTIONARY, ARROW_TIMESTAMP_NANOSECOND, BookOrder, HasTsInit,
250 OrderBookDelta, stubs::*,
251 },
252 enums::{BookAction, OrderSide, RecordFlag},
253 identifiers::InstrumentId,
254 types::{Price, Quantity, fixed::FIXED_DECIMAL},
255 };
256
257 fn create_test_delta() -> OrderBookDelta {
258 let order = BookOrder::new(
259 OrderSide::Buy,
260 Price::from("1.0500"),
261 Quantity::from("100000"),
262 12345,
263 );
264 OrderBookDelta::new(
265 InstrumentId::from("EURUSD.SIM"),
266 BookAction::Add,
267 order,
268 0,
269 123,
270 UnixNanos::from(1_000_000_000),
271 UnixNanos::from(2_000_000_000),
272 )
273 }
274
275 #[rstest]
276 fn test_order_book_delta_new() {
277 let delta = create_test_delta();
278
279 assert_eq!(delta.instrument_id, InstrumentId::from("EURUSD.SIM"));
280 assert_eq!(delta.action, BookAction::Add);
281 assert_eq!(delta.order.side, OrderSide::Buy.into());
282 assert_eq!(delta.order.price, Price::from("1.0500"));
283 assert_eq!(delta.order.size, Quantity::from("100000"));
284 assert_eq!(delta.order.order_id, 12345);
285 assert_eq!(delta.flags, 0);
286 assert_eq!(delta.sequence, 123);
287 assert_eq!(delta.ts_event, UnixNanos::from(1_000_000_000));
288 assert_eq!(delta.ts_init, UnixNanos::from(2_000_000_000));
289 }
290
291 #[rstest]
292 fn test_order_book_delta_new_checked_valid() {
293 let order = BookOrder::new(
294 OrderSide::Sell,
295 Price::from("1.0505"),
296 Quantity::from("50000"),
297 67890,
298 );
299 let result = OrderBookDelta::new_checked(
300 InstrumentId::from("GBPUSD.SIM"),
301 BookAction::Update,
302 order,
303 16,
304 456,
305 UnixNanos::from(500_000_000),
306 UnixNanos::from(1_500_000_000),
307 );
308
309 assert!(result.is_ok());
310 let delta = result.unwrap();
311 assert_eq!(delta.instrument_id, InstrumentId::from("GBPUSD.SIM"));
312 assert_eq!(delta.action, BookAction::Update);
313 assert_eq!(delta.order.side, OrderSide::Sell.into());
314 assert_eq!(delta.flags, 16);
315 }
316
317 #[rstest]
318 #[should_panic(expected = "invalid `Quantity` for 'order.size' not positive, was 0")]
319 fn test_order_book_delta_new_with_zero_size_panics() {
320 let instrument_id = InstrumentId::from("AAPL.XNAS");
321 let action = BookAction::Add;
322 let price = Price::from("100.00");
323 let zero_size = Quantity::from(0);
324 let side = OrderSide::Buy;
325 let order_id = 123_456;
326 let flags = 0;
327 let sequence = 1;
328 let ts_event = UnixNanos::from(0);
329 let ts_init = UnixNanos::from(1);
330
331 let order = BookOrder::new(side, price, zero_size, order_id);
332
333 let _ = OrderBookDelta::new(
334 instrument_id,
335 action,
336 order,
337 flags,
338 sequence,
339 ts_event,
340 ts_init,
341 );
342 }
343
344 #[rstest]
345 fn test_order_book_delta_new_checked_with_zero_size_error() {
346 let instrument_id = InstrumentId::from("AAPL.XNAS");
347 let action = BookAction::Add;
348 let price = Price::from("100.00");
349 let zero_size = Quantity::from(0);
350 let side = OrderSide::Buy;
351 let order_id = 123_456;
352 let flags = 0;
353 let sequence = 1;
354 let ts_event = UnixNanos::from(0);
355 let ts_init = UnixNanos::from(1);
356
357 let order = BookOrder::new(side, price, zero_size, order_id);
358
359 let result = OrderBookDelta::new_checked(
360 instrument_id,
361 action,
362 order,
363 flags,
364 sequence,
365 ts_event,
366 ts_init,
367 );
368
369 assert!(result.is_err());
370 assert!(
371 result
372 .unwrap_err()
373 .to_string()
374 .contains("invalid `Quantity` for 'order.size' not positive")
375 );
376 }
377
378 #[rstest]
379 fn test_order_book_delta_new_checked_delete_with_zero_size_ok() {
380 let order = BookOrder::new(
381 OrderSide::Buy,
382 Price::from("100.00"),
383 Quantity::from(0),
384 123_456,
385 );
386 let result = OrderBookDelta::new_checked(
387 InstrumentId::from("TEST.SIM"),
388 BookAction::Delete,
389 order,
390 0,
391 1,
392 UnixNanos::from(0),
393 UnixNanos::from(1),
394 );
395
396 assert!(result.is_ok());
397 }
398
399 #[rstest]
400 fn test_order_book_delta_clear() {
401 let instrument_id = InstrumentId::from("BTCUSD.CRYPTO");
402 let sequence = 999;
403 let ts_event = UnixNanos::from(3_000_000_000);
404 let ts_init = UnixNanos::from(4_000_000_000);
405
406 let delta = OrderBookDelta::clear(instrument_id, sequence, ts_event, ts_init);
407
408 assert_eq!(delta.instrument_id, instrument_id);
409 assert_eq!(delta.action, BookAction::Clear);
410 assert!(delta.order.price.is_zero());
411 assert!(delta.order.size.is_zero());
412 assert_eq!(delta.order.side, None);
413 assert_eq!(delta.order.order_id, 0);
414 assert_eq!(delta.flags, RecordFlag::F_SNAPSHOT as u8);
415 assert_eq!(delta.sequence, sequence);
416 assert_eq!(delta.ts_event, ts_event);
417 assert_eq!(delta.ts_init, ts_init);
418 }
419
420 #[rstest]
421 fn test_get_metadata() {
422 let instrument_id = InstrumentId::from("EURUSD.SIM");
423 let metadata = OrderBookDelta::get_metadata(&instrument_id, 5, 8);
424
425 assert_eq!(metadata.len(), 3);
426 assert_eq!(
427 metadata.get("instrument_id"),
428 Some(&"EURUSD.SIM".to_string())
429 );
430 assert_eq!(metadata.get("price_precision"), Some(&"5".to_string()));
431 assert_eq!(metadata.get("size_precision"), Some(&"8".to_string()));
432 }
433
434 #[rstest]
435 fn test_get_fields() {
436 let fields = OrderBookDelta::get_fields();
437
438 assert_eq!(fields.len(), 9);
439 assert_eq!(
440 fields.get("action"),
441 Some(&ARROW_ENUM_DICTIONARY.to_string())
442 );
443 assert_eq!(fields.get("side"), Some(&ARROW_ENUM_DICTIONARY.to_string()));
444
445 assert_eq!(fields.get("price"), Some(&FIXED_DECIMAL.to_string()));
446 assert_eq!(fields.get("size"), Some(&FIXED_DECIMAL.to_string()));
447
448 assert_eq!(fields.get("order_id"), Some(&"UInt64".to_string()));
449 assert_eq!(fields.get("flags"), Some(&"UInt8".to_string()));
450 assert_eq!(fields.get("sequence"), Some(&"UInt64".to_string()));
451 assert_eq!(
452 fields.get("ts_event"),
453 Some(&ARROW_TIMESTAMP_NANOSECOND.to_string())
454 );
455 assert_eq!(
456 fields.get("ts_init"),
457 Some(&ARROW_TIMESTAMP_NANOSECOND.to_string())
458 );
459 assert_eq!(fields.get("identifier"), None);
460 }
461
462 #[rstest]
463 #[case::add(BookAction::Add, (true, false, false, false))]
464 #[case::update(BookAction::Update, (false, true, false, false))]
465 #[case::delete(BookAction::Delete, (false, false, true, false))]
466 #[case::clear(BookAction::Clear, (false, false, false, true))]
467 fn test_order_book_delta_action_predicates(
468 #[case] action: BookAction,
469 #[case] expected: (bool, bool, bool, bool),
470 ) {
471 let order = BookOrder::new(
472 OrderSide::Buy,
473 Price::from("100.00"),
474 if matches!(action, BookAction::Delete | BookAction::Clear) {
475 Quantity::from(0)
476 } else {
477 Quantity::from("1000")
478 },
479 123_456,
480 );
481
482 let result = if matches!(action, BookAction::Clear) {
483 Ok(OrderBookDelta::clear(
484 InstrumentId::from("TEST.SIM"),
485 1,
486 UnixNanos::from(1_000_000_000),
487 UnixNanos::from(2_000_000_000),
488 ))
489 } else {
490 OrderBookDelta::new_checked(
491 InstrumentId::from("TEST.SIM"),
492 action,
493 order,
494 0,
495 1,
496 UnixNanos::from(1_000_000_000),
497 UnixNanos::from(2_000_000_000),
498 )
499 };
500
501 assert!(result.is_ok());
502 let delta = result.unwrap();
503 assert_eq!(delta.action, action);
504 assert_eq!(
505 (
506 delta.is_add(),
507 delta.is_update(),
508 delta.is_delete(),
509 delta.is_clear(),
510 ),
511 expected
512 );
513 }
514
515 #[rstest]
516 #[case(OrderSide::Buy)]
517 #[case(OrderSide::Sell)]
518 fn test_order_book_delta_with_different_sides(#[case] side: OrderSide) {
519 let order = BookOrder::new(side, Price::from("100.00"), Quantity::from("1000"), 123_456);
520
521 let delta = OrderBookDelta::new(
522 InstrumentId::from("TEST.SIM"),
523 BookAction::Add,
524 order,
525 0,
526 1,
527 UnixNanos::from(1_000_000_000),
528 UnixNanos::from(2_000_000_000),
529 );
530
531 assert_eq!(delta.order.side, side.into());
532 }
533
534 #[rstest]
535 fn test_order_book_delta_has_ts_init() {
536 let delta = create_test_delta();
537 assert_eq!(delta.ts_init(), UnixNanos::from(2_000_000_000));
538 }
539
540 #[rstest]
541 fn test_order_book_delta_display() {
542 let delta = create_test_delta();
543 let display_str = format!("{delta}");
544
545 assert!(display_str.contains("EURUSD.SIM"));
546 assert!(display_str.contains("ADD"));
547 assert!(display_str.contains("BUY"));
548 assert!(display_str.contains("1.0500"));
549 assert!(display_str.contains("100000"));
550 assert!(display_str.contains("12345"));
551 assert!(display_str.contains("123"));
552 }
553
554 #[rstest]
555 fn test_order_book_delta_with_zero_timestamps() {
556 let order = BookOrder::new(
557 OrderSide::Buy,
558 Price::from("100.00"),
559 Quantity::from("1000"),
560 123_456,
561 );
562 let delta = OrderBookDelta::new(
563 InstrumentId::from("TEST.SIM"),
564 BookAction::Add,
565 order,
566 0,
567 0,
568 UnixNanos::from(0),
569 UnixNanos::from(0),
570 );
571
572 assert_eq!(delta.sequence, 0);
573 assert_eq!(delta.ts_event, UnixNanos::from(0));
574 assert_eq!(delta.ts_init, UnixNanos::from(0));
575 }
576
577 #[rstest]
578 fn test_order_book_delta_with_max_values() {
579 let order = BookOrder::new(
580 OrderSide::Sell,
581 Price::from("999999.9999"),
582 Quantity::from("999999999.9999"),
583 u64::MAX,
584 );
585 let delta = OrderBookDelta::new(
586 InstrumentId::from("TEST.SIM"),
587 BookAction::Update,
588 order,
589 u8::MAX,
590 u64::MAX,
591 UnixNanos::from(u64::MAX),
592 UnixNanos::from(u64::MAX),
593 );
594
595 assert_eq!(delta.flags, u8::MAX);
596 assert_eq!(delta.sequence, u64::MAX);
597 assert_eq!(delta.order.order_id, u64::MAX);
598 assert_eq!(delta.ts_event, UnixNanos::from(u64::MAX));
599 assert_eq!(delta.ts_init, UnixNanos::from(u64::MAX));
600 }
601
602 #[rstest]
603 fn test_new() {
604 let instrument_id = InstrumentId::from("AAPL.XNAS");
605 let action = BookAction::Add;
606 let price = Price::from("100.00");
607 let size = Quantity::from("10");
608 let side = OrderSide::Buy;
609 let order_id = 123_456;
610 let flags = 0;
611 let sequence = 1;
612 let ts_event = 1;
613 let ts_init = 2;
614
615 let order = BookOrder::new(side, price, size, order_id);
616
617 let delta = OrderBookDelta::new(
618 instrument_id,
619 action,
620 order,
621 flags,
622 sequence,
623 ts_event.into(),
624 ts_init.into(),
625 );
626
627 assert_eq!(delta.instrument_id, instrument_id);
628 assert_eq!(delta.action, action);
629 assert_eq!(delta.order.price, price);
630 assert_eq!(delta.order.size, size);
631 assert_eq!(delta.order.side, side.into());
632 assert_eq!(delta.order.order_id, order_id);
633 assert_eq!(delta.flags, flags);
634 assert_eq!(delta.sequence, sequence);
635 assert_eq!(delta.ts_event, ts_event);
636 assert_eq!(delta.ts_init, ts_init);
637 }
638
639 #[rstest]
640 fn test_clear() {
641 let instrument_id = InstrumentId::from("AAPL.XNAS");
642 let sequence = 1;
643 let ts_event = 2;
644 let ts_init = 3;
645
646 let delta = OrderBookDelta::clear(instrument_id, sequence, ts_event.into(), ts_init.into());
647
648 assert_eq!(delta.instrument_id, instrument_id);
649 assert_eq!(delta.action, BookAction::Clear);
650 assert!(delta.order.price.is_zero());
651 assert!(delta.order.size.is_zero());
652 assert_eq!(delta.order.side, None);
653 assert_eq!(delta.order.order_id, 0);
654 assert_eq!(delta.flags, 32);
655 assert_eq!(delta.sequence, sequence);
656 assert_eq!(delta.ts_event, ts_event);
657 assert_eq!(delta.ts_init, ts_init);
658 }
659
660 #[rstest]
661 fn test_order_book_delta_hash() {
662 let delta1 = create_test_delta();
663 let delta2 = create_test_delta();
664
665 let mut hasher1 = DefaultHasher::new();
666 let mut hasher2 = DefaultHasher::new();
667
668 delta1.hash(&mut hasher1);
669 delta2.hash(&mut hasher2);
670
671 assert_eq!(hasher1.finish(), hasher2.finish());
672 }
673
674 #[rstest]
675 fn test_order_book_delta_hash_different_deltas() {
676 let delta1 = create_test_delta();
677 let order2 = BookOrder::new(
678 OrderSide::Sell,
679 Price::from("1.0505"),
680 Quantity::from("50000"),
681 67890,
682 );
683 let delta2 = OrderBookDelta::new(
684 InstrumentId::from("EURUSD.SIM"),
685 BookAction::Add,
686 order2,
687 0,
688 123,
689 UnixNanos::from(1_000_000_000),
690 UnixNanos::from(2_000_000_000),
691 );
692
693 let mut hasher1 = DefaultHasher::new();
694 let mut hasher2 = DefaultHasher::new();
695
696 delta1.hash(&mut hasher1);
697 delta2.hash(&mut hasher2);
698
699 assert_ne!(hasher1.finish(), hasher2.finish());
700 }
701
702 #[rstest]
703 fn test_order_book_delta_partial_eq() {
704 let delta1 = create_test_delta();
705 let delta2 = create_test_delta();
706
707 assert_eq!(delta1, delta2);
709
710 let order3 = BookOrder::new(
712 OrderSide::Buy,
713 Price::from("1.0500"),
714 Quantity::from("100000"),
715 12345,
716 );
717 let delta3 = OrderBookDelta::new(
718 InstrumentId::from("GBPUSD.SIM"),
719 BookAction::Add,
720 order3,
721 0,
722 123,
723 UnixNanos::from(1_000_000_000),
724 UnixNanos::from(2_000_000_000),
725 );
726
727 assert_ne!(delta1, delta3);
728 }
729
730 #[rstest]
731 fn test_order_book_delta_clone() {
732 let delta1 = create_test_delta();
733 let delta2 = delta1;
734
735 assert_eq!(delta1, delta2);
736 assert_eq!(delta1.instrument_id, delta2.instrument_id);
737 assert_eq!(delta1.action, delta2.action);
738 assert_eq!(delta1.order, delta2.order);
739 assert_eq!(delta1.flags, delta2.flags);
740 assert_eq!(delta1.sequence, delta2.sequence);
741 assert_eq!(delta1.ts_event, delta2.ts_event);
742 assert_eq!(delta1.ts_init, delta2.ts_init);
743 }
744
745 #[rstest]
746 fn test_order_book_delta_debug() {
747 let delta = create_test_delta();
748 let debug_str = format!("{delta:?}");
749
750 assert!(debug_str.contains("OrderBookDelta"));
751 assert!(debug_str.contains("EURUSD.SIM"));
752 assert!(debug_str.contains("Add"));
753 assert!(debug_str.contains("BUY"));
754 assert!(debug_str.contains("1.0500"));
755 }
756
757 #[rstest]
758 fn test_order_book_delta_serialization() {
759 let delta = create_test_delta();
760
761 let json = serde_json::to_string(&delta).unwrap();
762 let deserialized: OrderBookDelta = serde_json::from_str(&json).unwrap();
763
764 assert_order_book_delta_fields(&delta, &deserialized);
765 }
766
767 #[rstest]
768 fn test_json_serialization(stub_delta: OrderBookDelta) {
769 let delta = stub_delta;
770 let serialized = delta.to_json_bytes().unwrap();
771 let deserialized = OrderBookDelta::from_json_bytes(serialized.as_ref()).unwrap();
772 assert_order_book_delta_fields(&delta, &deserialized);
773 }
774
775 #[rstest]
776 fn test_msgpack_serialization(stub_delta: OrderBookDelta) {
777 let delta = stub_delta;
778 let serialized = delta.to_msgpack_bytes().unwrap();
779 let deserialized = OrderBookDelta::from_msgpack_bytes(serialized.as_ref()).unwrap();
780 assert_order_book_delta_fields(&delta, &deserialized);
781 }
782
783 fn assert_order_book_delta_fields(expected: &OrderBookDelta, actual: &OrderBookDelta) {
784 assert_eq!(expected.instrument_id, actual.instrument_id);
785 assert_eq!(expected.action, actual.action);
786 assert_eq!(expected.order.side, actual.order.side);
787 assert_eq!(expected.order.price, actual.order.price);
788 assert_eq!(expected.order.size, actual.order.size);
789 assert_eq!(expected.order.order_id, actual.order.order_id);
790 assert_eq!(expected.flags, actual.flags);
791 assert_eq!(expected.sequence, actual.sequence);
792 assert_eq!(expected.ts_event, actual.ts_event);
793 assert_eq!(expected.ts_init, actual.ts_init);
794 }
795}