1use std::{str::FromStr, sync::OnceLock};
19
20use ahash::AHashSet;
21use serde::{Deserialize, Deserializer, Serialize, Serializer};
22use strum::{AsRefStr, Display, EnumIter, EnumString, FromRepr};
23
24use crate::enum_strum_serde;
25
26pub trait FromU8 {
28 fn from_u8(value: u8) -> Option<Self>
32 where
33 Self: Sized;
34}
35
36pub trait FromU16 {
38 fn from_u16(value: u16) -> Option<Self>
42 where
43 Self: Sized;
44}
45
46#[repr(C)]
48#[derive(
49 Copy,
50 Clone,
51 Debug,
52 Display,
53 Hash,
54 PartialEq,
55 Eq,
56 PartialOrd,
57 Ord,
58 AsRefStr,
59 FromRepr,
60 EnumIter,
61 EnumString,
62)]
63#[strum(ascii_case_insensitive)]
64#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
65#[cfg_attr(
66 feature = "python",
67 pyo3::pyclass(
68 frozen,
69 eq,
70 eq_int,
71 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
72 from_py_object,
73 rename_all = "SCREAMING_SNAKE_CASE",
74 )
75)]
76#[cfg_attr(
77 feature = "python",
78 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
79)]
80pub enum AccountType {
81 Cash = 1,
83 Margin = 2,
85 Betting = 3,
87 Wallet = 4,
89}
90
91#[repr(C)]
93#[derive(
94 Copy,
95 Clone,
96 Debug,
97 Display,
98 Hash,
99 PartialEq,
100 Eq,
101 PartialOrd,
102 Ord,
103 AsRefStr,
104 FromRepr,
105 EnumIter,
106 EnumString,
107)]
108#[strum(ascii_case_insensitive)]
109#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
110#[cfg_attr(
111 feature = "python",
112 pyo3::pyclass(
113 frozen,
114 eq,
115 eq_int,
116 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
117 from_py_object,
118 rename_all = "SCREAMING_SNAKE_CASE",
119 )
120)]
121#[cfg_attr(
122 feature = "python",
123 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
124)]
125pub enum AggregationSource {
126 External = 1,
128 Internal = 2,
130}
131
132#[repr(C)]
134#[derive(
135 Copy,
136 Clone,
137 Debug,
138 Default,
139 Display,
140 Hash,
141 PartialEq,
142 Eq,
143 PartialOrd,
144 Ord,
145 AsRefStr,
146 FromRepr,
147 EnumIter,
148 EnumString,
149)]
150#[strum(ascii_case_insensitive)]
151#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
152#[cfg_attr(
153 feature = "python",
154 pyo3::pyclass(
155 frozen,
156 eq,
157 eq_int,
158 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
159 from_py_object,
160 rename_all = "SCREAMING_SNAKE_CASE",
161 )
162)]
163#[cfg_attr(
164 feature = "python",
165 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
166)]
167pub enum AggressorSide {
168 #[default]
170 NoAggressor = 0,
171 Buyer = 1,
173 Seller = 2,
175}
176
177impl FromU8 for AggressorSide {
178 fn from_u8(value: u8) -> Option<Self> {
179 match value {
180 0 => Some(Self::NoAggressor),
181 1 => Some(Self::Buyer),
182 2 => Some(Self::Seller),
183 _ => None,
184 }
185 }
186}
187
188#[repr(C)]
190#[derive(
191 Copy,
192 Clone,
193 Debug,
194 Display,
195 Hash,
196 PartialEq,
197 Eq,
198 PartialOrd,
199 Ord,
200 AsRefStr,
201 FromRepr,
202 EnumIter,
203 EnumString,
204)]
205#[strum(ascii_case_insensitive)]
206#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
207#[cfg_attr(
208 feature = "python",
209 pyo3::pyclass(
210 frozen,
211 eq,
212 eq_int,
213 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
214 from_py_object,
215 rename_all = "SCREAMING_SNAKE_CASE",
216 )
217)]
218#[cfg_attr(
219 feature = "python",
220 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
221)]
222#[allow(non_camel_case_types)]
223pub enum AssetClass {
224 FX = 1,
226 Equity = 2,
228 Commodity = 3,
230 Debt = 4,
232 Index = 5,
234 Cryptocurrency = 6,
236 Alternative = 7,
238}
239
240impl FromU8 for AssetClass {
241 fn from_u8(value: u8) -> Option<Self> {
242 match value {
243 1 => Some(Self::FX),
244 2 => Some(Self::Equity),
245 3 => Some(Self::Commodity),
246 4 => Some(Self::Debt),
247 5 => Some(Self::Index),
248 6 => Some(Self::Cryptocurrency),
249 7 => Some(Self::Alternative),
250 _ => None,
251 }
252 }
253}
254
255#[repr(C)]
257#[derive(
258 Copy,
259 Clone,
260 Debug,
261 Display,
262 Hash,
263 PartialEq,
264 Eq,
265 PartialOrd,
266 Ord,
267 AsRefStr,
268 FromRepr,
269 EnumIter,
270 EnumString,
271)]
272#[strum(ascii_case_insensitive)]
273#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
274#[cfg_attr(
275 feature = "python",
276 pyo3::pyclass(
277 frozen,
278 eq,
279 eq_int,
280 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
281 from_py_object,
282 rename_all = "SCREAMING_SNAKE_CASE",
283 )
284)]
285#[cfg_attr(
286 feature = "python",
287 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
288)]
289pub enum BarAggregation {
290 Tick = 1,
292 TickImbalance = 2,
294 TickRuns = 3,
296 Volume = 4,
298 VolumeImbalance = 5,
300 VolumeRuns = 6,
302 Value = 7,
304 ValueImbalance = 8,
306 ValueRuns = 9,
308 Millisecond = 10,
310 Second = 11,
312 Minute = 12,
314 Hour = 13,
316 Day = 14,
318 Week = 15,
320 Month = 16,
322 Year = 17,
324 Renko = 18,
326}
327
328#[repr(C)]
330#[derive(
331 Copy,
332 Clone,
333 Debug,
334 Default,
335 Display,
336 Hash,
337 PartialEq,
338 Eq,
339 PartialOrd,
340 Ord,
341 AsRefStr,
342 FromRepr,
343 EnumIter,
344 EnumString,
345)]
346#[strum(ascii_case_insensitive)]
347#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
348#[cfg_attr(
349 feature = "python",
350 pyo3::pyclass(
351 frozen,
352 eq,
353 eq_int,
354 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
355 from_py_object,
356 rename_all = "SCREAMING_SNAKE_CASE",
357 )
358)]
359#[cfg_attr(
360 feature = "python",
361 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
362)]
363pub enum BarIntervalType {
364 #[default]
366 LeftOpen = 1,
367 RightOpen = 2,
369}
370
371#[repr(C)]
373#[derive(
374 Copy,
375 Clone,
376 Debug,
377 Display,
378 Hash,
379 PartialEq,
380 Eq,
381 PartialOrd,
382 Ord,
383 AsRefStr,
384 FromRepr,
385 EnumIter,
386 EnumString,
387)]
388#[strum(ascii_case_insensitive)]
389#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
390#[cfg_attr(
391 feature = "python",
392 pyo3::pyclass(
393 frozen,
394 eq,
395 eq_int,
396 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
397 from_py_object,
398 rename_all = "SCREAMING_SNAKE_CASE",
399 )
400)]
401#[cfg_attr(
402 feature = "python",
403 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
404)]
405pub enum BetSide {
406 Back = 1,
408 Lay = 2,
410}
411
412impl BetSide {
413 #[must_use]
415 pub fn opposite(&self) -> Self {
416 match self {
417 Self::Back => Self::Lay,
418 Self::Lay => Self::Back,
419 }
420 }
421}
422
423impl From<OrderSide> for BetSide {
424 fn from(side: OrderSide) -> Self {
430 match side {
431 OrderSide::Buy => Self::Back,
432 OrderSide::Sell => Self::Lay,
433 OrderSide::NoOrderSide => panic!("Invalid `OrderSide` for `BetSide`, was {side}"),
434 }
435 }
436}
437
438#[repr(C)]
440#[derive(
441 Copy,
442 Clone,
443 Debug,
444 Display,
445 Hash,
446 PartialEq,
447 Eq,
448 PartialOrd,
449 Ord,
450 AsRefStr,
451 FromRepr,
452 EnumIter,
453 EnumString,
454)]
455#[strum(ascii_case_insensitive)]
456#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
457#[cfg_attr(
458 feature = "python",
459 pyo3::pyclass(
460 frozen,
461 eq,
462 eq_int,
463 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
464 from_py_object,
465 rename_all = "SCREAMING_SNAKE_CASE",
466 )
467)]
468#[cfg_attr(
469 feature = "python",
470 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
471)]
472pub enum BookAction {
473 Add = 1,
475 Update = 2,
477 Delete = 3,
479 Clear = 4,
481}
482
483impl FromU8 for BookAction {
484 fn from_u8(value: u8) -> Option<Self> {
485 match value {
486 1 => Some(Self::Add),
487 2 => Some(Self::Update),
488 3 => Some(Self::Delete),
489 4 => Some(Self::Clear),
490 _ => None,
491 }
492 }
493}
494
495#[repr(C)]
497#[derive(
498 Copy,
499 Clone,
500 Debug,
501 Display,
502 Hash,
503 PartialEq,
504 Eq,
505 PartialOrd,
506 Ord,
507 AsRefStr,
508 FromRepr,
509 EnumIter,
510 EnumString,
511)]
512#[strum(ascii_case_insensitive)]
513#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
514#[cfg_attr(
515 feature = "python",
516 pyo3::pyclass(
517 frozen,
518 eq,
519 eq_int,
520 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
521 from_py_object,
522 rename_all = "SCREAMING_SNAKE_CASE",
523 )
524)]
525#[cfg_attr(
526 feature = "python",
527 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
528)]
529#[allow(non_camel_case_types)]
530pub enum BookType {
531 L1_MBP = 1,
533 L2_MBP = 2,
535 L3_MBO = 3,
537}
538
539impl FromU8 for BookType {
540 fn from_u8(value: u8) -> Option<Self> {
541 match value {
542 1 => Some(Self::L1_MBP),
543 2 => Some(Self::L2_MBP),
544 3 => Some(Self::L3_MBO),
545 _ => None,
546 }
547 }
548}
549
550#[repr(C)]
554#[derive(
555 Copy,
556 Clone,
557 Debug,
558 Default,
559 Display,
560 Hash,
561 PartialEq,
562 Eq,
563 PartialOrd,
564 Ord,
565 AsRefStr,
566 FromRepr,
567 EnumIter,
568 EnumString,
569)]
570#[strum(ascii_case_insensitive)]
571#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
572#[cfg_attr(
573 feature = "python",
574 pyo3::pyclass(
575 frozen,
576 eq,
577 eq_int,
578 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
579 from_py_object,
580 rename_all = "SCREAMING_SNAKE_CASE",
581 )
582)]
583#[cfg_attr(
584 feature = "python",
585 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
586)]
587pub enum ContingencyType {
588 #[default]
590 NoContingency = 0,
591 Oco = 1,
593 Oto = 2,
595 Ouo = 3,
597}
598
599#[repr(C)]
613#[derive(
614 Copy,
615 Clone,
616 Debug,
617 Default,
618 Display,
619 Hash,
620 PartialEq,
621 Eq,
622 PartialOrd,
623 Ord,
624 AsRefStr,
625 FromRepr,
626 EnumIter,
627 EnumString,
628)]
629#[strum(ascii_case_insensitive)]
630#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
631#[cfg_attr(
632 feature = "python",
633 pyo3::pyclass(
634 frozen,
635 eq,
636 eq_int,
637 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
638 from_py_object,
639 rename_all = "SCREAMING_SNAKE_CASE",
640 )
641)]
642#[cfg_attr(
643 feature = "python",
644 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
645)]
646pub enum ContinuousFutureAdjustmentType {
647 #[default]
649 BackwardSpread = 1,
650 ForwardSpread = 2,
652 BackwardRatio = 3,
654 ForwardRatio = 4,
656}
657
658impl ContinuousFutureAdjustmentType {
659 #[must_use]
661 pub const fn is_ratio(&self) -> bool {
662 matches!(self, Self::BackwardRatio | Self::ForwardRatio)
663 }
664
665 #[must_use]
667 pub const fn is_backward(&self) -> bool {
668 matches!(self, Self::BackwardSpread | Self::BackwardRatio)
669 }
670}
671
672#[repr(C)]
674#[derive(
675 Copy,
676 Clone,
677 Debug,
678 Display,
679 Hash,
680 PartialEq,
681 Eq,
682 PartialOrd,
683 Ord,
684 AsRefStr,
685 FromRepr,
686 EnumIter,
687 EnumString,
688)]
689#[strum(ascii_case_insensitive)]
690#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
691#[cfg_attr(
692 feature = "python",
693 pyo3::pyclass(
694 frozen,
695 eq,
696 eq_int,
697 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
698 from_py_object,
699 rename_all = "SCREAMING_SNAKE_CASE",
700 )
701)]
702#[cfg_attr(
703 feature = "python",
704 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
705)]
706pub enum CurrencyType {
707 Crypto = 1,
709 Fiat = 2,
711 CommodityBacked = 3,
713}
714
715#[repr(C)]
717#[derive(
718 Copy,
719 Clone,
720 Debug,
721 Display,
722 Hash,
723 PartialEq,
724 Eq,
725 PartialOrd,
726 Ord,
727 AsRefStr,
728 FromRepr,
729 EnumIter,
730 EnumString,
731)]
732#[strum(ascii_case_insensitive)]
733#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
734#[cfg_attr(
735 feature = "python",
736 pyo3::pyclass(
737 frozen,
738 eq,
739 eq_int,
740 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
741 from_py_object,
742 rename_all = "SCREAMING_SNAKE_CASE",
743 )
744)]
745#[cfg_attr(
746 feature = "python",
747 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
748)]
749pub enum InstrumentClass {
750 Spot = 1,
752 Swap = 2,
754 Future = 3,
756 FuturesSpread = 4,
758 Forward = 5,
760 Cfd = 6,
762 Bond = 7,
764 Option = 8,
766 OptionSpread = 9,
768 Warrant = 10,
770 SportsBetting = 11,
772 BinaryOption = 12,
774}
775
776impl InstrumentClass {
777 #[must_use]
779 pub const fn has_expiration(&self) -> bool {
780 matches!(
781 self,
782 Self::Future | Self::FuturesSpread | Self::Option | Self::OptionSpread
783 )
784 }
785
786 #[must_use]
788 pub const fn allows_negative_price(&self) -> bool {
789 matches!(
790 self,
791 Self::Option | Self::FuturesSpread | Self::OptionSpread
792 )
793 }
794
795 #[must_use]
800 pub fn try_from_parent_suffix(suffix: &str) -> Option<Self> {
801 match suffix {
802 "FUT" | "FUTURE" => Some(Self::Future),
803 "OPT" | "OPTION" => Some(Self::Option),
804 _ => None,
805 }
806 }
807
808 #[must_use]
813 pub const fn parent_suffix(self) -> Option<&'static str> {
814 match self {
815 Self::Future => Some("FUT"),
816 Self::Option => Some("OPT"),
817 _ => None,
818 }
819 }
820}
821
822#[repr(C)]
824#[derive(
825 Copy,
826 Clone,
827 Debug,
828 Display,
829 Hash,
830 PartialEq,
831 Eq,
832 PartialOrd,
833 Ord,
834 AsRefStr,
835 FromRepr,
836 EnumIter,
837 EnumString,
838)]
839#[strum(ascii_case_insensitive)]
840#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
841#[cfg_attr(
842 feature = "python",
843 pyo3::pyclass(
844 frozen,
845 eq,
846 eq_int,
847 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
848 from_py_object,
849 rename_all = "SCREAMING_SNAKE_CASE",
850 )
851)]
852#[cfg_attr(
853 feature = "python",
854 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
855)]
856pub enum InstrumentCloseType {
857 EndOfSession = 1,
859 ContractExpired = 2,
861}
862
863impl FromU8 for InstrumentCloseType {
865 fn from_u8(value: u8) -> Option<Self> {
866 match value {
867 1 => Some(Self::EndOfSession),
868 2 => Some(Self::ContractExpired),
869 _ => None,
870 }
871 }
872}
873
874#[repr(C)]
876#[derive(
877 Copy,
878 Clone,
879 Debug,
880 Display,
881 Hash,
882 PartialEq,
883 Eq,
884 PartialOrd,
885 Ord,
886 AsRefStr,
887 FromRepr,
888 EnumIter,
889 EnumString,
890)]
891#[strum(ascii_case_insensitive)]
892#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
893#[cfg_attr(
894 feature = "python",
895 pyo3::pyclass(
896 frozen,
897 eq,
898 eq_int,
899 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
900 from_py_object,
901 rename_all = "SCREAMING_SNAKE_CASE",
902 )
903)]
904#[cfg_attr(
905 feature = "python",
906 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
907)]
908pub enum LiquiditySide {
909 NoLiquiditySide = 0,
911 Maker = 1,
913 Taker = 2,
915}
916
917#[repr(C)]
919#[derive(
920 Copy,
921 Clone,
922 Debug,
923 Display,
924 Hash,
925 PartialEq,
926 Eq,
927 PartialOrd,
928 Ord,
929 AsRefStr,
930 FromRepr,
931 EnumIter,
932 EnumString,
933)]
934#[strum(ascii_case_insensitive)]
935#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
936#[cfg_attr(
937 feature = "python",
938 pyo3::pyclass(
939 frozen,
940 eq,
941 eq_int,
942 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
943 from_py_object,
944 rename_all = "SCREAMING_SNAKE_CASE",
945 )
946)]
947#[cfg_attr(
948 feature = "python",
949 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
950)]
951pub enum MarketStatus {
952 Open = 1,
954 Closed = 2,
956 Paused = 3,
958 Suspended = 5,
962 NotAvailable = 6,
964}
965
966#[repr(C)]
968#[derive(
969 Copy,
970 Clone,
971 Debug,
972 Display,
973 Hash,
974 PartialEq,
975 Eq,
976 PartialOrd,
977 Ord,
978 AsRefStr,
979 FromRepr,
980 EnumIter,
981 EnumString,
982)]
983#[strum(ascii_case_insensitive)]
984#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
985#[cfg_attr(
986 feature = "python",
987 pyo3::pyclass(
988 frozen,
989 eq,
990 eq_int,
991 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
992 from_py_object,
993 rename_all = "SCREAMING_SNAKE_CASE",
994 )
995)]
996#[cfg_attr(
997 feature = "python",
998 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
999)]
1000pub enum MarketStatusAction {
1001 None = 0,
1003 PreOpen = 1,
1005 PreCross = 2,
1007 Quoting = 3,
1009 Cross = 4,
1011 Rotation = 5,
1013 NewPriceIndication = 6,
1015 Trading = 7,
1017 Halt = 8,
1019 Pause = 9,
1021 Suspend = 10,
1023 PreClose = 11,
1025 Close = 12,
1027 PostClose = 13,
1029 ShortSellRestrictionChange = 14,
1031 NotAvailableForTrading = 15,
1033}
1034
1035impl FromU16 for MarketStatusAction {
1037 fn from_u16(value: u16) -> Option<Self> {
1038 match value {
1039 0 => Some(Self::None),
1040 1 => Some(Self::PreOpen),
1041 2 => Some(Self::PreCross),
1042 3 => Some(Self::Quoting),
1043 4 => Some(Self::Cross),
1044 5 => Some(Self::Rotation),
1045 6 => Some(Self::NewPriceIndication),
1046 7 => Some(Self::Trading),
1047 8 => Some(Self::Halt),
1048 9 => Some(Self::Pause),
1049 10 => Some(Self::Suspend),
1050 11 => Some(Self::PreClose),
1051 12 => Some(Self::Close),
1052 13 => Some(Self::PostClose),
1053 14 => Some(Self::ShortSellRestrictionChange),
1054 15 => Some(Self::NotAvailableForTrading),
1055 _ => None,
1056 }
1057 }
1058}
1059
1060#[repr(C)]
1062#[derive(
1063 Copy,
1064 Clone,
1065 Debug,
1066 Default,
1067 Display,
1068 Hash,
1069 PartialEq,
1070 Eq,
1071 PartialOrd,
1072 Ord,
1073 AsRefStr,
1074 FromRepr,
1075 EnumIter,
1076 EnumString,
1077)]
1078#[strum(ascii_case_insensitive)]
1079#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1080#[cfg_attr(
1081 feature = "python",
1082 pyo3::pyclass(
1083 frozen,
1084 eq,
1085 eq_int,
1086 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1087 from_py_object,
1088 rename_all = "SCREAMING_SNAKE_CASE",
1089 )
1090)]
1091#[cfg_attr(
1092 feature = "python",
1093 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1094)]
1095pub enum OmsType {
1096 #[default]
1098 Unspecified = 0,
1099 Netting = 1,
1101 Hedging = 2,
1105}
1106
1107#[repr(C)]
1109#[derive(
1110 Copy,
1111 Clone,
1112 Debug,
1113 Display,
1114 Hash,
1115 PartialEq,
1116 Eq,
1117 PartialOrd,
1118 Ord,
1119 AsRefStr,
1120 FromRepr,
1121 EnumIter,
1122 EnumString,
1123)]
1124#[strum(ascii_case_insensitive)]
1125#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1126#[cfg_attr(
1127 feature = "python",
1128 pyo3::pyclass(
1129 frozen,
1130 eq,
1131 eq_int,
1132 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1133 from_py_object,
1134 rename_all = "SCREAMING_SNAKE_CASE",
1135 )
1136)]
1137#[cfg_attr(
1138 feature = "python",
1139 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1140)]
1141pub enum OptionKind {
1142 Call = 1,
1144 Put = 2,
1146}
1147
1148#[repr(C)]
1160#[derive(
1161 Copy,
1162 Clone,
1163 Debug,
1164 Default,
1165 Display,
1166 Hash,
1167 PartialEq,
1168 Eq,
1169 PartialOrd,
1170 Ord,
1171 AsRefStr,
1172 FromRepr,
1173 EnumIter,
1174 EnumString,
1175)]
1176#[strum(ascii_case_insensitive)]
1177#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1178#[cfg_attr(
1179 feature = "python",
1180 pyo3::pyclass(
1181 frozen,
1182 eq,
1183 eq_int,
1184 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1185 from_py_object,
1186 rename_all = "SCREAMING_SNAKE_CASE",
1187 )
1188)]
1189#[cfg_attr(
1190 feature = "python",
1191 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1192)]
1193pub enum GreeksConvention {
1194 #[default]
1196 BlackScholes = 1,
1197 PriceAdjusted = 2,
1199}
1200
1201#[repr(C)]
1203#[derive(
1204 Copy,
1205 Clone,
1206 Debug,
1207 Default,
1208 Display,
1209 Hash,
1210 PartialEq,
1211 Eq,
1212 PartialOrd,
1213 Ord,
1214 AsRefStr,
1215 FromRepr,
1216 EnumIter,
1217 EnumString,
1218)]
1219#[strum(ascii_case_insensitive)]
1220#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1221#[cfg_attr(
1222 feature = "python",
1223 pyo3::pyclass(
1224 frozen,
1225 eq,
1226 eq_int,
1227 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1228 from_py_object,
1229 rename_all = "SCREAMING_SNAKE_CASE",
1230 )
1231)]
1232#[cfg_attr(
1233 feature = "python",
1234 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1235)]
1236pub enum OtoTriggerMode {
1237 #[default]
1239 Partial = 0,
1240 Full = 1,
1242}
1243
1244#[repr(C)]
1246#[derive(
1247 Copy,
1248 Clone,
1249 Debug,
1250 Default,
1251 Display,
1252 Hash,
1253 PartialEq,
1254 Eq,
1255 PartialOrd,
1256 Ord,
1257 AsRefStr,
1258 FromRepr,
1259 EnumIter,
1260 EnumString,
1261)]
1262#[strum(ascii_case_insensitive)]
1263#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1264#[cfg_attr(
1265 feature = "python",
1266 pyo3::pyclass(
1267 frozen,
1268 eq,
1269 eq_int,
1270 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1271 from_py_object,
1272 rename_all = "SCREAMING_SNAKE_CASE",
1273 )
1274)]
1275#[cfg_attr(
1276 feature = "python",
1277 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1278)]
1279pub enum OrderSide {
1280 #[default]
1282 NoOrderSide = 0,
1283 Buy = 1,
1285 Sell = 2,
1287}
1288
1289impl OrderSide {
1290 #[must_use]
1296 pub fn as_specified(&self) -> OrderSideSpecified {
1297 match &self {
1298 Self::Buy => OrderSideSpecified::Buy,
1299 Self::Sell => OrderSideSpecified::Sell,
1300 Self::NoOrderSide => panic!("Order invariant failed: side must be `Buy` or `Sell`"),
1301 }
1302 }
1303}
1304
1305impl FromU8 for OrderSide {
1307 fn from_u8(value: u8) -> Option<Self> {
1308 match value {
1309 0 => Some(Self::NoOrderSide),
1310 1 => Some(Self::Buy),
1311 2 => Some(Self::Sell),
1312 _ => None,
1313 }
1314 }
1315}
1316
1317#[repr(C)]
1319#[derive(
1320 Copy,
1321 Clone,
1322 Debug,
1323 Display,
1324 Hash,
1325 PartialEq,
1326 Eq,
1327 PartialOrd,
1328 Ord,
1329 AsRefStr,
1330 FromRepr,
1331 EnumIter,
1332 EnumString,
1333)]
1334#[strum(ascii_case_insensitive)]
1335#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1336pub enum OrderSideSpecified {
1337 Buy = 1,
1339 Sell = 2,
1341}
1342
1343impl OrderSideSpecified {
1344 #[must_use]
1346 pub fn opposite(&self) -> Self {
1347 match &self {
1348 Self::Buy => Self::Sell,
1349 Self::Sell => Self::Buy,
1350 }
1351 }
1352
1353 #[must_use]
1355 pub fn as_order_side(&self) -> OrderSide {
1356 match &self {
1357 Self::Buy => OrderSide::Buy,
1358 Self::Sell => OrderSide::Sell,
1359 }
1360 }
1361}
1362
1363#[repr(C)]
1384#[derive(
1385 Copy,
1386 Clone,
1387 Debug,
1388 Display,
1389 Hash,
1390 PartialEq,
1391 Eq,
1392 PartialOrd,
1393 Ord,
1394 AsRefStr,
1395 FromRepr,
1396 EnumIter,
1397 EnumString,
1398)]
1399#[strum(ascii_case_insensitive)]
1400#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1401#[cfg_attr(
1402 feature = "python",
1403 pyo3::pyclass(
1404 frozen,
1405 eq,
1406 eq_int,
1407 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1408 from_py_object,
1409 rename_all = "SCREAMING_SNAKE_CASE",
1410 )
1411)]
1412#[cfg_attr(
1413 feature = "python",
1414 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1415)]
1416pub enum OrderStatus {
1417 Initialized = 1,
1419 Denied = 2,
1421 Emulated = 3,
1423 Released = 4,
1425 Submitted = 5,
1427 Accepted = 6,
1429 Rejected = 7,
1431 Canceled = 8,
1433 Expired = 9,
1435 Triggered = 10,
1437 PendingUpdate = 11,
1439 PendingCancel = 12,
1441 PartiallyFilled = 13,
1443 Filled = 14,
1445}
1446
1447impl OrderStatus {
1448 #[must_use]
1450 pub const fn is_open(self) -> bool {
1451 matches!(
1452 self,
1453 Self::Submitted
1454 | Self::Accepted
1455 | Self::Triggered
1456 | Self::PendingUpdate
1457 | Self::PendingCancel
1458 | Self::PartiallyFilled
1459 )
1460 }
1461
1462 #[must_use]
1464 pub const fn is_closed(self) -> bool {
1465 matches!(
1466 self,
1467 Self::Denied | Self::Rejected | Self::Canceled | Self::Expired | Self::Filled
1468 )
1469 }
1470
1471 #[must_use]
1473 pub const fn is_cancellable(self) -> bool {
1474 matches!(
1475 self,
1476 Self::Accepted | Self::Triggered | Self::PendingUpdate | Self::PartiallyFilled
1477 )
1478 }
1479
1480 #[must_use]
1495 pub fn cancellable_statuses_set() -> &'static AHashSet<Self> {
1496 static CANCELLABLE_SET: OnceLock<AHashSet<OrderStatus>> = OnceLock::new();
1497 CANCELLABLE_SET.get_or_init(|| {
1498 AHashSet::from_iter([
1499 Self::Accepted,
1500 Self::Triggered,
1501 Self::PendingUpdate,
1502 Self::PartiallyFilled,
1503 ])
1504 })
1505 }
1506}
1507
1508#[repr(C)]
1510#[derive(
1511 Copy,
1512 Clone,
1513 Debug,
1514 Display,
1515 Hash,
1516 PartialEq,
1517 Eq,
1518 PartialOrd,
1519 Ord,
1520 AsRefStr,
1521 FromRepr,
1522 EnumIter,
1523 EnumString,
1524)]
1525#[strum(ascii_case_insensitive)]
1526#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1527#[cfg_attr(
1528 feature = "python",
1529 pyo3::pyclass(
1530 frozen,
1531 eq,
1532 eq_int,
1533 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1534 from_py_object,
1535 rename_all = "SCREAMING_SNAKE_CASE",
1536 )
1537)]
1538#[cfg_attr(
1539 feature = "python",
1540 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1541)]
1542pub enum OrderType {
1543 Market = 1,
1545 Limit = 2,
1547 StopMarket = 3,
1549 StopLimit = 4,
1551 MarketToLimit = 5,
1553 MarketIfTouched = 6,
1555 LimitIfTouched = 7,
1557 TrailingStopMarket = 8,
1559 TrailingStopLimit = 9,
1561}
1562
1563#[repr(C)]
1565#[derive(
1566 Copy,
1567 Clone,
1568 Debug,
1569 Display,
1570 Hash,
1571 PartialEq,
1572 Eq,
1573 PartialOrd,
1574 Ord,
1575 AsRefStr,
1576 FromRepr,
1577 EnumIter,
1578 EnumString,
1579)]
1580#[strum(ascii_case_insensitive)]
1581#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1582#[cfg_attr(
1583 feature = "python",
1584 pyo3::pyclass(
1585 frozen,
1586 eq,
1587 eq_int,
1588 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1589 from_py_object,
1590 rename_all = "SCREAMING_SNAKE_CASE",
1591 )
1592)]
1593#[cfg_attr(
1594 feature = "python",
1595 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1596)]
1597pub enum PositionAdjustmentType {
1598 Commission = 1,
1600 Funding = 2,
1602}
1603
1604impl FromU8 for PositionAdjustmentType {
1605 fn from_u8(value: u8) -> Option<Self> {
1606 match value {
1607 1 => Some(Self::Commission),
1608 2 => Some(Self::Funding),
1609 _ => None,
1610 }
1611 }
1612}
1613
1614#[repr(C)]
1616#[derive(
1617 Copy,
1618 Clone,
1619 Debug,
1620 Default,
1621 Display,
1622 Hash,
1623 PartialEq,
1624 Eq,
1625 PartialOrd,
1626 Ord,
1627 AsRefStr,
1628 FromRepr,
1629 EnumIter,
1630 EnumString,
1631)]
1632#[strum(ascii_case_insensitive)]
1633#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1634#[cfg_attr(
1635 feature = "python",
1636 pyo3::pyclass(
1637 frozen,
1638 eq,
1639 eq_int,
1640 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1641 from_py_object,
1642 rename_all = "SCREAMING_SNAKE_CASE",
1643 )
1644)]
1645#[cfg_attr(
1646 feature = "python",
1647 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1648)]
1649pub enum PositionSide {
1650 #[default]
1652 NoPositionSide = 0,
1653 Flat = 1,
1655 Long = 2,
1657 Short = 3,
1659}
1660
1661impl PositionSide {
1662 #[must_use]
1668 pub fn as_specified(&self) -> PositionSideSpecified {
1669 match &self {
1670 Self::Long => PositionSideSpecified::Long,
1671 Self::Short => PositionSideSpecified::Short,
1672 Self::Flat => PositionSideSpecified::Flat,
1673 Self::NoPositionSide => {
1674 panic!("Position invariant failed: side must be `Long`, `Short`, or `Flat`")
1675 }
1676 }
1677 }
1678}
1679
1680#[repr(C)]
1682#[derive(
1683 Copy,
1684 Clone,
1685 Debug,
1686 Display,
1687 Hash,
1688 PartialEq,
1689 Eq,
1690 PartialOrd,
1691 Ord,
1692 AsRefStr,
1693 FromRepr,
1694 EnumIter,
1695 EnumString,
1696)]
1697#[strum(ascii_case_insensitive)]
1698#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1699#[cfg_attr(
1700 feature = "python",
1701 pyo3::pyclass(
1702 frozen,
1703 eq,
1704 eq_int,
1705 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1706 from_py_object,
1707 rename_all = "SCREAMING_SNAKE_CASE",
1708 )
1709)]
1710#[cfg_attr(
1711 feature = "python",
1712 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1713)]
1714pub enum PositionSideSpecified {
1715 Flat = 1,
1717 Long = 2,
1719 Short = 3,
1721}
1722
1723impl PositionSideSpecified {
1724 #[must_use]
1726 pub fn as_position_side(&self) -> PositionSide {
1727 match &self {
1728 Self::Long => PositionSide::Long,
1729 Self::Short => PositionSide::Short,
1730 Self::Flat => PositionSide::Flat,
1731 }
1732 }
1733}
1734
1735#[repr(C)]
1737#[derive(
1738 Copy,
1739 Clone,
1740 Debug,
1741 Display,
1742 Hash,
1743 PartialEq,
1744 Eq,
1745 PartialOrd,
1746 Ord,
1747 AsRefStr,
1748 FromRepr,
1749 EnumIter,
1750 EnumString,
1751)]
1752#[strum(ascii_case_insensitive)]
1753#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1754#[cfg_attr(
1755 feature = "python",
1756 pyo3::pyclass(
1757 frozen,
1758 eq,
1759 eq_int,
1760 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1761 from_py_object,
1762 rename_all = "SCREAMING_SNAKE_CASE",
1763 )
1764)]
1765#[cfg_attr(
1766 feature = "python",
1767 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1768)]
1769pub enum PriceType {
1770 Bid = 1,
1773 Ask = 2,
1776 Mid = 3,
1778 Last = 4,
1780 Mark = 5,
1783}
1784
1785#[repr(C)]
1787#[derive(
1788 Copy,
1789 Clone,
1790 Debug,
1791 Display,
1792 Hash,
1793 PartialEq,
1794 Eq,
1795 PartialOrd,
1796 Ord,
1797 AsRefStr,
1798 FromRepr,
1799 EnumIter,
1800 EnumString,
1801)]
1802#[strum(ascii_case_insensitive)]
1803#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1804#[cfg_attr(
1805 feature = "python",
1806 pyo3::pyclass(
1807 frozen,
1808 eq,
1809 eq_int,
1810 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1811 from_py_object,
1812 rename_all = "SCREAMING_SNAKE_CASE",
1813 )
1814)]
1815#[cfg_attr(
1816 feature = "python",
1817 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1818)]
1819#[allow(non_camel_case_types)]
1820pub enum RecordFlag {
1821 F_LAST = 1 << 7, F_TOB = 1 << 6, F_SNAPSHOT = 1 << 5, F_MBP = 1 << 4, RESERVED_2 = 1 << 3, RESERVED_1 = 1 << 2, }
1834
1835impl RecordFlag {
1836 #[must_use]
1838 pub fn matches(self, value: u8) -> bool {
1839 (self as u8) & value != 0
1840 }
1841}
1842
1843#[repr(C)]
1845#[derive(
1846 Copy,
1847 Clone,
1848 Debug,
1849 Display,
1850 Hash,
1851 PartialEq,
1852 Eq,
1853 PartialOrd,
1854 Ord,
1855 AsRefStr,
1856 FromRepr,
1857 EnumIter,
1858 EnumString,
1859)]
1860#[strum(ascii_case_insensitive)]
1861#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1862#[cfg_attr(
1863 feature = "python",
1864 pyo3::pyclass(
1865 frozen,
1866 eq,
1867 eq_int,
1868 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1869 from_py_object,
1870 rename_all = "SCREAMING_SNAKE_CASE",
1871 )
1872)]
1873#[cfg_attr(
1874 feature = "python",
1875 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1876)]
1877pub enum TimeInForce {
1878 Gtc = 1,
1880 Ioc = 2,
1882 Fok = 3,
1884 Gtd = 4,
1886 Day = 5,
1888 AtTheOpen = 6,
1890 AtTheClose = 7,
1892}
1893
1894#[repr(C)]
1896#[derive(
1897 Copy,
1898 Clone,
1899 Debug,
1900 Display,
1901 Hash,
1902 PartialEq,
1903 Eq,
1904 PartialOrd,
1905 Ord,
1906 AsRefStr,
1907 FromRepr,
1908 EnumIter,
1909 EnumString,
1910)]
1911#[strum(ascii_case_insensitive)]
1912#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1913#[cfg_attr(
1914 feature = "python",
1915 pyo3::pyclass(
1916 frozen,
1917 eq,
1918 eq_int,
1919 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1920 from_py_object,
1921 rename_all = "SCREAMING_SNAKE_CASE",
1922 )
1923)]
1924#[cfg_attr(
1925 feature = "python",
1926 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1927)]
1928pub enum TradingState {
1929 Active = 1,
1931 Halted = 2,
1933 Reducing = 3,
1935}
1936
1937#[repr(C)]
1939#[derive(
1940 Copy,
1941 Clone,
1942 Debug,
1943 Default,
1944 Display,
1945 Hash,
1946 PartialEq,
1947 Eq,
1948 PartialOrd,
1949 Ord,
1950 AsRefStr,
1951 FromRepr,
1952 EnumIter,
1953 EnumString,
1954)]
1955#[strum(ascii_case_insensitive)]
1956#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1957#[cfg_attr(
1958 feature = "python",
1959 pyo3::pyclass(
1960 frozen,
1961 eq,
1962 eq_int,
1963 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1964 from_py_object,
1965 rename_all = "SCREAMING_SNAKE_CASE",
1966 )
1967)]
1968#[cfg_attr(
1969 feature = "python",
1970 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1971)]
1972pub enum TrailingOffsetType {
1973 #[default]
1975 NoTrailingOffset = 0,
1976 Price = 1,
1978 BasisPoints = 2,
1980 Ticks = 3,
1982 PriceTier = 4,
1984}
1985
1986#[repr(C)]
1988#[derive(
1989 Copy,
1990 Clone,
1991 Debug,
1992 Default,
1993 Display,
1994 Hash,
1995 PartialEq,
1996 Eq,
1997 PartialOrd,
1998 Ord,
1999 AsRefStr,
2000 FromRepr,
2001 EnumIter,
2002 EnumString,
2003)]
2004#[strum(ascii_case_insensitive)]
2005#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
2006#[cfg_attr(
2007 feature = "python",
2008 pyo3::pyclass(
2009 frozen,
2010 eq,
2011 eq_int,
2012 module = "nautilus_trader.core.nautilus_pyo3.model.enums",
2013 from_py_object,
2014 rename_all = "SCREAMING_SNAKE_CASE",
2015 )
2016)]
2017#[cfg_attr(
2018 feature = "python",
2019 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
2020)]
2021pub enum TriggerType {
2022 #[default]
2024 NoTrigger = 0,
2025 Default = 1,
2027 LastPrice = 2,
2029 MarkPrice = 3,
2031 IndexPrice = 4,
2033 BidAsk = 5,
2035 DoubleLast = 6,
2037 DoubleBidAsk = 7,
2039 LastOrBidAsk = 8,
2041 MidPoint = 9,
2043}
2044
2045enum_strum_serde!(AccountType);
2046enum_strum_serde!(AggregationSource);
2047enum_strum_serde!(AggressorSide);
2048enum_strum_serde!(AssetClass);
2049enum_strum_serde!(BarAggregation);
2050enum_strum_serde!(BarIntervalType);
2051enum_strum_serde!(BookAction);
2052enum_strum_serde!(BookType);
2053enum_strum_serde!(ContingencyType);
2054enum_strum_serde!(ContinuousFutureAdjustmentType);
2055enum_strum_serde!(CurrencyType);
2056enum_strum_serde!(GreeksConvention);
2057enum_strum_serde!(InstrumentClass);
2058enum_strum_serde!(InstrumentCloseType);
2059enum_strum_serde!(LiquiditySide);
2060enum_strum_serde!(MarketStatus);
2061enum_strum_serde!(MarketStatusAction);
2062enum_strum_serde!(OmsType);
2063enum_strum_serde!(OptionKind);
2064enum_strum_serde!(OrderSide);
2065enum_strum_serde!(OrderSideSpecified);
2066enum_strum_serde!(OrderStatus);
2067enum_strum_serde!(OrderType);
2068enum_strum_serde!(PositionAdjustmentType);
2069enum_strum_serde!(PositionSide);
2070enum_strum_serde!(PositionSideSpecified);
2071enum_strum_serde!(PriceType);
2072enum_strum_serde!(RecordFlag);
2073enum_strum_serde!(TimeInForce);
2074enum_strum_serde!(TradingState);
2075enum_strum_serde!(TrailingOffsetType);
2076enum_strum_serde!(TriggerType);
2077
2078#[cfg(test)]
2079mod tests {
2080 use rstest::rstest;
2081
2082 use super::*;
2083
2084 #[rstest]
2085 #[case::no_aggressor(0, Some(AggressorSide::NoAggressor))]
2086 #[case::buyer(1, Some(AggressorSide::Buyer))]
2087 #[case::seller(2, Some(AggressorSide::Seller))]
2088 #[case::invalid(3, None)]
2089 #[case::max_u8(255, None)]
2090 fn test_aggressor_side_from_u8(#[case] value: u8, #[case] expected: Option<AggressorSide>) {
2091 assert_eq!(AggressorSide::from_u8(value), expected);
2092 }
2093
2094 #[rstest]
2095 #[case(GreeksConvention::BlackScholes, "\"BLACK_SCHOLES\"")]
2096 #[case(GreeksConvention::PriceAdjusted, "\"PRICE_ADJUSTED\"")]
2097 fn test_greeks_convention_serde_roundtrip(
2098 #[case] input: GreeksConvention,
2099 #[case] expected: &str,
2100 ) {
2101 let json = serde_json::to_string(&input).unwrap();
2102 assert_eq!(json, expected);
2103 let parsed: GreeksConvention = serde_json::from_str(expected).unwrap();
2104 assert_eq!(parsed, input);
2105 }
2106
2107 #[rstest]
2108 fn test_greeks_convention_default_is_black_scholes() {
2109 assert_eq!(GreeksConvention::default(), GreeksConvention::BlackScholes);
2110 }
2111
2112 #[rstest]
2113 #[case(ContinuousFutureAdjustmentType::BackwardSpread, false, true)]
2114 #[case(ContinuousFutureAdjustmentType::ForwardSpread, false, false)]
2115 #[case(ContinuousFutureAdjustmentType::BackwardRatio, true, true)]
2116 #[case(ContinuousFutureAdjustmentType::ForwardRatio, true, false)]
2117 fn test_continuous_future_adjustment_type_predicates(
2118 #[case] mode: ContinuousFutureAdjustmentType,
2119 #[case] expected_is_ratio: bool,
2120 #[case] expected_is_backward: bool,
2121 ) {
2122 assert_eq!(mode.is_ratio(), expected_is_ratio);
2123 assert_eq!(mode.is_backward(), expected_is_backward);
2124 }
2125
2126 #[rstest]
2127 #[case(ContinuousFutureAdjustmentType::BackwardSpread, "\"BACKWARD_SPREAD\"")]
2128 #[case(ContinuousFutureAdjustmentType::ForwardSpread, "\"FORWARD_SPREAD\"")]
2129 #[case(ContinuousFutureAdjustmentType::BackwardRatio, "\"BACKWARD_RATIO\"")]
2130 #[case(ContinuousFutureAdjustmentType::ForwardRatio, "\"FORWARD_RATIO\"")]
2131 fn test_continuous_future_adjustment_type_serde_roundtrip(
2132 #[case] input: ContinuousFutureAdjustmentType,
2133 #[case] expected: &str,
2134 ) {
2135 let json = serde_json::to_string(&input).unwrap();
2136 assert_eq!(json, expected);
2137 let parsed: ContinuousFutureAdjustmentType = serde_json::from_str(expected).unwrap();
2138 assert_eq!(parsed, input);
2139 }
2140
2141 #[rstest]
2142 fn test_continuous_future_adjustment_type_default_is_backward_spread() {
2143 assert_eq!(
2144 ContinuousFutureAdjustmentType::default(),
2145 ContinuousFutureAdjustmentType::BackwardSpread,
2146 );
2147 }
2148
2149 #[rstest]
2150 #[case(InstrumentClass::Option, true)]
2151 #[case(InstrumentClass::FuturesSpread, true)]
2152 #[case(InstrumentClass::OptionSpread, true)]
2153 #[case(InstrumentClass::Spot, false)]
2154 #[case(InstrumentClass::Swap, false)]
2155 #[case(InstrumentClass::Future, false)]
2156 #[case(InstrumentClass::Forward, false)]
2157 #[case(InstrumentClass::Cfd, false)]
2158 #[case(InstrumentClass::Bond, false)]
2159 #[case(InstrumentClass::Warrant, false)]
2160 #[case(InstrumentClass::SportsBetting, false)]
2161 #[case(InstrumentClass::BinaryOption, false)]
2162 fn test_instrument_class_allows_negative_price(
2163 #[case] class: InstrumentClass,
2164 #[case] expected: bool,
2165 ) {
2166 assert_eq!(class.allows_negative_price(), expected);
2167 }
2168
2169 #[rstest]
2170 #[case("FUT", Some(InstrumentClass::Future))]
2171 #[case("FUTURE", Some(InstrumentClass::Future))]
2172 #[case("OPT", Some(InstrumentClass::Option))]
2173 #[case("OPTION", Some(InstrumentClass::Option))]
2174 #[case("fut", None)]
2175 #[case("Fut", None)]
2176 #[case("option", None)]
2177 #[case("Option", None)]
2178 #[case("SPREAD", None)]
2179 #[case("UNKNOWN", None)]
2180 #[case("", None)]
2181 fn test_instrument_class_try_from_parent_suffix(
2182 #[case] suffix: &str,
2183 #[case] expected: Option<InstrumentClass>,
2184 ) {
2185 assert_eq!(InstrumentClass::try_from_parent_suffix(suffix), expected);
2186 }
2187
2188 #[rstest]
2189 #[case(InstrumentClass::Future, Some("FUT"))]
2190 #[case(InstrumentClass::Option, Some("OPT"))]
2191 #[case(InstrumentClass::Spot, None)]
2192 #[case(InstrumentClass::Swap, None)]
2193 #[case(InstrumentClass::FuturesSpread, None)]
2194 #[case(InstrumentClass::Forward, None)]
2195 #[case(InstrumentClass::Cfd, None)]
2196 #[case(InstrumentClass::Bond, None)]
2197 #[case(InstrumentClass::OptionSpread, None)]
2198 #[case(InstrumentClass::Warrant, None)]
2199 #[case(InstrumentClass::SportsBetting, None)]
2200 #[case(InstrumentClass::BinaryOption, None)]
2201 fn test_instrument_class_parent_suffix(
2202 #[case] class: InstrumentClass,
2203 #[case] expected: Option<&'static str>,
2204 ) {
2205 assert_eq!(class.parent_suffix(), expected);
2206 }
2207
2208 #[rstest]
2209 #[case(InstrumentClass::Future)]
2210 #[case(InstrumentClass::Option)]
2211 fn test_instrument_class_parent_suffix_roundtrip(#[case] class: InstrumentClass) {
2212 let suffix = class.parent_suffix().unwrap();
2213 assert_eq!(InstrumentClass::try_from_parent_suffix(suffix), Some(class));
2214 }
2215}