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}
726
727#[derive(
729 Clone,
730 Copy,
731 Debug,
732 Display,
733 AsRefStr,
734 EnumString,
735 FromRepr,
736 PartialEq,
737 Eq,
738 Hash,
739 Serialize,
740 Deserialize,
741)]
742#[cfg_attr(
743 feature = "python",
744 pyo3::pyclass(module = "nautilus_trader.adapters.kraken", eq, eq_int, from_py_object)
745)]
746#[serde(rename_all = "snake_case")]
747#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
748pub enum KrakenTriggerSide {
749 #[serde(rename = "trigger_above")]
751 #[strum(serialize = "trigger_above")]
752 TriggerAbove,
753 #[serde(rename = "trigger_below")]
755 #[strum(serialize = "trigger_below")]
756 TriggerBelow,
757 #[serde(rename = "unknown")]
759 Unknown,
760}
761
762impl From<KrakenOrderSide> for OrderSide {
763 fn from(value: KrakenOrderSide) -> Self {
764 match value {
765 KrakenOrderSide::Buy => Self::Buy,
766 KrakenOrderSide::Sell => Self::Sell,
767 }
768 }
769}
770
771impl From<KrakenFillType> for LiquiditySide {
772 fn from(value: KrakenFillType) -> Self {
773 match value {
774 KrakenFillType::Maker => Self::Maker,
775 KrakenFillType::Taker | KrakenFillType::TakerAfterEdit => Self::Taker,
776 KrakenFillType::Liquidation
777 | KrakenFillType::PartialLiquidation
778 | KrakenFillType::Assignor
779 | KrakenFillType::Assignee
780 | KrakenFillType::UnwindBankrupt
781 | KrakenFillType::UnwindCounterparty => Self::NoLiquiditySide,
782 }
783 }
784}
785
786impl From<KrakenOrderType> for OrderType {
787 fn from(value: KrakenOrderType) -> Self {
793 match value {
794 KrakenOrderType::Market => Self::Market,
795 KrakenOrderType::Limit => Self::Limit,
796 KrakenOrderType::StopLoss => Self::StopMarket,
797 KrakenOrderType::TakeProfit => Self::MarketIfTouched,
798 KrakenOrderType::StopLossLimit => Self::StopLimit,
799 KrakenOrderType::TakeProfitLimit => Self::LimitIfTouched,
800 KrakenOrderType::TrailingStop => Self::StopMarket,
801 KrakenOrderType::TrailingStopLimit => Self::StopLimit,
802 KrakenOrderType::SettlePosition => Self::Market,
803 }
804 }
805}
806
807impl From<KrakenOrderStatus> for OrderStatus {
808 fn from(value: KrakenOrderStatus) -> Self {
809 match value {
810 KrakenOrderStatus::Pending => Self::Initialized,
811 KrakenOrderStatus::Open => Self::Accepted,
812 KrakenOrderStatus::Closed => Self::Filled,
813 KrakenOrderStatus::Canceled => Self::Canceled,
814 KrakenOrderStatus::Expired => Self::Expired,
815 }
816 }
817}
818
819#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
822#[serde(rename_all = "UPPERCASE")]
823pub enum KrakenFuturesQtyMode {
824 Absolute,
825 Relative,
826}
827
828#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
830pub enum KrakenFuturesHistoryDirection {
831 Buy,
832 Sell,
833 #[serde(other)]
835 Unknown,
836}
837
838#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
844pub enum KrakenFuturesHistoryOrderType {
845 Limit,
846 #[serde(rename = "IoC")]
847 Ioc,
848 Post,
849 Market,
850 Stop,
851 FillOrKill,
852 Liquidation,
853 PartialLiquidation,
854 CoveredLiquidation,
855 Assignment,
856 HedgeAssignment,
857 HedgeImmediateOrCancel,
858 Unwind,
859 Block,
860 Rfq,
861 #[serde(other)]
862 Unknown,
863}
864
865impl From<KrakenFuturesHistoryOrderType> for KrakenFuturesOrderType {
866 fn from(value: KrakenFuturesHistoryOrderType) -> Self {
867 match value {
868 KrakenFuturesHistoryOrderType::Limit => Self::Limit,
869 KrakenFuturesHistoryOrderType::Ioc
870 | KrakenFuturesHistoryOrderType::FillOrKill
871 | KrakenFuturesHistoryOrderType::HedgeImmediateOrCancel => Self::Ioc,
872 KrakenFuturesHistoryOrderType::Post => Self::Post,
873 KrakenFuturesHistoryOrderType::Stop => Self::Stop,
874 KrakenFuturesHistoryOrderType::Market
875 | KrakenFuturesHistoryOrderType::Liquidation
876 | KrakenFuturesHistoryOrderType::PartialLiquidation
877 | KrakenFuturesHistoryOrderType::CoveredLiquidation
878 | KrakenFuturesHistoryOrderType::Assignment
879 | KrakenFuturesHistoryOrderType::HedgeAssignment
880 | KrakenFuturesHistoryOrderType::Unwind
881 | KrakenFuturesHistoryOrderType::Block
882 | KrakenFuturesHistoryOrderType::Rfq => Self::Market,
883 KrakenFuturesHistoryOrderType::Unknown => Self::Unknown,
884 }
885 }
886}
887
888impl From<KrakenFuturesOrderType> for OrderType {
889 fn from(value: KrakenFuturesOrderType) -> Self {
890 match value {
891 KrakenFuturesOrderType::Limit
892 | KrakenFuturesOrderType::Ioc
893 | KrakenFuturesOrderType::Post => Self::Limit,
894 KrakenFuturesOrderType::Market => Self::Market,
895 KrakenFuturesOrderType::Stop | KrakenFuturesOrderType::StopLower => Self::StopMarket,
896 KrakenFuturesOrderType::TakeProfit => Self::MarketIfTouched,
897 KrakenFuturesOrderType::StopLoss => Self::StopMarket,
898 KrakenFuturesOrderType::Unknown => {
899 log::warn!(
900 "KrakenFuturesOrderType::Unknown received from venue, defaulting to Market"
901 );
902 Self::Market
903 }
904 }
905 }
906}
907
908impl From<OrderSide> for KrakenOrderSide {
909 fn from(value: OrderSide) -> Self {
910 match value {
911 OrderSide::Buy => Self::Buy,
912 OrderSide::Sell => Self::Sell,
913 }
914 }
915}
916
917impl From<KrakenFuturesOrderStatus> for OrderStatus {
918 fn from(value: KrakenFuturesOrderStatus) -> Self {
919 match value {
920 KrakenFuturesOrderStatus::Untouched => Self::Accepted,
921 KrakenFuturesOrderStatus::PartiallyFilled => Self::PartiallyFilled,
922 KrakenFuturesOrderStatus::Filled => Self::Filled,
923 KrakenFuturesOrderStatus::Cancelled => Self::Canceled,
924 KrakenFuturesOrderStatus::Expired => Self::Expired,
925 }
926 }
927}
928
929impl From<KrakenPairStatus> for MarketStatusAction {
930 fn from(value: KrakenPairStatus) -> Self {
931 match value {
932 KrakenPairStatus::Online => Self::Trading,
933 KrakenPairStatus::CancelOnly => Self::Halt,
934 KrakenPairStatus::PostOnly => Self::Pause,
935 KrakenPairStatus::LimitOnly => Self::Pause,
936 KrakenPairStatus::ReduceOnly => Self::Pause,
937 }
938 }
939}
940
941#[must_use]
952pub fn product_type_from_symbol(symbol: &str) -> KrakenProductType {
953 if symbol.starts_with("PI_")
954 || symbol.starts_with("PF_")
955 || symbol.starts_with("PV_")
956 || symbol.starts_with("FI_")
957 || symbol.starts_with("FF_")
958 {
959 KrakenProductType::Futures
960 } else {
961 KrakenProductType::Spot
962 }
963}
964
965#[cfg(test)]
966mod tests {
967 use nautilus_model::enums::{LiquiditySide, MarketStatusAction, OrderType};
968 use rstest::rstest;
969
970 use super::*;
971
972 #[rstest]
973 #[case::online(KrakenPairStatus::Online, MarketStatusAction::Trading)]
974 #[case::cancel_only(KrakenPairStatus::CancelOnly, MarketStatusAction::Halt)]
975 #[case::post_only(KrakenPairStatus::PostOnly, MarketStatusAction::Pause)]
976 #[case::limit_only(KrakenPairStatus::LimitOnly, MarketStatusAction::Pause)]
977 #[case::reduce_only(KrakenPairStatus::ReduceOnly, MarketStatusAction::Pause)]
978 fn test_pair_status_to_market_status_action(
979 #[case] input: KrakenPairStatus,
980 #[case] expected: MarketStatusAction,
981 ) {
982 assert_eq!(MarketStatusAction::from(input), expected);
983 }
984
985 #[rstest]
986 #[case::trailing_stop(KrakenOrderType::TrailingStop, OrderType::StopMarket)]
987 #[case::trailing_stop_limit(KrakenOrderType::TrailingStopLimit, OrderType::StopLimit)]
988 fn test_trailing_stop_order_type_mapping(
989 #[case] input: KrakenOrderType,
990 #[case] expected: OrderType,
991 ) {
992 assert_eq!(OrderType::from(input), expected);
993 }
994
995 #[rstest]
996 #[case::maker(KrakenFillType::Maker, LiquiditySide::Maker)]
997 #[case::taker(KrakenFillType::Taker, LiquiditySide::Taker)]
998 #[case::liquidation(KrakenFillType::Liquidation, LiquiditySide::NoLiquiditySide)]
999 #[case::partial_liquidation(KrakenFillType::PartialLiquidation, LiquiditySide::NoLiquiditySide)]
1000 #[case::assignor(KrakenFillType::Assignor, LiquiditySide::NoLiquiditySide)]
1001 #[case::assignee(KrakenFillType::Assignee, LiquiditySide::NoLiquiditySide)]
1002 #[case::taker_after_edit(KrakenFillType::TakerAfterEdit, LiquiditySide::Taker)]
1003 #[case::unwind_bankrupt(KrakenFillType::UnwindBankrupt, LiquiditySide::NoLiquiditySide)]
1004 #[case::unwind_counterparty(KrakenFillType::UnwindCounterparty, LiquiditySide::NoLiquiditySide)]
1005 fn test_fill_type_to_liquidity_side(
1006 #[case] fill_type: KrakenFillType,
1007 #[case] expected: LiquiditySide,
1008 ) {
1009 assert_eq!(LiquiditySide::from(fill_type), expected);
1010 }
1011
1012 #[rstest]
1013 fn test_fill_type_deserialization() {
1014 let json = include_str!("../../test_data/futures_fill_types.json");
1015 let fill_types: Vec<KrakenFillType> = serde_json::from_str(json).unwrap();
1016
1017 assert_eq!(
1018 fill_types,
1019 vec![
1020 KrakenFillType::Maker,
1021 KrakenFillType::Taker,
1022 KrakenFillType::Liquidation,
1023 KrakenFillType::PartialLiquidation,
1024 KrakenFillType::Assignor,
1025 KrakenFillType::Assignee,
1026 KrakenFillType::TakerAfterEdit,
1027 KrakenFillType::UnwindBankrupt,
1028 KrakenFillType::UnwindCounterparty,
1029 ]
1030 );
1031 }
1032
1033 #[rstest]
1034 fn test_time_in_force_deserializes_fok() {
1035 let tif: KrakenTimeInForce = serde_json::from_str("\"FOK\"").unwrap();
1038 assert_eq!(tif, KrakenTimeInForce::FillOrKill);
1039 }
1040
1041 #[rstest]
1042 #[case("\"placed\"", KrakenSendStatus::Placed)]
1043 #[case("\"cancelled\"", KrakenSendStatus::Cancelled)]
1044 #[case("\"edited\"", KrakenSendStatus::Edited)]
1045 #[case("\"notFound\"", KrakenSendStatus::NotFound)]
1046 #[case("\"noOrdersToCancel\"", KrakenSendStatus::NoOrdersToCancel)]
1047 #[case(
1048 "\"insufficientAvailableFunds\"",
1049 KrakenSendStatus::InsufficientAvailableFunds
1050 )]
1051 #[case("\"invalidOrderType\"", KrakenSendStatus::InvalidOrderType)]
1052 #[case("\"invalidSize\"", KrakenSendStatus::InvalidSize)]
1053 #[case("\"wouldCauseLiquidation\"", KrakenSendStatus::WouldCauseLiquidation)]
1054 #[case("\"postWouldExecute\"", KrakenSendStatus::PostWouldExecute)]
1055 #[case("\"iocWouldNotExecute\"", KrakenSendStatus::IocWouldNotExecute)]
1056 #[case(
1057 "\"reduceOnlyWouldIncreasePosition\"",
1058 KrakenSendStatus::ReduceOnlyWouldIncreasePosition
1059 )]
1060 fn test_send_status_deserialization(#[case] raw: &str, #[case] expected: KrakenSendStatus) {
1061 let parsed: KrakenSendStatus = serde_json::from_str(raw).unwrap();
1062 assert_eq!(parsed, expected);
1063 }
1064
1065 #[rstest]
1066 #[case("\"last\"", KrakenTriggerSignal::Last)]
1067 #[case("\"last_price\"", KrakenTriggerSignal::Last)]
1068 #[case("\"mark\"", KrakenTriggerSignal::Mark)]
1069 #[case("\"mark_price\"", KrakenTriggerSignal::Mark)]
1070 #[case("\"spot\"", KrakenTriggerSignal::Index)]
1071 #[case("\"spot_price\"", KrakenTriggerSignal::Index)]
1072 #[case("\"index\"", KrakenTriggerSignal::Index)]
1073 #[case("\"index_price\"", KrakenTriggerSignal::Index)]
1074 #[case("\"unknown\"", KrakenTriggerSignal::Unknown)]
1075 fn test_trigger_signal_deserialization(
1076 #[case] raw: &str,
1077 #[case] expected: KrakenTriggerSignal,
1078 ) {
1079 let parsed: KrakenTriggerSignal = serde_json::from_str(raw).unwrap();
1080 assert_eq!(parsed, expected);
1081 }
1082
1083 #[rstest]
1084 #[case("\"trigger_above\"", KrakenTriggerSide::TriggerAbove)]
1085 #[case("\"trigger_below\"", KrakenTriggerSide::TriggerBelow)]
1086 #[case("\"unknown\"", KrakenTriggerSide::Unknown)]
1087 fn test_trigger_side_deserialization(#[case] raw: &str, #[case] expected: KrakenTriggerSide) {
1088 let parsed: KrakenTriggerSide = serde_json::from_str(raw).unwrap();
1089 assert_eq!(parsed, expected);
1090 }
1091
1092 #[rstest]
1093 #[case("\"lmt\"", KrakenFuturesOrderType::Limit)]
1094 #[case("\"limit\"", KrakenFuturesOrderType::Limit)]
1095 #[case("\"ioc\"", KrakenFuturesOrderType::Ioc)]
1096 #[case("\"post\"", KrakenFuturesOrderType::Post)]
1097 #[case("\"mkt\"", KrakenFuturesOrderType::Market)]
1098 #[case("\"market\"", KrakenFuturesOrderType::Market)]
1099 #[case("\"stp\"", KrakenFuturesOrderType::Stop)]
1100 #[case("\"stop\"", KrakenFuturesOrderType::StopLower)]
1101 #[case("\"take_profit\"", KrakenFuturesOrderType::TakeProfit)]
1102 #[case("\"stop_loss\"", KrakenFuturesOrderType::StopLoss)]
1103 #[case("\"unknown\"", KrakenFuturesOrderType::Unknown)]
1104 fn test_futures_order_type_deserialization(
1105 #[case] raw: &str,
1106 #[case] expected: KrakenFuturesOrderType,
1107 ) {
1108 let parsed: KrakenFuturesOrderType = serde_json::from_str(raw).unwrap();
1109 assert_eq!(parsed, expected);
1110 }
1111
1112 #[rstest]
1113 fn test_order_metadata_enums_fail_loud_on_unmodeled_value() {
1114 assert!(serde_json::from_str::<KrakenFuturesOrderType>("\"iceberg\"").is_err());
1117 assert!(serde_json::from_str::<KrakenTriggerSignal>("\"vwap\"").is_err());
1118 assert!(serde_json::from_str::<KrakenTriggerSide>("\"sideways\"").is_err());
1119 }
1120
1121 #[rstest]
1122 fn test_futures_order_type_unknown_maps_to_market_default() {
1123 assert_eq!(
1124 OrderType::from(KrakenFuturesOrderType::Unknown),
1125 OrderType::Market,
1126 );
1127 }
1128
1129 #[rstest]
1130 #[case("\"PLACE\"", KrakenFuturesOrderEventType::Place)]
1131 #[case("\"FILL\"", KrakenFuturesOrderEventType::Fill)]
1132 #[case("\"EXECUTION\"", KrakenFuturesOrderEventType::Execution)]
1133 #[case("\"REJECT\"", KrakenFuturesOrderEventType::Reject)]
1134 #[case("\"CANCEL\"", KrakenFuturesOrderEventType::Cancel)]
1135 #[case("\"EDIT\"", KrakenFuturesOrderEventType::Edit)]
1136 #[case("\"EXPIRE\"", KrakenFuturesOrderEventType::Expire)]
1137 #[case("\"EXPIRED\"", KrakenFuturesOrderEventType::Expire)]
1138 fn test_futures_order_event_type_deserialization(
1139 #[case] raw: &str,
1140 #[case] expected: KrakenFuturesOrderEventType,
1141 ) {
1142 let parsed: KrakenFuturesOrderEventType = serde_json::from_str(raw).unwrap();
1143 assert_eq!(parsed, expected);
1144 }
1145}