1use std::str::FromStr;
19
20use serde::{Deserialize, Deserializer, Serialize, Serializer};
21use strum::{AsRefStr, Display, EnumIter, EnumString, FromRepr};
22
23use crate::enum_strum_serde;
24
25pub trait FromU8 {
27 fn from_u8(value: u8) -> Option<Self>
31 where
32 Self: Sized;
33}
34
35pub trait FromU16 {
37 fn from_u16(value: u16) -> Option<Self>
41 where
42 Self: Sized;
43}
44
45#[repr(C)]
47#[derive(
48 Copy,
49 Clone,
50 Debug,
51 Display,
52 Hash,
53 PartialEq,
54 Eq,
55 PartialOrd,
56 Ord,
57 AsRefStr,
58 FromRepr,
59 EnumIter,
60 EnumString,
61)]
62#[strum(ascii_case_insensitive)]
63#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
64#[cfg_attr(
65 feature = "python",
66 pyo3::pyclass(
67 frozen,
68 eq,
69 eq_int,
70 module = "nautilus_trader.model",
71 from_py_object,
72 rename_all = "SCREAMING_SNAKE_CASE",
73 )
74)]
75#[cfg_attr(
76 feature = "python",
77 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
78)]
79pub enum AccountType {
80 Cash = 1,
82 Margin = 2,
84 Betting = 3,
86 Wallet = 4,
88}
89
90#[repr(C)]
92#[derive(
93 Copy,
94 Clone,
95 Debug,
96 Display,
97 Hash,
98 PartialEq,
99 Eq,
100 PartialOrd,
101 Ord,
102 AsRefStr,
103 FromRepr,
104 EnumIter,
105 EnumString,
106)]
107#[strum(ascii_case_insensitive)]
108#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
109#[cfg_attr(
110 feature = "python",
111 pyo3::pyclass(
112 frozen,
113 eq,
114 eq_int,
115 module = "nautilus_trader.model",
116 from_py_object,
117 rename_all = "SCREAMING_SNAKE_CASE",
118 )
119)]
120#[cfg_attr(
121 feature = "python",
122 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
123)]
124pub enum AggregationSource {
125 External = 1,
127 Internal = 2,
129}
130
131#[repr(C)]
133#[derive(
134 Copy,
135 Clone,
136 Debug,
137 Default,
138 Display,
139 Hash,
140 PartialEq,
141 Eq,
142 PartialOrd,
143 Ord,
144 AsRefStr,
145 FromRepr,
146 EnumIter,
147 EnumString,
148)]
149#[strum(ascii_case_insensitive)]
150#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
151#[cfg_attr(
152 feature = "python",
153 pyo3::pyclass(
154 frozen,
155 eq,
156 eq_int,
157 module = "nautilus_trader.model",
158 from_py_object,
159 rename_all = "SCREAMING_SNAKE_CASE",
160 )
161)]
162#[cfg_attr(
163 feature = "python",
164 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
165)]
166pub enum AggressorSide {
167 #[default]
169 NoAggressor = 0,
170 #[strum(serialize = "BUYER", to_string = "BUY")]
174 Buy = 1,
175 #[strum(serialize = "SELLER", to_string = "SELL")]
179 Sell = 2,
180}
181
182impl FromU8 for AggressorSide {
183 fn from_u8(value: u8) -> Option<Self> {
184 match value {
185 0 => Some(Self::NoAggressor),
186 1 => Some(Self::Buy),
187 2 => Some(Self::Sell),
188 _ => None,
189 }
190 }
191}
192
193#[repr(C)]
195#[derive(
196 Copy,
197 Clone,
198 Debug,
199 Display,
200 Hash,
201 PartialEq,
202 Eq,
203 PartialOrd,
204 Ord,
205 AsRefStr,
206 FromRepr,
207 EnumIter,
208 EnumString,
209)]
210#[strum(ascii_case_insensitive)]
211#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
212#[cfg_attr(
213 feature = "python",
214 pyo3::pyclass(
215 frozen,
216 eq,
217 eq_int,
218 module = "nautilus_trader.model",
219 from_py_object,
220 rename_all = "SCREAMING_SNAKE_CASE",
221 )
222)]
223#[cfg_attr(
224 feature = "python",
225 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
226)]
227#[allow(non_camel_case_types)]
228pub enum AssetClass {
229 FX = 1,
231 Equity = 2,
233 Commodity = 3,
235 Debt = 4,
237 Index = 5,
239 Cryptocurrency = 6,
241 Alternative = 7,
243}
244
245impl FromU8 for AssetClass {
246 fn from_u8(value: u8) -> Option<Self> {
247 match value {
248 1 => Some(Self::FX),
249 2 => Some(Self::Equity),
250 3 => Some(Self::Commodity),
251 4 => Some(Self::Debt),
252 5 => Some(Self::Index),
253 6 => Some(Self::Cryptocurrency),
254 7 => Some(Self::Alternative),
255 _ => None,
256 }
257 }
258}
259
260#[repr(C)]
262#[derive(
263 Copy,
264 Clone,
265 Debug,
266 Display,
267 Hash,
268 PartialEq,
269 Eq,
270 PartialOrd,
271 Ord,
272 AsRefStr,
273 FromRepr,
274 EnumIter,
275 EnumString,
276)]
277#[strum(ascii_case_insensitive)]
278#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
279#[cfg_attr(
280 feature = "python",
281 pyo3::pyclass(
282 frozen,
283 eq,
284 eq_int,
285 module = "nautilus_trader.model",
286 from_py_object,
287 rename_all = "SCREAMING_SNAKE_CASE",
288 )
289)]
290#[cfg_attr(
291 feature = "python",
292 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
293)]
294pub enum BarAggregation {
295 Tick = 1,
297 TickImbalance = 2,
299 TickRuns = 3,
301 Volume = 4,
303 VolumeImbalance = 5,
305 VolumeRuns = 6,
307 Value = 7,
309 ValueImbalance = 8,
311 ValueRuns = 9,
313 Millisecond = 10,
315 Second = 11,
317 Minute = 12,
319 Hour = 13,
321 Day = 14,
323 Week = 15,
325 Month = 16,
327 Year = 17,
329 Renko = 18,
331}
332
333#[repr(C)]
335#[derive(
336 Copy,
337 Clone,
338 Debug,
339 Default,
340 Display,
341 Hash,
342 PartialEq,
343 Eq,
344 PartialOrd,
345 Ord,
346 AsRefStr,
347 FromRepr,
348 EnumIter,
349 EnumString,
350)]
351#[strum(ascii_case_insensitive)]
352#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
353#[cfg_attr(
354 feature = "python",
355 pyo3::pyclass(
356 frozen,
357 eq,
358 eq_int,
359 module = "nautilus_trader.model",
360 from_py_object,
361 rename_all = "SCREAMING_SNAKE_CASE",
362 )
363)]
364#[cfg_attr(
365 feature = "python",
366 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
367)]
368pub enum BarIntervalType {
369 #[default]
371 LeftOpen = 1,
372 RightOpen = 2,
374}
375
376#[repr(C)]
378#[derive(
379 Copy,
380 Clone,
381 Debug,
382 Display,
383 Hash,
384 PartialEq,
385 Eq,
386 PartialOrd,
387 Ord,
388 AsRefStr,
389 FromRepr,
390 EnumIter,
391 EnumString,
392)]
393#[strum(ascii_case_insensitive)]
394#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
395#[cfg_attr(
396 feature = "python",
397 pyo3::pyclass(
398 frozen,
399 eq,
400 eq_int,
401 module = "nautilus_trader.model",
402 from_py_object,
403 rename_all = "SCREAMING_SNAKE_CASE",
404 )
405)]
406#[cfg_attr(
407 feature = "python",
408 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
409)]
410pub enum BetSide {
411 Back = 1,
413 Lay = 2,
415}
416
417impl BetSide {
418 #[must_use]
420 pub fn opposite(&self) -> Self {
421 match self {
422 Self::Back => Self::Lay,
423 Self::Lay => Self::Back,
424 }
425 }
426}
427
428impl From<OrderSide> for BetSide {
429 fn from(side: OrderSide) -> Self {
435 match side {
436 OrderSide::Buy => Self::Back,
437 OrderSide::Sell => Self::Lay,
438 OrderSide::NoOrderSide => panic!("Invalid `OrderSide` for `BetSide`, was {side}"),
439 }
440 }
441}
442
443#[repr(C)]
445#[derive(
446 Copy,
447 Clone,
448 Debug,
449 Display,
450 Hash,
451 PartialEq,
452 Eq,
453 PartialOrd,
454 Ord,
455 AsRefStr,
456 FromRepr,
457 EnumIter,
458 EnumString,
459)]
460#[strum(ascii_case_insensitive)]
461#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
462#[cfg_attr(
463 feature = "python",
464 pyo3::pyclass(
465 frozen,
466 eq,
467 eq_int,
468 module = "nautilus_trader.model",
469 from_py_object,
470 rename_all = "SCREAMING_SNAKE_CASE",
471 )
472)]
473#[cfg_attr(
474 feature = "python",
475 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
476)]
477pub enum BookAction {
478 Add = 1,
480 Update = 2,
482 Delete = 3,
484 Clear = 4,
486}
487
488impl FromU8 for BookAction {
489 fn from_u8(value: u8) -> Option<Self> {
490 match value {
491 1 => Some(Self::Add),
492 2 => Some(Self::Update),
493 3 => Some(Self::Delete),
494 4 => Some(Self::Clear),
495 _ => None,
496 }
497 }
498}
499
500#[repr(C)]
502#[derive(
503 Copy,
504 Clone,
505 Debug,
506 Display,
507 Hash,
508 PartialEq,
509 Eq,
510 PartialOrd,
511 Ord,
512 AsRefStr,
513 FromRepr,
514 EnumIter,
515 EnumString,
516)]
517#[strum(ascii_case_insensitive)]
518#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
519#[cfg_attr(
520 feature = "python",
521 pyo3::pyclass(
522 frozen,
523 eq,
524 eq_int,
525 module = "nautilus_trader.model",
526 from_py_object,
527 rename_all = "SCREAMING_SNAKE_CASE",
528 )
529)]
530#[cfg_attr(
531 feature = "python",
532 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
533)]
534#[allow(non_camel_case_types)]
535pub enum BookType {
536 L1_MBP = 1,
538 L2_MBP = 2,
540 L3_MBO = 3,
542}
543
544impl FromU8 for BookType {
545 fn from_u8(value: u8) -> Option<Self> {
546 match value {
547 1 => Some(Self::L1_MBP),
548 2 => Some(Self::L2_MBP),
549 3 => Some(Self::L3_MBO),
550 _ => None,
551 }
552 }
553}
554
555#[repr(C)]
559#[derive(
560 Copy,
561 Clone,
562 Debug,
563 Default,
564 Display,
565 Hash,
566 PartialEq,
567 Eq,
568 PartialOrd,
569 Ord,
570 AsRefStr,
571 FromRepr,
572 EnumIter,
573 EnumString,
574)]
575#[strum(ascii_case_insensitive)]
576#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
577#[cfg_attr(
578 feature = "python",
579 pyo3::pyclass(
580 frozen,
581 eq,
582 eq_int,
583 module = "nautilus_trader.model",
584 from_py_object,
585 rename_all = "SCREAMING_SNAKE_CASE",
586 )
587)]
588#[cfg_attr(
589 feature = "python",
590 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
591)]
592pub enum ContingencyType {
593 #[default]
595 NoContingency = 0,
596 Oco = 1,
598 Oto = 2,
600 Ouo = 3,
602}
603
604#[repr(C)]
618#[derive(
619 Copy,
620 Clone,
621 Debug,
622 Default,
623 Display,
624 Hash,
625 PartialEq,
626 Eq,
627 PartialOrd,
628 Ord,
629 AsRefStr,
630 FromRepr,
631 EnumIter,
632 EnumString,
633)]
634#[strum(ascii_case_insensitive)]
635#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
636#[cfg_attr(
637 feature = "python",
638 pyo3::pyclass(
639 frozen,
640 eq,
641 eq_int,
642 module = "nautilus_trader.model",
643 from_py_object,
644 rename_all = "SCREAMING_SNAKE_CASE",
645 )
646)]
647#[cfg_attr(
648 feature = "python",
649 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
650)]
651pub enum ContinuousFutureAdjustmentType {
652 #[default]
654 BackwardSpread = 1,
655 ForwardSpread = 2,
657 BackwardRatio = 3,
659 ForwardRatio = 4,
661}
662
663impl ContinuousFutureAdjustmentType {
664 #[must_use]
666 pub const fn is_ratio(&self) -> bool {
667 matches!(self, Self::BackwardRatio | Self::ForwardRatio)
668 }
669
670 #[must_use]
672 pub const fn is_backward(&self) -> bool {
673 matches!(self, Self::BackwardSpread | Self::BackwardRatio)
674 }
675}
676
677#[repr(C)]
679#[derive(
680 Copy,
681 Clone,
682 Debug,
683 Display,
684 Hash,
685 PartialEq,
686 Eq,
687 PartialOrd,
688 Ord,
689 AsRefStr,
690 FromRepr,
691 EnumIter,
692 EnumString,
693)]
694#[strum(ascii_case_insensitive)]
695#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
696#[cfg_attr(
697 feature = "python",
698 pyo3::pyclass(
699 frozen,
700 eq,
701 eq_int,
702 module = "nautilus_trader.model",
703 from_py_object,
704 rename_all = "SCREAMING_SNAKE_CASE",
705 )
706)]
707#[cfg_attr(
708 feature = "python",
709 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
710)]
711pub enum CurrencyType {
712 Crypto = 1,
714 Fiat = 2,
716 CommodityBacked = 3,
718}
719
720#[repr(C)]
722#[derive(
723 Copy,
724 Clone,
725 Debug,
726 Display,
727 Hash,
728 PartialEq,
729 Eq,
730 PartialOrd,
731 Ord,
732 AsRefStr,
733 FromRepr,
734 EnumIter,
735 EnumString,
736)]
737#[strum(ascii_case_insensitive)]
738#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
739#[cfg_attr(
740 feature = "python",
741 pyo3::pyclass(
742 frozen,
743 eq,
744 eq_int,
745 module = "nautilus_trader.model",
746 from_py_object,
747 rename_all = "SCREAMING_SNAKE_CASE",
748 )
749)]
750#[cfg_attr(
751 feature = "python",
752 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
753)]
754pub enum InstrumentClass {
755 Spot = 1,
757 Swap = 2,
759 Future = 3,
761 FuturesSpread = 4,
763 Forward = 5,
765 Cfd = 6,
767 Bond = 7,
769 Option = 8,
771 OptionSpread = 9,
773 Warrant = 10,
775 SportsBetting = 11,
777 BinaryOption = 12,
779}
780
781impl InstrumentClass {
782 #[must_use]
784 pub const fn has_expiration(&self) -> bool {
785 matches!(
786 self,
787 Self::Future | Self::FuturesSpread | Self::Option | Self::OptionSpread
788 )
789 }
790
791 #[must_use]
793 pub const fn allows_negative_price(&self) -> bool {
794 matches!(
795 self,
796 Self::Option | Self::FuturesSpread | Self::OptionSpread
797 )
798 }
799
800 #[must_use]
805 pub fn try_from_parent_suffix(suffix: &str) -> Option<Self> {
806 match suffix {
807 "FUT" | "FUTURE" => Some(Self::Future),
808 "OPT" | "OPTION" => Some(Self::Option),
809 _ => None,
810 }
811 }
812
813 #[must_use]
818 pub const fn parent_suffix(self) -> Option<&'static str> {
819 match self {
820 Self::Future => Some("FUT"),
821 Self::Option => Some("OPT"),
822 _ => None,
823 }
824 }
825}
826
827#[repr(C)]
829#[derive(
830 Copy,
831 Clone,
832 Debug,
833 Display,
834 Hash,
835 PartialEq,
836 Eq,
837 PartialOrd,
838 Ord,
839 AsRefStr,
840 FromRepr,
841 EnumIter,
842 EnumString,
843)]
844#[strum(ascii_case_insensitive)]
845#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
846#[cfg_attr(
847 feature = "python",
848 pyo3::pyclass(
849 frozen,
850 eq,
851 eq_int,
852 module = "nautilus_trader.model",
853 from_py_object,
854 rename_all = "SCREAMING_SNAKE_CASE",
855 )
856)]
857#[cfg_attr(
858 feature = "python",
859 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
860)]
861pub enum InstrumentCloseType {
862 EndOfSession = 1,
864 ContractExpired = 2,
866}
867
868impl FromU8 for InstrumentCloseType {
870 fn from_u8(value: u8) -> Option<Self> {
871 match value {
872 1 => Some(Self::EndOfSession),
873 2 => Some(Self::ContractExpired),
874 _ => None,
875 }
876 }
877}
878
879#[repr(C)]
881#[derive(
882 Copy,
883 Clone,
884 Debug,
885 Display,
886 Hash,
887 PartialEq,
888 Eq,
889 PartialOrd,
890 Ord,
891 AsRefStr,
892 FromRepr,
893 EnumIter,
894 EnumString,
895)]
896#[strum(ascii_case_insensitive)]
897#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
898#[cfg_attr(
899 feature = "python",
900 pyo3::pyclass(
901 frozen,
902 eq,
903 eq_int,
904 module = "nautilus_trader.model",
905 from_py_object,
906 rename_all = "SCREAMING_SNAKE_CASE",
907 )
908)]
909#[cfg_attr(
910 feature = "python",
911 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
912)]
913pub enum LiquiditySide {
914 NoLiquiditySide = 0,
916 Maker = 1,
918 Taker = 2,
920}
921
922#[repr(C)]
924#[derive(
925 Copy,
926 Clone,
927 Debug,
928 Display,
929 Hash,
930 PartialEq,
931 Eq,
932 PartialOrd,
933 Ord,
934 AsRefStr,
935 FromRepr,
936 EnumIter,
937 EnumString,
938)]
939#[strum(ascii_case_insensitive)]
940#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
941#[cfg_attr(
942 feature = "python",
943 pyo3::pyclass(
944 frozen,
945 eq,
946 eq_int,
947 module = "nautilus_trader.model",
948 from_py_object,
949 rename_all = "SCREAMING_SNAKE_CASE",
950 )
951)]
952#[cfg_attr(
953 feature = "python",
954 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
955)]
956pub enum MarketStatus {
957 Open = 1,
959 Closed = 2,
961 Paused = 3,
963 Halted = 4,
965 Suspended = 5,
967 NotAvailable = 6,
969}
970
971#[repr(C)]
973#[derive(
974 Copy,
975 Clone,
976 Debug,
977 Display,
978 Hash,
979 PartialEq,
980 Eq,
981 PartialOrd,
982 Ord,
983 AsRefStr,
984 FromRepr,
985 EnumIter,
986 EnumString,
987)]
988#[strum(ascii_case_insensitive)]
989#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
990#[cfg_attr(
991 feature = "python",
992 pyo3::pyclass(
993 frozen,
994 eq,
995 eq_int,
996 module = "nautilus_trader.model",
997 from_py_object,
998 rename_all = "SCREAMING_SNAKE_CASE",
999 )
1000)]
1001#[cfg_attr(
1002 feature = "python",
1003 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1004)]
1005pub enum MarketStatusAction {
1006 None = 0,
1008 PreOpen = 1,
1010 PreCross = 2,
1012 Quoting = 3,
1014 Cross = 4,
1016 Rotation = 5,
1018 NewPriceIndication = 6,
1020 Trading = 7,
1022 Halt = 8,
1024 Pause = 9,
1026 Suspend = 10,
1028 PreClose = 11,
1030 Close = 12,
1032 PostClose = 13,
1034 ShortSellRestrictionChange = 14,
1036 NotAvailableForTrading = 15,
1038}
1039
1040impl FromU16 for MarketStatusAction {
1042 fn from_u16(value: u16) -> Option<Self> {
1043 match value {
1044 0 => Some(Self::None),
1045 1 => Some(Self::PreOpen),
1046 2 => Some(Self::PreCross),
1047 3 => Some(Self::Quoting),
1048 4 => Some(Self::Cross),
1049 5 => Some(Self::Rotation),
1050 6 => Some(Self::NewPriceIndication),
1051 7 => Some(Self::Trading),
1052 8 => Some(Self::Halt),
1053 9 => Some(Self::Pause),
1054 10 => Some(Self::Suspend),
1055 11 => Some(Self::PreClose),
1056 12 => Some(Self::Close),
1057 13 => Some(Self::PostClose),
1058 14 => Some(Self::ShortSellRestrictionChange),
1059 15 => Some(Self::NotAvailableForTrading),
1060 _ => None,
1061 }
1062 }
1063}
1064
1065#[repr(C)]
1067#[derive(
1068 Copy,
1069 Clone,
1070 Debug,
1071 Default,
1072 Display,
1073 Hash,
1074 PartialEq,
1075 Eq,
1076 PartialOrd,
1077 Ord,
1078 AsRefStr,
1079 FromRepr,
1080 EnumIter,
1081 EnumString,
1082)]
1083#[strum(ascii_case_insensitive)]
1084#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1085#[cfg_attr(
1086 feature = "python",
1087 pyo3::pyclass(
1088 frozen,
1089 eq,
1090 eq_int,
1091 module = "nautilus_trader.model",
1092 from_py_object,
1093 rename_all = "SCREAMING_SNAKE_CASE",
1094 )
1095)]
1096#[cfg_attr(
1097 feature = "python",
1098 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1099)]
1100pub enum OmsType {
1101 #[default]
1103 Unspecified = 0,
1104 Netting = 1,
1106 Hedging = 2,
1110}
1111
1112#[repr(C)]
1114#[derive(
1115 Copy,
1116 Clone,
1117 Debug,
1118 Display,
1119 Hash,
1120 PartialEq,
1121 Eq,
1122 PartialOrd,
1123 Ord,
1124 AsRefStr,
1125 FromRepr,
1126 EnumIter,
1127 EnumString,
1128)]
1129#[strum(ascii_case_insensitive)]
1130#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1131#[cfg_attr(
1132 feature = "python",
1133 pyo3::pyclass(
1134 frozen,
1135 eq,
1136 eq_int,
1137 module = "nautilus_trader.model",
1138 from_py_object,
1139 rename_all = "SCREAMING_SNAKE_CASE",
1140 )
1141)]
1142#[cfg_attr(
1143 feature = "python",
1144 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1145)]
1146pub enum OptionKind {
1147 Call = 1,
1149 Put = 2,
1151}
1152
1153#[repr(C)]
1165#[derive(
1166 Copy,
1167 Clone,
1168 Debug,
1169 Default,
1170 Display,
1171 Hash,
1172 PartialEq,
1173 Eq,
1174 PartialOrd,
1175 Ord,
1176 AsRefStr,
1177 FromRepr,
1178 EnumIter,
1179 EnumString,
1180)]
1181#[strum(ascii_case_insensitive)]
1182#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1183#[cfg_attr(
1184 feature = "python",
1185 pyo3::pyclass(
1186 frozen,
1187 eq,
1188 eq_int,
1189 module = "nautilus_trader.model",
1190 from_py_object,
1191 rename_all = "SCREAMING_SNAKE_CASE",
1192 )
1193)]
1194#[cfg_attr(
1195 feature = "python",
1196 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1197)]
1198pub enum GreeksConvention {
1199 #[default]
1201 BlackScholes = 1,
1202 PriceAdjusted = 2,
1204}
1205
1206#[repr(C)]
1208#[derive(
1209 Copy,
1210 Clone,
1211 Debug,
1212 Default,
1213 Display,
1214 Hash,
1215 PartialEq,
1216 Eq,
1217 PartialOrd,
1218 Ord,
1219 AsRefStr,
1220 FromRepr,
1221 EnumIter,
1222 EnumString,
1223)]
1224#[strum(ascii_case_insensitive)]
1225#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1226#[cfg_attr(
1227 feature = "python",
1228 pyo3::pyclass(
1229 frozen,
1230 eq,
1231 eq_int,
1232 module = "nautilus_trader.model",
1233 from_py_object,
1234 rename_all = "SCREAMING_SNAKE_CASE",
1235 )
1236)]
1237#[cfg_attr(
1238 feature = "python",
1239 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1240)]
1241pub enum OtoTriggerMode {
1242 #[default]
1244 Partial = 0,
1245 Full = 1,
1247}
1248
1249#[repr(C)]
1251#[derive(
1252 Copy,
1253 Clone,
1254 Debug,
1255 Default,
1256 Display,
1257 Hash,
1258 PartialEq,
1259 Eq,
1260 PartialOrd,
1261 Ord,
1262 AsRefStr,
1263 FromRepr,
1264 EnumIter,
1265 EnumString,
1266)]
1267#[strum(ascii_case_insensitive)]
1268#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1269#[cfg_attr(
1270 feature = "python",
1271 pyo3::pyclass(
1272 frozen,
1273 eq,
1274 eq_int,
1275 module = "nautilus_trader.model",
1276 from_py_object,
1277 rename_all = "SCREAMING_SNAKE_CASE",
1278 )
1279)]
1280#[cfg_attr(
1281 feature = "python",
1282 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1283)]
1284pub enum OrderSide {
1285 #[default]
1287 NoOrderSide = 0,
1288 Buy = 1,
1290 Sell = 2,
1292}
1293
1294impl OrderSide {
1295 #[must_use]
1301 pub fn as_specified(&self) -> OrderSideSpecified {
1302 match &self {
1303 Self::Buy => OrderSideSpecified::Buy,
1304 Self::Sell => OrderSideSpecified::Sell,
1305 Self::NoOrderSide => panic!("Order invariant failed: side must be `Buy` or `Sell`"),
1306 }
1307 }
1308}
1309
1310impl FromU8 for OrderSide {
1312 fn from_u8(value: u8) -> Option<Self> {
1313 match value {
1314 0 => Some(Self::NoOrderSide),
1315 1 => Some(Self::Buy),
1316 2 => Some(Self::Sell),
1317 _ => None,
1318 }
1319 }
1320}
1321
1322#[repr(C)]
1324#[derive(
1325 Copy,
1326 Clone,
1327 Debug,
1328 Display,
1329 Hash,
1330 PartialEq,
1331 Eq,
1332 PartialOrd,
1333 Ord,
1334 AsRefStr,
1335 FromRepr,
1336 EnumIter,
1337 EnumString,
1338)]
1339#[strum(ascii_case_insensitive)]
1340#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1341pub enum OrderSideSpecified {
1342 Buy = 1,
1344 Sell = 2,
1346}
1347
1348impl OrderSideSpecified {
1349 #[must_use]
1351 pub fn opposite(&self) -> Self {
1352 match &self {
1353 Self::Buy => Self::Sell,
1354 Self::Sell => Self::Buy,
1355 }
1356 }
1357
1358 #[must_use]
1360 pub fn as_order_side(&self) -> OrderSide {
1361 match &self {
1362 Self::Buy => OrderSide::Buy,
1363 Self::Sell => OrderSide::Sell,
1364 }
1365 }
1366}
1367
1368#[repr(C)]
1390#[derive(
1391 Copy,
1392 Clone,
1393 Debug,
1394 Display,
1395 Hash,
1396 PartialEq,
1397 Eq,
1398 PartialOrd,
1399 Ord,
1400 AsRefStr,
1401 FromRepr,
1402 EnumIter,
1403 EnumString,
1404)]
1405#[strum(ascii_case_insensitive)]
1406#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1407#[cfg_attr(
1408 feature = "python",
1409 pyo3::pyclass(
1410 frozen,
1411 eq,
1412 eq_int,
1413 module = "nautilus_trader.model",
1414 from_py_object,
1415 rename_all = "SCREAMING_SNAKE_CASE",
1416 )
1417)]
1418#[cfg_attr(
1419 feature = "python",
1420 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1421)]
1422pub enum OrderStatus {
1423 Initialized = 1,
1425 Denied = 2,
1427 Emulated = 3,
1429 Released = 4,
1431 Submitted = 5,
1433 Accepted = 6,
1435 Rejected = 7,
1437 Canceled = 8,
1439 Expired = 9,
1441 Triggered = 10,
1443 PendingUpdate = 11,
1445 PendingCancel = 12,
1447 PartiallyFilled = 13,
1449 Filled = 14,
1451 Voided = 15,
1453}
1454
1455impl OrderStatus {
1456 #[must_use]
1458 pub const fn is_open(self) -> bool {
1459 matches!(
1460 self,
1461 Self::Submitted
1462 | Self::Accepted
1463 | Self::Triggered
1464 | Self::PendingUpdate
1465 | Self::PendingCancel
1466 | Self::PartiallyFilled
1467 )
1468 }
1469
1470 #[must_use]
1472 pub const fn is_closed(self) -> bool {
1473 matches!(
1474 self,
1475 Self::Denied
1476 | Self::Rejected
1477 | Self::Canceled
1478 | Self::Expired
1479 | Self::Filled
1480 | Self::Voided
1481 )
1482 }
1483
1484 #[must_use]
1486 pub const fn is_cancellable(self) -> bool {
1487 matches!(
1488 self,
1489 Self::Accepted | Self::Triggered | Self::PendingUpdate | Self::PartiallyFilled
1490 )
1491 }
1492}
1493
1494#[repr(C)]
1496#[derive(
1497 Copy,
1498 Clone,
1499 Debug,
1500 Display,
1501 Hash,
1502 PartialEq,
1503 Eq,
1504 PartialOrd,
1505 Ord,
1506 AsRefStr,
1507 FromRepr,
1508 EnumIter,
1509 EnumString,
1510)]
1511#[strum(ascii_case_insensitive)]
1512#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1513#[cfg_attr(
1514 feature = "python",
1515 pyo3::pyclass(
1516 frozen,
1517 eq,
1518 eq_int,
1519 module = "nautilus_trader.model",
1520 from_py_object,
1521 rename_all = "SCREAMING_SNAKE_CASE",
1522 )
1523)]
1524#[cfg_attr(
1525 feature = "python",
1526 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1527)]
1528pub enum OrderType {
1529 Market = 1,
1531 Limit = 2,
1533 StopMarket = 3,
1535 StopLimit = 4,
1537 MarketToLimit = 5,
1539 MarketIfTouched = 6,
1541 LimitIfTouched = 7,
1543 TrailingStopMarket = 8,
1545 TrailingStopLimit = 9,
1547}
1548
1549#[repr(C)]
1551#[derive(
1552 Copy,
1553 Clone,
1554 Debug,
1555 Display,
1556 Hash,
1557 PartialEq,
1558 Eq,
1559 PartialOrd,
1560 Ord,
1561 AsRefStr,
1562 FromRepr,
1563 EnumIter,
1564 EnumString,
1565)]
1566#[strum(ascii_case_insensitive)]
1567#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1568#[cfg_attr(
1569 feature = "python",
1570 pyo3::pyclass(
1571 frozen,
1572 eq,
1573 eq_int,
1574 module = "nautilus_trader.model",
1575 from_py_object,
1576 rename_all = "SCREAMING_SNAKE_CASE",
1577 )
1578)]
1579#[cfg_attr(
1580 feature = "python",
1581 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1582)]
1583pub enum PositionAdjustmentType {
1584 Commission = 1,
1586 Funding = 2,
1588}
1589
1590impl FromU8 for PositionAdjustmentType {
1591 fn from_u8(value: u8) -> Option<Self> {
1592 match value {
1593 1 => Some(Self::Commission),
1594 2 => Some(Self::Funding),
1595 _ => None,
1596 }
1597 }
1598}
1599
1600#[repr(C)]
1602#[derive(
1603 Copy,
1604 Clone,
1605 Debug,
1606 Default,
1607 Display,
1608 Hash,
1609 PartialEq,
1610 Eq,
1611 PartialOrd,
1612 Ord,
1613 AsRefStr,
1614 FromRepr,
1615 EnumIter,
1616 EnumString,
1617)]
1618#[strum(ascii_case_insensitive)]
1619#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1620#[cfg_attr(
1621 feature = "python",
1622 pyo3::pyclass(
1623 frozen,
1624 eq,
1625 eq_int,
1626 module = "nautilus_trader.model",
1627 from_py_object,
1628 rename_all = "SCREAMING_SNAKE_CASE",
1629 )
1630)]
1631#[cfg_attr(
1632 feature = "python",
1633 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1634)]
1635pub enum PositionSide {
1636 #[default]
1638 NoPositionSide = 0,
1639 Flat = 1,
1641 Long = 2,
1643 Short = 3,
1645}
1646
1647impl PositionSide {
1648 #[must_use]
1654 pub fn as_specified(&self) -> PositionSideSpecified {
1655 match &self {
1656 Self::Long => PositionSideSpecified::Long,
1657 Self::Short => PositionSideSpecified::Short,
1658 Self::Flat => PositionSideSpecified::Flat,
1659 Self::NoPositionSide => {
1660 panic!("Position invariant failed: side must be `Long`, `Short`, or `Flat`")
1661 }
1662 }
1663 }
1664}
1665
1666#[repr(C)]
1668#[derive(
1669 Copy,
1670 Clone,
1671 Debug,
1672 Display,
1673 Hash,
1674 PartialEq,
1675 Eq,
1676 PartialOrd,
1677 Ord,
1678 AsRefStr,
1679 FromRepr,
1680 EnumIter,
1681 EnumString,
1682)]
1683#[strum(ascii_case_insensitive)]
1684#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1685pub enum PositionSideSpecified {
1686 Flat = 1,
1688 Long = 2,
1690 Short = 3,
1692}
1693
1694impl PositionSideSpecified {
1695 #[must_use]
1697 pub fn as_position_side(&self) -> PositionSide {
1698 match &self {
1699 Self::Long => PositionSide::Long,
1700 Self::Short => PositionSide::Short,
1701 Self::Flat => PositionSide::Flat,
1702 }
1703 }
1704}
1705
1706#[repr(C)]
1708#[derive(
1709 Copy,
1710 Clone,
1711 Debug,
1712 Display,
1713 Hash,
1714 PartialEq,
1715 Eq,
1716 PartialOrd,
1717 Ord,
1718 AsRefStr,
1719 FromRepr,
1720 EnumIter,
1721 EnumString,
1722)]
1723#[strum(ascii_case_insensitive)]
1724#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1725#[cfg_attr(
1726 feature = "python",
1727 pyo3::pyclass(
1728 frozen,
1729 eq,
1730 eq_int,
1731 module = "nautilus_trader.model",
1732 from_py_object,
1733 rename_all = "SCREAMING_SNAKE_CASE",
1734 )
1735)]
1736#[cfg_attr(
1737 feature = "python",
1738 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1739)]
1740pub enum PriceType {
1741 Bid = 1,
1747 Ask = 2,
1750 Mid = 3,
1752 Last = 4,
1754 Mark = 5,
1757}
1758
1759#[repr(C)]
1761#[derive(
1762 Copy,
1763 Clone,
1764 Debug,
1765 Display,
1766 Hash,
1767 PartialEq,
1768 Eq,
1769 PartialOrd,
1770 Ord,
1771 AsRefStr,
1772 FromRepr,
1773 EnumIter,
1774 EnumString,
1775)]
1776#[strum(ascii_case_insensitive)]
1777#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1778#[cfg_attr(
1779 feature = "python",
1780 pyo3::pyclass(
1781 frozen,
1782 eq,
1783 eq_int,
1784 module = "nautilus_trader.model",
1785 from_py_object,
1786 rename_all = "SCREAMING_SNAKE_CASE",
1787 )
1788)]
1789#[cfg_attr(
1790 feature = "python",
1791 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1792)]
1793#[allow(non_camel_case_types)]
1794pub enum RecordFlag {
1795 F_LAST = 1 << 7, F_TOB = 1 << 6, F_SNAPSHOT = 1 << 5, F_MBP = 1 << 4, RESERVED_2 = 1 << 3, RESERVED_1 = 1 << 2, }
1808
1809impl RecordFlag {
1810 #[must_use]
1812 pub fn matches(self, value: u8) -> bool {
1813 (self as u8) & value != 0
1814 }
1815}
1816
1817#[repr(C)]
1819#[derive(
1820 Copy,
1821 Clone,
1822 Debug,
1823 Display,
1824 Hash,
1825 PartialEq,
1826 Eq,
1827 PartialOrd,
1828 Ord,
1829 AsRefStr,
1830 FromRepr,
1831 EnumIter,
1832 EnumString,
1833)]
1834#[strum(ascii_case_insensitive)]
1835#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1836#[cfg_attr(
1837 feature = "python",
1838 pyo3::pyclass(
1839 frozen,
1840 eq,
1841 eq_int,
1842 module = "nautilus_trader.model",
1843 from_py_object,
1844 rename_all = "SCREAMING_SNAKE_CASE",
1845 )
1846)]
1847#[cfg_attr(
1848 feature = "python",
1849 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1850)]
1851pub enum TimeInForce {
1852 Gtc = 1,
1854 Ioc = 2,
1856 Fok = 3,
1858 Gtd = 4,
1860 Day = 5,
1862 AtTheOpen = 6,
1864 AtTheClose = 7,
1866}
1867
1868#[repr(C)]
1870#[derive(
1871 Copy,
1872 Clone,
1873 Debug,
1874 Display,
1875 Hash,
1876 PartialEq,
1877 Eq,
1878 PartialOrd,
1879 Ord,
1880 AsRefStr,
1881 FromRepr,
1882 EnumIter,
1883 EnumString,
1884)]
1885#[strum(ascii_case_insensitive)]
1886#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1887#[cfg_attr(
1888 feature = "python",
1889 pyo3::pyclass(
1890 frozen,
1891 eq,
1892 eq_int,
1893 module = "nautilus_trader.model",
1894 from_py_object,
1895 rename_all = "SCREAMING_SNAKE_CASE",
1896 )
1897)]
1898#[cfg_attr(
1899 feature = "python",
1900 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1901)]
1902pub enum TradingState {
1903 Active = 1,
1905 Halted = 2,
1907 Reducing = 3,
1909}
1910
1911#[repr(C)]
1913#[derive(
1914 Copy,
1915 Clone,
1916 Debug,
1917 Default,
1918 Display,
1919 Hash,
1920 PartialEq,
1921 Eq,
1922 PartialOrd,
1923 Ord,
1924 AsRefStr,
1925 FromRepr,
1926 EnumIter,
1927 EnumString,
1928)]
1929#[strum(ascii_case_insensitive)]
1930#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1931#[cfg_attr(
1932 feature = "python",
1933 pyo3::pyclass(
1934 frozen,
1935 eq,
1936 eq_int,
1937 module = "nautilus_trader.model",
1938 from_py_object,
1939 rename_all = "SCREAMING_SNAKE_CASE",
1940 )
1941)]
1942#[cfg_attr(
1943 feature = "python",
1944 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1945)]
1946pub enum TrailingOffsetType {
1947 #[default]
1949 NoTrailingOffset = 0,
1950 Price = 1,
1952 BasisPoints = 2,
1954 Ticks = 3,
1956 PriceTier = 4,
1958}
1959
1960#[repr(C)]
1962#[derive(
1963 Copy,
1964 Clone,
1965 Debug,
1966 Default,
1967 Display,
1968 Hash,
1969 PartialEq,
1970 Eq,
1971 PartialOrd,
1972 Ord,
1973 AsRefStr,
1974 FromRepr,
1975 EnumIter,
1976 EnumString,
1977)]
1978#[strum(ascii_case_insensitive)]
1979#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1980#[cfg_attr(
1981 feature = "python",
1982 pyo3::pyclass(
1983 frozen,
1984 eq,
1985 eq_int,
1986 module = "nautilus_trader.model",
1987 from_py_object,
1988 rename_all = "SCREAMING_SNAKE_CASE",
1989 )
1990)]
1991#[cfg_attr(
1992 feature = "python",
1993 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1994)]
1995pub enum TriggerType {
1996 #[default]
1998 NoTrigger = 0,
1999 Default = 1,
2001 LastPrice = 2,
2003 MarkPrice = 3,
2005 IndexPrice = 4,
2007 BidAsk = 5,
2009 DoubleLast = 6,
2011 DoubleBidAsk = 7,
2013 LastOrBidAsk = 8,
2015 MidPoint = 9,
2017}
2018
2019enum_strum_serde!(AccountType);
2020enum_strum_serde!(AggregationSource);
2021enum_strum_serde!(AggressorSide);
2022enum_strum_serde!(AssetClass);
2023enum_strum_serde!(BarAggregation);
2024enum_strum_serde!(BarIntervalType);
2025enum_strum_serde!(BookAction);
2026enum_strum_serde!(BookType);
2027enum_strum_serde!(ContingencyType);
2028enum_strum_serde!(ContinuousFutureAdjustmentType);
2029enum_strum_serde!(CurrencyType);
2030enum_strum_serde!(GreeksConvention);
2031enum_strum_serde!(InstrumentClass);
2032enum_strum_serde!(InstrumentCloseType);
2033enum_strum_serde!(LiquiditySide);
2034enum_strum_serde!(MarketStatus);
2035enum_strum_serde!(MarketStatusAction);
2036enum_strum_serde!(OmsType);
2037enum_strum_serde!(OptionKind);
2038enum_strum_serde!(OrderSide);
2039enum_strum_serde!(OrderSideSpecified);
2040enum_strum_serde!(OrderStatus);
2041enum_strum_serde!(OrderType);
2042enum_strum_serde!(PositionAdjustmentType);
2043enum_strum_serde!(PositionSide);
2044enum_strum_serde!(PositionSideSpecified);
2045enum_strum_serde!(PriceType);
2046enum_strum_serde!(RecordFlag);
2047enum_strum_serde!(TimeInForce);
2048enum_strum_serde!(TradingState);
2049enum_strum_serde!(TrailingOffsetType);
2050enum_strum_serde!(TriggerType);
2051
2052#[cfg(test)]
2053mod tests {
2054 use rstest::rstest;
2055
2056 use super::*;
2057
2058 #[rstest]
2059 #[case::no_aggressor(0, Some(AggressorSide::NoAggressor))]
2060 #[case::buy(1, Some(AggressorSide::Buy))]
2061 #[case::sell(2, Some(AggressorSide::Sell))]
2062 #[case::invalid(3, None)]
2063 #[case::max_u8(255, None)]
2064 fn test_aggressor_side_from_u8(#[case] value: u8, #[case] expected: Option<AggressorSide>) {
2065 assert_eq!(AggressorSide::from_u8(value), expected);
2066 }
2067
2068 #[rstest]
2069 #[case(AggressorSide::NoAggressor, "NO_AGGRESSOR")]
2070 #[case(AggressorSide::Buy, "BUY")]
2071 #[case(AggressorSide::Sell, "SELL")]
2072 fn test_aggressor_side_to_string(#[case] value: AggressorSide, #[case] expected: &str) {
2073 assert_eq!(value.to_string(), expected);
2074 assert_eq!(value.as_ref(), expected);
2075 }
2076
2077 #[rstest]
2078 #[case(AggressorSide::NoAggressor, "NO_AGGRESSOR")]
2079 #[case(AggressorSide::Buy, "BUY")]
2080 #[case(AggressorSide::Sell, "SELL")]
2081 #[case(AggressorSide::Buy, "BUYER")]
2082 #[case(AggressorSide::Sell, "SELLER")]
2083 #[case(AggressorSide::Buy, "buy")]
2084 #[case(AggressorSide::Sell, "seller")]
2085 fn test_aggressor_side_from_str(#[case] expected: AggressorSide, #[case] value: &str) {
2086 assert_eq!(AggressorSide::from_str(value), Ok(expected));
2087 }
2088
2089 #[rstest]
2090 #[case(AggressorSide::Buy, "\"BUY\"")]
2091 #[case(AggressorSide::Sell, "\"SELL\"")]
2092 #[case(AggressorSide::NoAggressor, "\"NO_AGGRESSOR\"")]
2093 fn test_aggressor_side_serde_roundtrip(#[case] input: AggressorSide, #[case] expected: &str) {
2094 let json = serde_json::to_string(&input).unwrap();
2095 assert_eq!(json, expected);
2096 let parsed: AggressorSide = serde_json::from_str(expected).unwrap();
2097 assert_eq!(parsed, input);
2098 }
2099
2100 #[rstest]
2101 #[case("BUYER", AggressorSide::Buy)]
2102 #[case("SELLER", AggressorSide::Sell)]
2103 fn test_aggressor_side_serde_accepts_historical(
2104 #[case] value: &str,
2105 #[case] expected: AggressorSide,
2106 ) {
2107 let parsed: AggressorSide = serde_json::from_str(&format!("\"{value}\"")).unwrap();
2108 assert_eq!(parsed, expected);
2109 }
2110
2111 #[rstest]
2112 #[case(GreeksConvention::BlackScholes, "\"BLACK_SCHOLES\"")]
2113 #[case(GreeksConvention::PriceAdjusted, "\"PRICE_ADJUSTED\"")]
2114 fn test_greeks_convention_serde_roundtrip(
2115 #[case] input: GreeksConvention,
2116 #[case] expected: &str,
2117 ) {
2118 let json = serde_json::to_string(&input).unwrap();
2119 assert_eq!(json, expected);
2120 let parsed: GreeksConvention = serde_json::from_str(expected).unwrap();
2121 assert_eq!(parsed, input);
2122 }
2123
2124 #[rstest]
2125 fn test_greeks_convention_default_is_black_scholes() {
2126 assert_eq!(GreeksConvention::default(), GreeksConvention::BlackScholes);
2127 }
2128
2129 #[rstest]
2130 #[case(ContinuousFutureAdjustmentType::BackwardSpread, false, true)]
2131 #[case(ContinuousFutureAdjustmentType::ForwardSpread, false, false)]
2132 #[case(ContinuousFutureAdjustmentType::BackwardRatio, true, true)]
2133 #[case(ContinuousFutureAdjustmentType::ForwardRatio, true, false)]
2134 fn test_continuous_future_adjustment_type_predicates(
2135 #[case] mode: ContinuousFutureAdjustmentType,
2136 #[case] expected_is_ratio: bool,
2137 #[case] expected_is_backward: bool,
2138 ) {
2139 assert_eq!(mode.is_ratio(), expected_is_ratio);
2140 assert_eq!(mode.is_backward(), expected_is_backward);
2141 }
2142
2143 #[rstest]
2144 #[case(ContinuousFutureAdjustmentType::BackwardSpread, "\"BACKWARD_SPREAD\"")]
2145 #[case(ContinuousFutureAdjustmentType::ForwardSpread, "\"FORWARD_SPREAD\"")]
2146 #[case(ContinuousFutureAdjustmentType::BackwardRatio, "\"BACKWARD_RATIO\"")]
2147 #[case(ContinuousFutureAdjustmentType::ForwardRatio, "\"FORWARD_RATIO\"")]
2148 fn test_continuous_future_adjustment_type_serde_roundtrip(
2149 #[case] input: ContinuousFutureAdjustmentType,
2150 #[case] expected: &str,
2151 ) {
2152 let json = serde_json::to_string(&input).unwrap();
2153 assert_eq!(json, expected);
2154 let parsed: ContinuousFutureAdjustmentType = serde_json::from_str(expected).unwrap();
2155 assert_eq!(parsed, input);
2156 }
2157
2158 #[rstest]
2159 fn test_continuous_future_adjustment_type_default_is_backward_spread() {
2160 assert_eq!(
2161 ContinuousFutureAdjustmentType::default(),
2162 ContinuousFutureAdjustmentType::BackwardSpread,
2163 );
2164 }
2165
2166 #[rstest]
2167 #[case(InstrumentClass::Option, true)]
2168 #[case(InstrumentClass::FuturesSpread, true)]
2169 #[case(InstrumentClass::OptionSpread, true)]
2170 #[case(InstrumentClass::Spot, false)]
2171 #[case(InstrumentClass::Swap, false)]
2172 #[case(InstrumentClass::Future, false)]
2173 #[case(InstrumentClass::Forward, false)]
2174 #[case(InstrumentClass::Cfd, false)]
2175 #[case(InstrumentClass::Bond, false)]
2176 #[case(InstrumentClass::Warrant, false)]
2177 #[case(InstrumentClass::SportsBetting, false)]
2178 #[case(InstrumentClass::BinaryOption, false)]
2179 fn test_instrument_class_allows_negative_price(
2180 #[case] class: InstrumentClass,
2181 #[case] expected: bool,
2182 ) {
2183 assert_eq!(class.allows_negative_price(), expected);
2184 }
2185
2186 #[rstest]
2187 #[case("FUT", Some(InstrumentClass::Future))]
2188 #[case("FUTURE", Some(InstrumentClass::Future))]
2189 #[case("OPT", Some(InstrumentClass::Option))]
2190 #[case("OPTION", Some(InstrumentClass::Option))]
2191 #[case("fut", None)]
2192 #[case("Fut", None)]
2193 #[case("option", None)]
2194 #[case("Option", None)]
2195 #[case("SPREAD", None)]
2196 #[case("UNKNOWN", None)]
2197 #[case("", None)]
2198 fn test_instrument_class_try_from_parent_suffix(
2199 #[case] suffix: &str,
2200 #[case] expected: Option<InstrumentClass>,
2201 ) {
2202 assert_eq!(InstrumentClass::try_from_parent_suffix(suffix), expected);
2203 }
2204
2205 #[rstest]
2206 #[case(InstrumentClass::Future, Some("FUT"))]
2207 #[case(InstrumentClass::Option, Some("OPT"))]
2208 #[case(InstrumentClass::Spot, None)]
2209 #[case(InstrumentClass::Swap, None)]
2210 #[case(InstrumentClass::FuturesSpread, None)]
2211 #[case(InstrumentClass::Forward, None)]
2212 #[case(InstrumentClass::Cfd, None)]
2213 #[case(InstrumentClass::Bond, None)]
2214 #[case(InstrumentClass::OptionSpread, None)]
2215 #[case(InstrumentClass::Warrant, None)]
2216 #[case(InstrumentClass::SportsBetting, None)]
2217 #[case(InstrumentClass::BinaryOption, None)]
2218 fn test_instrument_class_parent_suffix(
2219 #[case] class: InstrumentClass,
2220 #[case] expected: Option<&'static str>,
2221 ) {
2222 assert_eq!(class.parent_suffix(), expected);
2223 }
2224
2225 #[rstest]
2226 #[case(InstrumentClass::Future)]
2227 #[case(InstrumentClass::Option)]
2228 fn test_instrument_class_parent_suffix_roundtrip(#[case] class: InstrumentClass) {
2229 let suffix = class.parent_suffix().unwrap();
2230 assert_eq!(InstrumentClass::try_from_parent_suffix(suffix), Some(class));
2231 }
2232}