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.okx")
175)]
176pub enum OKXOrderStatus {
177 Canceled,
178 Live,
179 Effective,
180 PartiallyFilled,
181 Filled,
182 MmpCanceled,
183 OrderPlaced,
184}
185
186impl TryFrom<OrderStatus> for OKXOrderStatus {
187 type Error = OrderStatus;
188
189 fn try_from(value: OrderStatus) -> Result<Self, Self::Error> {
195 match value {
196 OrderStatus::Canceled => Ok(Self::Canceled),
197 OrderStatus::Accepted => Ok(Self::Live),
198 OrderStatus::PartiallyFilled => Ok(Self::PartiallyFilled),
199 OrderStatus::Filled => Ok(Self::Filled),
200 other => Err(other),
201 }
202 }
203}
204
205#[derive(
207 Copy,
208 Clone,
209 Debug,
210 Default,
211 Display,
212 PartialEq,
213 Eq,
214 Hash,
215 AsRefStr,
216 EnumIter,
217 EnumString,
218 Serialize,
219 Deserialize,
220)]
221pub enum OKXExecType {
222 #[serde(rename = "")]
223 #[default]
224 None,
225 #[serde(rename = "T")]
226 Taker,
227 #[serde(rename = "M")]
228 Maker,
229}
230
231impl From<LiquiditySide> for OKXExecType {
232 fn from(value: LiquiditySide) -> Self {
233 match value {
234 LiquiditySide::NoLiquiditySide => Self::None,
235 LiquiditySide::Taker => Self::Taker,
236 LiquiditySide::Maker => Self::Maker,
237 }
238 }
239}
240
241#[derive(
243 Copy,
244 Clone,
245 Debug,
246 Display,
247 Default,
248 PartialEq,
249 Eq,
250 Hash,
251 AsRefStr,
252 EnumIter,
253 EnumString,
254 Serialize,
255 Deserialize,
256)]
257#[serde(rename_all = "UPPERCASE")]
258#[cfg_attr(
259 feature = "python",
260 pyo3::pyclass(
261 eq,
262 eq_int,
263 module = "nautilus_trader.core.nautilus_pyo3.okx",
264 from_py_object,
265 rename_all = "SCREAMING_SNAKE_CASE",
266 )
267)]
268#[cfg_attr(
269 feature = "python",
270 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.okx")
271)]
272pub enum OKXInstrumentType {
273 #[default]
274 Any,
275 Spot,
277 Margin,
279 Swap,
281 Futures,
283 Option,
285}
286
287#[derive(
289 Copy,
290 Clone,
291 Debug,
292 Display,
293 PartialEq,
294 Eq,
295 Hash,
296 AsRefStr,
297 EnumIter,
298 EnumString,
299 Serialize,
300 Deserialize,
301)]
302#[serde(rename_all = "snake_case")]
303pub enum OKXInstrumentStatus {
304 Live,
305 Suspend,
306 Preopen,
307 Test,
308}
309
310#[derive(
312 Copy,
313 Clone,
314 Default,
315 Debug,
316 Display,
317 PartialEq,
318 Eq,
319 Hash,
320 AsRefStr,
321 EnumIter,
322 EnumString,
323 Serialize,
324 Deserialize,
325)]
326#[serde(rename_all = "snake_case")]
327#[cfg_attr(
328 feature = "python",
329 pyo3::pyclass(
330 eq,
331 eq_int,
332 module = "nautilus_trader.core.nautilus_pyo3.okx",
333 from_py_object,
334 rename_all = "SCREAMING_SNAKE_CASE",
335 )
336)]
337#[cfg_attr(
338 feature = "python",
339 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.okx")
340)]
341pub enum OKXContractType {
342 #[serde(rename = "")]
343 #[default]
344 None,
345 Linear,
346 Inverse,
347}
348
349#[derive(
351 Copy,
352 Clone,
353 Debug,
354 Display,
355 PartialEq,
356 Eq,
357 Hash,
358 AsRefStr,
359 EnumIter,
360 EnumString,
361 Serialize,
362 Deserialize,
363)]
364pub enum OKXOptionType {
365 #[serde(rename = "")]
366 None,
367 #[serde(rename = "C")]
368 Call,
369 #[serde(rename = "P")]
370 Put,
371}
372
373impl TryFrom<OKXOptionType> for OptionKind {
374 type Error = OKXOptionType;
375
376 fn try_from(option_type: OKXOptionType) -> Result<Self, Self::Error> {
383 match option_type {
384 OKXOptionType::Call => Ok(Self::Call),
385 OKXOptionType::Put => Ok(Self::Put),
386 other => Err(other),
387 }
388 }
389}
390
391#[derive(
397 Copy,
398 Clone,
399 Debug,
400 Default,
401 Display,
402 PartialEq,
403 Eq,
404 Hash,
405 AsRefStr,
406 EnumIter,
407 EnumString,
408 Serialize,
409 Deserialize,
410)]
411#[serde(rename_all = "UPPERCASE")]
412#[strum(serialize_all = "UPPERCASE", ascii_case_insensitive)]
413#[cfg_attr(
414 feature = "python",
415 pyo3::pyclass(
416 eq,
417 eq_int,
418 module = "nautilus_trader.core.nautilus_pyo3.okx",
419 from_py_object,
420 rename_all = "SCREAMING_SNAKE_CASE",
421 )
422)]
423#[cfg_attr(
424 feature = "python",
425 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.okx")
426)]
427pub enum OKXGreeksType {
428 #[default]
430 Bs = 0,
431 Pa = 1,
433}
434
435impl From<u8> for OKXGreeksType {
436 fn from(value: u8) -> Self {
437 match value {
438 0 => Self::Bs,
439 1 => Self::Pa,
440 _ => {
441 log::warn!("Invalid OKXGreeksType {value}, defaulting to Bs");
442 Self::Bs
443 }
444 }
445 }
446}
447
448impl From<GreeksConvention> for OKXGreeksType {
449 fn from(convention: GreeksConvention) -> Self {
450 match convention {
451 GreeksConvention::BlackScholes => Self::Bs,
452 GreeksConvention::PriceAdjusted => Self::Pa,
453 }
454 }
455}
456
457impl From<OKXGreeksType> for GreeksConvention {
458 fn from(greeks_type: OKXGreeksType) -> Self {
459 match greeks_type {
460 OKXGreeksType::Bs => Self::BlackScholes,
461 OKXGreeksType::Pa => Self::PriceAdjusted,
462 }
463 }
464}
465
466#[derive(
468 Copy,
469 Clone,
470 Debug,
471 Display,
472 Default,
473 PartialEq,
474 Eq,
475 Hash,
476 AsRefStr,
477 EnumIter,
478 EnumString,
479 Serialize,
480 Deserialize,
481)]
482#[serde(rename_all = "snake_case")]
483#[strum(ascii_case_insensitive)]
484#[cfg_attr(
485 feature = "python",
486 pyo3::pyclass(
487 eq,
488 eq_int,
489 module = "nautilus_trader.core.nautilus_pyo3.okx",
490 from_py_object,
491 rename_all = "SCREAMING_SNAKE_CASE",
492 )
493)]
494#[cfg_attr(
495 feature = "python",
496 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.okx")
497)]
498pub enum OKXTradeMode {
499 #[default]
500 Cash,
501 Isolated,
502 Cross,
503 #[strum(serialize = "spot_isolated")]
504 SpotIsolated,
505}
506
507#[derive(
513 Copy,
514 Clone,
515 Debug,
516 Display,
517 PartialEq,
518 Eq,
519 Hash,
520 AsRefStr,
521 EnumIter,
522 EnumString,
523 Serialize,
524 Deserialize,
525)]
526pub enum OKXAccountMode {
527 #[serde(rename = "Spot mode")]
528 Spot,
529 #[serde(rename = "Spot and futures mode")]
530 SpotAndFutures,
531 #[serde(rename = "Multi-currency margin mode")]
532 MultiCurrencyMarginMode,
533 #[serde(rename = "Portfolio margin mode")]
534 PortfolioMarginMode,
535}
536
537#[derive(
545 Copy,
546 Clone,
547 Default,
548 Debug,
549 Display,
550 PartialEq,
551 Eq,
552 Hash,
553 AsRefStr,
554 EnumIter,
555 EnumString,
556 Serialize,
557 Deserialize,
558)]
559#[serde(rename_all = "snake_case")]
560#[cfg_attr(
561 feature = "python",
562 pyo3::pyclass(
563 eq,
564 eq_int,
565 module = "nautilus_trader.core.nautilus_pyo3.okx",
566 from_py_object,
567 rename_all = "SCREAMING_SNAKE_CASE",
568 )
569)]
570#[cfg_attr(
571 feature = "python",
572 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.okx")
573)]
574pub enum OKXMarginMode {
575 #[serde(rename = "")]
576 #[default]
577 None,
578 Isolated,
579 Cross,
580}
581
582#[derive(
588 Copy,
589 Clone,
590 Default,
591 Debug,
592 Display,
593 PartialEq,
594 Eq,
595 Hash,
596 AsRefStr,
597 EnumIter,
598 EnumString,
599 Serialize,
600 Deserialize,
601)]
602#[cfg_attr(
603 feature = "python",
604 pyo3::pyclass(
605 eq,
606 eq_int,
607 module = "nautilus_trader.core.nautilus_pyo3.okx",
608 from_py_object,
609 rename_all = "SCREAMING_SNAKE_CASE",
610 )
611)]
612#[cfg_attr(
613 feature = "python",
614 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.okx")
615)]
616pub enum OKXPositionMode {
617 #[default]
618 #[serde(rename = "net_mode")]
619 NetMode,
620 #[serde(rename = "long_short_mode")]
621 LongShortMode,
622}
623
624#[derive(
625 Copy,
626 Clone,
627 Debug,
628 Display,
629 PartialEq,
630 Eq,
631 Hash,
632 AsRefStr,
633 EnumIter,
634 EnumString,
635 Serialize,
636 Deserialize,
637)]
638#[serde(rename_all = "snake_case")]
639pub enum OKXPositionSide {
640 #[serde(rename = "")]
641 None,
642 Net,
643 Long,
644 Short,
645}
646
647#[derive(
648 Copy,
649 Clone,
650 Debug,
651 Default,
652 Display,
653 PartialEq,
654 Eq,
655 Hash,
656 AsRefStr,
657 EnumIter,
658 EnumString,
659 Serialize,
660 Deserialize,
661)]
662#[serde(rename_all = "snake_case")]
663pub enum OKXSelfTradePreventionMode {
664 #[default]
665 #[serde(rename = "")]
666 None,
667 CancelMaker,
668 CancelTaker,
669 CancelBoth,
670}
671
672#[derive(
673 Copy,
674 Clone,
675 Debug,
676 Display,
677 PartialEq,
678 Eq,
679 Hash,
680 AsRefStr,
681 EnumIter,
682 EnumString,
683 Serialize,
684 Deserialize,
685)]
686#[serde(rename_all = "snake_case")]
687pub enum OKXTakeProfitKind {
688 #[serde(rename = "")]
689 None,
690 Condition,
691 Limit,
692}
693
694#[derive(
695 Copy,
696 Clone,
697 Debug,
698 Default,
699 Display,
700 PartialEq,
701 Eq,
702 Hash,
703 AsRefStr,
704 EnumIter,
705 EnumString,
706 Serialize,
707 Deserialize,
708)]
709#[serde(rename_all = "snake_case")]
710#[strum(serialize_all = "snake_case", ascii_case_insensitive)]
711pub enum OKXTriggerType {
712 #[default]
713 #[serde(rename = "")]
714 None,
715 Last,
716 Index,
717 Mark,
718}
719
720impl From<TriggerType> for OKXTriggerType {
721 fn from(value: TriggerType) -> Self {
722 match value {
723 TriggerType::LastPrice => Self::Last,
724 TriggerType::MarkPrice => Self::Mark,
725 TriggerType::IndexPrice => Self::Index,
726 _ => Self::Last,
727 }
728 }
729}
730
731#[cfg(test)]
732mod tests {
733 use std::str::FromStr;
734
735 use nautilus_model::enums::{GreeksConvention, OptionKind, OrderStatus};
736 use rstest::rstest;
737
738 use super::{OKXGreeksType, OKXOptionType, OKXOrderStatus, OKXOrderType, OKXTriggerType};
739
740 #[rstest]
741 fn test_okx_trigger_type_from_str_accepts_snake_case_values() {
742 assert_eq!(
743 OKXTriggerType::from_str("last").unwrap(),
744 OKXTriggerType::Last
745 );
746 assert_eq!(
747 OKXTriggerType::from_str("mark").unwrap(),
748 OKXTriggerType::Mark
749 );
750 assert_eq!(
751 OKXTriggerType::from_str("index").unwrap(),
752 OKXTriggerType::Index
753 );
754 }
755
756 #[rstest]
757 #[case(OKXGreeksType::Bs, "\"BS\"")]
758 #[case(OKXGreeksType::Pa, "\"PA\"")]
759 fn test_greeks_type_serde_roundtrip(#[case] input: OKXGreeksType, #[case] expected: &str) {
760 let json = serde_json::to_string(&input).unwrap();
761 assert_eq!(json, expected);
762 let parsed: OKXGreeksType = serde_json::from_str(expected).unwrap();
763 assert_eq!(parsed, input);
764 }
765
766 #[rstest]
767 fn test_greeks_type_default_is_bs() {
768 assert_eq!(OKXGreeksType::default(), OKXGreeksType::Bs);
769 }
770
771 #[rstest]
772 fn test_greeks_type_from_u8() {
773 assert_eq!(OKXGreeksType::from(0_u8), OKXGreeksType::Bs);
774 assert_eq!(OKXGreeksType::from(1_u8), OKXGreeksType::Pa);
775 assert_eq!(OKXGreeksType::from(99_u8), OKXGreeksType::Bs);
776 }
777
778 #[rstest]
779 #[case(GreeksConvention::BlackScholes, OKXGreeksType::Bs)]
780 #[case(GreeksConvention::PriceAdjusted, OKXGreeksType::Pa)]
781 fn test_greeks_type_convention_roundtrip(
782 #[case] convention: GreeksConvention,
783 #[case] expected: OKXGreeksType,
784 ) {
785 let mapped: OKXGreeksType = convention.into();
786 assert_eq!(mapped, expected);
787 let back: GreeksConvention = mapped.into();
788 assert_eq!(back, convention);
789 }
790
791 #[rstest]
792 fn test_op_fok_serializes_to_snake_case() {
793 let json = serde_json::to_string(&OKXOrderType::OpFok).unwrap();
794 assert_eq!(json, "\"op_fok\"");
795 }
796
797 #[rstest]
798 fn test_op_fok_deserializes_from_snake_case() {
799 let parsed: OKXOrderType = serde_json::from_str("\"op_fok\"").unwrap();
800 assert_eq!(parsed, OKXOrderType::OpFok);
801 }
802
803 #[rstest]
804 fn test_op_fok_converts_to_limit_order_type() {
805 use nautilus_model::enums::OrderType;
806 let order_type: OrderType = OKXOrderType::OpFok.into();
807 assert_eq!(order_type, OrderType::Limit);
808 }
809
810 #[rstest]
811 #[case::call(OKXOptionType::Call, Ok(OptionKind::Call))]
812 #[case::put(OKXOptionType::Put, Ok(OptionKind::Put))]
813 #[case::none(OKXOptionType::None, Err(OKXOptionType::None))]
814 fn test_try_from_okx_option_type(
815 #[case] input: OKXOptionType,
816 #[case] expected: Result<OptionKind, OKXOptionType>,
817 ) {
818 let actual: Result<OptionKind, OKXOptionType> = input.try_into();
819 assert_eq!(actual, expected);
820 }
821
822 #[rstest]
823 #[case::canceled(OrderStatus::Canceled, Ok(OKXOrderStatus::Canceled))]
824 #[case::accepted(OrderStatus::Accepted, Ok(OKXOrderStatus::Live))]
825 #[case::partially_filled(OrderStatus::PartiallyFilled, Ok(OKXOrderStatus::PartiallyFilled))]
826 #[case::filled(OrderStatus::Filled, Ok(OKXOrderStatus::Filled))]
827 #[case::submitted(OrderStatus::Submitted, Err(OrderStatus::Submitted))]
828 #[case::pending_update(OrderStatus::PendingUpdate, Err(OrderStatus::PendingUpdate))]
829 #[case::pending_cancel(OrderStatus::PendingCancel, Err(OrderStatus::PendingCancel))]
830 #[case::triggered(OrderStatus::Triggered, Err(OrderStatus::Triggered))]
831 #[case::expired(OrderStatus::Expired, Err(OrderStatus::Expired))]
832 #[case::rejected(OrderStatus::Rejected, Err(OrderStatus::Rejected))]
833 fn test_try_from_order_status(
834 #[case] input: OrderStatus,
835 #[case] expected: Result<OKXOrderStatus, OrderStatus>,
836 ) {
837 let actual: Result<OKXOrderStatus, OrderStatus> = input.try_into();
838 assert_eq!(actual, expected);
839 }
840}
841
842#[derive(
844 Copy,
845 Clone,
846 Debug,
847 Display,
848 PartialEq,
849 Eq,
850 Hash,
851 AsRefStr,
852 EnumIter,
853 EnumString,
854 Serialize,
855 Deserialize,
856)]
857#[serde(rename_all = "snake_case")]
858#[strum(serialize_all = "snake_case")]
859pub enum OKXTargetCurrency {
860 BaseCcy,
862 QuoteCcy,
864}
865
866#[derive(Copy, Clone, Debug, PartialEq, Eq)]
868pub enum OKXBookChannel {
869 Book,
871 BookL2Tbt,
873 Books50L2Tbt,
875}
876
877#[derive(
891 Copy,
892 Clone,
893 Debug,
894 Display,
895 PartialEq,
896 Eq,
897 PartialOrd,
898 Ord,
899 Hash,
900 AsRefStr,
901 EnumIter,
902 EnumString,
903 Serialize,
904 Deserialize,
905)]
906#[cfg_attr(
907 feature = "python",
908 pyo3::pyclass(
909 module = "nautilus_trader.core.nautilus_pyo3.okx",
910 from_py_object,
911 rename_all = "SCREAMING_SNAKE_CASE",
912 )
913)]
914#[cfg_attr(
915 feature = "python",
916 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.okx")
917)]
918pub enum OKXVipLevel {
919 #[serde(rename = "0")]
921 #[strum(serialize = "0")]
922 Vip0 = 0,
923 #[serde(rename = "1")]
925 #[strum(serialize = "1")]
926 Vip1 = 1,
927 #[serde(rename = "2")]
929 #[strum(serialize = "2")]
930 Vip2 = 2,
931 #[serde(rename = "3")]
933 #[strum(serialize = "3")]
934 Vip3 = 3,
935 #[serde(rename = "4")]
937 #[strum(serialize = "4")]
938 Vip4 = 4,
939 #[serde(rename = "5")]
941 #[strum(serialize = "5")]
942 Vip5 = 5,
943 #[serde(rename = "6")]
945 #[strum(serialize = "6")]
946 Vip6 = 6,
947 #[serde(rename = "7")]
949 #[strum(serialize = "7")]
950 Vip7 = 7,
951 #[serde(rename = "8")]
953 #[strum(serialize = "8")]
954 Vip8 = 8,
955 #[serde(rename = "9")]
957 #[strum(serialize = "9")]
958 Vip9 = 9,
959}
960
961impl From<u8> for OKXVipLevel {
962 fn from(value: u8) -> Self {
963 match value {
964 0 => Self::Vip0,
965 1 => Self::Vip1,
966 2 => Self::Vip2,
967 3 => Self::Vip3,
968 4 => Self::Vip4,
969 5 => Self::Vip5,
970 6 => Self::Vip6,
971 7 => Self::Vip7,
972 8 => Self::Vip8,
973 9 => Self::Vip9,
974 _ => {
975 log::warn!("Invalid VIP level {value}, defaulting to Vip0");
976 Self::Vip0
977 }
978 }
979 }
980}
981
982impl From<OKXSide> for OrderSide {
983 fn from(side: OKXSide) -> Self {
984 match side {
985 OKXSide::Buy => Self::Buy,
986 OKXSide::Sell => Self::Sell,
987 }
988 }
989}
990
991impl From<OKXExecType> for LiquiditySide {
992 fn from(exec: OKXExecType) -> Self {
993 match exec {
994 OKXExecType::Maker => Self::Maker,
995 OKXExecType::Taker => Self::Taker,
996 OKXExecType::None => Self::NoLiquiditySide,
997 }
998 }
999}
1000
1001impl From<OKXPositionSide> for PositionSide {
1002 fn from(side: OKXPositionSide) -> Self {
1003 match side {
1004 OKXPositionSide::Long => Self::Long,
1005 OKXPositionSide::Short => Self::Short,
1006 _ => Self::Flat,
1007 }
1008 }
1009}
1010
1011impl From<OKXOrderStatus> for OrderStatus {
1012 fn from(status: OKXOrderStatus) -> Self {
1013 match status {
1014 OKXOrderStatus::Live => Self::Accepted,
1015 OKXOrderStatus::Effective => Self::Triggered,
1016 OKXOrderStatus::PartiallyFilled => Self::PartiallyFilled,
1017 OKXOrderStatus::Filled => Self::Filled,
1018 OKXOrderStatus::Canceled | OKXOrderStatus::MmpCanceled => Self::Canceled,
1019 OKXOrderStatus::OrderPlaced => Self::Triggered,
1020 }
1021 }
1022}
1023
1024impl From<OKXOrderType> for OrderType {
1025 fn from(ord_type: OKXOrderType) -> Self {
1026 match ord_type {
1027 OKXOrderType::Market => Self::Market,
1028 OKXOrderType::Limit
1029 | OKXOrderType::PostOnly
1030 | OKXOrderType::OptimalLimitIoc
1031 | OKXOrderType::Mmp
1032 | OKXOrderType::MmpAndPostOnly
1033 | OKXOrderType::Fok
1034 | OKXOrderType::OpFok
1035 | OKXOrderType::Ioc => Self::Limit,
1036 OKXOrderType::Trigger => Self::StopMarket,
1037 }
1038 }
1039}
1040
1041impl From<OrderType> for OKXOrderType {
1042 fn from(value: OrderType) -> Self {
1043 match value {
1044 OrderType::Market => Self::Market,
1045 OrderType::Limit => Self::Limit,
1046 OrderType::MarketToLimit => Self::Ioc,
1047 OrderType::StopMarket
1049 | OrderType::StopLimit
1050 | OrderType::MarketIfTouched
1051 | OrderType::LimitIfTouched
1052 | OrderType::TrailingStopMarket => {
1053 panic!("Conditional order types must use OKXAlgoOrderType")
1054 }
1055 _ => panic!("Invalid `OrderType` cannot be represented on OKX: {value:?}"),
1056 }
1057 }
1058}
1059
1060impl From<PositionSide> for OKXPositionSide {
1061 fn from(value: PositionSide) -> Self {
1062 match value {
1063 PositionSide::Long => Self::Long,
1064 PositionSide::Short => Self::Short,
1065 _ => Self::None,
1066 }
1067 }
1068}
1069
1070#[derive(
1071 Copy,
1072 Clone,
1073 Debug,
1074 Display,
1075 PartialEq,
1076 Eq,
1077 Hash,
1078 AsRefStr,
1079 EnumIter,
1080 EnumString,
1081 Serialize,
1082 Deserialize,
1083)]
1084#[serde(rename_all = "snake_case")]
1085pub enum OKXAlgoOrderType {
1086 Conditional,
1087 Oco,
1088 Trigger,
1089 MoveOrderStop,
1090 Iceberg,
1091 Twap,
1092}
1093
1094pub fn is_conditional_order(order_type: OrderType) -> bool {
1096 OKX_CONDITIONAL_ORDER_TYPES.contains(&order_type)
1097}
1098
1099pub fn is_advance_algo_order(order_type: OrderType) -> bool {
1101 OKX_ADVANCE_ALGO_ORDER_TYPES.contains(&order_type)
1102}
1103
1104pub fn conditional_order_to_algo_type(order_type: OrderType) -> anyhow::Result<OKXAlgoOrderType> {
1110 match order_type {
1111 OrderType::StopMarket
1112 | OrderType::StopLimit
1113 | OrderType::MarketIfTouched
1114 | OrderType::LimitIfTouched => Ok(OKXAlgoOrderType::Trigger),
1115 OrderType::TrailingStopMarket => Ok(OKXAlgoOrderType::MoveOrderStop),
1116 _ => anyhow::bail!("Not a conditional order type: {order_type:?}"),
1117 }
1118}
1119
1120#[derive(
1121 Copy,
1122 Clone,
1123 Debug,
1124 Display,
1125 PartialEq,
1126 Eq,
1127 Hash,
1128 AsRefStr,
1129 EnumIter,
1130 EnumString,
1131 Serialize,
1132 Deserialize,
1133)]
1134#[serde(rename_all = "snake_case")]
1135pub enum OKXAlgoOrderStatus {
1136 Live,
1137 Pause,
1138 PartiallyEffective,
1139 Effective,
1140 Canceled,
1141 OrderFailed,
1142 PartiallyFailed,
1143}
1144
1145#[derive(
1146 Copy,
1147 Clone,
1148 Debug,
1149 Display,
1150 PartialEq,
1151 Eq,
1152 Hash,
1153 AsRefStr,
1154 EnumIter,
1155 EnumString,
1156 Serialize,
1157 Deserialize,
1158)]
1159pub enum OKXTransactionType {
1160 #[serde(rename = "1")]
1161 Buy,
1162 #[serde(rename = "2")]
1163 Sell,
1164 #[serde(rename = "3")]
1165 OpenLong,
1166 #[serde(rename = "4")]
1167 OpenShort,
1168 #[serde(rename = "5")]
1169 CloseLong,
1170 #[serde(rename = "6")]
1171 CloseShort,
1172 #[serde(rename = "100")]
1173 PartialLiquidationCloseLong,
1174 #[serde(rename = "101")]
1175 PartialLiquidationCloseShort,
1176 #[serde(rename = "102")]
1177 PartialLiquidationBuy,
1178 #[serde(rename = "103")]
1179 PartialLiquidationSell,
1180 #[serde(rename = "104")]
1181 LiquidationLong,
1182 #[serde(rename = "105")]
1183 LiquidationShort,
1184 #[serde(rename = "106")]
1185 LiquidationBuy,
1186 #[serde(rename = "107")]
1187 LiquidationSell,
1188 #[serde(rename = "110")]
1189 LiquidationTransferIn,
1190 #[serde(rename = "111")]
1191 LiquidationTransferOut,
1192 #[serde(rename = "118")]
1193 SystemTokenConversionTransferIn,
1194 #[serde(rename = "119")]
1195 SystemTokenConversionTransferOut,
1196 #[serde(rename = "125")]
1197 AdlCloseLong,
1198 #[serde(rename = "126")]
1199 AdlCloseShort,
1200 #[serde(rename = "127")]
1201 AdlBuy,
1202 #[serde(rename = "128")]
1203 AdlSell,
1204 #[serde(rename = "212")]
1205 AutoBorrowOfQuickMargin,
1206 #[serde(rename = "213")]
1207 AutoRepayOfQuickMargin,
1208 #[serde(rename = "204")]
1209 BlockTradeBuy,
1210 #[serde(rename = "205")]
1211 BlockTradeSell,
1212 #[serde(rename = "206")]
1213 BlockTradeOpenLong,
1214 #[serde(rename = "207")]
1215 BlockTradeOpenShort,
1216 #[serde(rename = "208")]
1217 BlockTradeCloseOpen,
1218 #[serde(rename = "209")]
1219 BlockTradeCloseShort,
1220 #[serde(rename = "270")]
1221 SpreadTradingBuy,
1222 #[serde(rename = "271")]
1223 SpreadTradingSell,
1224 #[serde(rename = "272")]
1225 SpreadTradingOpenLong,
1226 #[serde(rename = "273")]
1227 SpreadTradingOpenShort,
1228 #[serde(rename = "274")]
1229 SpreadTradingCloseLong,
1230 #[serde(rename = "275")]
1231 SpreadTradingCloseShort,
1232}
1233
1234#[derive(
1244 Copy,
1245 Clone,
1246 Debug,
1247 Display,
1248 PartialEq,
1249 Eq,
1250 Hash,
1251 AsRefStr,
1252 EnumIter,
1253 EnumString,
1254 Serialize,
1255 Deserialize,
1256)]
1257#[serde(rename_all = "snake_case")]
1258pub enum OKXOrderCategory {
1259 Normal,
1261 FullLiquidation,
1263 PartialLiquidation,
1265 Adl,
1267 Twap,
1269 Iceberg,
1271 Oco,
1273 Conditional,
1275 MoveOrderStop,
1277 Ddh,
1279 #[serde(other)]
1281 Other,
1282}
1283
1284#[derive(
1285 Copy,
1286 Clone,
1287 Debug,
1288 Display,
1289 PartialEq,
1290 Eq,
1291 Hash,
1292 AsRefStr,
1293 EnumIter,
1294 EnumString,
1295 Serialize,
1296 Deserialize,
1297)]
1298pub enum OKXBarSize {
1299 #[serde(rename = "1s")]
1300 Second1,
1301 #[serde(rename = "1m")]
1302 Minute1,
1303 #[serde(rename = "3m")]
1304 Minute3,
1305 #[serde(rename = "5m")]
1306 Minute5,
1307 #[serde(rename = "15m")]
1308 Minute15,
1309 #[serde(rename = "30m")]
1310 Minute30,
1311 #[serde(rename = "1H")]
1312 Hour1,
1313 #[serde(rename = "2H")]
1314 Hour2,
1315 #[serde(rename = "4H")]
1316 Hour4,
1317 #[serde(rename = "6H")]
1318 Hour6,
1319 #[serde(rename = "12H")]
1320 Hour12,
1321 #[serde(rename = "1D")]
1322 Day1,
1323 #[serde(rename = "2D")]
1324 Day2,
1325 #[serde(rename = "3D")]
1326 Day3,
1327 #[serde(rename = "5D")]
1328 Day5,
1329 #[serde(rename = "1W")]
1330 Week1,
1331 #[serde(rename = "1M")]
1332 Month1,
1333 #[serde(rename = "3M")]
1334 Month3,
1335}
1336
1337#[derive(
1339 Copy,
1340 Clone,
1341 Debug,
1342 Default,
1343 Display,
1344 PartialEq,
1345 Eq,
1346 Hash,
1347 AsRefStr,
1348 EnumIter,
1349 EnumString,
1350 Serialize,
1351 Deserialize,
1352)]
1353#[serde(rename_all = "snake_case")]
1354pub enum OKXPriceType {
1355 #[default]
1357 #[serde(rename = "")]
1358 None,
1359 Px,
1361 Usd,
1363 Vol,
1365}
1366
1367#[derive(
1369 Copy,
1370 Clone,
1371 Debug,
1372 Default,
1373 Display,
1374 PartialEq,
1375 Eq,
1376 Hash,
1377 AsRefStr,
1378 EnumIter,
1379 EnumString,
1380 Serialize,
1381 Deserialize,
1382)]
1383#[serde(rename_all = "snake_case")]
1384pub enum OKXSettlementState {
1385 #[default]
1387 #[serde(rename = "")]
1388 None,
1389 Processing,
1391 Settled,
1393}
1394
1395#[derive(
1397 Copy,
1398 Clone,
1399 Debug,
1400 Default,
1401 Display,
1402 PartialEq,
1403 Eq,
1404 Hash,
1405 AsRefStr,
1406 EnumIter,
1407 EnumString,
1408 Serialize,
1409 Deserialize,
1410)]
1411#[serde(rename_all = "snake_case")]
1412pub enum OKXQuickMarginType {
1413 #[default]
1415 #[serde(rename = "")]
1416 None,
1417 Manual,
1419 AutoBorrow,
1421 AutoRepay,
1423}
1424
1425#[derive(
1427 Copy,
1428 Clone,
1429 Debug,
1430 Default,
1431 Display,
1432 PartialEq,
1433 Eq,
1434 Hash,
1435 AsRefStr,
1436 EnumIter,
1437 EnumString,
1438 Serialize,
1439 Deserialize,
1440)]
1441#[serde(rename_all = "lowercase")]
1442#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
1443#[cfg_attr(
1444 feature = "python",
1445 pyo3::pyclass(
1446 eq,
1447 eq_int,
1448 module = "nautilus_trader.core.nautilus_pyo3.okx",
1449 from_py_object,
1450 rename_all = "SCREAMING_SNAKE_CASE",
1451 )
1452)]
1453#[cfg_attr(
1454 feature = "python",
1455 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.okx")
1456)]
1457pub enum OKXEnvironment {
1458 #[default]
1460 Live,
1461 Demo,
1463}