1use nautilus_model::enums::{LiquiditySide, MarketStatusAction, OrderSide, OrderStatus, OrderType};
19use serde::{Deserialize, Serialize};
20use strum::{AsRefStr, Display, EnumString, FromRepr};
21
22#[derive(
24 Clone,
25 Copy,
26 Debug,
27 Default,
28 Display,
29 AsRefStr,
30 EnumString,
31 FromRepr,
32 PartialEq,
33 Eq,
34 Hash,
35 Serialize,
36 Deserialize,
37)]
38#[cfg_attr(
39 feature = "python",
40 pyo3::pyclass(
41 module = "nautilus_trader.adapters.kraken",
42 eq,
43 eq_int,
44 frozen,
45 hash,
46 from_py_object,
47 rename_all = "SCREAMING_SNAKE_CASE",
48 )
49)]
50#[cfg_attr(
51 feature = "python",
52 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.kraken")
53)]
54#[serde(rename_all = "lowercase")]
55#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
56pub enum KrakenEnvironment {
57 #[default]
58 Live,
59 Demo,
60}
61
62#[derive(
64 Clone,
65 Copy,
66 Debug,
67 Default,
68 Display,
69 AsRefStr,
70 EnumString,
71 FromRepr,
72 PartialEq,
73 Eq,
74 Hash,
75 Serialize,
76 Deserialize,
77)]
78#[cfg_attr(
79 feature = "python",
80 pyo3::pyclass(
81 module = "nautilus_trader.adapters.kraken",
82 eq,
83 eq_int,
84 frozen,
85 hash,
86 from_py_object,
87 rename_all = "SCREAMING_SNAKE_CASE",
88 )
89)]
90#[cfg_attr(
91 feature = "python",
92 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.kraken")
93)]
94#[serde(rename_all = "lowercase")]
95#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
96pub enum KrakenProductType {
97 #[default]
98 Spot,
99 Futures,
100}
101
102#[derive(
104 Clone,
105 Copy,
106 Debug,
107 Display,
108 AsRefStr,
109 EnumString,
110 FromRepr,
111 PartialEq,
112 Eq,
113 Hash,
114 Serialize,
115 Deserialize,
116)]
117#[cfg_attr(
118 feature = "python",
119 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
120)]
121#[serde(rename_all = "lowercase")]
122#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
123pub enum KrakenOrderType {
124 Market,
125 Limit,
126 #[serde(rename = "stop-loss")]
127 #[strum(serialize = "stop-loss")]
128 StopLoss,
129 #[serde(rename = "take-profit")]
130 #[strum(serialize = "take-profit")]
131 TakeProfit,
132 #[serde(rename = "stop-loss-limit")]
133 #[strum(serialize = "stop-loss-limit")]
134 StopLossLimit,
135 #[serde(rename = "take-profit-limit")]
136 #[strum(serialize = "take-profit-limit")]
137 TakeProfitLimit,
138 #[serde(rename = "trailing-stop")]
139 #[strum(serialize = "trailing-stop")]
140 TrailingStop,
141 #[serde(rename = "trailing-stop-limit")]
142 #[strum(serialize = "trailing-stop-limit")]
143 TrailingStopLimit,
144 #[serde(rename = "settle-position")]
145 #[strum(serialize = "settle-position")]
146 SettlePosition,
147}
148
149#[derive(
151 Clone,
152 Copy,
153 Debug,
154 Display,
155 AsRefStr,
156 EnumString,
157 FromRepr,
158 PartialEq,
159 Eq,
160 Hash,
161 Serialize,
162 Deserialize,
163)]
164#[cfg_attr(
165 feature = "python",
166 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
167)]
168#[serde(rename_all = "lowercase")]
169#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
170pub enum KrakenOrderSide {
171 Buy,
172 Sell,
173}
174
175#[derive(
177 Clone,
178 Copy,
179 Debug,
180 Display,
181 AsRefStr,
182 EnumString,
183 FromRepr,
184 PartialEq,
185 Eq,
186 Hash,
187 Serialize,
188 Deserialize,
189)]
190#[cfg_attr(
191 feature = "python",
192 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
193)]
194#[serde(rename_all = "UPPERCASE")]
195#[strum(ascii_case_insensitive, serialize_all = "UPPERCASE")]
196pub enum KrakenTimeInForce {
197 #[serde(rename = "IOC")]
198 #[strum(serialize = "IOC")]
199 ImmediateOrCancel,
200 #[serde(rename = "FOK")]
201 #[strum(serialize = "FOK")]
202 FillOrKill,
203 #[serde(rename = "GTC")]
204 #[strum(serialize = "GTC")]
205 GoodTilCancelled,
206 #[serde(rename = "GTD")]
207 #[strum(serialize = "GTD")]
208 GoodTilDate,
209}
210
211#[derive(
213 Clone,
214 Copy,
215 Debug,
216 Display,
217 AsRefStr,
218 EnumString,
219 FromRepr,
220 PartialEq,
221 Eq,
222 Hash,
223 Serialize,
224 Deserialize,
225)]
226#[cfg_attr(
227 feature = "python",
228 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
229)]
230#[serde(rename_all = "lowercase")]
231#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
232pub enum KrakenOrderStatus {
233 Pending,
234 Open,
235 Closed,
236 Canceled,
237 Expired,
238}
239
240#[derive(
242 Clone,
243 Copy,
244 Debug,
245 Display,
246 AsRefStr,
247 EnumString,
248 FromRepr,
249 PartialEq,
250 Eq,
251 Hash,
252 Serialize,
253 Deserialize,
254)]
255#[cfg_attr(
256 feature = "python",
257 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
258)]
259#[serde(rename_all = "lowercase")]
260#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
261pub enum KrakenPositionSide {
262 Long,
263 Short,
264}
265
266#[derive(
268 Clone,
269 Copy,
270 Debug,
271 Display,
272 AsRefStr,
273 EnumString,
274 FromRepr,
275 PartialEq,
276 Eq,
277 Hash,
278 Serialize,
279 Deserialize,
280)]
281#[cfg_attr(
282 feature = "python",
283 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
284)]
285#[serde(rename_all = "snake_case")]
286#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
287pub enum KrakenPairStatus {
288 Online,
289 #[serde(rename = "cancel_only")]
290 #[strum(serialize = "cancel_only")]
291 CancelOnly,
292 #[serde(rename = "post_only")]
293 #[strum(serialize = "post_only")]
294 PostOnly,
295 #[serde(rename = "limit_only")]
296 #[strum(serialize = "limit_only")]
297 LimitOnly,
298 #[serde(rename = "reduce_only")]
299 #[strum(serialize = "reduce_only")]
300 ReduceOnly,
301}
302
303#[derive(
305 Clone,
306 Copy,
307 Debug,
308 Display,
309 AsRefStr,
310 EnumString,
311 FromRepr,
312 PartialEq,
313 Eq,
314 Hash,
315 Serialize,
316 Deserialize,
317)]
318#[cfg_attr(
319 feature = "python",
320 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
321)]
322#[serde(rename_all = "lowercase")]
323#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
324pub enum KrakenSystemStatus {
325 Online,
326 Maintenance,
327 #[serde(rename = "cancel_only")]
328 #[strum(serialize = "cancel_only")]
329 CancelOnly,
330 #[serde(rename = "post_only")]
331 #[strum(serialize = "post_only")]
332 PostOnly,
333}
334
335#[derive(
337 Clone,
338 Copy,
339 Debug,
340 Display,
341 AsRefStr,
342 EnumString,
343 FromRepr,
344 PartialEq,
345 Eq,
346 Hash,
347 Serialize,
348 Deserialize,
349)]
350#[cfg_attr(
351 feature = "python",
352 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
353)]
354#[serde(rename_all = "lowercase")]
355#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
356pub enum KrakenAssetClass {
357 Currency,
358 #[serde(rename = "tokenized_asset")]
359 #[strum(serialize = "tokenized_asset")]
360 TokenizedAsset,
361}
362
363#[derive(
365 Clone,
366 Copy,
367 Debug,
368 Display,
369 AsRefStr,
370 EnumString,
371 FromRepr,
372 PartialEq,
373 Eq,
374 Hash,
375 Serialize,
376 Deserialize,
377)]
378#[cfg_attr(
379 feature = "python",
380 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
381)]
382#[serde(rename_all = "lowercase")]
383#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
384pub enum KrakenFuturesOrderType {
385 #[serde(rename = "lmt", alias = "limit")]
386 #[strum(serialize = "lmt")]
387 Limit,
388 #[serde(rename = "ioc")]
389 #[strum(serialize = "ioc")]
390 Ioc,
391 #[serde(rename = "post")]
392 #[strum(serialize = "post")]
393 Post,
394 #[serde(rename = "mkt", alias = "market")]
395 #[strum(serialize = "mkt")]
396 Market,
397 #[serde(rename = "stp")]
398 #[strum(serialize = "stp")]
399 Stop,
400 #[serde(rename = "stop")]
401 #[strum(serialize = "stop")]
402 StopLower,
403 #[serde(rename = "take_profit")]
404 #[strum(serialize = "take_profit")]
405 TakeProfit,
406 #[serde(rename = "stop_loss")]
407 #[strum(serialize = "stop_loss")]
408 StopLoss,
409 #[serde(rename = "unknown")]
410 Unknown,
411}
412
413#[derive(
415 Clone,
416 Copy,
417 Debug,
418 Display,
419 AsRefStr,
420 EnumString,
421 FromRepr,
422 PartialEq,
423 Eq,
424 Hash,
425 Serialize,
426 Deserialize,
427)]
428#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
429#[strum(ascii_case_insensitive, serialize_all = "SCREAMING_SNAKE_CASE")]
430pub enum KrakenFuturesOrderEventType {
431 Place,
433 Fill,
435 Execution,
437 Reject,
439 Cancel,
441 Edit,
443 #[serde(alias = "EXPIRED")]
445 #[strum(serialize = "EXPIRED")]
446 Expire,
447}
448
449#[derive(
451 Clone,
452 Copy,
453 Debug,
454 Display,
455 AsRefStr,
456 EnumString,
457 FromRepr,
458 PartialEq,
459 Eq,
460 Hash,
461 Serialize,
462 Deserialize,
463)]
464#[cfg_attr(
465 feature = "python",
466 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
467)]
468#[serde(rename_all = "camelCase")]
469#[strum(ascii_case_insensitive, serialize_all = "camelCase")]
470pub enum KrakenFuturesOrderStatus {
471 Untouched,
472 PartiallyFilled,
473 Filled,
474 Cancelled,
475 Expired,
476}
477
478#[derive(
481 Clone,
482 Copy,
483 Debug,
484 Display,
485 AsRefStr,
486 EnumString,
487 FromRepr,
488 PartialEq,
489 Eq,
490 Hash,
491 Serialize,
492 Deserialize,
493)]
494#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
495#[strum(ascii_case_insensitive, serialize_all = "SCREAMING_SNAKE_CASE")]
496pub enum KrakenFuturesOrderLifecycleStatus {
497 EnteredBook,
499 FullyExecuted,
501 Rejected,
503 Cancelled,
506 TriggerPlaced,
508 TriggerActivationFailure,
510}
511
512#[derive(
514 Clone,
515 Copy,
516 Debug,
517 Display,
518 AsRefStr,
519 EnumString,
520 FromRepr,
521 PartialEq,
522 Eq,
523 Hash,
524 Serialize,
525 Deserialize,
526)]
527#[cfg_attr(
528 feature = "python",
529 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
530)]
531#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
532pub enum KrakenTriggerSignal {
533 #[serde(rename = "last", alias = "last_price")]
534 Last,
535 #[serde(rename = "mark", alias = "mark_price")]
536 Mark,
537 #[serde(
538 rename = "spot",
539 alias = "spot_price",
540 alias = "index",
541 alias = "index_price"
542 )]
543 #[strum(
544 serialize = "spot",
545 serialize = "spot_price",
546 serialize = "index",
547 serialize = "index_price"
548 )]
549 Index,
550 #[serde(rename = "unknown")]
551 Unknown,
552}
553
554#[derive(
556 Clone,
557 Copy,
558 Debug,
559 Display,
560 AsRefStr,
561 EnumString,
562 FromRepr,
563 PartialEq,
564 Eq,
565 Hash,
566 Serialize,
567 Deserialize,
568)]
569#[cfg_attr(
570 feature = "python",
571 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
572)]
573#[serde(rename_all = "lowercase")]
574#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
575pub enum KrakenSpotTrigger {
576 Last,
578 Index,
580}
581
582#[derive(
584 Clone,
585 Copy,
586 Debug,
587 Display,
588 AsRefStr,
589 EnumString,
590 FromRepr,
591 PartialEq,
592 Eq,
593 Hash,
594 Serialize,
595 Deserialize,
596)]
597#[cfg_attr(
598 feature = "python",
599 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
600)]
601#[serde(rename_all = "camelCase")]
602#[strum(ascii_case_insensitive, serialize_all = "camelCase")]
603pub enum KrakenFillType {
604 Maker,
605 Taker,
606 Liquidation,
607 PartialLiquidation,
608 Assignor,
609 Assignee,
610 TakerAfterEdit,
611 UnwindBankrupt,
612 UnwindCounterparty,
613}
614
615#[derive(
617 Clone,
618 Copy,
619 Debug,
620 Display,
621 AsRefStr,
622 EnumString,
623 FromRepr,
624 PartialEq,
625 Eq,
626 Hash,
627 Serialize,
628 Deserialize,
629)]
630#[cfg_attr(
631 feature = "python",
632 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
633)]
634#[serde(rename_all = "lowercase")]
635#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
636pub enum KrakenApiResult {
637 Success,
638 Error,
639}
640
641#[derive(
643 Clone,
644 Copy,
645 Debug,
646 Display,
647 AsRefStr,
648 EnumString,
649 FromRepr,
650 PartialEq,
651 Eq,
652 Hash,
653 Serialize,
654 Deserialize,
655)]
656#[cfg_attr(
657 feature = "python",
658 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
659)]
660#[serde(rename_all = "snake_case")]
661#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
662pub enum KrakenInstrumentType {
663 FuturesInverse,
665 FlexibleFutures,
667}
668
669#[derive(
671 Clone,
672 Copy,
673 Debug,
674 Display,
675 AsRefStr,
676 EnumString,
677 FromRepr,
678 PartialEq,
679 Eq,
680 Hash,
681 Serialize,
682 Deserialize,
683)]
684#[cfg_attr(
685 feature = "python",
686 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
687)]
688#[serde(rename_all = "camelCase")]
689#[strum(ascii_case_insensitive, serialize_all = "camelCase")]
690pub enum KrakenSendStatus {
691 Placed,
693 Cancelled,
695 Edited,
697 NotFound,
699 NoOrdersToCancel,
707 InsufficientAvailableFunds,
709 InvalidOrderType,
711 InvalidSize,
713 WouldCauseLiquidation,
715 PostWouldExecute,
717 IocWouldNotExecute,
723 ReduceOnlyWouldIncreasePosition,
725 ClientOrderIdAlreadyExist,
727 ClientOrderIdTooBig,
730 ClientOrderIdTooLong,
733 ClientOrderIdInvalid,
735}
736
737#[derive(
739 Clone,
740 Copy,
741 Debug,
742 Display,
743 AsRefStr,
744 EnumString,
745 FromRepr,
746 PartialEq,
747 Eq,
748 Hash,
749 Serialize,
750 Deserialize,
751)]
752#[cfg_attr(
753 feature = "python",
754 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
755)]
756#[serde(rename_all = "snake_case")]
757#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
758pub enum KrakenTriggerSide {
759 #[serde(rename = "trigger_above")]
761 #[strum(serialize = "trigger_above")]
762 TriggerAbove,
763 #[serde(rename = "trigger_below")]
765 #[strum(serialize = "trigger_below")]
766 TriggerBelow,
767 #[serde(rename = "unknown")]
769 Unknown,
770}
771
772impl From<KrakenOrderSide> for OrderSide {
773 fn from(value: KrakenOrderSide) -> Self {
774 match value {
775 KrakenOrderSide::Buy => Self::Buy,
776 KrakenOrderSide::Sell => Self::Sell,
777 }
778 }
779}
780
781impl From<KrakenFillType> for LiquiditySide {
782 fn from(value: KrakenFillType) -> Self {
783 match value {
784 KrakenFillType::Maker => Self::Maker,
785 KrakenFillType::Taker | KrakenFillType::TakerAfterEdit => Self::Taker,
786 KrakenFillType::Liquidation
787 | KrakenFillType::PartialLiquidation
788 | KrakenFillType::Assignor
789 | KrakenFillType::Assignee
790 | KrakenFillType::UnwindBankrupt
791 | KrakenFillType::UnwindCounterparty => Self::NoLiquiditySide,
792 }
793 }
794}
795
796impl From<KrakenOrderType> for OrderType {
797 fn from(value: KrakenOrderType) -> Self {
803 match value {
804 KrakenOrderType::Market => Self::Market,
805 KrakenOrderType::Limit => Self::Limit,
806 KrakenOrderType::StopLoss => Self::StopMarket,
807 KrakenOrderType::TakeProfit => Self::MarketIfTouched,
808 KrakenOrderType::StopLossLimit => Self::StopLimit,
809 KrakenOrderType::TakeProfitLimit => Self::LimitIfTouched,
810 KrakenOrderType::TrailingStop => Self::StopMarket,
811 KrakenOrderType::TrailingStopLimit => Self::StopLimit,
812 KrakenOrderType::SettlePosition => Self::Market,
813 }
814 }
815}
816
817impl From<KrakenOrderStatus> for OrderStatus {
818 fn from(value: KrakenOrderStatus) -> Self {
819 match value {
820 KrakenOrderStatus::Pending => Self::Initialized,
821 KrakenOrderStatus::Open => Self::Accepted,
822 KrakenOrderStatus::Closed => Self::Filled,
823 KrakenOrderStatus::Canceled => Self::Canceled,
824 KrakenOrderStatus::Expired => Self::Expired,
825 }
826 }
827}
828
829#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
832#[serde(rename_all = "UPPERCASE")]
833pub enum KrakenFuturesQtyMode {
834 Absolute,
835 Relative,
836}
837
838#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
840pub enum KrakenFuturesHistoryDirection {
841 Buy,
842 Sell,
843 #[serde(other)]
845 Unknown,
846}
847
848#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
854pub enum KrakenFuturesHistoryOrderType {
855 Limit,
856 #[serde(rename = "IoC")]
857 Ioc,
858 Post,
859 Market,
860 Stop,
861 FillOrKill,
862 Liquidation,
863 PartialLiquidation,
864 CoveredLiquidation,
865 Assignment,
866 HedgeAssignment,
867 HedgeImmediateOrCancel,
868 Unwind,
869 Block,
870 Rfq,
871 #[serde(other)]
872 Unknown,
873}
874
875impl From<KrakenFuturesHistoryOrderType> for KrakenFuturesOrderType {
876 fn from(value: KrakenFuturesHistoryOrderType) -> Self {
877 match value {
878 KrakenFuturesHistoryOrderType::Limit => Self::Limit,
879 KrakenFuturesHistoryOrderType::Ioc
880 | KrakenFuturesHistoryOrderType::FillOrKill
881 | KrakenFuturesHistoryOrderType::HedgeImmediateOrCancel => Self::Ioc,
882 KrakenFuturesHistoryOrderType::Post => Self::Post,
883 KrakenFuturesHistoryOrderType::Stop => Self::Stop,
884 KrakenFuturesHistoryOrderType::Market
885 | KrakenFuturesHistoryOrderType::Liquidation
886 | KrakenFuturesHistoryOrderType::PartialLiquidation
887 | KrakenFuturesHistoryOrderType::CoveredLiquidation
888 | KrakenFuturesHistoryOrderType::Assignment
889 | KrakenFuturesHistoryOrderType::HedgeAssignment
890 | KrakenFuturesHistoryOrderType::Unwind
891 | KrakenFuturesHistoryOrderType::Block
892 | KrakenFuturesHistoryOrderType::Rfq => Self::Market,
893 KrakenFuturesHistoryOrderType::Unknown => Self::Unknown,
894 }
895 }
896}
897
898impl From<KrakenFuturesOrderType> for OrderType {
899 fn from(value: KrakenFuturesOrderType) -> Self {
900 match value {
901 KrakenFuturesOrderType::Limit
902 | KrakenFuturesOrderType::Ioc
903 | KrakenFuturesOrderType::Post => Self::Limit,
904 KrakenFuturesOrderType::Market => Self::Market,
905 KrakenFuturesOrderType::Stop | KrakenFuturesOrderType::StopLower => Self::StopMarket,
906 KrakenFuturesOrderType::TakeProfit => Self::MarketIfTouched,
907 KrakenFuturesOrderType::StopLoss => Self::StopMarket,
908 KrakenFuturesOrderType::Unknown => {
909 log::warn!(
910 "KrakenFuturesOrderType::Unknown received from venue, defaulting to Market"
911 );
912 Self::Market
913 }
914 }
915 }
916}
917
918impl From<OrderSide> for KrakenOrderSide {
919 fn from(value: OrderSide) -> Self {
920 match value {
921 OrderSide::Buy => Self::Buy,
922 OrderSide::Sell => Self::Sell,
923 }
924 }
925}
926
927impl From<KrakenFuturesOrderStatus> for OrderStatus {
928 fn from(value: KrakenFuturesOrderStatus) -> Self {
929 match value {
930 KrakenFuturesOrderStatus::Untouched => Self::Accepted,
931 KrakenFuturesOrderStatus::PartiallyFilled => Self::PartiallyFilled,
932 KrakenFuturesOrderStatus::Filled => Self::Filled,
933 KrakenFuturesOrderStatus::Cancelled => Self::Canceled,
934 KrakenFuturesOrderStatus::Expired => Self::Expired,
935 }
936 }
937}
938
939impl From<KrakenPairStatus> for MarketStatusAction {
940 fn from(value: KrakenPairStatus) -> Self {
941 match value {
942 KrakenPairStatus::Online => Self::Trading,
943 KrakenPairStatus::CancelOnly => Self::Halt,
944 KrakenPairStatus::PostOnly => Self::Pause,
945 KrakenPairStatus::LimitOnly => Self::Pause,
946 KrakenPairStatus::ReduceOnly => Self::Pause,
947 }
948 }
949}
950
951#[must_use]
962pub fn product_type_from_symbol(symbol: &str) -> KrakenProductType {
963 if symbol.starts_with("PI_")
964 || symbol.starts_with("PF_")
965 || symbol.starts_with("PV_")
966 || symbol.starts_with("FI_")
967 || symbol.starts_with("FF_")
968 {
969 KrakenProductType::Futures
970 } else {
971 KrakenProductType::Spot
972 }
973}
974
975#[cfg(test)]
976mod tests {
977 use nautilus_model::enums::{LiquiditySide, MarketStatusAction, OrderType};
978 use rstest::rstest;
979
980 use super::*;
981
982 #[rstest]
983 #[case::online(KrakenPairStatus::Online, MarketStatusAction::Trading)]
984 #[case::cancel_only(KrakenPairStatus::CancelOnly, MarketStatusAction::Halt)]
985 #[case::post_only(KrakenPairStatus::PostOnly, MarketStatusAction::Pause)]
986 #[case::limit_only(KrakenPairStatus::LimitOnly, MarketStatusAction::Pause)]
987 #[case::reduce_only(KrakenPairStatus::ReduceOnly, MarketStatusAction::Pause)]
988 fn test_pair_status_to_market_status_action(
989 #[case] input: KrakenPairStatus,
990 #[case] expected: MarketStatusAction,
991 ) {
992 assert_eq!(MarketStatusAction::from(input), expected);
993 }
994
995 #[rstest]
996 #[case::trailing_stop(KrakenOrderType::TrailingStop, OrderType::StopMarket)]
997 #[case::trailing_stop_limit(KrakenOrderType::TrailingStopLimit, OrderType::StopLimit)]
998 fn test_trailing_stop_order_type_mapping(
999 #[case] input: KrakenOrderType,
1000 #[case] expected: OrderType,
1001 ) {
1002 assert_eq!(OrderType::from(input), expected);
1003 }
1004
1005 #[rstest]
1006 #[case::maker(KrakenFillType::Maker, LiquiditySide::Maker)]
1007 #[case::taker(KrakenFillType::Taker, LiquiditySide::Taker)]
1008 #[case::liquidation(KrakenFillType::Liquidation, LiquiditySide::NoLiquiditySide)]
1009 #[case::partial_liquidation(KrakenFillType::PartialLiquidation, LiquiditySide::NoLiquiditySide)]
1010 #[case::assignor(KrakenFillType::Assignor, LiquiditySide::NoLiquiditySide)]
1011 #[case::assignee(KrakenFillType::Assignee, LiquiditySide::NoLiquiditySide)]
1012 #[case::taker_after_edit(KrakenFillType::TakerAfterEdit, LiquiditySide::Taker)]
1013 #[case::unwind_bankrupt(KrakenFillType::UnwindBankrupt, LiquiditySide::NoLiquiditySide)]
1014 #[case::unwind_counterparty(KrakenFillType::UnwindCounterparty, LiquiditySide::NoLiquiditySide)]
1015 fn test_fill_type_to_liquidity_side(
1016 #[case] fill_type: KrakenFillType,
1017 #[case] expected: LiquiditySide,
1018 ) {
1019 assert_eq!(LiquiditySide::from(fill_type), expected);
1020 }
1021
1022 #[rstest]
1023 fn test_fill_type_deserialization() {
1024 let json = include_str!("../../test_data/futures_fill_types.json");
1025 let fill_types: Vec<KrakenFillType> = serde_json::from_str(json).unwrap();
1026
1027 assert_eq!(
1028 fill_types,
1029 vec![
1030 KrakenFillType::Maker,
1031 KrakenFillType::Taker,
1032 KrakenFillType::Liquidation,
1033 KrakenFillType::PartialLiquidation,
1034 KrakenFillType::Assignor,
1035 KrakenFillType::Assignee,
1036 KrakenFillType::TakerAfterEdit,
1037 KrakenFillType::UnwindBankrupt,
1038 KrakenFillType::UnwindCounterparty,
1039 ]
1040 );
1041 }
1042
1043 #[rstest]
1044 fn test_time_in_force_deserializes_fok() {
1045 let tif: KrakenTimeInForce = serde_json::from_str("\"FOK\"").unwrap();
1048 assert_eq!(tif, KrakenTimeInForce::FillOrKill);
1049 }
1050
1051 #[rstest]
1052 #[case("\"placed\"", KrakenSendStatus::Placed)]
1053 #[case("\"cancelled\"", KrakenSendStatus::Cancelled)]
1054 #[case("\"edited\"", KrakenSendStatus::Edited)]
1055 #[case("\"notFound\"", KrakenSendStatus::NotFound)]
1056 #[case("\"noOrdersToCancel\"", KrakenSendStatus::NoOrdersToCancel)]
1057 #[case(
1058 "\"insufficientAvailableFunds\"",
1059 KrakenSendStatus::InsufficientAvailableFunds
1060 )]
1061 #[case("\"invalidOrderType\"", KrakenSendStatus::InvalidOrderType)]
1062 #[case("\"invalidSize\"", KrakenSendStatus::InvalidSize)]
1063 #[case("\"wouldCauseLiquidation\"", KrakenSendStatus::WouldCauseLiquidation)]
1064 #[case("\"postWouldExecute\"", KrakenSendStatus::PostWouldExecute)]
1065 #[case("\"iocWouldNotExecute\"", KrakenSendStatus::IocWouldNotExecute)]
1066 #[case(
1067 "\"reduceOnlyWouldIncreasePosition\"",
1068 KrakenSendStatus::ReduceOnlyWouldIncreasePosition
1069 )]
1070 fn test_send_status_deserialization(#[case] raw: &str, #[case] expected: KrakenSendStatus) {
1071 let parsed: KrakenSendStatus = serde_json::from_str(raw).unwrap();
1072 assert_eq!(parsed, expected);
1073 }
1074
1075 #[rstest]
1076 #[case("\"last\"", KrakenTriggerSignal::Last)]
1077 #[case("\"last_price\"", KrakenTriggerSignal::Last)]
1078 #[case("\"mark\"", KrakenTriggerSignal::Mark)]
1079 #[case("\"mark_price\"", KrakenTriggerSignal::Mark)]
1080 #[case("\"spot\"", KrakenTriggerSignal::Index)]
1081 #[case("\"spot_price\"", KrakenTriggerSignal::Index)]
1082 #[case("\"index\"", KrakenTriggerSignal::Index)]
1083 #[case("\"index_price\"", KrakenTriggerSignal::Index)]
1084 #[case("\"unknown\"", KrakenTriggerSignal::Unknown)]
1085 fn test_trigger_signal_deserialization(
1086 #[case] raw: &str,
1087 #[case] expected: KrakenTriggerSignal,
1088 ) {
1089 let parsed: KrakenTriggerSignal = serde_json::from_str(raw).unwrap();
1090 assert_eq!(parsed, expected);
1091 }
1092
1093 #[rstest]
1094 #[case("\"trigger_above\"", KrakenTriggerSide::TriggerAbove)]
1095 #[case("\"trigger_below\"", KrakenTriggerSide::TriggerBelow)]
1096 #[case("\"unknown\"", KrakenTriggerSide::Unknown)]
1097 fn test_trigger_side_deserialization(#[case] raw: &str, #[case] expected: KrakenTriggerSide) {
1098 let parsed: KrakenTriggerSide = serde_json::from_str(raw).unwrap();
1099 assert_eq!(parsed, expected);
1100 }
1101
1102 #[rstest]
1103 #[case("\"lmt\"", KrakenFuturesOrderType::Limit)]
1104 #[case("\"limit\"", KrakenFuturesOrderType::Limit)]
1105 #[case("\"ioc\"", KrakenFuturesOrderType::Ioc)]
1106 #[case("\"post\"", KrakenFuturesOrderType::Post)]
1107 #[case("\"mkt\"", KrakenFuturesOrderType::Market)]
1108 #[case("\"market\"", KrakenFuturesOrderType::Market)]
1109 #[case("\"stp\"", KrakenFuturesOrderType::Stop)]
1110 #[case("\"stop\"", KrakenFuturesOrderType::StopLower)]
1111 #[case("\"take_profit\"", KrakenFuturesOrderType::TakeProfit)]
1112 #[case("\"stop_loss\"", KrakenFuturesOrderType::StopLoss)]
1113 #[case("\"unknown\"", KrakenFuturesOrderType::Unknown)]
1114 fn test_futures_order_type_deserialization(
1115 #[case] raw: &str,
1116 #[case] expected: KrakenFuturesOrderType,
1117 ) {
1118 let parsed: KrakenFuturesOrderType = serde_json::from_str(raw).unwrap();
1119 assert_eq!(parsed, expected);
1120 }
1121
1122 #[rstest]
1123 fn test_order_metadata_enums_fail_loud_on_unmodeled_value() {
1124 assert!(serde_json::from_str::<KrakenFuturesOrderType>("\"iceberg\"").is_err());
1127 assert!(serde_json::from_str::<KrakenTriggerSignal>("\"vwap\"").is_err());
1128 assert!(serde_json::from_str::<KrakenTriggerSide>("\"sideways\"").is_err());
1129 }
1130
1131 #[rstest]
1132 fn test_futures_order_type_unknown_maps_to_market_default() {
1133 assert_eq!(
1134 OrderType::from(KrakenFuturesOrderType::Unknown),
1135 OrderType::Market,
1136 );
1137 }
1138
1139 #[rstest]
1140 #[case("\"PLACE\"", KrakenFuturesOrderEventType::Place)]
1141 #[case("\"FILL\"", KrakenFuturesOrderEventType::Fill)]
1142 #[case("\"EXECUTION\"", KrakenFuturesOrderEventType::Execution)]
1143 #[case("\"REJECT\"", KrakenFuturesOrderEventType::Reject)]
1144 #[case("\"CANCEL\"", KrakenFuturesOrderEventType::Cancel)]
1145 #[case("\"EDIT\"", KrakenFuturesOrderEventType::Edit)]
1146 #[case("\"EXPIRE\"", KrakenFuturesOrderEventType::Expire)]
1147 #[case("\"EXPIRED\"", KrakenFuturesOrderEventType::Expire)]
1148 fn test_futures_order_event_type_deserialization(
1149 #[case] raw: &str,
1150 #[case] expected: KrakenFuturesOrderEventType,
1151 ) {
1152 let parsed: KrakenFuturesOrderEventType = serde_json::from_str(raw).unwrap();
1153 assert_eq!(parsed, expected);
1154 }
1155}