nautilus_okx/common/
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 mapping OKX concepts onto idiomatic Nautilus variants.
17
18use nautilus_model::enums::{
19    AggressorSide, LiquiditySide, OptionKind, OrderSide, OrderStatus, OrderType, PositionSide,
20    TriggerType,
21};
22use serde::{Deserialize, Serialize};
23use strum::{AsRefStr, Display, EnumIter, EnumString};
24
25use crate::common::consts::OKX_CONDITIONAL_ORDER_TYPES;
26
27/// Represents the type of book action.
28#[derive(
29    Copy,
30    Clone,
31    Debug,
32    Display,
33    PartialEq,
34    Eq,
35    Hash,
36    AsRefStr,
37    EnumIter,
38    EnumString,
39    Serialize,
40    Deserialize,
41)]
42#[serde(rename_all = "lowercase")]
43pub enum OKXBookAction {
44    /// Incremental update.
45    Update,
46    /// Full snapshot.
47    Snapshot,
48}
49
50/// Represents the possible states of an order throughout its lifecycle.
51#[derive(
52    Copy,
53    Clone,
54    Debug,
55    Display,
56    PartialEq,
57    Eq,
58    Hash,
59    AsRefStr,
60    EnumIter,
61    EnumString,
62    Serialize,
63    Deserialize,
64)]
65pub enum OKXCandleConfirm {
66    /// K-line is incomplete.
67    #[serde(rename = "0")]
68    Partial,
69    /// K-line is completed.
70    #[serde(rename = "1")]
71    Closed,
72}
73
74/// Represents the side of an order or trade (Buy/Sell).
75#[derive(
76    Copy,
77    Clone,
78    Debug,
79    Display,
80    PartialEq,
81    Eq,
82    Hash,
83    AsRefStr,
84    EnumIter,
85    EnumString,
86    Serialize,
87    Deserialize,
88)]
89#[serde(rename_all = "snake_case")]
90pub enum OKXSide {
91    /// Buy side of a trade or order.
92    Buy,
93    /// Sell side of a trade or order.
94    Sell,
95}
96
97impl From<OrderSide> for OKXSide {
98    fn from(value: OrderSide) -> Self {
99        match value {
100            OrderSide::Buy => Self::Buy,
101            OrderSide::Sell => Self::Sell,
102            _ => panic!("Invalid `OrderSide`"),
103        }
104    }
105}
106
107impl From<OKXSide> for AggressorSide {
108    fn from(value: OKXSide) -> Self {
109        match value {
110            OKXSide::Buy => Self::Buyer,
111            OKXSide::Sell => Self::Seller,
112        }
113    }
114}
115
116/// Represents the available order types on OKX.
117#[derive(
118    Copy,
119    Clone,
120    Debug,
121    Display,
122    PartialEq,
123    Eq,
124    Hash,
125    AsRefStr,
126    EnumIter,
127    EnumString,
128    Serialize,
129    Deserialize,
130)]
131#[serde(rename_all = "snake_case")]
132pub enum OKXOrderType {
133    /// Market order, executed immediately at current market price.
134    Market,
135    /// Limit order, executed only at specified price or better.
136    Limit,
137    PostOnly,        // limit only, requires "px" to be provided
138    Fok,             // Market order if "px" is not provided, otherwise limit order
139    Ioc,             // Market order if "px" is not provided, otherwise limit order
140    OptimalLimitIoc, // Market order with immediate-or-cancel order
141    Mmp,             // Market Maker Protection (only applicable to Option in Portfolio Margin mode)
142    MmpAndPostOnly, // Market Maker Protection and Post-only order(only applicable to Option in Portfolio Margin mode)
143    Trigger,        // Conditional/algo order (stop orders, etc.)
144}
145
146/// Represents the possible states of an order throughout its lifecycle.
147#[derive(
148    Copy,
149    Clone,
150    Debug,
151    Display,
152    PartialEq,
153    Eq,
154    Hash,
155    AsRefStr,
156    EnumIter,
157    EnumString,
158    Serialize,
159    Deserialize,
160)]
161#[serde(rename_all = "snake_case")]
162#[cfg_attr(
163    feature = "python",
164    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.okx")
165)]
166pub enum OKXOrderStatus {
167    Canceled,
168    Live,
169    Effective,
170    PartiallyFilled,
171    Filled,
172    MmpCanceled,
173    OrderPlaced,
174}
175
176impl From<OrderStatus> for OKXOrderStatus {
177    fn from(value: OrderStatus) -> Self {
178        match value {
179            OrderStatus::Canceled => Self::Canceled,
180            OrderStatus::Accepted => Self::Live,
181            OrderStatus::PartiallyFilled => Self::PartiallyFilled,
182            OrderStatus::Filled => Self::Filled,
183            _ => panic!("Invalid `OrderStatus`"),
184        }
185    }
186}
187
188/// Represents the type of execution that generated a trade.
189#[derive(
190    Copy,
191    Clone,
192    Debug,
193    Default,
194    Display,
195    PartialEq,
196    Eq,
197    Hash,
198    AsRefStr,
199    EnumIter,
200    EnumString,
201    Serialize,
202    Deserialize,
203)]
204pub enum OKXExecType {
205    #[serde(rename = "")]
206    #[default]
207    None,
208    #[serde(rename = "T")]
209    Taker,
210    #[serde(rename = "M")]
211    Maker,
212}
213
214impl From<LiquiditySide> for OKXExecType {
215    fn from(value: LiquiditySide) -> Self {
216        match value {
217            LiquiditySide::NoLiquiditySide => Self::None,
218            LiquiditySide::Taker => Self::Taker,
219            LiquiditySide::Maker => Self::Maker,
220        }
221    }
222}
223
224/// Represents instrument types on OKX.
225#[derive(
226    Copy,
227    Clone,
228    Debug,
229    Display,
230    Default,
231    PartialEq,
232    Eq,
233    Hash,
234    AsRefStr,
235    EnumIter,
236    EnumString,
237    Serialize,
238    Deserialize,
239)]
240#[serde(rename_all = "UPPERCASE")]
241#[cfg_attr(
242    feature = "python",
243    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.okx")
244)]
245pub enum OKXInstrumentType {
246    #[default]
247    Any,
248    /// Spot products.
249    Spot,
250    /// Margin products.
251    Margin,
252    /// Swap products.
253    Swap,
254    /// Futures products.
255    Futures,
256    /// Option products.
257    Option,
258}
259
260/// Represents an instrument status on OKX.
261#[derive(
262    Copy,
263    Clone,
264    Debug,
265    Display,
266    PartialEq,
267    Eq,
268    Hash,
269    AsRefStr,
270    EnumIter,
271    EnumString,
272    Serialize,
273    Deserialize,
274)]
275#[serde(rename_all = "snake_case")]
276pub enum OKXInstrumentStatus {
277    Live,
278    Suspend,
279    Preopen,
280    Test,
281}
282
283/// Represents an instrument contract type on OKX.
284#[derive(
285    Copy,
286    Clone,
287    Default,
288    Debug,
289    Display,
290    PartialEq,
291    Eq,
292    Hash,
293    AsRefStr,
294    EnumIter,
295    EnumString,
296    Serialize,
297    Deserialize,
298)]
299#[serde(rename_all = "snake_case")]
300#[cfg_attr(
301    feature = "python",
302    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.okx")
303)]
304pub enum OKXContractType {
305    #[serde(rename = "")]
306    #[default]
307    None,
308    Linear,
309    Inverse,
310}
311
312/// Represents an option type on OKX.
313#[derive(
314    Copy,
315    Clone,
316    Debug,
317    Display,
318    PartialEq,
319    Eq,
320    Hash,
321    AsRefStr,
322    EnumIter,
323    EnumString,
324    Serialize,
325    Deserialize,
326)]
327pub enum OKXOptionType {
328    #[serde(rename = "")]
329    None,
330    #[serde(rename = "C")]
331    Call,
332    #[serde(rename = "P")]
333    Put,
334}
335
336impl From<OKXOptionType> for OptionKind {
337    fn from(option_type: OKXOptionType) -> Self {
338        match option_type {
339            OKXOptionType::Call => Self::Call,
340            OKXOptionType::Put => Self::Put,
341            _ => panic!("Invalid `option_type`, was None"),
342        }
343    }
344}
345
346/// Represents the trading mode for OKX orders.
347#[derive(
348    Copy,
349    Clone,
350    Debug,
351    Display,
352    Default,
353    PartialEq,
354    Eq,
355    Hash,
356    AsRefStr,
357    EnumIter,
358    EnumString,
359    Serialize,
360    Deserialize,
361)]
362#[serde(rename_all = "snake_case")]
363#[strum(ascii_case_insensitive)]
364#[cfg_attr(
365    feature = "python",
366    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.okx")
367)]
368pub enum OKXTradeMode {
369    #[default]
370    Cash,
371    Isolated,
372    Cross,
373    #[strum(serialize = "spot_isolated")]
374    SpotIsolated,
375}
376
377/// Represents an OKX account mode.
378///
379/// # References
380///
381/// <https://www.okx.com/docs-v5/en/#overview-account-mode>
382#[derive(
383    Copy,
384    Clone,
385    Debug,
386    Display,
387    PartialEq,
388    Eq,
389    Hash,
390    AsRefStr,
391    EnumIter,
392    EnumString,
393    Serialize,
394    Deserialize,
395)]
396pub enum OKXAccountMode {
397    #[serde(rename = "Spot mode")]
398    Spot,
399    #[serde(rename = "Spot and futures mode")]
400    SpotAndFutures,
401    #[serde(rename = "Multi-currency margin mode")]
402    MultiCurrencyMarginMode,
403    #[serde(rename = "Portfolio margin mode")]
404    PortfolioMarginMode,
405}
406
407/// Represents the margin mode for OKX accounts.
408///
409/// # Reference
410///
411/// - <https://www.okx.com/en-au/help/iv-isolated-margin-mode>
412/// - <https://www.okx.com/en-au/help/iii-single-currency-margin-cross-margin-trading>
413/// - <https://www.okx.com/en-au/help/iv-multi-currency-margin-mode-cross-margin-trading>
414#[derive(
415    Copy,
416    Clone,
417    Default,
418    Debug,
419    Display,
420    PartialEq,
421    Eq,
422    Hash,
423    AsRefStr,
424    EnumIter,
425    EnumString,
426    Serialize,
427    Deserialize,
428)]
429#[serde(rename_all = "snake_case")]
430#[cfg_attr(
431    feature = "python",
432    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.okx")
433)]
434pub enum OKXMarginMode {
435    #[serde(rename = "")]
436    #[default]
437    None,
438    Isolated,
439    Cross,
440}
441
442/// Represents the position mode for OKX accounts.
443///
444/// # References
445///
446/// <https://www.okx.com/docs-v5/en/#trading-account-rest-api-set-position-mode>
447#[derive(
448    Copy,
449    Clone,
450    Default,
451    Debug,
452    Display,
453    PartialEq,
454    Eq,
455    Hash,
456    AsRefStr,
457    EnumIter,
458    EnumString,
459    Serialize,
460    Deserialize,
461)]
462#[cfg_attr(
463    feature = "python",
464    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.okx")
465)]
466pub enum OKXPositionMode {
467    #[default]
468    #[serde(rename = "net_mode")]
469    NetMode,
470    #[serde(rename = "long_short_mode")]
471    LongShortMode,
472}
473
474#[derive(
475    Copy,
476    Clone,
477    Debug,
478    Display,
479    PartialEq,
480    Eq,
481    Hash,
482    AsRefStr,
483    EnumIter,
484    EnumString,
485    Serialize,
486    Deserialize,
487)]
488#[serde(rename_all = "snake_case")]
489pub enum OKXPositionSide {
490    #[serde(rename = "")]
491    None,
492    Net,
493    Long,
494    Short,
495}
496
497#[derive(
498    Copy,
499    Clone,
500    Debug,
501    Display,
502    PartialEq,
503    Eq,
504    Hash,
505    AsRefStr,
506    EnumIter,
507    EnumString,
508    Serialize,
509    Deserialize,
510)]
511#[serde(rename_all = "snake_case")]
512pub enum OKXSelfTradePreventionMode {
513    #[serde(rename = "")]
514    None,
515    CancelMaker,
516    CancelTaker,
517    CancelBoth,
518}
519
520#[derive(
521    Copy,
522    Clone,
523    Debug,
524    Display,
525    PartialEq,
526    Eq,
527    Hash,
528    AsRefStr,
529    EnumIter,
530    EnumString,
531    Serialize,
532    Deserialize,
533)]
534#[serde(rename_all = "snake_case")]
535pub enum OKXTakeProfitKind {
536    #[serde(rename = "")]
537    None,
538    Condition,
539    Limit,
540}
541
542#[derive(
543    Copy,
544    Clone,
545    Debug,
546    Display,
547    PartialEq,
548    Eq,
549    Hash,
550    AsRefStr,
551    EnumIter,
552    EnumString,
553    Serialize,
554    Deserialize,
555)]
556#[serde(rename_all = "snake_case")]
557pub enum OKXTriggerType {
558    #[serde(rename = "")]
559    None,
560    Last,
561    Index,
562    Mark,
563}
564
565impl From<TriggerType> for OKXTriggerType {
566    fn from(value: TriggerType) -> Self {
567        match value {
568            TriggerType::LastPrice => Self::Last,
569            TriggerType::MarkPrice => Self::Mark,
570            TriggerType::IndexPrice => Self::Index,
571            _ => Self::Last,
572        }
573    }
574}
575
576/// Represents the target currency for order quantity.
577#[derive(
578    Copy,
579    Clone,
580    Debug,
581    Display,
582    PartialEq,
583    Eq,
584    Hash,
585    AsRefStr,
586    EnumIter,
587    EnumString,
588    Serialize,
589    Deserialize,
590)]
591#[serde(rename_all = "snake_case")]
592#[strum(serialize_all = "snake_case")]
593pub enum OKXTargetCurrency {
594    /// Base currency.
595    BaseCcy,
596    /// Quote currency.
597    QuoteCcy,
598}
599
600/// Represents an OKX order book channel.
601#[derive(Copy, Clone, Debug, PartialEq, Eq)]
602pub enum OKXBookChannel {
603    /// Standard depth-first book channel (`books`).
604    Book,
605    /// Low-latency 400-depth channel (`books-l2-tbt`).
606    BookL2Tbt,
607    /// Low-latency 50-depth channel (`books50-l2-tbt`).
608    Books50L2Tbt,
609}
610
611/// Represents OKX VIP level tiers for trading fee structure and API limits.
612///
613/// VIP levels determine:
614/// - Trading fee discounts.
615/// - API rate limits.
616/// - Access to advanced order book channels (L2/L3 depth).
617///
618/// Higher VIP levels (VIP4+) get access to:
619/// - "books50-l2-tbt" channel (50 depth, 10ms updates).
620/// - "bbo-tbt" channel (1 depth, 10ms updates).
621///
622/// VIP5+ get access to:
623/// - "books-l2-tbt" channel (400 depth, 10ms updates).
624#[derive(
625    Copy,
626    Clone,
627    Debug,
628    Display,
629    PartialEq,
630    Eq,
631    PartialOrd,
632    Ord,
633    Hash,
634    AsRefStr,
635    EnumIter,
636    EnumString,
637    Serialize,
638    Deserialize,
639)]
640#[cfg_attr(
641    feature = "python",
642    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.adapters")
643)]
644pub enum OKXVipLevel {
645    /// VIP level 0 (default tier).
646    #[serde(rename = "0")]
647    #[strum(serialize = "0")]
648    Vip0 = 0,
649    /// VIP level 1.
650    #[serde(rename = "1")]
651    #[strum(serialize = "1")]
652    Vip1 = 1,
653    /// VIP level 2.
654    #[serde(rename = "2")]
655    #[strum(serialize = "2")]
656    Vip2 = 2,
657    /// VIP level 3.
658    #[serde(rename = "3")]
659    #[strum(serialize = "3")]
660    Vip3 = 3,
661    /// VIP level 4 (can access books50-l2-tbt channel).
662    #[serde(rename = "4")]
663    #[strum(serialize = "4")]
664    Vip4 = 4,
665    /// VIP level 5 (can access books-l2-tbt channel).
666    #[serde(rename = "5")]
667    #[strum(serialize = "5")]
668    Vip5 = 5,
669    /// VIP level 6.
670    #[serde(rename = "6")]
671    #[strum(serialize = "6")]
672    Vip6 = 6,
673    /// VIP level 7.
674    #[serde(rename = "7")]
675    #[strum(serialize = "7")]
676    Vip7 = 7,
677    /// VIP level 8.
678    #[serde(rename = "8")]
679    #[strum(serialize = "8")]
680    Vip8 = 8,
681    /// VIP level 9 (highest tier).
682    #[serde(rename = "9")]
683    #[strum(serialize = "9")]
684    Vip9 = 9,
685}
686
687impl From<u8> for OKXVipLevel {
688    fn from(value: u8) -> Self {
689        match value {
690            0 => Self::Vip0,
691            1 => Self::Vip1,
692            2 => Self::Vip2,
693            3 => Self::Vip3,
694            4 => Self::Vip4,
695            5 => Self::Vip5,
696            6 => Self::Vip6,
697            7 => Self::Vip7,
698            8 => Self::Vip8,
699            9 => Self::Vip9,
700            _ => {
701                tracing::warn!("Invalid VIP level {value}, defaulting to Vip0");
702                Self::Vip0
703            }
704        }
705    }
706}
707
708impl From<OKXSide> for OrderSide {
709    fn from(side: OKXSide) -> Self {
710        match side {
711            OKXSide::Buy => Self::Buy,
712            OKXSide::Sell => Self::Sell,
713        }
714    }
715}
716
717impl From<OKXExecType> for LiquiditySide {
718    fn from(exec: OKXExecType) -> Self {
719        match exec {
720            OKXExecType::Maker => Self::Maker,
721            OKXExecType::Taker => Self::Taker,
722            OKXExecType::None => Self::NoLiquiditySide,
723        }
724    }
725}
726
727impl From<OKXPositionSide> for PositionSide {
728    fn from(side: OKXPositionSide) -> Self {
729        match side {
730            OKXPositionSide::Long => Self::Long,
731            OKXPositionSide::Short => Self::Short,
732            _ => Self::Flat,
733        }
734    }
735}
736
737impl From<OKXOrderStatus> for OrderStatus {
738    fn from(status: OKXOrderStatus) -> Self {
739        match status {
740            OKXOrderStatus::Live => Self::Accepted,
741            OKXOrderStatus::Effective => Self::Triggered,
742            OKXOrderStatus::PartiallyFilled => Self::PartiallyFilled,
743            OKXOrderStatus::Filled => Self::Filled,
744            OKXOrderStatus::Canceled | OKXOrderStatus::MmpCanceled => Self::Canceled,
745            OKXOrderStatus::OrderPlaced => Self::Triggered,
746        }
747    }
748}
749
750impl From<OKXOrderType> for OrderType {
751    fn from(ord_type: OKXOrderType) -> Self {
752        match ord_type {
753            OKXOrderType::Market => Self::Market,
754            OKXOrderType::Limit
755            | OKXOrderType::PostOnly
756            | OKXOrderType::OptimalLimitIoc
757            | OKXOrderType::Mmp
758            | OKXOrderType::MmpAndPostOnly
759            | OKXOrderType::Fok
760            | OKXOrderType::Ioc => Self::Limit,
761            OKXOrderType::Trigger => Self::StopMarket,
762        }
763    }
764}
765
766impl From<OrderType> for OKXOrderType {
767    fn from(value: OrderType) -> Self {
768        match value {
769            OrderType::Market => Self::Market,
770            OrderType::Limit => Self::Limit,
771            OrderType::MarketToLimit => Self::Ioc,
772            // Conditional orders will be handled separately via algo orders
773            OrderType::StopMarket
774            | OrderType::StopLimit
775            | OrderType::MarketIfTouched
776            | OrderType::LimitIfTouched => {
777                panic!("Conditional order types must use OKXAlgoOrderType")
778            }
779            _ => panic!("Invalid `OrderType` cannot be represented on OKX"),
780        }
781    }
782}
783
784impl From<PositionSide> for OKXPositionSide {
785    fn from(value: PositionSide) -> Self {
786        match value {
787            PositionSide::Long => Self::Long,
788            PositionSide::Short => Self::Short,
789            _ => Self::None,
790        }
791    }
792}
793
794#[derive(
795    Copy,
796    Clone,
797    Debug,
798    Display,
799    PartialEq,
800    Eq,
801    Hash,
802    AsRefStr,
803    EnumIter,
804    EnumString,
805    Serialize,
806    Deserialize,
807)]
808#[serde(rename_all = "snake_case")]
809pub enum OKXAlgoOrderType {
810    Conditional,
811    Oco,
812    Trigger,
813    MoveOrderStop,
814    Iceberg,
815    Twap,
816}
817
818/// Helper to determine if an order type requires algo order handling.
819pub fn is_conditional_order(order_type: OrderType) -> bool {
820    OKX_CONDITIONAL_ORDER_TYPES.contains(&order_type)
821}
822
823/// Converts Nautilus conditional order types to OKX algo order type.
824///
825/// # Errors
826///
827/// Returns an error if the provided `order_type` is not a conditional order type.
828pub fn conditional_order_to_algo_type(order_type: OrderType) -> anyhow::Result<OKXAlgoOrderType> {
829    match order_type {
830        OrderType::StopMarket
831        | OrderType::StopLimit
832        | OrderType::MarketIfTouched
833        | OrderType::LimitIfTouched => Ok(OKXAlgoOrderType::Trigger),
834        _ => anyhow::bail!("Not a conditional order type: {order_type:?}"),
835    }
836}
837
838#[derive(
839    Copy,
840    Clone,
841    Debug,
842    Display,
843    PartialEq,
844    Eq,
845    Hash,
846    AsRefStr,
847    EnumIter,
848    EnumString,
849    Serialize,
850    Deserialize,
851)]
852#[serde(rename_all = "snake_case")]
853pub enum OKXAlgoOrderStatus {
854    Live,
855    Pause,
856    PartiallyEffective,
857    Effective,
858    Canceled,
859    OrderFailed,
860    PartiallyFailed,
861}
862
863#[derive(
864    Copy,
865    Clone,
866    Debug,
867    Display,
868    PartialEq,
869    Eq,
870    Hash,
871    AsRefStr,
872    EnumIter,
873    EnumString,
874    Serialize,
875    Deserialize,
876)]
877pub enum OKXTransactionType {
878    #[serde(rename = "1")]
879    Buy,
880    #[serde(rename = "2")]
881    Sell,
882    #[serde(rename = "3")]
883    OpenLong,
884    #[serde(rename = "4")]
885    OpenShort,
886    #[serde(rename = "5")]
887    CloseLong,
888    #[serde(rename = "6")]
889    CloseShort,
890    #[serde(rename = "100")]
891    PartialLiquidationCloseLong,
892    #[serde(rename = "101")]
893    PartialLiquidationCloseShort,
894    #[serde(rename = "102")]
895    PartialLiquidationBuy,
896    #[serde(rename = "103")]
897    PartialLiquidationSell,
898    #[serde(rename = "104")]
899    LiquidationLong,
900    #[serde(rename = "105")]
901    LiquidationShort,
902    #[serde(rename = "106")]
903    LiquidationBuy,
904    #[serde(rename = "107")]
905    LiquidationSell,
906    #[serde(rename = "110")]
907    LiquidationTransferIn,
908    #[serde(rename = "111")]
909    LiquidationTransferOut,
910    #[serde(rename = "118")]
911    SystemTokenConversionTransferIn,
912    #[serde(rename = "119")]
913    SystemTokenConversionTransferOut,
914    #[serde(rename = "125")]
915    AdlCloseLong,
916    #[serde(rename = "126")]
917    AdlCloseShort,
918    #[serde(rename = "127")]
919    AdlBuy,
920    #[serde(rename = "128")]
921    AdlSell,
922    #[serde(rename = "212")]
923    AutoBorrowOfQuickMargin,
924    #[serde(rename = "213")]
925    AutoRepayOfQuickMargin,
926    #[serde(rename = "204")]
927    BlockTradeBuy,
928    #[serde(rename = "205")]
929    BlockTradeSell,
930    #[serde(rename = "206")]
931    BlockTradeOpenLong,
932    #[serde(rename = "207")]
933    BlockTradeOpenShort,
934    #[serde(rename = "208")]
935    BlockTradeCloseOpen,
936    #[serde(rename = "209")]
937    BlockTradeCloseShort,
938    #[serde(rename = "270")]
939    SpreadTradingBuy,
940    #[serde(rename = "271")]
941    SpreadTradingSell,
942    #[serde(rename = "272")]
943    SpreadTradingOpenLong,
944    #[serde(rename = "273")]
945    SpreadTradingOpenShort,
946    #[serde(rename = "274")]
947    SpreadTradingCloseLong,
948    #[serde(rename = "275")]
949    SpreadTradingCloseShort,
950}
951
952/// Represents the category of an order on OKX.
953///
954/// The category field indicates whether an order is a normal trade, liquidation,
955/// auto-deleveraging (ADL) event, or algorithmic order type. This is critical for
956/// risk management and proper handling of exchange-generated orders.
957///
958/// # References
959///
960/// <https://www.okx.com/docs-v5/en/#order-book-trading-ws-order-channel>
961#[derive(
962    Copy,
963    Clone,
964    Debug,
965    Display,
966    PartialEq,
967    Eq,
968    Hash,
969    AsRefStr,
970    EnumIter,
971    EnumString,
972    Serialize,
973    Deserialize,
974)]
975#[serde(rename_all = "snake_case")]
976pub enum OKXOrderCategory {
977    /// Normal trading order.
978    Normal,
979    /// Full liquidation order (position completely closed by exchange).
980    FullLiquidation,
981    /// Partial liquidation order (position partially closed by exchange).
982    PartialLiquidation,
983    /// Auto-deleveraging order (position closed to offset counterparty liquidation).
984    Adl,
985    /// Time-Weighted Average Price algorithmic order.
986    Twap,
987    /// Iceberg algorithmic order (hidden quantity).
988    Iceberg,
989    /// One-Cancels-the-Other algorithmic order.
990    Oco,
991    /// Conditional/trigger order.
992    Conditional,
993    /// Move order stop algorithmic order.
994    MoveOrderStop,
995    /// Delivery and exercise (for futures/options settlement).
996    Ddh,
997    /// Unknown or future category (graceful fallback).
998    #[serde(other)]
999    Other,
1000}
1001
1002#[derive(
1003    Copy,
1004    Clone,
1005    Debug,
1006    Display,
1007    PartialEq,
1008    Eq,
1009    Hash,
1010    AsRefStr,
1011    EnumIter,
1012    EnumString,
1013    Serialize,
1014    Deserialize,
1015)]
1016pub enum OKXBarSize {
1017    #[serde(rename = "1s")]
1018    Second1,
1019    #[serde(rename = "1m")]
1020    Minute1,
1021    #[serde(rename = "3m")]
1022    Minute3,
1023    #[serde(rename = "5m")]
1024    Minute5,
1025    #[serde(rename = "15m")]
1026    Minute15,
1027    #[serde(rename = "30m")]
1028    Minute30,
1029    #[serde(rename = "1H")]
1030    Hour1,
1031    #[serde(rename = "2H")]
1032    Hour2,
1033    #[serde(rename = "4H")]
1034    Hour4,
1035    #[serde(rename = "6H")]
1036    Hour6,
1037    #[serde(rename = "12H")]
1038    Hour12,
1039    #[serde(rename = "1D")]
1040    Day1,
1041    #[serde(rename = "2D")]
1042    Day2,
1043    #[serde(rename = "3D")]
1044    Day3,
1045    #[serde(rename = "5D")]
1046    Day5,
1047    #[serde(rename = "1W")]
1048    Week1,
1049    #[serde(rename = "1M")]
1050    Month1,
1051    #[serde(rename = "3M")]
1052    Month3,
1053}