Skip to main content

nautilus_model/
enums.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Enumerations for the trading domain model.
17
18use 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
26/// Provides conversion from a `u8` value to an enum type.
27pub trait FromU8 {
28    /// Converts a `u8` value to the implementing type.
29    ///
30    /// Returns `None` if the value is not a valid representation.
31    fn from_u8(value: u8) -> Option<Self>
32    where
33        Self: Sized;
34}
35
36/// Provides conversion from a `u16` value to an enum type.
37pub trait FromU16 {
38    /// Converts a `u16` value to the implementing type.
39    ///
40    /// Returns `None` if the value is not a valid representation.
41    fn from_u16(value: u16) -> Option<Self>
42    where
43        Self: Sized;
44}
45
46/// An account type provided by a trading venue or broker.
47#[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    /// An account with unleveraged cash assets only.
82    Cash = 1,
83    /// An account which facilitates trading on margin, using account assets as collateral.
84    Margin = 2,
85    /// An account specific to betting markets.
86    Betting = 3,
87    /// An account which represents a blockchain wallet,
88    Wallet = 4,
89}
90
91/// An aggregation source for derived data.
92#[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    /// The data is externally aggregated (outside the Nautilus system boundary).
127    External = 1,
128    /// The data is internally aggregated (inside the Nautilus system boundary).
129    Internal = 2,
130}
131
132/// The side for the aggressing order of a trade in a market.
133#[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    /// There was no specific aggressor for the trade.
169    #[default]
170    NoAggressor = 0,
171    /// The BUY order was the aggressor for the trade.
172    Buyer = 1,
173    /// The SELL order was the aggressor for the trade.
174    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/// A broad financial market asset class.
189#[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    /// Foreign exchange (FOREX) assets.
225    FX = 1,
226    /// Equity / stock assets.
227    Equity = 2,
228    /// Commodity assets.
229    Commodity = 3,
230    /// Debt based assets.
231    Debt = 4,
232    /// Index based assets (baskets).
233    Index = 5,
234    /// Cryptocurrency or crypto token assets.
235    Cryptocurrency = 6,
236    /// Alternative assets.
237    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/// The aggregation method through which a bar is generated and closed.
256#[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    /// Based on a number of ticks.
291    Tick = 1,
292    /// Based on the buy/sell imbalance of ticks.
293    TickImbalance = 2,
294    /// Based on sequential buy/sell runs of ticks.
295    TickRuns = 3,
296    /// Based on traded volume.
297    Volume = 4,
298    /// Based on the buy/sell imbalance of traded volume.
299    VolumeImbalance = 5,
300    /// Based on sequential runs of buy/sell traded volume.
301    VolumeRuns = 6,
302    /// Based on the 'notional' value of the instrument.
303    Value = 7,
304    /// Based on the buy/sell imbalance of trading by notional value.
305    ValueImbalance = 8,
306    /// Based on sequential buy/sell runs of trading by notional value.
307    ValueRuns = 9,
308    /// Based on time intervals with millisecond granularity.
309    Millisecond = 10,
310    /// Based on time intervals with second granularity.
311    Second = 11,
312    /// Based on time intervals with minute granularity.
313    Minute = 12,
314    /// Based on time intervals with hour granularity.
315    Hour = 13,
316    /// Based on time intervals with day granularity.
317    Day = 14,
318    /// Based on time intervals with week granularity.
319    Week = 15,
320    /// Based on time intervals with month granularity.
321    Month = 16,
322    /// Based on time intervals with year granularity.
323    Year = 17,
324    /// Based on fixed price movements (brick size).
325    Renko = 18,
326}
327
328/// The interval type for bar aggregation.
329#[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    /// Left-open interval `(start, end]`: start is exclusive, end is inclusive (default).
365    #[default]
366    LeftOpen = 1,
367    /// Right-open interval `[start, end)`: start is inclusive, end is exclusive.
368    RightOpen = 2,
369}
370
371/// Represents the side of a bet in a betting market.
372#[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    /// A "Back" bet signifies support for a specific outcome.
407    Back = 1,
408    /// A "Lay" bet signifies opposition to a specific outcome.
409    Lay = 2,
410}
411
412impl BetSide {
413    /// Returns the opposite betting side.
414    #[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    /// Returns the equivalent [`BetSide`] for a given [`OrderSide`].
425    ///
426    /// # Panics
427    ///
428    /// Panics if `side` is [`OrderSide::NoOrderSide`].
429    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/// The type of order book action for an order book event.
439#[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    /// An order is added to the book.
474    Add = 1,
475    /// An existing order in the book is updated/modified.
476    Update = 2,
477    /// An existing order in the book is deleted/canceled.
478    Delete = 3,
479    /// The state of the order book is cleared.
480    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/// The order book type, representing the type of levels granularity and delta updating heuristics.
496#[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    /// Top-of-book best bid/ask, one level per side.
532    L1_MBP = 1,
533    /// Market by price, one order per level (aggregated).
534    L2_MBP = 2,
535    /// Market by order, multiple orders per level (full granularity).
536    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/// The order contingency type which specifies the behavior of linked orders.
551///
552/// [FIX 5.0 SP2 : ContingencyType <1385> field](https://www.onixs.biz/fix-dictionary/5.0.sp2/tagnum_1385.html).
553#[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    /// Not a contingent order.
589    #[default]
590    NoContingency = 0,
591    /// One-Cancels-the-Other.
592    Oco = 1,
593    /// One-Triggers-the-Other.
594    Oto = 2,
595    /// One-Updates-the-Other (by proportional quantity).
596    Ouo = 3,
597}
598
599/// The broad currency type.
600#[repr(C)]
601#[derive(
602    Copy,
603    Clone,
604    Debug,
605    Display,
606    Hash,
607    PartialEq,
608    Eq,
609    PartialOrd,
610    Ord,
611    AsRefStr,
612    FromRepr,
613    EnumIter,
614    EnumString,
615)]
616#[strum(ascii_case_insensitive)]
617#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
618#[cfg_attr(
619    feature = "python",
620    pyo3::pyclass(
621        frozen,
622        eq,
623        eq_int,
624        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
625        from_py_object,
626        rename_all = "SCREAMING_SNAKE_CASE",
627    )
628)]
629#[cfg_attr(
630    feature = "python",
631    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
632)]
633pub enum CurrencyType {
634    /// A type of cryptocurrency or crypto token.
635    Crypto = 1,
636    /// A type of currency issued by governments which is not backed by a commodity.
637    Fiat = 2,
638    /// A type of currency that is based on the value of an underlying commodity.
639    CommodityBacked = 3,
640}
641
642/// The instrument class.
643#[repr(C)]
644#[derive(
645    Copy,
646    Clone,
647    Debug,
648    Display,
649    Hash,
650    PartialEq,
651    Eq,
652    PartialOrd,
653    Ord,
654    AsRefStr,
655    FromRepr,
656    EnumIter,
657    EnumString,
658)]
659#[strum(ascii_case_insensitive)]
660#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
661#[cfg_attr(
662    feature = "python",
663    pyo3::pyclass(
664        frozen,
665        eq,
666        eq_int,
667        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
668        from_py_object,
669        rename_all = "SCREAMING_SNAKE_CASE",
670    )
671)]
672#[cfg_attr(
673    feature = "python",
674    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
675)]
676pub enum InstrumentClass {
677    /// A spot market instrument class. The current market price of an instrument that is bought or sold for immediate delivery and payment.
678    Spot = 1,
679    /// A swap instrument class. A derivative contract through which two parties exchange the cash flows or liabilities from two different financial instruments.
680    Swap = 2,
681    /// A futures contract instrument class. A legal agreement to buy or sell an asset at a predetermined price at a specified time in the future.
682    Future = 3,
683    /// A futures spread instrument class. A strategy involving the use of futures contracts to take advantage of price differentials between different contract months, underlying assets, or marketplaces.
684    FuturesSpread = 4,
685    /// A forward derivative instrument class. A customized contract between two parties to buy or sell an asset at a specified price on a future date.
686    Forward = 5,
687    /// A contract-for-difference (CFD) instrument class. A contract between an investor and a CFD broker to exchange the difference in the value of a financial product between the time the contract opens and closes.
688    Cfd = 6,
689    /// A bond instrument class. A type of debt investment where an investor loans money to an entity (typically corporate or governmental) which borrows the funds for a defined period of time at a variable or fixed interest rate.
690    Bond = 7,
691    /// An option contract instrument class. A type of derivative that gives the holder the right, but not the obligation, to buy or sell an underlying asset at a predetermined price before or at a certain future date.
692    Option = 8,
693    /// An option spread instrument class. A strategy involving the purchase and/or sale of multiple option contracts on the same underlying asset with different strike prices or expiration dates to hedge risk or speculate on price movements.
694    OptionSpread = 9,
695    /// A warrant instrument class. A derivative that gives the holder the right, but not the obligation, to buy or sell a security—most commonly an equity—at a certain price before expiration.
696    Warrant = 10,
697    /// A sports betting instrument class. A financialized derivative that allows wagering on the outcome of sports events using structured contracts or prediction markets.
698    SportsBetting = 11,
699    /// A binary option instrument class. A type of derivative where the payoff is either a fixed monetary amount or nothing, depending on whether the price of an underlying asset is above or below a predetermined level at expiration.
700    BinaryOption = 12,
701}
702
703impl InstrumentClass {
704    /// Returns whether this instrument class has an expiration.
705    #[must_use]
706    pub const fn has_expiration(&self) -> bool {
707        matches!(
708            self,
709            Self::Future | Self::FuturesSpread | Self::Option | Self::OptionSpread
710        )
711    }
712
713    /// Returns whether this instrument class allows negative prices.
714    #[must_use]
715    pub const fn allows_negative_price(&self) -> bool {
716        matches!(
717            self,
718            Self::Option | Self::FuturesSpread | Self::OptionSpread
719        )
720    }
721}
722
723/// The type of event for an instrument close.
724#[repr(C)]
725#[derive(
726    Copy,
727    Clone,
728    Debug,
729    Display,
730    Hash,
731    PartialEq,
732    Eq,
733    PartialOrd,
734    Ord,
735    AsRefStr,
736    FromRepr,
737    EnumIter,
738    EnumString,
739)]
740#[strum(ascii_case_insensitive)]
741#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
742#[cfg_attr(
743    feature = "python",
744    pyo3::pyclass(
745        frozen,
746        eq,
747        eq_int,
748        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
749        from_py_object,
750        rename_all = "SCREAMING_SNAKE_CASE",
751    )
752)]
753#[cfg_attr(
754    feature = "python",
755    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
756)]
757pub enum InstrumentCloseType {
758    /// When the market session ended.
759    EndOfSession = 1,
760    /// When the instrument expiration was reached.
761    ContractExpired = 2,
762}
763
764/// Convert the given `value` to an [`InstrumentCloseType`].
765impl FromU8 for InstrumentCloseType {
766    fn from_u8(value: u8) -> Option<Self> {
767        match value {
768            1 => Some(Self::EndOfSession),
769            2 => Some(Self::ContractExpired),
770            _ => None,
771        }
772    }
773}
774
775/// The liquidity side for a trade.
776#[repr(C)]
777#[derive(
778    Copy,
779    Clone,
780    Debug,
781    Display,
782    Hash,
783    PartialEq,
784    Eq,
785    PartialOrd,
786    Ord,
787    AsRefStr,
788    FromRepr,
789    EnumIter,
790    EnumString,
791)]
792#[strum(ascii_case_insensitive)]
793#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
794#[cfg_attr(
795    feature = "python",
796    pyo3::pyclass(
797        frozen,
798        eq,
799        eq_int,
800        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
801        from_py_object,
802        rename_all = "SCREAMING_SNAKE_CASE",
803    )
804)]
805#[cfg_attr(
806    feature = "python",
807    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
808)]
809pub enum LiquiditySide {
810    /// No liquidity side specified.
811    NoLiquiditySide = 0,
812    /// The order passively provided liquidity to the market to complete the trade (made a market).
813    Maker = 1,
814    /// The order aggressively took liquidity from the market to complete the trade.
815    Taker = 2,
816}
817
818/// The status of an individual market on a trading venue.
819#[repr(C)]
820#[derive(
821    Copy,
822    Clone,
823    Debug,
824    Display,
825    Hash,
826    PartialEq,
827    Eq,
828    PartialOrd,
829    Ord,
830    AsRefStr,
831    FromRepr,
832    EnumIter,
833    EnumString,
834)]
835#[strum(ascii_case_insensitive)]
836#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
837#[cfg_attr(
838    feature = "python",
839    pyo3::pyclass(
840        frozen,
841        eq,
842        eq_int,
843        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
844        from_py_object,
845        rename_all = "SCREAMING_SNAKE_CASE",
846    )
847)]
848#[cfg_attr(
849    feature = "python",
850    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
851)]
852pub enum MarketStatus {
853    /// The instrument is trading.
854    Open = 1,
855    /// The instrument is in a pre-open period.
856    Closed = 2,
857    /// Trading in the instrument has been paused.
858    Paused = 3,
859    /// Trading in the instrument has been halted.
860    // Halted = 4,  # TODO: Unfortunately can't use this yet due to Cython (C enum namespacing)
861    /// Trading in the instrument has been suspended.
862    Suspended = 5,
863    /// Trading in the instrument is not available.
864    NotAvailable = 6,
865}
866
867/// An action affecting the status of an individual market on a trading venue.
868#[repr(C)]
869#[derive(
870    Copy,
871    Clone,
872    Debug,
873    Display,
874    Hash,
875    PartialEq,
876    Eq,
877    PartialOrd,
878    Ord,
879    AsRefStr,
880    FromRepr,
881    EnumIter,
882    EnumString,
883)]
884#[strum(ascii_case_insensitive)]
885#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
886#[cfg_attr(
887    feature = "python",
888    pyo3::pyclass(
889        frozen,
890        eq,
891        eq_int,
892        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
893        from_py_object,
894        rename_all = "SCREAMING_SNAKE_CASE",
895    )
896)]
897#[cfg_attr(
898    feature = "python",
899    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
900)]
901pub enum MarketStatusAction {
902    /// No change.
903    None = 0,
904    /// The instrument is in a pre-open period.
905    PreOpen = 1,
906    /// The instrument is in a pre-cross period.
907    PreCross = 2,
908    /// The instrument is quoting but not trading.
909    Quoting = 3,
910    /// The instrument is in a cross/auction.
911    Cross = 4,
912    /// The instrument is being opened through a trading rotation.
913    Rotation = 5,
914    /// A new price indication is available for the instrument.
915    NewPriceIndication = 6,
916    /// The instrument is trading.
917    Trading = 7,
918    /// Trading in the instrument has been halted.
919    Halt = 8,
920    /// Trading in the instrument has been paused.
921    Pause = 9,
922    /// Trading in the instrument has been suspended.
923    Suspend = 10,
924    /// The instrument is in a pre-close period.
925    PreClose = 11,
926    /// Trading in the instrument has closed.
927    Close = 12,
928    /// The instrument is in a post-close period.
929    PostClose = 13,
930    /// A change in short-selling restrictions.
931    ShortSellRestrictionChange = 14,
932    /// The instrument is not available for trading, either trading has closed or been halted.
933    NotAvailableForTrading = 15,
934}
935
936/// Convert the given `value` to an [`OrderSide`].
937impl FromU16 for MarketStatusAction {
938    fn from_u16(value: u16) -> Option<Self> {
939        match value {
940            0 => Some(Self::None),
941            1 => Some(Self::PreOpen),
942            2 => Some(Self::PreCross),
943            3 => Some(Self::Quoting),
944            4 => Some(Self::Cross),
945            5 => Some(Self::Rotation),
946            6 => Some(Self::NewPriceIndication),
947            7 => Some(Self::Trading),
948            8 => Some(Self::Halt),
949            9 => Some(Self::Pause),
950            10 => Some(Self::Suspend),
951            11 => Some(Self::PreClose),
952            12 => Some(Self::Close),
953            13 => Some(Self::PostClose),
954            14 => Some(Self::ShortSellRestrictionChange),
955            15 => Some(Self::NotAvailableForTrading),
956            _ => None,
957        }
958    }
959}
960
961/// The order management system (OMS) type for a trading venue or trading strategy.
962#[repr(C)]
963#[derive(
964    Copy,
965    Clone,
966    Debug,
967    Default,
968    Display,
969    Hash,
970    PartialEq,
971    Eq,
972    PartialOrd,
973    Ord,
974    AsRefStr,
975    FromRepr,
976    EnumIter,
977    EnumString,
978)]
979#[strum(ascii_case_insensitive)]
980#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
981#[cfg_attr(
982    feature = "python",
983    pyo3::pyclass(
984        frozen,
985        eq,
986        eq_int,
987        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
988        from_py_object,
989        rename_all = "SCREAMING_SNAKE_CASE",
990    )
991)]
992#[cfg_attr(
993    feature = "python",
994    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
995)]
996pub enum OmsType {
997    /// There is no specific type of order management specified (will defer to the venue OMS).
998    #[default]
999    Unspecified = 0,
1000    /// The netting type where there is one position per instrument.
1001    Netting = 1,
1002    /// The hedging type where there can be multiple positions per instrument.
1003    /// This can be in LONG/SHORT directions, by position/ticket ID, or tracked virtually by
1004    /// Nautilus.
1005    Hedging = 2,
1006}
1007
1008/// The kind of option contract.
1009#[repr(C)]
1010#[derive(
1011    Copy,
1012    Clone,
1013    Debug,
1014    Display,
1015    Hash,
1016    PartialEq,
1017    Eq,
1018    PartialOrd,
1019    Ord,
1020    AsRefStr,
1021    FromRepr,
1022    EnumIter,
1023    EnumString,
1024)]
1025#[strum(ascii_case_insensitive)]
1026#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1027#[cfg_attr(
1028    feature = "python",
1029    pyo3::pyclass(
1030        frozen,
1031        eq,
1032        eq_int,
1033        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1034        from_py_object,
1035        rename_all = "SCREAMING_SNAKE_CASE",
1036    )
1037)]
1038#[cfg_attr(
1039    feature = "python",
1040    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1041)]
1042pub enum OptionKind {
1043    /// A Call option gives the holder the right, but not the obligation, to buy an underlying asset at a specified strike price within a specified period of time.
1044    Call = 1,
1045    /// A Put option gives the holder the right, but not the obligation, to sell an underlying asset at a specified strike price within a specified period of time.
1046    Put = 2,
1047}
1048
1049/// The numeraire convention for option greeks published by a venue.
1050///
1051/// Crypto option venues commonly publish two parallel greek sets for the same
1052/// instrument: Black-Scholes greeks in USD, and price-adjusted greeks denominated
1053/// in the underlying/coin units. Deribit and OKX both expose the distinction;
1054/// see the OKX reference for the canonical definition:
1055/// <https://www.okx.com/docs-v5/en/#public-data-websocket-option-market-data>.
1056///
1057/// This is orthogonal to the percent-greeks transformation in the internal
1058/// [`GreeksCalculator`](../../../nautilus_common/greeks/struct.GreeksCalculator.html),
1059/// which rescales the delta/gamma input step rather than the numeraire.
1060#[repr(C)]
1061#[derive(
1062    Copy,
1063    Clone,
1064    Debug,
1065    Default,
1066    Display,
1067    Hash,
1068    PartialEq,
1069    Eq,
1070    PartialOrd,
1071    Ord,
1072    AsRefStr,
1073    FromRepr,
1074    EnumIter,
1075    EnumString,
1076)]
1077#[strum(ascii_case_insensitive)]
1078#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1079#[cfg_attr(
1080    feature = "python",
1081    pyo3::pyclass(
1082        frozen,
1083        eq,
1084        eq_int,
1085        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1086        from_py_object,
1087        rename_all = "SCREAMING_SNAKE_CASE",
1088    )
1089)]
1090#[cfg_attr(
1091    feature = "python",
1092    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1093)]
1094pub enum GreeksConvention {
1095    /// Black-Scholes greeks in USD.
1096    #[default]
1097    BlackScholes = 1,
1098    /// Price-adjusted greeks in the underlying/coin units.
1099    PriceAdjusted = 2,
1100}
1101
1102/// Defines when OTO (One-Triggers-Other) child orders are released.
1103#[repr(C)]
1104#[derive(
1105    Copy,
1106    Clone,
1107    Debug,
1108    Default,
1109    Display,
1110    Hash,
1111    PartialEq,
1112    Eq,
1113    PartialOrd,
1114    Ord,
1115    AsRefStr,
1116    FromRepr,
1117    EnumIter,
1118    EnumString,
1119)]
1120#[strum(ascii_case_insensitive)]
1121#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1122#[cfg_attr(
1123    feature = "python",
1124    pyo3::pyclass(
1125        frozen,
1126        eq,
1127        eq_int,
1128        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1129        from_py_object,
1130        rename_all = "SCREAMING_SNAKE_CASE",
1131    )
1132)]
1133#[cfg_attr(
1134    feature = "python",
1135    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1136)]
1137pub enum OtoTriggerMode {
1138    /// Release child order(s) pro-rata to each partial fill (default).
1139    #[default]
1140    Partial = 0,
1141    /// Release child order(s) only once the parent is fully filled.
1142    Full = 1,
1143}
1144
1145/// The order side for a specific order, or action related to orders.
1146#[repr(C)]
1147#[derive(
1148    Copy,
1149    Clone,
1150    Debug,
1151    Default,
1152    Display,
1153    Hash,
1154    PartialEq,
1155    Eq,
1156    PartialOrd,
1157    Ord,
1158    AsRefStr,
1159    FromRepr,
1160    EnumIter,
1161    EnumString,
1162)]
1163#[strum(ascii_case_insensitive)]
1164#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1165#[cfg_attr(
1166    feature = "python",
1167    pyo3::pyclass(
1168        frozen,
1169        eq,
1170        eq_int,
1171        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1172        from_py_object,
1173        rename_all = "SCREAMING_SNAKE_CASE",
1174    )
1175)]
1176#[cfg_attr(
1177    feature = "python",
1178    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1179)]
1180pub enum OrderSide {
1181    /// No order side is specified.
1182    #[default]
1183    NoOrderSide = 0,
1184    /// The order is a BUY.
1185    Buy = 1,
1186    /// The order is a SELL.
1187    Sell = 2,
1188}
1189
1190impl OrderSide {
1191    /// Returns the specified [`OrderSideSpecified`] (BUY or SELL) for this side.
1192    ///
1193    /// # Panics
1194    ///
1195    /// Panics if `self` is [`OrderSide::NoOrderSide`].
1196    #[must_use]
1197    pub fn as_specified(&self) -> OrderSideSpecified {
1198        match &self {
1199            Self::Buy => OrderSideSpecified::Buy,
1200            Self::Sell => OrderSideSpecified::Sell,
1201            Self::NoOrderSide => panic!("Order invariant failed: side must be `Buy` or `Sell`"),
1202        }
1203    }
1204}
1205
1206/// Convert the given `value` to an [`OrderSide`].
1207impl FromU8 for OrderSide {
1208    fn from_u8(value: u8) -> Option<Self> {
1209        match value {
1210            0 => Some(Self::NoOrderSide),
1211            1 => Some(Self::Buy),
1212            2 => Some(Self::Sell),
1213            _ => None,
1214        }
1215    }
1216}
1217
1218/// The specified order side (BUY or SELL).
1219#[repr(C)]
1220#[derive(
1221    Copy,
1222    Clone,
1223    Debug,
1224    Display,
1225    Hash,
1226    PartialEq,
1227    Eq,
1228    PartialOrd,
1229    Ord,
1230    AsRefStr,
1231    FromRepr,
1232    EnumIter,
1233    EnumString,
1234)]
1235#[strum(ascii_case_insensitive)]
1236#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1237pub enum OrderSideSpecified {
1238    /// The order is a BUY.
1239    Buy = 1,
1240    /// The order is a SELL.
1241    Sell = 2,
1242}
1243
1244impl OrderSideSpecified {
1245    /// Returns the opposite order side.
1246    #[must_use]
1247    pub fn opposite(&self) -> Self {
1248        match &self {
1249            Self::Buy => Self::Sell,
1250            Self::Sell => Self::Buy,
1251        }
1252    }
1253
1254    /// Converts this specified side into an [`OrderSide`].
1255    #[must_use]
1256    pub fn as_order_side(&self) -> OrderSide {
1257        match &self {
1258            Self::Buy => OrderSide::Buy,
1259            Self::Sell => OrderSide::Sell,
1260        }
1261    }
1262}
1263
1264/// The status for a specific order.
1265///
1266/// An order is considered _open_ for the following status:
1267///  - `ACCEPTED`
1268///  - `TRIGGERED`
1269///  - `PENDING_UPDATE`
1270///  - `PENDING_CANCEL`
1271///  - `PARTIALLY_FILLED`
1272///
1273/// An order is considered _in-flight_ for the following status:
1274///  - `SUBMITTED`
1275///  - `PENDING_UPDATE`
1276///  - `PENDING_CANCEL`
1277///
1278/// An order is considered _closed_ for the following status:
1279///  - `DENIED`
1280///  - `REJECTED`
1281///  - `CANCELED`
1282///  - `EXPIRED`
1283///  - `FILLED`
1284#[repr(C)]
1285#[derive(
1286    Copy,
1287    Clone,
1288    Debug,
1289    Display,
1290    Hash,
1291    PartialEq,
1292    Eq,
1293    PartialOrd,
1294    Ord,
1295    AsRefStr,
1296    FromRepr,
1297    EnumIter,
1298    EnumString,
1299)]
1300#[strum(ascii_case_insensitive)]
1301#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1302#[cfg_attr(
1303    feature = "python",
1304    pyo3::pyclass(
1305        frozen,
1306        eq,
1307        eq_int,
1308        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1309        from_py_object,
1310        rename_all = "SCREAMING_SNAKE_CASE",
1311    )
1312)]
1313#[cfg_attr(
1314    feature = "python",
1315    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1316)]
1317pub enum OrderStatus {
1318    /// The order is initialized (instantiated) within the Nautilus system.
1319    Initialized = 1,
1320    /// The order was denied by the Nautilus system, either for being invalid, unprocessable or exceeding a risk limit.
1321    Denied = 2,
1322    /// The order became emulated by the Nautilus system in the `OrderEmulator` component.
1323    Emulated = 3,
1324    /// The order was released by the Nautilus system from the `OrderEmulator` component.
1325    Released = 4,
1326    /// The order was submitted by the Nautilus system to the external service or trading venue (awaiting acknowledgement).
1327    Submitted = 5,
1328    /// The order was acknowledged by the trading venue as being received and valid (may now be working).
1329    Accepted = 6,
1330    /// The order was rejected by the trading venue.
1331    Rejected = 7,
1332    /// The order was canceled (closed/done).
1333    Canceled = 8,
1334    /// The order reached a GTD expiration (closed/done).
1335    Expired = 9,
1336    /// The order STOP price was triggered on a trading venue.
1337    Triggered = 10,
1338    /// The order is currently pending a request to modify on a trading venue.
1339    PendingUpdate = 11,
1340    /// The order is currently pending a request to cancel on a trading venue.
1341    PendingCancel = 12,
1342    /// The order has been partially filled on a trading venue.
1343    PartiallyFilled = 13,
1344    /// The order has been completely filled on a trading venue (closed/done).
1345    Filled = 14,
1346}
1347
1348impl OrderStatus {
1349    /// Returns whether the order status represents an open/working order.
1350    #[must_use]
1351    pub const fn is_open(self) -> bool {
1352        matches!(
1353            self,
1354            Self::Submitted
1355                | Self::Accepted
1356                | Self::Triggered
1357                | Self::PendingUpdate
1358                | Self::PendingCancel
1359                | Self::PartiallyFilled
1360        )
1361    }
1362
1363    /// Returns whether the order status represents a terminal (closed) state.
1364    #[must_use]
1365    pub const fn is_closed(self) -> bool {
1366        matches!(
1367            self,
1368            Self::Denied | Self::Rejected | Self::Canceled | Self::Expired | Self::Filled
1369        )
1370    }
1371
1372    /// Returns whether the order can be cancelled from this status.
1373    #[must_use]
1374    pub const fn is_cancellable(self) -> bool {
1375        matches!(
1376            self,
1377            Self::Accepted | Self::Triggered | Self::PendingUpdate | Self::PartiallyFilled
1378        )
1379    }
1380
1381    /// Returns a cached `AHashSet` of order statuses safe for cancellation queries.
1382    ///
1383    /// These are statuses where an order is working on the venue but not already
1384    /// in the process of being cancelled or updated. Including `PENDING_CANCEL`
1385    /// in cancellation filters can cause duplicate cancel attempts or incorrect open order counts.
1386    ///
1387    /// Returns:
1388    /// - `ACCEPTED`: Order is working on the venue.
1389    /// - `TRIGGERED`: Stop order has been triggered.
1390    /// - `PENDING_UPDATE`: Order being updated.
1391    /// - `PARTIALLY_FILLED`: Order is partially filled but still working.
1392    ///
1393    /// Excludes:
1394    /// - `PENDING_CANCEL`: Already being cancelled.
1395    #[must_use]
1396    pub fn cancellable_statuses_set() -> &'static AHashSet<Self> {
1397        static CANCELLABLE_SET: OnceLock<AHashSet<OrderStatus>> = OnceLock::new();
1398        CANCELLABLE_SET.get_or_init(|| {
1399            AHashSet::from_iter([
1400                Self::Accepted,
1401                Self::Triggered,
1402                Self::PendingUpdate,
1403                Self::PartiallyFilled,
1404            ])
1405        })
1406    }
1407}
1408
1409/// The type of order.
1410#[repr(C)]
1411#[derive(
1412    Copy,
1413    Clone,
1414    Debug,
1415    Display,
1416    Hash,
1417    PartialEq,
1418    Eq,
1419    PartialOrd,
1420    Ord,
1421    AsRefStr,
1422    FromRepr,
1423    EnumIter,
1424    EnumString,
1425)]
1426#[strum(ascii_case_insensitive)]
1427#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1428#[cfg_attr(
1429    feature = "python",
1430    pyo3::pyclass(
1431        frozen,
1432        eq,
1433        eq_int,
1434        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1435        from_py_object,
1436        rename_all = "SCREAMING_SNAKE_CASE",
1437    )
1438)]
1439#[cfg_attr(
1440    feature = "python",
1441    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1442)]
1443pub enum OrderType {
1444    /// A market order to buy or sell at the best available price in the current market.
1445    Market = 1,
1446    /// A limit order to buy or sell at a specific price or better.
1447    Limit = 2,
1448    /// A stop market order to buy or sell once the price reaches the specified stop/trigger price. When the stop price is reached, the order effectively becomes a market order.
1449    StopMarket = 3,
1450    /// A stop limit order to buy or sell which combines the features of a stop order and a limit order. Once the stop/trigger price is reached, a stop-limit order effectively becomes a limit order.
1451    StopLimit = 4,
1452    /// A market-to-limit order is a market order that is to be executed as a limit order at the current best market price after reaching the market.
1453    MarketToLimit = 5,
1454    /// A market-if-touched order effectively becomes a market order when the specified trigger price is reached.
1455    MarketIfTouched = 6,
1456    /// A limit-if-touched order effectively becomes a limit order when the specified trigger price is reached.
1457    LimitIfTouched = 7,
1458    /// A trailing stop market order sets the stop/trigger price at a fixed "trailing offset" amount from the market.
1459    TrailingStopMarket = 8,
1460    /// A trailing stop limit order combines the features of a trailing stop order with those of a limit order.
1461    TrailingStopLimit = 9,
1462}
1463
1464/// The type of position adjustment.
1465#[repr(C)]
1466#[derive(
1467    Copy,
1468    Clone,
1469    Debug,
1470    Display,
1471    Hash,
1472    PartialEq,
1473    Eq,
1474    PartialOrd,
1475    Ord,
1476    AsRefStr,
1477    FromRepr,
1478    EnumIter,
1479    EnumString,
1480)]
1481#[strum(ascii_case_insensitive)]
1482#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1483#[cfg_attr(
1484    feature = "python",
1485    pyo3::pyclass(
1486        frozen,
1487        eq,
1488        eq_int,
1489        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1490        from_py_object,
1491        rename_all = "SCREAMING_SNAKE_CASE",
1492    )
1493)]
1494#[cfg_attr(
1495    feature = "python",
1496    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1497)]
1498pub enum PositionAdjustmentType {
1499    /// Commission adjustment affecting position quantity.
1500    Commission = 1,
1501    /// Funding payment affecting position realized PnL.
1502    Funding = 2,
1503}
1504
1505impl FromU8 for PositionAdjustmentType {
1506    fn from_u8(value: u8) -> Option<Self> {
1507        match value {
1508            1 => Some(Self::Commission),
1509            2 => Some(Self::Funding),
1510            _ => None,
1511        }
1512    }
1513}
1514
1515/// The market side for a specific position, or action related to positions.
1516#[repr(C)]
1517#[derive(
1518    Copy,
1519    Clone,
1520    Debug,
1521    Default,
1522    Display,
1523    Hash,
1524    PartialEq,
1525    Eq,
1526    PartialOrd,
1527    Ord,
1528    AsRefStr,
1529    FromRepr,
1530    EnumIter,
1531    EnumString,
1532)]
1533#[strum(ascii_case_insensitive)]
1534#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1535#[cfg_attr(
1536    feature = "python",
1537    pyo3::pyclass(
1538        frozen,
1539        eq,
1540        eq_int,
1541        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1542        from_py_object,
1543        rename_all = "SCREAMING_SNAKE_CASE",
1544    )
1545)]
1546#[cfg_attr(
1547    feature = "python",
1548    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1549)]
1550pub enum PositionSide {
1551    /// No position side is specified (only valid in the context of a filter for actions involving positions).
1552    #[default]
1553    NoPositionSide = 0,
1554    /// A neural/flat position, where no position is currently held in the market.
1555    Flat = 1,
1556    /// A long position in the market, typically acquired through one or many BUY orders.
1557    Long = 2,
1558    /// A short position in the market, typically acquired through one or many SELL orders.
1559    Short = 3,
1560}
1561
1562impl PositionSide {
1563    /// Returns the specified [`PositionSideSpecified`] (`Long`, `Short`, or `Flat`) for this side.
1564    ///
1565    /// # Panics
1566    ///
1567    /// Panics if `self` is [`PositionSide::NoPositionSide`].
1568    #[must_use]
1569    pub fn as_specified(&self) -> PositionSideSpecified {
1570        match &self {
1571            Self::Long => PositionSideSpecified::Long,
1572            Self::Short => PositionSideSpecified::Short,
1573            Self::Flat => PositionSideSpecified::Flat,
1574            Self::NoPositionSide => {
1575                panic!("Position invariant failed: side must be `Long`, `Short`, or `Flat`")
1576            }
1577        }
1578    }
1579}
1580
1581/// The market side for a specific position, or action related to positions.
1582#[repr(C)]
1583#[derive(
1584    Copy,
1585    Clone,
1586    Debug,
1587    Display,
1588    Hash,
1589    PartialEq,
1590    Eq,
1591    PartialOrd,
1592    Ord,
1593    AsRefStr,
1594    FromRepr,
1595    EnumIter,
1596    EnumString,
1597)]
1598#[strum(ascii_case_insensitive)]
1599#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1600#[cfg_attr(
1601    feature = "python",
1602    pyo3::pyclass(
1603        frozen,
1604        eq,
1605        eq_int,
1606        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1607        from_py_object,
1608        rename_all = "SCREAMING_SNAKE_CASE",
1609    )
1610)]
1611#[cfg_attr(
1612    feature = "python",
1613    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1614)]
1615pub enum PositionSideSpecified {
1616    /// A neural/flat position, where no position is currently held in the market.
1617    Flat = 1,
1618    /// A long position in the market, typically acquired through one or many BUY orders.
1619    Long = 2,
1620    /// A short position in the market, typically acquired through one or many SELL orders.
1621    Short = 3,
1622}
1623
1624impl PositionSideSpecified {
1625    /// Converts this specified side into a [`PositionSide`].
1626    #[must_use]
1627    pub fn as_position_side(&self) -> PositionSide {
1628        match &self {
1629            Self::Long => PositionSide::Long,
1630            Self::Short => PositionSide::Short,
1631            Self::Flat => PositionSide::Flat,
1632        }
1633    }
1634}
1635
1636/// The type of price for an instrument in a market.
1637#[repr(C)]
1638#[derive(
1639    Copy,
1640    Clone,
1641    Debug,
1642    Display,
1643    Hash,
1644    PartialEq,
1645    Eq,
1646    PartialOrd,
1647    Ord,
1648    AsRefStr,
1649    FromRepr,
1650    EnumIter,
1651    EnumString,
1652)]
1653#[strum(ascii_case_insensitive)]
1654#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1655#[cfg_attr(
1656    feature = "python",
1657    pyo3::pyclass(
1658        frozen,
1659        eq,
1660        eq_int,
1661        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1662        from_py_object,
1663        rename_all = "SCREAMING_SNAKE_CASE",
1664    )
1665)]
1666#[cfg_attr(
1667    feature = "python",
1668    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1669)]
1670pub enum PriceType {
1671    /// The best quoted price at which buyers are willing to buy a quantity of an instrument.
1672    /// Often considered the best bid in the order book.
1673    Bid = 1,
1674    /// The best quoted price at which sellers are willing to sell a quantity of an instrument.
1675    /// Often considered the best ask in the order book.
1676    Ask = 2,
1677    /// The arithmetic midpoint between the best bid and ask quotes.
1678    Mid = 3,
1679    /// The price at which the last trade of an instrument was executed.
1680    Last = 4,
1681    /// A reference price reflecting an instrument's fair value, often used for portfolio
1682    /// calculations and risk management.
1683    Mark = 5,
1684}
1685
1686/// A record flag bit field, indicating event end and data information.
1687#[repr(C)]
1688#[derive(
1689    Copy,
1690    Clone,
1691    Debug,
1692    Display,
1693    Hash,
1694    PartialEq,
1695    Eq,
1696    PartialOrd,
1697    Ord,
1698    AsRefStr,
1699    FromRepr,
1700    EnumIter,
1701    EnumString,
1702)]
1703#[strum(ascii_case_insensitive)]
1704#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1705#[cfg_attr(
1706    feature = "python",
1707    pyo3::pyclass(
1708        frozen,
1709        eq,
1710        eq_int,
1711        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1712        from_py_object,
1713        rename_all = "SCREAMING_SNAKE_CASE",
1714    )
1715)]
1716#[cfg_attr(
1717    feature = "python",
1718    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1719)]
1720#[allow(non_camel_case_types)]
1721pub enum RecordFlag {
1722    /// Last message in the book event or packet from the venue for a given `instrument_id`.
1723    F_LAST = 1 << 7, // 128
1724    /// Top-of-book message, not an individual order.
1725    F_TOB = 1 << 6, // 64
1726    /// Message sourced from a replay, such as a snapshot server.
1727    F_SNAPSHOT = 1 << 5, // 32
1728    /// Aggregated price level message, not an individual order.
1729    F_MBP = 1 << 4, // 16
1730    /// Reserved for future use.
1731    RESERVED_2 = 1 << 3, // 8
1732    /// Reserved for future use.
1733    RESERVED_1 = 1 << 2, // 4
1734}
1735
1736impl RecordFlag {
1737    /// Checks if the flag matches a given value.
1738    #[must_use]
1739    pub fn matches(self, value: u8) -> bool {
1740        (self as u8) & value != 0
1741    }
1742}
1743
1744/// The 'Time in Force' instruction for an order.
1745#[repr(C)]
1746#[derive(
1747    Copy,
1748    Clone,
1749    Debug,
1750    Display,
1751    Hash,
1752    PartialEq,
1753    Eq,
1754    PartialOrd,
1755    Ord,
1756    AsRefStr,
1757    FromRepr,
1758    EnumIter,
1759    EnumString,
1760)]
1761#[strum(ascii_case_insensitive)]
1762#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1763#[cfg_attr(
1764    feature = "python",
1765    pyo3::pyclass(
1766        frozen,
1767        eq,
1768        eq_int,
1769        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1770        from_py_object,
1771        rename_all = "SCREAMING_SNAKE_CASE",
1772    )
1773)]
1774#[cfg_attr(
1775    feature = "python",
1776    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1777)]
1778pub enum TimeInForce {
1779    /// Good Till Cancel (GTC) - Remains active until canceled.
1780    Gtc = 1,
1781    /// Immediate or Cancel (IOC) - Executes immediately to the extent possible, with any unfilled portion canceled.
1782    Ioc = 2,
1783    /// Fill or Kill (FOK) - Executes in its entirety immediately or is canceled if full execution is not possible.
1784    Fok = 3,
1785    /// Good Till Date (GTD) - Remains active until the specified expiration date or time is reached.
1786    Gtd = 4,
1787    /// Day - Remains active until the close of the current trading session.
1788    Day = 5,
1789    /// At the Opening (ATO) - Executes at the market opening or expires if not filled.
1790    AtTheOpen = 6,
1791    /// At the Closing (ATC) - Executes at the market close or expires if not filled.
1792    AtTheClose = 7,
1793}
1794
1795/// The trading state for a node.
1796#[repr(C)]
1797#[derive(
1798    Copy,
1799    Clone,
1800    Debug,
1801    Display,
1802    Hash,
1803    PartialEq,
1804    Eq,
1805    PartialOrd,
1806    Ord,
1807    AsRefStr,
1808    FromRepr,
1809    EnumIter,
1810    EnumString,
1811)]
1812#[strum(ascii_case_insensitive)]
1813#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1814#[cfg_attr(
1815    feature = "python",
1816    pyo3::pyclass(
1817        frozen,
1818        eq,
1819        eq_int,
1820        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1821        from_py_object,
1822        rename_all = "SCREAMING_SNAKE_CASE",
1823    )
1824)]
1825#[cfg_attr(
1826    feature = "python",
1827    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1828)]
1829pub enum TradingState {
1830    /// Normal trading operations.
1831    Active = 1,
1832    /// Trading is completely halted, no new order commands will be emitted.
1833    Halted = 2,
1834    /// Only order commands which would cancel order, or reduce position sizes are permitted.
1835    Reducing = 3,
1836}
1837
1838/// The trailing offset type for an order type which specifies a trailing stop/trigger or limit price.
1839#[repr(C)]
1840#[derive(
1841    Copy,
1842    Clone,
1843    Debug,
1844    Default,
1845    Display,
1846    Hash,
1847    PartialEq,
1848    Eq,
1849    PartialOrd,
1850    Ord,
1851    AsRefStr,
1852    FromRepr,
1853    EnumIter,
1854    EnumString,
1855)]
1856#[strum(ascii_case_insensitive)]
1857#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1858#[cfg_attr(
1859    feature = "python",
1860    pyo3::pyclass(
1861        frozen,
1862        eq,
1863        eq_int,
1864        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1865        from_py_object,
1866        rename_all = "SCREAMING_SNAKE_CASE",
1867    )
1868)]
1869#[cfg_attr(
1870    feature = "python",
1871    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1872)]
1873pub enum TrailingOffsetType {
1874    /// No trailing offset type is specified (invalid for trailing type orders).
1875    #[default]
1876    NoTrailingOffset = 0,
1877    /// The trailing offset is based on a market price.
1878    Price = 1,
1879    /// The trailing offset is based on a percentage represented in basis points, of a market price.
1880    BasisPoints = 2,
1881    /// The trailing offset is based on the number of ticks from a market price.
1882    Ticks = 3,
1883    /// The trailing offset is based on a price tier set by a specific trading venue.
1884    PriceTier = 4,
1885}
1886
1887/// The trigger type for the stop/trigger price of an order.
1888#[repr(C)]
1889#[derive(
1890    Copy,
1891    Clone,
1892    Debug,
1893    Default,
1894    Display,
1895    Hash,
1896    PartialEq,
1897    Eq,
1898    PartialOrd,
1899    Ord,
1900    AsRefStr,
1901    FromRepr,
1902    EnumIter,
1903    EnumString,
1904)]
1905#[strum(ascii_case_insensitive)]
1906#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1907#[cfg_attr(
1908    feature = "python",
1909    pyo3::pyclass(
1910        frozen,
1911        eq,
1912        eq_int,
1913        module = "nautilus_trader.core.nautilus_pyo3.model.enums",
1914        from_py_object,
1915        rename_all = "SCREAMING_SNAKE_CASE",
1916    )
1917)]
1918#[cfg_attr(
1919    feature = "python",
1920    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
1921)]
1922pub enum TriggerType {
1923    /// No trigger type is specified (invalid for orders with a trigger).
1924    #[default]
1925    NoTrigger = 0,
1926    /// The default trigger type set by the trading venue.
1927    Default = 1,
1928    /// Based on the last traded price for the instrument.
1929    LastPrice = 2,
1930    /// Based on the mark price for the instrument.
1931    MarkPrice = 3,
1932    /// Based on the index price for the instrument.
1933    IndexPrice = 4,
1934    /// Based on the top-of-book quoted prices for the instrument.
1935    BidAsk = 5,
1936    /// Based on a 'double match' of the last traded price for the instrument
1937    DoubleLast = 6,
1938    /// Based on a 'double match' of the bid/ask price for the instrument
1939    DoubleBidAsk = 7,
1940    /// Based on both the [`TriggerType::LastPrice`] and [`TriggerType::BidAsk`].
1941    LastOrBidAsk = 8,
1942    /// Based on the mid-point of the [`TriggerType::BidAsk`].
1943    MidPoint = 9,
1944}
1945
1946enum_strum_serde!(AccountType);
1947enum_strum_serde!(AggregationSource);
1948enum_strum_serde!(AggressorSide);
1949enum_strum_serde!(AssetClass);
1950enum_strum_serde!(BarAggregation);
1951enum_strum_serde!(BarIntervalType);
1952enum_strum_serde!(BookAction);
1953enum_strum_serde!(BookType);
1954enum_strum_serde!(ContingencyType);
1955enum_strum_serde!(CurrencyType);
1956enum_strum_serde!(GreeksConvention);
1957enum_strum_serde!(InstrumentClass);
1958enum_strum_serde!(InstrumentCloseType);
1959enum_strum_serde!(LiquiditySide);
1960enum_strum_serde!(MarketStatus);
1961enum_strum_serde!(MarketStatusAction);
1962enum_strum_serde!(OmsType);
1963enum_strum_serde!(OptionKind);
1964enum_strum_serde!(OrderSide);
1965enum_strum_serde!(OrderSideSpecified);
1966enum_strum_serde!(OrderStatus);
1967enum_strum_serde!(OrderType);
1968enum_strum_serde!(PositionAdjustmentType);
1969enum_strum_serde!(PositionSide);
1970enum_strum_serde!(PositionSideSpecified);
1971enum_strum_serde!(PriceType);
1972enum_strum_serde!(RecordFlag);
1973enum_strum_serde!(TimeInForce);
1974enum_strum_serde!(TradingState);
1975enum_strum_serde!(TrailingOffsetType);
1976enum_strum_serde!(TriggerType);
1977
1978#[cfg(test)]
1979mod tests {
1980    use rstest::rstest;
1981
1982    use super::*;
1983
1984    #[rstest]
1985    #[case::no_aggressor(0, Some(AggressorSide::NoAggressor))]
1986    #[case::buyer(1, Some(AggressorSide::Buyer))]
1987    #[case::seller(2, Some(AggressorSide::Seller))]
1988    #[case::invalid(3, None)]
1989    #[case::max_u8(255, None)]
1990    fn test_aggressor_side_from_u8(#[case] value: u8, #[case] expected: Option<AggressorSide>) {
1991        assert_eq!(AggressorSide::from_u8(value), expected);
1992    }
1993
1994    #[rstest]
1995    #[case(GreeksConvention::BlackScholes, "\"BLACK_SCHOLES\"")]
1996    #[case(GreeksConvention::PriceAdjusted, "\"PRICE_ADJUSTED\"")]
1997    fn test_greeks_convention_serde_roundtrip(
1998        #[case] input: GreeksConvention,
1999        #[case] expected: &str,
2000    ) {
2001        let json = serde_json::to_string(&input).unwrap();
2002        assert_eq!(json, expected);
2003        let parsed: GreeksConvention = serde_json::from_str(expected).unwrap();
2004        assert_eq!(parsed, input);
2005    }
2006
2007    #[rstest]
2008    fn test_greeks_convention_default_is_black_scholes() {
2009        assert_eq!(GreeksConvention::default(), GreeksConvention::BlackScholes);
2010    }
2011}