1use nautilus_model::enums::{
19 AggressorSide, GreeksConvention, LiquiditySide, OptionKind, OrderSide, OrderSideSpecified,
20 OrderStatus, OrderType, PositionSide, TriggerType,
21};
22use serde::{Deserialize, Serialize};
23use strum::{AsRefStr, Display, EnumIter, EnumString};
24
25use crate::common::consts::{OKX_ADVANCE_ALGO_ORDER_TYPES, OKX_CONDITIONAL_ORDER_TYPES};
26
27#[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 Update,
46 Snapshot,
48}
49
50#[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 #[serde(rename = "0")]
68 Partial,
69 #[serde(rename = "1")]
71 Closed,
72}
73
74#[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,
93 Sell,
95}
96
97impl From<OrderSideSpecified> for OKXSide {
98 fn from(value: OrderSideSpecified) -> Self {
99 match value {
100 OrderSideSpecified::Buy => Self::Buy,
101 OrderSideSpecified::Sell => Self::Sell,
102 }
103 }
104}
105
106impl From<OKXSide> for AggressorSide {
107 fn from(value: OKXSide) -> Self {
108 match value {
109 OKXSide::Buy => Self::Buyer,
110 OKXSide::Sell => Self::Seller,
111 }
112 }
113}
114
115#[derive(
117 Copy,
118 Clone,
119 Debug,
120 Display,
121 PartialEq,
122 Eq,
123 Hash,
124 AsRefStr,
125 EnumIter,
126 EnumString,
127 Serialize,
128 Deserialize,
129)]
130#[serde(rename_all = "snake_case")]
131pub enum OKXOrderType {
132 Market,
134 Limit,
136 PostOnly, Fok, Ioc, OptimalLimitIoc, Mmp, MmpAndPostOnly, OpFok, Trigger, }
145
146#[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(
165 eq,
166 eq_int,
167 module = "nautilus_trader.core.nautilus_pyo3.okx",
168 from_py_object,
169 rename_all = "SCREAMING_SNAKE_CASE",
170 )
171)]
172#[cfg_attr(
173 feature = "python",
174 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.okx")
175)]
176pub enum OKXOrderStatus {
177 Canceled,
178 Live,
179 PartiallyFilled,
180 Filled,
181 MmpCanceled,
182}
183
184impl TryFrom<OrderStatus> for OKXOrderStatus {
185 type Error = OrderStatus;
186
187 fn try_from(value: OrderStatus) -> Result<Self, Self::Error> {
193 match value {
194 OrderStatus::Canceled => Ok(Self::Canceled),
195 OrderStatus::Accepted => Ok(Self::Live),
196 OrderStatus::PartiallyFilled => Ok(Self::PartiallyFilled),
197 OrderStatus::Filled => Ok(Self::Filled),
198 other => Err(other),
199 }
200 }
201}
202
203#[derive(
205 Copy,
206 Clone,
207 Debug,
208 Default,
209 Display,
210 PartialEq,
211 Eq,
212 Hash,
213 AsRefStr,
214 EnumIter,
215 EnumString,
216 Serialize,
217 Deserialize,
218)]
219pub enum OKXExecType {
220 #[serde(rename = "")]
221 #[default]
222 None,
223 #[serde(rename = "T")]
224 Taker,
225 #[serde(rename = "M")]
226 Maker,
227}
228
229impl From<LiquiditySide> for OKXExecType {
230 fn from(value: LiquiditySide) -> Self {
231 match value {
232 LiquiditySide::NoLiquiditySide => Self::None,
233 LiquiditySide::Taker => Self::Taker,
234 LiquiditySide::Maker => Self::Maker,
235 }
236 }
237}
238
239#[derive(
241 Copy,
242 Clone,
243 Debug,
244 Display,
245 Default,
246 PartialEq,
247 Eq,
248 Hash,
249 AsRefStr,
250 EnumIter,
251 EnumString,
252 Serialize,
253 Deserialize,
254)]
255#[serde(rename_all = "UPPERCASE")]
256#[cfg_attr(
257 feature = "python",
258 pyo3::pyclass(
259 eq,
260 eq_int,
261 module = "nautilus_trader.core.nautilus_pyo3.okx",
262 from_py_object,
263 rename_all = "SCREAMING_SNAKE_CASE",
264 )
265)]
266#[cfg_attr(
267 feature = "python",
268 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.okx")
269)]
270pub enum OKXInstrumentType {
271 #[default]
272 Any,
274 Spot,
276 Margin,
278 Swap,
280 Futures,
282 Option,
284 Events,
286}
287
288#[derive(
295 Copy,
296 Clone,
297 Debug,
298 Default,
299 Display,
300 PartialEq,
301 Eq,
302 Hash,
303 AsRefStr,
304 EnumIter,
305 EnumString,
306 Serialize,
307 Deserialize,
308)]
309pub enum OKXInstrumentCategory {
310 #[serde(rename = "1")]
312 #[strum(serialize = "1")]
313 Crypto,
314 #[serde(rename = "3")]
316 #[strum(serialize = "3")]
317 Equity,
318 #[serde(rename = "4")]
320 #[strum(serialize = "4")]
321 Commodity,
322 #[serde(rename = "5")]
324 #[strum(serialize = "5")]
325 Fx,
326 #[serde(rename = "6")]
328 #[strum(serialize = "6")]
329 Debt,
330 #[default]
332 #[serde(other)]
333 #[strum(serialize = "")]
334 Unknown,
335}
336
337#[derive(
339 Copy,
340 Clone,
341 Debug,
342 Display,
343 PartialEq,
344 Eq,
345 Hash,
346 AsRefStr,
347 EnumIter,
348 EnumString,
349 Serialize,
350 Deserialize,
351)]
352#[serde(rename_all = "snake_case")]
353pub enum OKXInstrumentStatus {
354 Live,
355 Suspend,
356 Preopen,
357 Test,
358 PostOnly,
359 Rebase,
360 Settling,
361 #[serde(other)]
363 Unknown,
364}
365
366#[derive(
368 Copy,
369 Clone,
370 Debug,
371 Display,
372 PartialEq,
373 Eq,
374 Hash,
375 AsRefStr,
376 EnumIter,
377 EnumString,
378 Serialize,
379 Deserialize,
380)]
381#[serde(rename_all = "snake_case")]
382pub enum OKXSpreadType {
383 Linear,
384 Inverse,
385 Hybrid,
386 #[serde(other)]
388 Unknown,
389}
390
391#[derive(
393 Copy,
394 Clone,
395 Debug,
396 Display,
397 PartialEq,
398 Eq,
399 Hash,
400 AsRefStr,
401 EnumIter,
402 EnumString,
403 Serialize,
404 Deserialize,
405)]
406#[serde(rename_all = "snake_case")]
407pub enum OKXSpreadState {
408 Live,
409 Suspend,
410 Expired,
411 #[serde(other)]
413 Unknown,
414}
415
416#[derive(
418 Copy,
419 Clone,
420 Default,
421 Debug,
422 Display,
423 PartialEq,
424 Eq,
425 Hash,
426 AsRefStr,
427 EnumIter,
428 EnumString,
429 Serialize,
430 Deserialize,
431)]
432#[serde(rename_all = "snake_case")]
433#[cfg_attr(
434 feature = "python",
435 pyo3::pyclass(
436 eq,
437 eq_int,
438 module = "nautilus_trader.core.nautilus_pyo3.okx",
439 from_py_object,
440 rename_all = "SCREAMING_SNAKE_CASE",
441 )
442)]
443#[cfg_attr(
444 feature = "python",
445 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.okx")
446)]
447pub enum OKXContractType {
448 #[serde(rename = "")]
449 #[default]
450 None,
451 Linear,
452 Inverse,
453}
454
455#[derive(
457 Copy,
458 Clone,
459 Debug,
460 Display,
461 PartialEq,
462 Eq,
463 Hash,
464 AsRefStr,
465 EnumIter,
466 EnumString,
467 Serialize,
468 Deserialize,
469)]
470pub enum OKXOptionType {
471 #[serde(rename = "")]
472 None,
473 #[serde(rename = "C")]
474 Call,
475 #[serde(rename = "P")]
476 Put,
477}
478
479impl TryFrom<OKXOptionType> for OptionKind {
480 type Error = OKXOptionType;
481
482 fn try_from(option_type: OKXOptionType) -> Result<Self, Self::Error> {
489 match option_type {
490 OKXOptionType::Call => Ok(Self::Call),
491 OKXOptionType::Put => Ok(Self::Put),
492 other => Err(other),
493 }
494 }
495}
496
497#[derive(
503 Copy,
504 Clone,
505 Debug,
506 Default,
507 Display,
508 PartialEq,
509 Eq,
510 Hash,
511 AsRefStr,
512 EnumIter,
513 EnumString,
514 Serialize,
515 Deserialize,
516)]
517#[serde(rename_all = "UPPERCASE")]
518#[strum(serialize_all = "UPPERCASE", ascii_case_insensitive)]
519#[cfg_attr(
520 feature = "python",
521 pyo3::pyclass(
522 eq,
523 eq_int,
524 module = "nautilus_trader.core.nautilus_pyo3.okx",
525 from_py_object,
526 rename_all = "SCREAMING_SNAKE_CASE",
527 )
528)]
529#[cfg_attr(
530 feature = "python",
531 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.okx")
532)]
533pub enum OKXGreeksType {
534 #[default]
536 Bs = 0,
537 Pa = 1,
539}
540
541impl From<u8> for OKXGreeksType {
542 fn from(value: u8) -> Self {
543 match value {
544 0 => Self::Bs,
545 1 => Self::Pa,
546 _ => {
547 log::warn!("Invalid OKXGreeksType {value}, defaulting to Bs");
548 Self::Bs
549 }
550 }
551 }
552}
553
554impl From<GreeksConvention> for OKXGreeksType {
555 fn from(convention: GreeksConvention) -> Self {
556 match convention {
557 GreeksConvention::BlackScholes => Self::Bs,
558 GreeksConvention::PriceAdjusted => Self::Pa,
559 }
560 }
561}
562
563impl From<OKXGreeksType> for GreeksConvention {
564 fn from(greeks_type: OKXGreeksType) -> Self {
565 match greeks_type {
566 OKXGreeksType::Bs => Self::BlackScholes,
567 OKXGreeksType::Pa => Self::PriceAdjusted,
568 }
569 }
570}
571
572#[derive(
574 Copy,
575 Clone,
576 Debug,
577 Display,
578 Default,
579 PartialEq,
580 Eq,
581 Hash,
582 AsRefStr,
583 EnumIter,
584 EnumString,
585 Serialize,
586 Deserialize,
587)]
588#[serde(rename_all = "snake_case")]
589#[strum(ascii_case_insensitive)]
590#[cfg_attr(
591 feature = "python",
592 pyo3::pyclass(
593 eq,
594 eq_int,
595 module = "nautilus_trader.core.nautilus_pyo3.okx",
596 from_py_object,
597 rename_all = "SCREAMING_SNAKE_CASE",
598 )
599)]
600#[cfg_attr(
601 feature = "python",
602 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.okx")
603)]
604pub enum OKXTradeMode {
605 #[default]
606 Cash,
607 Isolated,
608 Cross,
609 #[strum(serialize = "spot_isolated")]
610 SpotIsolated,
611}
612
613#[derive(
619 Copy,
620 Clone,
621 Debug,
622 Display,
623 PartialEq,
624 Eq,
625 Hash,
626 AsRefStr,
627 EnumIter,
628 EnumString,
629 Serialize,
630 Deserialize,
631)]
632pub enum OKXAccountMode {
633 #[serde(rename = "Spot mode")]
634 Spot,
635 #[serde(rename = "Spot and futures mode")]
636 SpotAndFutures,
637 #[serde(rename = "Multi-currency margin mode")]
638 MultiCurrencyMarginMode,
639 #[serde(rename = "Portfolio margin mode")]
640 PortfolioMarginMode,
641}
642
643#[derive(
651 Copy,
652 Clone,
653 Default,
654 Debug,
655 Display,
656 PartialEq,
657 Eq,
658 Hash,
659 AsRefStr,
660 EnumIter,
661 EnumString,
662 Serialize,
663 Deserialize,
664)]
665#[serde(rename_all = "snake_case")]
666#[cfg_attr(
667 feature = "python",
668 pyo3::pyclass(
669 eq,
670 eq_int,
671 module = "nautilus_trader.core.nautilus_pyo3.okx",
672 from_py_object,
673 rename_all = "SCREAMING_SNAKE_CASE",
674 )
675)]
676#[cfg_attr(
677 feature = "python",
678 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.okx")
679)]
680pub enum OKXMarginMode {
681 #[serde(rename = "")]
682 #[default]
683 None,
684 Isolated,
685 Cross,
686}
687
688#[derive(
694 Copy,
695 Clone,
696 Default,
697 Debug,
698 Display,
699 PartialEq,
700 Eq,
701 Hash,
702 AsRefStr,
703 EnumIter,
704 EnumString,
705 Serialize,
706 Deserialize,
707)]
708#[cfg_attr(
709 feature = "python",
710 pyo3::pyclass(
711 eq,
712 eq_int,
713 module = "nautilus_trader.core.nautilus_pyo3.okx",
714 from_py_object,
715 rename_all = "SCREAMING_SNAKE_CASE",
716 )
717)]
718#[cfg_attr(
719 feature = "python",
720 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.okx")
721)]
722pub enum OKXPositionMode {
723 #[default]
724 #[serde(rename = "net_mode")]
725 NetMode,
726 #[serde(rename = "long_short_mode")]
727 LongShortMode,
728}
729
730#[derive(
731 Copy,
732 Clone,
733 Debug,
734 Display,
735 PartialEq,
736 Eq,
737 Hash,
738 AsRefStr,
739 EnumIter,
740 EnumString,
741 Serialize,
742 Deserialize,
743)]
744#[serde(rename_all = "snake_case")]
745pub enum OKXPositionSide {
746 #[serde(rename = "")]
747 None,
748 Net,
749 Long,
750 Short,
751}
752
753#[derive(
754 Copy,
755 Clone,
756 Debug,
757 Default,
758 Display,
759 PartialEq,
760 Eq,
761 Hash,
762 AsRefStr,
763 EnumIter,
764 EnumString,
765 Serialize,
766 Deserialize,
767)]
768#[serde(rename_all = "snake_case")]
769pub enum OKXSelfTradePreventionMode {
770 #[default]
771 #[serde(rename = "")]
772 None,
773 CancelMaker,
774 CancelTaker,
775 CancelBoth,
776}
777
778#[derive(
779 Copy,
780 Clone,
781 Debug,
782 Display,
783 PartialEq,
784 Eq,
785 Hash,
786 AsRefStr,
787 EnumIter,
788 EnumString,
789 Serialize,
790 Deserialize,
791)]
792#[serde(rename_all = "snake_case")]
793pub enum OKXTakeProfitKind {
794 #[serde(rename = "")]
795 None,
796 Condition,
797 Limit,
798}
799
800#[derive(
801 Copy,
802 Clone,
803 Debug,
804 Default,
805 Display,
806 PartialEq,
807 Eq,
808 Hash,
809 AsRefStr,
810 EnumIter,
811 EnumString,
812 Serialize,
813 Deserialize,
814)]
815#[serde(rename_all = "snake_case")]
816#[strum(serialize_all = "snake_case", ascii_case_insensitive)]
817pub enum OKXTriggerType {
818 #[default]
819 #[serde(rename = "")]
820 None,
821 Last,
822 Index,
823 Mark,
824}
825
826impl From<TriggerType> for OKXTriggerType {
827 fn from(value: TriggerType) -> Self {
828 match value {
829 TriggerType::LastPrice => Self::Last,
830 TriggerType::MarkPrice => Self::Mark,
831 TriggerType::IndexPrice => Self::Index,
832 _ => Self::Last,
833 }
834 }
835}
836
837#[cfg(test)]
838mod tests {
839 use std::str::FromStr;
840
841 use nautilus_model::enums::{GreeksConvention, OptionKind, OrderStatus};
842 use rstest::rstest;
843
844 use super::{OKXGreeksType, OKXOptionType, OKXOrderStatus, OKXOrderType, OKXTriggerType};
845
846 #[rstest]
847 fn test_okx_trigger_type_from_str_accepts_snake_case_values() {
848 assert_eq!(
849 OKXTriggerType::from_str("last").unwrap(),
850 OKXTriggerType::Last
851 );
852 assert_eq!(
853 OKXTriggerType::from_str("mark").unwrap(),
854 OKXTriggerType::Mark
855 );
856 assert_eq!(
857 OKXTriggerType::from_str("index").unwrap(),
858 OKXTriggerType::Index
859 );
860 }
861
862 #[rstest]
863 #[case(OKXGreeksType::Bs, "\"BS\"")]
864 #[case(OKXGreeksType::Pa, "\"PA\"")]
865 fn test_greeks_type_serde_roundtrip(#[case] input: OKXGreeksType, #[case] expected: &str) {
866 let json = serde_json::to_string(&input).unwrap();
867 assert_eq!(json, expected);
868 let parsed: OKXGreeksType = serde_json::from_str(expected).unwrap();
869 assert_eq!(parsed, input);
870 }
871
872 #[rstest]
873 fn test_greeks_type_default_is_bs() {
874 assert_eq!(OKXGreeksType::default(), OKXGreeksType::Bs);
875 }
876
877 #[rstest]
878 fn test_greeks_type_from_u8() {
879 assert_eq!(OKXGreeksType::from(0_u8), OKXGreeksType::Bs);
880 assert_eq!(OKXGreeksType::from(1_u8), OKXGreeksType::Pa);
881 assert_eq!(OKXGreeksType::from(99_u8), OKXGreeksType::Bs);
882 }
883
884 #[rstest]
885 #[case(GreeksConvention::BlackScholes, OKXGreeksType::Bs)]
886 #[case(GreeksConvention::PriceAdjusted, OKXGreeksType::Pa)]
887 fn test_greeks_type_convention_roundtrip(
888 #[case] convention: GreeksConvention,
889 #[case] expected: OKXGreeksType,
890 ) {
891 let mapped: OKXGreeksType = convention.into();
892 assert_eq!(mapped, expected);
893 let back: GreeksConvention = mapped.into();
894 assert_eq!(back, convention);
895 }
896
897 #[rstest]
898 fn test_op_fok_serializes_to_snake_case() {
899 let json = serde_json::to_string(&OKXOrderType::OpFok).unwrap();
900 assert_eq!(json, "\"op_fok\"");
901 }
902
903 #[rstest]
904 fn test_op_fok_deserializes_from_snake_case() {
905 let parsed: OKXOrderType = serde_json::from_str("\"op_fok\"").unwrap();
906 assert_eq!(parsed, OKXOrderType::OpFok);
907 }
908
909 #[rstest]
910 fn test_op_fok_converts_to_limit_order_type() {
911 use nautilus_model::enums::OrderType;
912 let order_type: OrderType = OKXOrderType::OpFok.into();
913 assert_eq!(order_type, OrderType::Limit);
914 }
915
916 #[rstest]
917 #[case::call(OKXOptionType::Call, Ok(OptionKind::Call))]
918 #[case::put(OKXOptionType::Put, Ok(OptionKind::Put))]
919 #[case::none(OKXOptionType::None, Err(OKXOptionType::None))]
920 fn test_try_from_okx_option_type(
921 #[case] input: OKXOptionType,
922 #[case] expected: Result<OptionKind, OKXOptionType>,
923 ) {
924 let actual: Result<OptionKind, OKXOptionType> = input.try_into();
925 assert_eq!(actual, expected);
926 }
927
928 #[rstest]
929 #[case::canceled(OrderStatus::Canceled, Ok(OKXOrderStatus::Canceled))]
930 #[case::accepted(OrderStatus::Accepted, Ok(OKXOrderStatus::Live))]
931 #[case::partially_filled(OrderStatus::PartiallyFilled, Ok(OKXOrderStatus::PartiallyFilled))]
932 #[case::filled(OrderStatus::Filled, Ok(OKXOrderStatus::Filled))]
933 #[case::submitted(OrderStatus::Submitted, Err(OrderStatus::Submitted))]
934 #[case::pending_update(OrderStatus::PendingUpdate, Err(OrderStatus::PendingUpdate))]
935 #[case::pending_cancel(OrderStatus::PendingCancel, Err(OrderStatus::PendingCancel))]
936 #[case::triggered(OrderStatus::Triggered, Err(OrderStatus::Triggered))]
937 #[case::expired(OrderStatus::Expired, Err(OrderStatus::Expired))]
938 #[case::rejected(OrderStatus::Rejected, Err(OrderStatus::Rejected))]
939 fn test_try_from_order_status(
940 #[case] input: OrderStatus,
941 #[case] expected: Result<OKXOrderStatus, OrderStatus>,
942 ) {
943 let actual: Result<OKXOrderStatus, OrderStatus> = input.try_into();
944 assert_eq!(actual, expected);
945 }
946}
947
948#[derive(
950 Copy,
951 Clone,
952 Debug,
953 Display,
954 PartialEq,
955 Eq,
956 Hash,
957 AsRefStr,
958 EnumIter,
959 EnumString,
960 Serialize,
961 Deserialize,
962)]
963#[serde(rename_all = "snake_case")]
964#[strum(serialize_all = "snake_case")]
965pub enum OKXTargetCurrency {
966 BaseCcy,
968 QuoteCcy,
970}
971
972#[derive(Copy, Clone, Debug, PartialEq, Eq)]
974pub enum OKXBookChannel {
975 Book,
977 BookL2Tbt,
979 Books50L2Tbt,
981}
982
983#[derive(
997 Copy,
998 Clone,
999 Debug,
1000 Display,
1001 PartialEq,
1002 Eq,
1003 PartialOrd,
1004 Ord,
1005 Hash,
1006 AsRefStr,
1007 EnumIter,
1008 EnumString,
1009 Serialize,
1010 Deserialize,
1011)]
1012#[cfg_attr(
1013 feature = "python",
1014 pyo3::pyclass(
1015 module = "nautilus_trader.core.nautilus_pyo3.okx",
1016 from_py_object,
1017 rename_all = "SCREAMING_SNAKE_CASE",
1018 )
1019)]
1020#[cfg_attr(
1021 feature = "python",
1022 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.okx")
1023)]
1024pub enum OKXVipLevel {
1025 #[serde(rename = "0")]
1027 #[strum(serialize = "0")]
1028 Vip0 = 0,
1029 #[serde(rename = "1")]
1031 #[strum(serialize = "1")]
1032 Vip1 = 1,
1033 #[serde(rename = "2")]
1035 #[strum(serialize = "2")]
1036 Vip2 = 2,
1037 #[serde(rename = "3")]
1039 #[strum(serialize = "3")]
1040 Vip3 = 3,
1041 #[serde(rename = "4")]
1043 #[strum(serialize = "4")]
1044 Vip4 = 4,
1045 #[serde(rename = "5")]
1047 #[strum(serialize = "5")]
1048 Vip5 = 5,
1049 #[serde(rename = "6")]
1051 #[strum(serialize = "6")]
1052 Vip6 = 6,
1053 #[serde(rename = "7")]
1055 #[strum(serialize = "7")]
1056 Vip7 = 7,
1057 #[serde(rename = "8")]
1059 #[strum(serialize = "8")]
1060 Vip8 = 8,
1061 #[serde(rename = "9")]
1063 #[strum(serialize = "9")]
1064 Vip9 = 9,
1065}
1066
1067impl From<u8> for OKXVipLevel {
1068 fn from(value: u8) -> Self {
1069 match value {
1070 0 => Self::Vip0,
1071 1 => Self::Vip1,
1072 2 => Self::Vip2,
1073 3 => Self::Vip3,
1074 4 => Self::Vip4,
1075 5 => Self::Vip5,
1076 6 => Self::Vip6,
1077 7 => Self::Vip7,
1078 8 => Self::Vip8,
1079 9 => Self::Vip9,
1080 _ => {
1081 log::warn!("Invalid VIP level {value}, defaulting to Vip0");
1082 Self::Vip0
1083 }
1084 }
1085 }
1086}
1087
1088impl From<OKXSide> for OrderSide {
1089 fn from(side: OKXSide) -> Self {
1090 match side {
1091 OKXSide::Buy => Self::Buy,
1092 OKXSide::Sell => Self::Sell,
1093 }
1094 }
1095}
1096
1097impl From<OKXExecType> for LiquiditySide {
1098 fn from(exec: OKXExecType) -> Self {
1099 match exec {
1100 OKXExecType::Maker => Self::Maker,
1101 OKXExecType::Taker => Self::Taker,
1102 OKXExecType::None => Self::NoLiquiditySide,
1103 }
1104 }
1105}
1106
1107impl From<OKXPositionSide> for PositionSide {
1108 fn from(side: OKXPositionSide) -> Self {
1109 match side {
1110 OKXPositionSide::Long => Self::Long,
1111 OKXPositionSide::Short => Self::Short,
1112 _ => Self::Flat,
1113 }
1114 }
1115}
1116
1117impl From<OKXOrderStatus> for OrderStatus {
1118 fn from(status: OKXOrderStatus) -> Self {
1119 match status {
1120 OKXOrderStatus::Live => Self::Accepted,
1121 OKXOrderStatus::PartiallyFilled => Self::PartiallyFilled,
1122 OKXOrderStatus::Filled => Self::Filled,
1123 OKXOrderStatus::Canceled | OKXOrderStatus::MmpCanceled => Self::Canceled,
1124 }
1125 }
1126}
1127
1128impl From<OKXAlgoOrderStatus> for OrderStatus {
1129 fn from(status: OKXAlgoOrderStatus) -> Self {
1130 match status {
1131 OKXAlgoOrderStatus::Live | OKXAlgoOrderStatus::Pause => Self::Accepted,
1132 OKXAlgoOrderStatus::Effective
1133 | OKXAlgoOrderStatus::OrderPlaced
1134 | OKXAlgoOrderStatus::PartiallyEffective => Self::Triggered,
1135 OKXAlgoOrderStatus::Filled => Self::Filled,
1136 OKXAlgoOrderStatus::Canceled => Self::Canceled,
1137 OKXAlgoOrderStatus::OrderFailed | OKXAlgoOrderStatus::PartiallyFailed => Self::Rejected,
1138 }
1139 }
1140}
1141
1142impl From<OKXOrderType> for OrderType {
1143 fn from(ord_type: OKXOrderType) -> Self {
1144 match ord_type {
1145 OKXOrderType::Market => Self::Market,
1146 OKXOrderType::Limit
1147 | OKXOrderType::PostOnly
1148 | OKXOrderType::OptimalLimitIoc
1149 | OKXOrderType::Mmp
1150 | OKXOrderType::MmpAndPostOnly
1151 | OKXOrderType::Fok
1152 | OKXOrderType::OpFok
1153 | OKXOrderType::Ioc => Self::Limit,
1154 OKXOrderType::Trigger => Self::StopMarket,
1155 }
1156 }
1157}
1158
1159impl From<OrderType> for OKXOrderType {
1160 fn from(value: OrderType) -> Self {
1161 match value {
1162 OrderType::Market => Self::Market,
1163 OrderType::Limit => Self::Limit,
1164 OrderType::MarketToLimit => Self::Ioc,
1165 OrderType::StopMarket
1167 | OrderType::StopLimit
1168 | OrderType::MarketIfTouched
1169 | OrderType::LimitIfTouched
1170 | OrderType::TrailingStopMarket => {
1171 panic!("Conditional order types must use OKXAlgoOrderType")
1172 }
1173 _ => panic!("Invalid `OrderType` cannot be represented on OKX: {value:?}"),
1174 }
1175 }
1176}
1177
1178impl From<PositionSide> for OKXPositionSide {
1179 fn from(value: PositionSide) -> Self {
1180 match value {
1181 PositionSide::Long => Self::Long,
1182 PositionSide::Short => Self::Short,
1183 _ => Self::None,
1184 }
1185 }
1186}
1187
1188#[derive(
1189 Copy,
1190 Clone,
1191 Debug,
1192 Display,
1193 PartialEq,
1194 Eq,
1195 Hash,
1196 AsRefStr,
1197 EnumIter,
1198 EnumString,
1199 Serialize,
1200 Deserialize,
1201)]
1202#[serde(rename_all = "snake_case")]
1203pub enum OKXAlgoOrderType {
1204 Conditional,
1205 Oco,
1206 Trigger,
1207 MoveOrderStop,
1208 Iceberg,
1209 Twap,
1210}
1211
1212pub fn is_conditional_order(order_type: OrderType) -> bool {
1214 OKX_CONDITIONAL_ORDER_TYPES.contains(&order_type)
1215}
1216
1217pub fn is_advance_algo_order(order_type: OrderType) -> bool {
1219 OKX_ADVANCE_ALGO_ORDER_TYPES.contains(&order_type)
1220}
1221
1222pub fn conditional_order_to_algo_type(order_type: OrderType) -> anyhow::Result<OKXAlgoOrderType> {
1228 match order_type {
1229 OrderType::StopMarket
1230 | OrderType::StopLimit
1231 | OrderType::MarketIfTouched
1232 | OrderType::LimitIfTouched => Ok(OKXAlgoOrderType::Trigger),
1233 OrderType::TrailingStopMarket => Ok(OKXAlgoOrderType::MoveOrderStop),
1234 _ => anyhow::bail!("Not a conditional order type: {order_type:?}"),
1235 }
1236}
1237
1238#[derive(
1240 Copy,
1241 Clone,
1242 Debug,
1243 Display,
1244 PartialEq,
1245 Eq,
1246 Hash,
1247 AsRefStr,
1248 EnumIter,
1249 EnumString,
1250 Serialize,
1251 Deserialize,
1252)]
1253#[serde(rename_all = "snake_case")]
1254pub enum OKXAlgoOrderStatus {
1255 Live,
1256 Pause,
1257 Effective,
1258 OrderPlaced,
1259 PartiallyEffective,
1260 Canceled,
1261 Filled,
1262 OrderFailed,
1263 PartiallyFailed,
1264}
1265
1266#[derive(
1276 Copy,
1277 Clone,
1278 Debug,
1279 Display,
1280 PartialEq,
1281 Eq,
1282 Hash,
1283 AsRefStr,
1284 EnumIter,
1285 EnumString,
1286 Serialize,
1287 Deserialize,
1288)]
1289#[serde(rename_all = "snake_case")]
1290pub enum OKXOrderCategory {
1291 Normal,
1293 FullLiquidation,
1295 PartialLiquidation,
1297 Adl,
1299 Twap,
1301 Iceberg,
1303 Oco,
1305 Conditional,
1307 MoveOrderStop,
1309 Ddh,
1311 Delivery,
1313 #[serde(other)]
1315 Other,
1316}
1317
1318#[derive(
1319 Copy,
1320 Clone,
1321 Debug,
1322 Display,
1323 PartialEq,
1324 Eq,
1325 Hash,
1326 AsRefStr,
1327 EnumIter,
1328 EnumString,
1329 Serialize,
1330 Deserialize,
1331)]
1332pub enum OKXBarSize {
1333 #[serde(rename = "1s")]
1334 Second1,
1335 #[serde(rename = "1m")]
1336 Minute1,
1337 #[serde(rename = "3m")]
1338 Minute3,
1339 #[serde(rename = "5m")]
1340 Minute5,
1341 #[serde(rename = "15m")]
1342 Minute15,
1343 #[serde(rename = "30m")]
1344 Minute30,
1345 #[serde(rename = "1H")]
1346 Hour1,
1347 #[serde(rename = "2H")]
1348 Hour2,
1349 #[serde(rename = "4H")]
1350 Hour4,
1351 #[serde(rename = "6H")]
1352 Hour6,
1353 #[serde(rename = "12H")]
1354 Hour12,
1355 #[serde(rename = "1D")]
1356 Day1,
1357 #[serde(rename = "2D")]
1358 Day2,
1359 #[serde(rename = "3D")]
1360 Day3,
1361 #[serde(rename = "5D")]
1362 Day5,
1363 #[serde(rename = "1W")]
1364 Week1,
1365 #[serde(rename = "1M")]
1366 Month1,
1367 #[serde(rename = "3M")]
1368 Month3,
1369}
1370
1371#[derive(
1373 Copy,
1374 Clone,
1375 Debug,
1376 Default,
1377 Display,
1378 PartialEq,
1379 Eq,
1380 Hash,
1381 AsRefStr,
1382 EnumIter,
1383 EnumString,
1384 Serialize,
1385 Deserialize,
1386)]
1387#[serde(rename_all = "snake_case")]
1388pub enum OKXPriceType {
1389 #[default]
1391 #[serde(rename = "")]
1392 None,
1393 Px,
1395 Usd,
1397 Vol,
1399}
1400
1401#[derive(
1403 Copy,
1404 Clone,
1405 Debug,
1406 Default,
1407 Display,
1408 PartialEq,
1409 Eq,
1410 Hash,
1411 AsRefStr,
1412 EnumIter,
1413 EnumString,
1414 Serialize,
1415 Deserialize,
1416)]
1417#[serde(rename_all = "snake_case")]
1418pub enum OKXSettlementState {
1419 #[default]
1421 #[serde(rename = "")]
1422 None,
1423 Processing,
1425 Settled,
1427}
1428
1429#[derive(
1431 Copy,
1432 Clone,
1433 Debug,
1434 Default,
1435 Display,
1436 PartialEq,
1437 Eq,
1438 Hash,
1439 AsRefStr,
1440 EnumIter,
1441 EnumString,
1442 Serialize,
1443 Deserialize,
1444)]
1445#[serde(rename_all = "snake_case")]
1446pub enum OKXQuickMarginType {
1447 #[default]
1449 #[serde(rename = "")]
1450 None,
1451 Manual,
1453 AutoBorrow,
1455 AutoRepay,
1457}
1458
1459#[derive(
1461 Copy,
1462 Clone,
1463 Debug,
1464 Default,
1465 Display,
1466 PartialEq,
1467 Eq,
1468 Hash,
1469 AsRefStr,
1470 EnumIter,
1471 EnumString,
1472 Serialize,
1473 Deserialize,
1474)]
1475#[serde(rename_all = "lowercase")]
1476#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
1477#[cfg_attr(
1478 feature = "python",
1479 pyo3::pyclass(
1480 eq,
1481 eq_int,
1482 module = "nautilus_trader.core.nautilus_pyo3.okx",
1483 from_py_object,
1484 rename_all = "SCREAMING_SNAKE_CASE",
1485 )
1486)]
1487#[cfg_attr(
1488 feature = "python",
1489 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.okx")
1490)]
1491pub enum OKXEnvironment {
1492 #[default]
1494 Live,
1495 Demo,
1497}
1498
1499#[derive(
1505 Copy,
1506 Clone,
1507 Debug,
1508 Default,
1509 Display,
1510 PartialEq,
1511 Eq,
1512 Hash,
1513 AsRefStr,
1514 EnumIter,
1515 EnumString,
1516 Serialize,
1517 Deserialize,
1518)]
1519#[serde(rename_all = "lowercase")]
1520#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
1521#[cfg_attr(
1522 feature = "python",
1523 pyo3::pyclass(
1524 eq,
1525 eq_int,
1526 module = "nautilus_trader.core.nautilus_pyo3.okx",
1527 from_py_object,
1528 rename_all = "SCREAMING_SNAKE_CASE",
1529 )
1530)]
1531#[cfg_attr(
1532 feature = "python",
1533 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.okx")
1534)]
1535pub enum OKXRegion {
1536 #[default]
1538 Global,
1539 Eea,
1541 Us,
1543}