nautilus_model/
enums.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 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(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
68)]
69pub enum AccountType {
70    /// An account with unleveraged cash assets only.
71    Cash = 1,
72    /// An account which facilitates trading on margin, using account assets as collateral.
73    Margin = 2,
74    /// An account specific to betting markets.
75    Betting = 3,
76}
77
78/// An aggregation source for derived data.
79#[repr(C)]
80#[derive(
81    Copy,
82    Clone,
83    Debug,
84    Display,
85    Hash,
86    PartialEq,
87    Eq,
88    PartialOrd,
89    Ord,
90    AsRefStr,
91    FromRepr,
92    EnumIter,
93    EnumString,
94)]
95#[strum(ascii_case_insensitive)]
96#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
97#[cfg_attr(
98    feature = "python",
99    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
100)]
101pub enum AggregationSource {
102    /// The data is externally aggregated (outside the Nautilus system boundary).
103    External = 1,
104    /// The data is internally aggregated (inside the Nautilus system boundary).
105    Internal = 2,
106}
107
108/// The side for the aggressing order of a trade in a market.
109#[repr(C)]
110#[derive(
111    Copy,
112    Clone,
113    Debug,
114    Default,
115    Display,
116    Hash,
117    PartialEq,
118    Eq,
119    PartialOrd,
120    Ord,
121    AsRefStr,
122    FromRepr,
123    EnumIter,
124    EnumString,
125)]
126#[strum(ascii_case_insensitive)]
127#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
128#[cfg_attr(
129    feature = "python",
130    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
131)]
132pub enum AggressorSide {
133    /// There was no specific aggressor for the trade.
134    #[default]
135    NoAggressor = 0,
136    /// The BUY order was the aggressor for the trade.
137    Buyer = 1,
138    /// The SELL order was the aggressor for the trade.
139    Seller = 2,
140}
141
142impl FromU8 for AggressorSide {
143    fn from_u8(value: u8) -> Option<Self> {
144        match value {
145            0 => Some(Self::NoAggressor),
146            1 => Some(Self::Buyer),
147            2 => Some(Self::Seller),
148            _ => None,
149        }
150    }
151}
152
153/// A broad financial market asset class.
154#[repr(C)]
155#[derive(
156    Copy,
157    Clone,
158    Debug,
159    Display,
160    Hash,
161    PartialEq,
162    Eq,
163    PartialOrd,
164    Ord,
165    AsRefStr,
166    FromRepr,
167    EnumIter,
168    EnumString,
169)]
170#[strum(ascii_case_insensitive)]
171#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
172#[cfg_attr(
173    feature = "python",
174    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
175)]
176#[allow(non_camel_case_types)]
177pub enum AssetClass {
178    /// Foreign exchange (FOREX) assets.
179    FX = 1,
180    /// Equity / stock assets.
181    Equity = 2,
182    /// Commodity assets.
183    Commodity = 3,
184    /// Debt based assets.
185    Debt = 4,
186    /// Index based assets (baskets).
187    Index = 5,
188    /// Cryptocurrency or crypto token assets.
189    Cryptocurrency = 6,
190    /// Alternative assets.
191    Alternative = 7,
192}
193
194impl FromU8 for AssetClass {
195    fn from_u8(value: u8) -> Option<Self> {
196        match value {
197            1 => Some(Self::FX),
198            2 => Some(Self::Equity),
199            3 => Some(Self::Commodity),
200            4 => Some(Self::Debt),
201            5 => Some(Self::Index),
202            6 => Some(Self::Cryptocurrency),
203            7 => Some(Self::Alternative),
204            _ => None,
205        }
206    }
207}
208
209/// The instrument class.
210#[repr(C)]
211#[derive(
212    Copy,
213    Clone,
214    Debug,
215    Display,
216    Hash,
217    PartialEq,
218    Eq,
219    PartialOrd,
220    Ord,
221    AsRefStr,
222    FromRepr,
223    EnumIter,
224    EnumString,
225)]
226#[strum(ascii_case_insensitive)]
227#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
228#[cfg_attr(
229    feature = "python",
230    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
231)]
232pub enum InstrumentClass {
233    /// A spot market instrument class. The current market price of an instrument that is bought or sold for immediate delivery and payment.
234    Spot = 1,
235    /// A swap instrument class. A derivative contract through which two parties exchange the cash flows or liabilities from two different financial instruments.
236    Swap = 2,
237    /// 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.
238    Future = 3,
239    /// 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.
240    FuturesSpread = 4,
241    /// 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.
242    Forward = 5,
243    /// 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.
244    Cfd = 6,
245    /// 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.
246    Bond = 7,
247    /// 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.
248    Option = 8,
249    /// 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.
250    OptionSpread = 9,
251    /// 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.
252    Warrant = 10,
253    /// A sports betting instrument class. A financialized derivative that allows wagering on the outcome of sports events using structured contracts or prediction markets.
254    SportsBetting = 11,
255    /// 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.
256    /// A binary option instrument class. A type of derivative where the payoff is either a fixed monetary amount or nothing, based on a yes/no proposition about an underlying event.
257    BinaryOption = 12,
258}
259
260/// The aggregation method through which a bar is generated and closed.
261#[repr(C)]
262#[derive(
263    Copy,
264    Clone,
265    Debug,
266    Display,
267    Hash,
268    PartialEq,
269    Eq,
270    PartialOrd,
271    Ord,
272    AsRefStr,
273    FromRepr,
274    EnumIter,
275    EnumString,
276)]
277#[strum(ascii_case_insensitive)]
278#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
279#[cfg_attr(
280    feature = "python",
281    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
282)]
283pub enum BarAggregation {
284    /// Based on a number of ticks.
285    Tick = 1,
286    /// Based on the buy/sell imbalance of ticks.
287    TickImbalance = 2,
288    /// Based on sequential buy/sell runs of ticks.
289    TickRuns = 3,
290    /// Based on traded volume.
291    Volume = 4,
292    /// Based on the buy/sell imbalance of traded volume.
293    VolumeImbalance = 5,
294    /// Based on sequential runs of buy/sell traded volume.
295    VolumeRuns = 6,
296    /// Based on the 'notional' value of the instrument.
297    Value = 7,
298    /// Based on the buy/sell imbalance of trading by notional value.
299    ValueImbalance = 8,
300    /// Based on sequential buy/sell runs of trading by notional value.
301    ValueRuns = 9,
302    /// Based on time intervals with millisecond granularity.
303    Millisecond = 10,
304    /// Based on time intervals with second granularity.
305    Second = 11,
306    /// Based on time intervals with minute granularity.
307    Minute = 12,
308    /// Based on time intervals with hour granularity.
309    Hour = 13,
310    /// Based on time intervals with day granularity.
311    Day = 14,
312    /// Based on time intervals with week granularity.
313    Week = 15,
314    /// Based on time intervals with month granularity.
315    Month = 16,
316    /// Based on time intervals with year granularity.
317    Year = 17,
318    /// Based on fixed price movements (brick size).
319    Renko = 18,
320}
321
322/// The interval type for bar aggregation.
323#[repr(C)]
324#[derive(
325    Copy,
326    Clone,
327    Debug,
328    Default,
329    Display,
330    Hash,
331    PartialEq,
332    Eq,
333    PartialOrd,
334    Ord,
335    AsRefStr,
336    FromRepr,
337    EnumIter,
338    EnumString,
339)]
340#[strum(ascii_case_insensitive)]
341#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
342#[cfg_attr(
343    feature = "python",
344    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
345)]
346pub enum BarIntervalType {
347    /// Left-open interval `(start, end]`: start is exclusive, end is inclusive (default).
348    #[default]
349    LeftOpen = 1,
350    /// Right-open interval `[start, end)`: start is inclusive, end is exclusive.
351    RightOpen = 2,
352}
353
354/// Represents the side of a bet in a betting market.
355#[repr(C)]
356#[derive(
357    Copy,
358    Clone,
359    Debug,
360    Display,
361    Hash,
362    PartialEq,
363    Eq,
364    PartialOrd,
365    Ord,
366    AsRefStr,
367    FromRepr,
368    EnumIter,
369    EnumString,
370)]
371#[strum(ascii_case_insensitive)]
372#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
373#[cfg_attr(
374    feature = "python",
375    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
376)]
377pub enum BetSide {
378    /// A "Back" bet signifies support for a specific outcome.
379    Back = 1,
380    /// A "Lay" bet signifies opposition to a specific outcome.
381    Lay = 2,
382}
383
384impl BetSide {
385    /// Returns the opposite betting side.
386    #[must_use]
387    pub fn opposite(&self) -> Self {
388        match self {
389            Self::Back => Self::Lay,
390            Self::Lay => Self::Back,
391        }
392    }
393}
394
395impl From<OrderSide> for BetSide {
396    /// Returns the equivalent [`BetSide`] for a given [`OrderSide`].
397    ///
398    /// # Panics
399    ///
400    /// Panics if `side` is [`OrderSide::NoOrderSide`].
401    fn from(side: OrderSide) -> Self {
402        match side {
403            OrderSide::Buy => BetSide::Back,
404            OrderSide::Sell => BetSide::Lay,
405            OrderSide::NoOrderSide => panic!("Invalid `OrderSide` for `BetSide`, was {side}"),
406        }
407    }
408}
409
410/// The type of order book action for an order book event.
411#[repr(C)]
412#[derive(
413    Copy,
414    Clone,
415    Debug,
416    Display,
417    Hash,
418    PartialEq,
419    Eq,
420    PartialOrd,
421    Ord,
422    AsRefStr,
423    FromRepr,
424    EnumIter,
425    EnumString,
426)]
427#[strum(ascii_case_insensitive)]
428#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
429#[cfg_attr(
430    feature = "python",
431    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
432)]
433pub enum BookAction {
434    /// An order is added to the book.
435    Add = 1,
436    /// An existing order in the book is updated/modified.
437    Update = 2,
438    /// An existing order in the book is deleted/canceled.
439    Delete = 3,
440    /// The state of the order book is cleared.
441    Clear = 4,
442}
443
444impl FromU8 for BookAction {
445    fn from_u8(value: u8) -> Option<Self> {
446        match value {
447            1 => Some(Self::Add),
448            2 => Some(Self::Update),
449            3 => Some(Self::Delete),
450            4 => Some(Self::Clear),
451            _ => None,
452        }
453    }
454}
455
456/// The order book type, representing the type of levels granularity and delta updating heuristics.
457#[repr(C)]
458#[derive(
459    Copy,
460    Clone,
461    Debug,
462    Display,
463    Hash,
464    PartialEq,
465    Eq,
466    PartialOrd,
467    Ord,
468    AsRefStr,
469    FromRepr,
470    EnumIter,
471    EnumString,
472)]
473#[strum(ascii_case_insensitive)]
474#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
475#[allow(non_camel_case_types)]
476#[cfg_attr(
477    feature = "python",
478    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
479)]
480pub enum BookType {
481    /// Top-of-book best bid/ask, one level per side.
482    L1_MBP = 1,
483    /// Market by price, one order per level (aggregated).
484    L2_MBP = 2,
485    /// Market by order, multiple orders per level (full granularity).
486    L3_MBO = 3,
487}
488
489impl FromU8 for BookType {
490    fn from_u8(value: u8) -> Option<Self> {
491        match value {
492            1 => Some(Self::L1_MBP),
493            2 => Some(Self::L2_MBP),
494            3 => Some(Self::L3_MBO),
495            _ => None,
496        }
497    }
498}
499
500/// The order contigency type which specifies the behavior of linked orders.
501///
502/// [FIX 5.0 SP2 : ContingencyType <1385> field](https://www.onixs.biz/fix-dictionary/5.0.sp2/tagnum_1385.html).
503#[repr(C)]
504#[derive(
505    Copy,
506    Clone,
507    Debug,
508    Default,
509    Display,
510    Hash,
511    PartialEq,
512    Eq,
513    PartialOrd,
514    Ord,
515    AsRefStr,
516    FromRepr,
517    EnumIter,
518    EnumString,
519)]
520#[strum(ascii_case_insensitive)]
521#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
522#[cfg_attr(
523    feature = "python",
524    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
525)]
526pub enum ContingencyType {
527    /// Not a contingent order.
528    #[default]
529    NoContingency = 0,
530    /// One-Cancels-the-Other.
531    Oco = 1,
532    /// One-Triggers-the-Other.
533    Oto = 2,
534    /// One-Updates-the-Other (by proportional quantity).
535    Ouo = 3,
536}
537
538/// The broad currency type.
539#[repr(C)]
540#[derive(
541    Copy,
542    Clone,
543    Debug,
544    Display,
545    Hash,
546    PartialEq,
547    Eq,
548    PartialOrd,
549    Ord,
550    AsRefStr,
551    FromRepr,
552    EnumIter,
553    EnumString,
554)]
555#[strum(ascii_case_insensitive)]
556#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
557#[cfg_attr(
558    feature = "python",
559    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
560)]
561pub enum CurrencyType {
562    /// A type of cryptocurrency or crypto token.
563    Crypto = 1,
564    /// A type of currency issued by governments which is not backed by a commodity.
565    Fiat = 2,
566    /// A type of currency that is based on the value of an underlying commodity.
567    CommodityBacked = 3,
568}
569
570/// The type of event for an instrument close.
571#[repr(C)]
572#[derive(
573    Copy,
574    Clone,
575    Debug,
576    Display,
577    Hash,
578    PartialEq,
579    Eq,
580    PartialOrd,
581    Ord,
582    AsRefStr,
583    FromRepr,
584    EnumIter,
585    EnumString,
586)]
587#[strum(ascii_case_insensitive)]
588#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
589#[cfg_attr(
590    feature = "python",
591    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
592)]
593pub enum InstrumentCloseType {
594    /// When the market session ended.
595    EndOfSession = 1,
596    /// When the instrument expiration was reached.
597    ContractExpired = 2,
598}
599
600/// Convert the given `value` to an [`InstrumentCloseType`].
601impl FromU8 for InstrumentCloseType {
602    fn from_u8(value: u8) -> Option<Self> {
603        match value {
604            1 => Some(Self::EndOfSession),
605            2 => Some(Self::ContractExpired),
606            _ => None,
607        }
608    }
609}
610
611/// The liqudity side for a trade.
612#[repr(C)]
613#[derive(
614    Copy,
615    Clone,
616    Debug,
617    Display,
618    Hash,
619    PartialEq,
620    Eq,
621    PartialOrd,
622    Ord,
623    AsRefStr,
624    FromRepr,
625    EnumIter,
626    EnumString,
627)]
628#[strum(ascii_case_insensitive)]
629#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
630#[cfg_attr(
631    feature = "python",
632    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
633)]
634#[allow(clippy::enum_variant_names)]
635pub enum LiquiditySide {
636    /// No liquidity side specified.
637    NoLiquiditySide = 0,
638    /// The order passively provided liqudity to the market to complete the trade (made a market).
639    Maker = 1,
640    /// The order aggressively took liqudity from the market to complete the trade.
641    Taker = 2,
642}
643
644/// The status of an individual market on a trading venue.
645#[repr(C)]
646#[derive(
647    Copy,
648    Clone,
649    Debug,
650    Display,
651    Hash,
652    PartialEq,
653    Eq,
654    PartialOrd,
655    Ord,
656    AsRefStr,
657    FromRepr,
658    EnumIter,
659    EnumString,
660)]
661#[strum(ascii_case_insensitive)]
662#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
663#[cfg_attr(
664    feature = "python",
665    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
666)]
667pub enum MarketStatus {
668    /// The instrument is trading.
669    Open = 1,
670    /// The instrument is in a pre-open period.
671    Closed = 2,
672    /// Trading in the instrument has been paused.
673    Paused = 3,
674    /// Trading in the instrument has been halted.
675    // Halted = 4,  # TODO: Unfortunately can't use this yet due to Cython (C enum namespacing)
676    /// Trading in the instrument has been suspended.
677    Suspended = 5,
678    /// Trading in the instrument is not available.
679    NotAvailable = 6,
680}
681
682/// An action affecting the status of an individual market on a trading venue.
683#[repr(C)]
684#[derive(
685    Copy,
686    Clone,
687    Debug,
688    Display,
689    Hash,
690    PartialEq,
691    Eq,
692    PartialOrd,
693    Ord,
694    AsRefStr,
695    FromRepr,
696    EnumIter,
697    EnumString,
698)]
699#[strum(ascii_case_insensitive)]
700#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
701#[cfg_attr(
702    feature = "python",
703    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
704)]
705pub enum MarketStatusAction {
706    /// No change.
707    None = 0,
708    /// The instrument is in a pre-open period.
709    PreOpen = 1,
710    /// The instrument is in a pre-cross period.
711    PreCross = 2,
712    /// The instrument is quoting but not trading.
713    Quoting = 3,
714    /// The instrument is in a cross/auction.
715    Cross = 4,
716    /// The instrument is being opened through a trading rotation.
717    Rotation = 5,
718    /// A new price indication is available for the instrument.
719    NewPriceIndication = 6,
720    /// The instrument is trading.
721    Trading = 7,
722    /// Trading in the instrument has been halted.
723    Halt = 8,
724    /// Trading in the instrument has been paused.
725    Pause = 9,
726    /// Trading in the instrument has been suspended.
727    Suspend = 10,
728    /// The instrument is in a pre-close period.
729    PreClose = 11,
730    /// Trading in the instrument has closed.
731    Close = 12,
732    /// The instrument is in a post-close period.
733    PostClose = 13,
734    /// A change in short-selling restrictions.
735    ShortSellRestrictionChange = 14,
736    /// The instrument is not available for trading, either trading has closed or been halted.
737    NotAvailableForTrading = 15,
738}
739
740/// Convert the given `value` to an [`OrderSide`].
741impl FromU16 for MarketStatusAction {
742    fn from_u16(value: u16) -> Option<Self> {
743        match value {
744            0 => Some(Self::None),
745            1 => Some(Self::PreOpen),
746            2 => Some(Self::PreCross),
747            3 => Some(Self::Quoting),
748            4 => Some(Self::Cross),
749            5 => Some(Self::Rotation),
750            6 => Some(Self::NewPriceIndication),
751            7 => Some(Self::Trading),
752            8 => Some(Self::Halt),
753            9 => Some(Self::Pause),
754            10 => Some(Self::Suspend),
755            11 => Some(Self::PreClose),
756            12 => Some(Self::Close),
757            13 => Some(Self::PostClose),
758            14 => Some(Self::ShortSellRestrictionChange),
759            15 => Some(Self::NotAvailableForTrading),
760            _ => None,
761        }
762    }
763}
764
765/// The order management system (OMS) type for a trading venue or trading strategy.
766#[repr(C)]
767#[derive(
768    Copy,
769    Clone,
770    Debug,
771    Default,
772    Display,
773    Hash,
774    PartialEq,
775    Eq,
776    PartialOrd,
777    Ord,
778    AsRefStr,
779    FromRepr,
780    EnumIter,
781    EnumString,
782)]
783#[strum(ascii_case_insensitive)]
784#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
785#[cfg_attr(
786    feature = "python",
787    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
788)]
789pub enum OmsType {
790    /// There is no specific type of order management specified (will defer to the venue OMS).
791    #[default]
792    Unspecified = 0,
793    /// The netting type where there is one position per instrument.
794    Netting = 1,
795    /// The hedging type where there can be multiple positions per instrument.
796    /// This can be in LONG/SHORT directions, by position/ticket ID, or tracked virtually by
797    /// Nautilus.
798    Hedging = 2,
799}
800
801/// The kind of option contract.
802#[repr(C)]
803#[derive(
804    Copy,
805    Clone,
806    Debug,
807    Display,
808    Hash,
809    PartialEq,
810    Eq,
811    PartialOrd,
812    Ord,
813    AsRefStr,
814    FromRepr,
815    EnumIter,
816    EnumString,
817)]
818#[strum(ascii_case_insensitive)]
819#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
820#[cfg_attr(
821    feature = "python",
822    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
823)]
824pub enum OptionKind {
825    /// 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.
826    Call = 1,
827    /// 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.
828    Put = 2,
829}
830
831/// The order side for a specific order, or action related to orders.
832#[repr(C)]
833#[derive(
834    Copy,
835    Clone,
836    Debug,
837    Default,
838    Display,
839    Hash,
840    PartialEq,
841    Eq,
842    PartialOrd,
843    Ord,
844    AsRefStr,
845    FromRepr,
846    EnumIter,
847    EnumString,
848)]
849#[strum(ascii_case_insensitive)]
850#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
851#[allow(clippy::enum_variant_names)]
852#[cfg_attr(
853    feature = "python",
854    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
855)]
856pub enum OrderSide {
857    /// No order side is specified.
858    #[default]
859    NoOrderSide = 0,
860    /// The order is a BUY.
861    Buy = 1,
862    /// The order is a SELL.
863    Sell = 2,
864}
865
866impl OrderSide {
867    /// Returns the specified [`OrderSideSpecified`] (BUY or SELL) for this side.
868    ///
869    /// # Panics
870    ///
871    /// Panics if `self` is [`OrderSide::NoOrderSide`].
872    #[must_use]
873    pub fn as_specified(&self) -> OrderSideSpecified {
874        match &self {
875            Self::Buy => OrderSideSpecified::Buy,
876            Self::Sell => OrderSideSpecified::Sell,
877            _ => panic!("Order invariant failed: side must be `Buy` or `Sell`"),
878        }
879    }
880}
881
882/// Convert the given `value` to an [`OrderSide`].
883impl FromU8 for OrderSide {
884    fn from_u8(value: u8) -> Option<Self> {
885        match value {
886            0 => Some(Self::NoOrderSide),
887            1 => Some(Self::Buy),
888            2 => Some(Self::Sell),
889            _ => None,
890        }
891    }
892}
893
894/// The specified order side (BUY or SELL).
895#[repr(C)]
896#[derive(
897    Copy,
898    Clone,
899    Debug,
900    Display,
901    Hash,
902    PartialEq,
903    Eq,
904    PartialOrd,
905    Ord,
906    AsRefStr,
907    FromRepr,
908    EnumIter,
909    EnumString,
910)]
911#[strum(ascii_case_insensitive)]
912#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
913#[allow(clippy::enum_variant_names)]
914pub enum OrderSideSpecified {
915    /// The order is a BUY.
916    Buy = 1,
917    /// The order is a SELL.
918    Sell = 2,
919}
920
921impl OrderSideSpecified {
922    /// Returns the opposite order side.
923    #[must_use]
924    pub fn opposite(&self) -> Self {
925        match &self {
926            Self::Buy => Self::Sell,
927            Self::Sell => Self::Buy,
928        }
929    }
930
931    /// Converts this specified side into an [`OrderSide`].
932    #[must_use]
933    pub fn as_order_side(&self) -> OrderSide {
934        match &self {
935            Self::Buy => OrderSide::Buy,
936            Self::Sell => OrderSide::Sell,
937        }
938    }
939}
940
941/// The status for a specific order.
942///
943/// An order is considered _open_ for the following status:
944///  - `ACCEPTED`
945///  - `TRIGGERED`
946///  - `PENDING_UPDATE`
947///  - `PENDING_CANCEL`
948///  - `PARTIALLY_FILLED`
949///
950/// An order is considered _in-flight_ for the following status:
951///  - `SUBMITTED`
952///  - `PENDING_UPDATE`
953///  - `PENDING_CANCEL`
954///
955/// An order is considered _closed_ for the following status:
956///  - `DENIED`
957///  - `REJECTED`
958///  - `CANCELED`
959///  - `EXPIRED`
960///  - `FILLED`
961#[repr(C)]
962#[derive(
963    Copy,
964    Clone,
965    Debug,
966    Display,
967    Hash,
968    PartialEq,
969    Eq,
970    PartialOrd,
971    Ord,
972    AsRefStr,
973    FromRepr,
974    EnumIter,
975    EnumString,
976)]
977#[strum(ascii_case_insensitive)]
978#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
979#[cfg_attr(
980    feature = "python",
981    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
982)]
983pub enum OrderStatus {
984    /// The order is initialized (instantiated) within the Nautilus system.
985    Initialized = 1,
986    /// The order was denied by the Nautilus system, either for being invalid, unprocessable or exceeding a risk limit.
987    Denied = 2,
988    /// The order became emulated by the Nautilus system in the `OrderEmulator` component.
989    Emulated = 3,
990    /// The order was released by the Nautilus system from the `OrderEmulator` component.
991    Released = 4,
992    /// The order was submitted by the Nautilus system to the external service or trading venue (awaiting acknowledgement).
993    Submitted = 5,
994    /// The order was acknowledged by the trading venue as being received and valid (may now be working).
995    Accepted = 6,
996    /// The order was rejected by the trading venue.
997    Rejected = 7,
998    /// The order was canceled (closed/done).
999    Canceled = 8,
1000    /// The order reached a GTD expiration (closed/done).
1001    Expired = 9,
1002    /// The order STOP price was triggered on a trading venue.
1003    Triggered = 10,
1004    /// The order is currently pending a request to modify on a trading venue.
1005    PendingUpdate = 11,
1006    /// The order is currently pending a request to cancel on a trading venue.
1007    PendingCancel = 12,
1008    /// The order has been partially filled on a trading venue.
1009    PartiallyFilled = 13,
1010    /// The order has been completely filled on a trading venue (closed/done).
1011    Filled = 14,
1012}
1013
1014impl OrderStatus {
1015    /// Returns a cached `AHashSet` of order statuses safe for cancellation queries.
1016    ///
1017    /// These are statuses where an order is working on the venue but not already
1018    /// in the process of being cancelled or updated. Including `PENDING_CANCEL`
1019    /// in cancellation filters can cause duplicate cancel attempts or incorrect open order counts.
1020    ///
1021    /// Returns:
1022    /// - `ACCEPTED`: Order is working on the venue.
1023    /// - `TRIGGERED`: Stop order has been triggered.
1024    /// - `PENDING_UPDATE`: Order being updated.
1025    /// - `PARTIALLY_FILLED`: Order is partially filled but still working.
1026    ///
1027    /// Excludes:
1028    /// - `PENDING_CANCEL`: Already being cancelled.
1029    #[must_use]
1030    pub fn cancellable_statuses_set() -> &'static AHashSet<Self> {
1031        static CANCELLABLE_SET: OnceLock<AHashSet<OrderStatus>> = OnceLock::new();
1032        CANCELLABLE_SET.get_or_init(|| {
1033            AHashSet::from_iter([
1034                Self::Accepted,
1035                Self::Triggered,
1036                Self::PendingUpdate,
1037                Self::PartiallyFilled,
1038            ])
1039        })
1040    }
1041}
1042
1043/// The type of order.
1044#[repr(C)]
1045#[derive(
1046    Copy,
1047    Clone,
1048    Debug,
1049    Display,
1050    Hash,
1051    PartialEq,
1052    Eq,
1053    PartialOrd,
1054    Ord,
1055    AsRefStr,
1056    FromRepr,
1057    EnumIter,
1058    EnumString,
1059)]
1060#[strum(ascii_case_insensitive)]
1061#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1062#[cfg_attr(
1063    feature = "python",
1064    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
1065)]
1066pub enum OrderType {
1067    /// A market order to buy or sell at the best available price in the current market.
1068    Market = 1,
1069    /// A limit order to buy or sell at a specific price or better.
1070    Limit = 2,
1071    /// 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.
1072    StopMarket = 3,
1073    /// 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.
1074    StopLimit = 4,
1075    /// 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.
1076    MarketToLimit = 5,
1077    /// A market-if-touched order effectively becomes a market order when the specified trigger price is reached.
1078    MarketIfTouched = 6,
1079    /// A limit-if-touched order effectively becomes a limit order when the specified trigger price is reached.
1080    LimitIfTouched = 7,
1081    /// A trailing stop market order sets the stop/trigger price at a fixed "trailing offset" amount from the market.
1082    TrailingStopMarket = 8,
1083    /// A trailing stop limit order combines the features of a trailing stop order with those of a limit order.
1084    TrailingStopLimit = 9,
1085}
1086
1087/// The market side for a specific position, or action related to positions.
1088#[repr(C)]
1089#[derive(
1090    Copy,
1091    Clone,
1092    Debug,
1093    Default,
1094    Display,
1095    Hash,
1096    PartialEq,
1097    Eq,
1098    PartialOrd,
1099    Ord,
1100    AsRefStr,
1101    FromRepr,
1102    EnumIter,
1103    EnumString,
1104)]
1105#[strum(ascii_case_insensitive)]
1106#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1107#[allow(clippy::enum_variant_names)]
1108#[cfg_attr(
1109    feature = "python",
1110    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
1111)]
1112pub enum PositionSide {
1113    /// No position side is specified (only valid in the context of a filter for actions involving positions).
1114    #[default]
1115    NoPositionSide = 0,
1116    /// A neural/flat position, where no position is currently held in the market.
1117    Flat = 1,
1118    /// A long position in the market, typically acquired through one or many BUY orders.
1119    Long = 2,
1120    /// A short position in the market, typically acquired through one or many SELL orders.
1121    Short = 3,
1122}
1123
1124impl PositionSide {
1125    /// Returns the specified [`PositionSideSpecified`] (`Long`, `Short`, or `Flat`) for this side.
1126    ///
1127    /// # Panics
1128    ///
1129    /// Panics if `self` is [`PositionSide::NoPositionSide`].
1130    #[must_use]
1131    pub fn as_specified(&self) -> PositionSideSpecified {
1132        match &self {
1133            Self::Long => PositionSideSpecified::Long,
1134            Self::Short => PositionSideSpecified::Short,
1135            Self::Flat => PositionSideSpecified::Flat,
1136            _ => panic!("Position invariant failed: side must be `Long`, `Short`, or `Flat`"),
1137        }
1138    }
1139}
1140
1141/// The market side for a specific position, or action related to positions.
1142#[repr(C)]
1143#[derive(
1144    Copy,
1145    Clone,
1146    Debug,
1147    Display,
1148    Hash,
1149    PartialEq,
1150    Eq,
1151    PartialOrd,
1152    Ord,
1153    AsRefStr,
1154    FromRepr,
1155    EnumIter,
1156    EnumString,
1157)]
1158#[strum(ascii_case_insensitive)]
1159#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1160#[allow(clippy::enum_variant_names)]
1161#[cfg_attr(
1162    feature = "python",
1163    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
1164)]
1165pub enum PositionSideSpecified {
1166    /// A neural/flat position, where no position is currently held in the market.
1167    Flat = 1,
1168    /// A long position in the market, typically acquired through one or many BUY orders.
1169    Long = 2,
1170    /// A short position in the market, typically acquired through one or many SELL orders.
1171    Short = 3,
1172}
1173
1174impl PositionSideSpecified {
1175    /// Converts this specified side into a [`PositionSide`].
1176    #[must_use]
1177    pub fn as_position_side(&self) -> PositionSide {
1178        match &self {
1179            Self::Long => PositionSide::Long,
1180            Self::Short => PositionSide::Short,
1181            Self::Flat => PositionSide::Flat,
1182        }
1183    }
1184}
1185
1186/// The type of price for an instrument in a market.
1187#[repr(C)]
1188#[derive(
1189    Copy,
1190    Clone,
1191    Debug,
1192    Display,
1193    Hash,
1194    PartialEq,
1195    Eq,
1196    PartialOrd,
1197    Ord,
1198    AsRefStr,
1199    FromRepr,
1200    EnumIter,
1201    EnumString,
1202)]
1203#[strum(ascii_case_insensitive)]
1204#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1205#[cfg_attr(
1206    feature = "python",
1207    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
1208)]
1209pub enum PriceType {
1210    /// The best quoted price at which buyers are willing to buy a quantity of an instrument.
1211    /// Often considered the best bid in the order book.
1212    Bid = 1,
1213    /// The best quoted price at which sellers are willing to sell a quantity of an instrument.
1214    /// Often considered the best ask in the order book.
1215    Ask = 2,
1216    /// The arithmetic midpoint between the best bid and ask quotes.
1217    Mid = 3,
1218    /// The price at which the last trade of an instrument was executed.
1219    Last = 4,
1220    /// A reference price reflecting an instrument's fair value, often used for portfolio
1221    /// calculations and risk management.
1222    Mark = 5,
1223}
1224
1225/// A record flag bit field, indicating event end and data information.
1226#[repr(C)]
1227#[derive(
1228    Copy,
1229    Clone,
1230    Debug,
1231    Display,
1232    Hash,
1233    PartialEq,
1234    Eq,
1235    PartialOrd,
1236    Ord,
1237    AsRefStr,
1238    FromRepr,
1239    EnumIter,
1240    EnumString,
1241)]
1242#[strum(ascii_case_insensitive)]
1243#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1244#[cfg_attr(
1245    feature = "python",
1246    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
1247)]
1248#[allow(non_camel_case_types)]
1249pub enum RecordFlag {
1250    /// Last message in the book event or packet from the venue for a given `instrument_id`.
1251    F_LAST = 1 << 7, // 128
1252    /// Top-of-book message, not an individual order.
1253    F_TOB = 1 << 6, // 64
1254    /// Message sourced from a replay, such as a snapshot server.
1255    F_SNAPSHOT = 1 << 5, // 32
1256    /// Aggregated price level message, not an individual order.
1257    F_MBP = 1 << 4, // 16
1258    /// Reserved for future use.
1259    RESERVED_2 = 1 << 3, // 8
1260    /// Reserved for future use.
1261    RESERVED_1 = 1 << 2, // 4
1262}
1263
1264impl RecordFlag {
1265    /// Checks if the flag matches a given value.
1266    #[must_use]
1267    pub fn matches(self, value: u8) -> bool {
1268        (self as u8) & value != 0
1269    }
1270}
1271
1272/// The 'Time in Force' instruction for an order.
1273#[repr(C)]
1274#[derive(
1275    Copy,
1276    Clone,
1277    Debug,
1278    Display,
1279    Hash,
1280    PartialEq,
1281    Eq,
1282    PartialOrd,
1283    Ord,
1284    AsRefStr,
1285    FromRepr,
1286    EnumIter,
1287    EnumString,
1288)]
1289#[strum(ascii_case_insensitive)]
1290#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1291#[cfg_attr(
1292    feature = "python",
1293    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
1294)]
1295pub enum TimeInForce {
1296    /// Good Till Cancel (GTC) - Remains active until canceled.
1297    Gtc = 1,
1298    /// Immediate or Cancel (IOC) - Executes immediately to the extent possible, with any unfilled portion canceled.
1299    Ioc = 2,
1300    /// Fill or Kill (FOK) - Executes in its entirety immediately or is canceled if full execution is not possible.
1301    Fok = 3,
1302    /// Good Till Date (GTD) - Remains active until the specified expiration date or time is reached.
1303    Gtd = 4,
1304    /// Day - Remains active until the close of the current trading session.
1305    Day = 5,
1306    /// At the Opening (ATO) - Executes at the market opening or expires if not filled.
1307    AtTheOpen = 6,
1308    /// At the Closing (ATC) - Executes at the market close or expires if not filled.
1309    AtTheClose = 7,
1310}
1311
1312/// The trading state for a node.
1313#[repr(C)]
1314#[derive(
1315    Copy,
1316    Clone,
1317    Debug,
1318    Display,
1319    Hash,
1320    PartialEq,
1321    Eq,
1322    PartialOrd,
1323    Ord,
1324    AsRefStr,
1325    FromRepr,
1326    EnumIter,
1327    EnumString,
1328)]
1329#[strum(ascii_case_insensitive)]
1330#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1331#[cfg_attr(
1332    feature = "python",
1333    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
1334)]
1335pub enum TradingState {
1336    /// Normal trading operations.
1337    Active = 1,
1338    /// Trading is completely halted, no new order commands will be emitted.
1339    Halted = 2,
1340    /// Only order commands which would cancel order, or reduce position sizes are permitted.
1341    Reducing = 3,
1342}
1343
1344/// The trailing offset type for an order type which specifies a trailing stop/trigger or limit price.
1345#[repr(C)]
1346#[derive(
1347    Copy,
1348    Clone,
1349    Debug,
1350    Default,
1351    Display,
1352    Hash,
1353    PartialEq,
1354    Eq,
1355    PartialOrd,
1356    Ord,
1357    AsRefStr,
1358    FromRepr,
1359    EnumIter,
1360    EnumString,
1361)]
1362#[strum(ascii_case_insensitive)]
1363#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1364#[cfg_attr(
1365    feature = "python",
1366    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
1367)]
1368pub enum TrailingOffsetType {
1369    /// No trailing offset type is specified (invalid for trailing type orders).
1370    #[default]
1371    NoTrailingOffset = 0,
1372    /// The trailing offset is based on a market price.
1373    Price = 1,
1374    /// The trailing offset is based on a percentage represented in basis points, of a market price.
1375    BasisPoints = 2,
1376    /// The trailing offset is based on the number of ticks from a market price.
1377    Ticks = 3,
1378    /// The trailing offset is based on a price tier set by a specific trading venue.
1379    PriceTier = 4,
1380}
1381
1382/// The trigger type for the stop/trigger price of an order.
1383#[repr(C)]
1384#[derive(
1385    Copy,
1386    Clone,
1387    Debug,
1388    Default,
1389    Display,
1390    Hash,
1391    PartialEq,
1392    Eq,
1393    PartialOrd,
1394    Ord,
1395    AsRefStr,
1396    FromRepr,
1397    EnumIter,
1398    EnumString,
1399)]
1400#[strum(ascii_case_insensitive)]
1401#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1402#[cfg_attr(
1403    feature = "python",
1404    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.model.enums")
1405)]
1406pub enum TriggerType {
1407    /// No trigger type is specified (invalid for orders with a trigger).
1408    #[default]
1409    NoTrigger = 0,
1410    /// The default trigger type set by the trading venue.
1411    Default = 1,
1412    /// Based on the last traded price for the instrument.
1413    LastPrice = 2,
1414    /// Based on the mark price for the instrument.
1415    MarkPrice = 3,
1416    /// Based on the index price for the instrument.
1417    IndexPrice = 4,
1418    /// Based on the top-of-book quoted prices for the instrument.
1419    BidAsk = 5,
1420    /// Based on a 'double match' of the last traded price for the instrument
1421    DoubleLast = 6,
1422    /// Based on a 'double match' of the bid/ask price for the instrument
1423    DoubleBidAsk = 7,
1424    /// Based on both the [`TriggerType::LastPrice`] and [`TriggerType::BidAsk`].
1425    LastOrBidAsk = 8,
1426    /// Based on the mid-point of the [`TriggerType::BidAsk`].
1427    MidPoint = 9,
1428}
1429
1430enum_strum_serde!(AccountType);
1431enum_strum_serde!(AggregationSource);
1432enum_strum_serde!(AggressorSide);
1433enum_strum_serde!(AssetClass);
1434enum_strum_serde!(InstrumentClass);
1435enum_strum_serde!(BarAggregation);
1436enum_strum_serde!(BarIntervalType);
1437enum_strum_serde!(BookAction);
1438enum_strum_serde!(BookType);
1439enum_strum_serde!(ContingencyType);
1440enum_strum_serde!(CurrencyType);
1441enum_strum_serde!(InstrumentCloseType);
1442enum_strum_serde!(LiquiditySide);
1443enum_strum_serde!(MarketStatus);
1444enum_strum_serde!(MarketStatusAction);
1445enum_strum_serde!(OmsType);
1446enum_strum_serde!(OptionKind);
1447enum_strum_serde!(OrderSide);
1448enum_strum_serde!(OrderSideSpecified);
1449enum_strum_serde!(OrderStatus);
1450enum_strum_serde!(OrderType);
1451enum_strum_serde!(PositionSide);
1452enum_strum_serde!(PositionSideSpecified);
1453enum_strum_serde!(PriceType);
1454enum_strum_serde!(RecordFlag);
1455enum_strum_serde!(TimeInForce);
1456enum_strum_serde!(TradingState);
1457enum_strum_serde!(TrailingOffsetType);
1458enum_strum_serde!(TriggerType);