Skip to main content

nautilus_kraken/websocket/spot_v2/
enums.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Enumerations for Kraken WebSocket v2 API.
17
18use nautilus_model::enums::{LiquiditySide, OrderStatus};
19use serde::{Deserialize, Serialize};
20use strum::{AsRefStr, Display, EnumString, FromRepr};
21
22#[derive(
23    Clone,
24    Copy,
25    Debug,
26    Display,
27    AsRefStr,
28    EnumString,
29    FromRepr,
30    PartialEq,
31    Eq,
32    Hash,
33    Serialize,
34    Deserialize,
35)]
36#[cfg_attr(
37    feature = "python",
38    pyo3::pyclass(
39        module = "nautilus_trader.core.nautilus_pyo3.kraken",
40        eq,
41        eq_int,
42        from_py_object
43    )
44)]
45#[cfg_attr(
46    feature = "python",
47    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.kraken")
48)]
49#[serde(rename_all = "lowercase")]
50#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
51pub enum KrakenWsMethod {
52    Subscribe,
53    Unsubscribe,
54    Ping,
55    Pong,
56    #[serde(rename = "add_order")]
57    #[strum(serialize = "add_order")]
58    AddOrder,
59    #[serde(rename = "amend_order")]
60    #[strum(serialize = "amend_order")]
61    AmendOrder,
62    #[serde(rename = "cancel_order")]
63    #[strum(serialize = "cancel_order")]
64    CancelOrder,
65    #[serde(rename = "batch_add")]
66    #[strum(serialize = "batch_add")]
67    BatchAdd,
68}
69
70#[derive(
71    Clone,
72    Copy,
73    Debug,
74    Display,
75    AsRefStr,
76    EnumString,
77    FromRepr,
78    PartialEq,
79    Eq,
80    Hash,
81    Serialize,
82    Deserialize,
83)]
84#[cfg_attr(
85    feature = "python",
86    pyo3::pyclass(
87        module = "nautilus_trader.core.nautilus_pyo3.kraken",
88        eq,
89        eq_int,
90        from_py_object
91    )
92)]
93#[cfg_attr(
94    feature = "python",
95    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.kraken")
96)]
97#[serde(rename_all = "lowercase")]
98#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
99pub enum KrakenWsChannel {
100    Ticker,
101    #[serde(rename = "trade")]
102    #[strum(serialize = "trade")]
103    Trade,
104    #[serde(rename = "book")]
105    #[strum(serialize = "book")]
106    Book,
107    #[serde(rename = "ohlc")]
108    #[strum(serialize = "ohlc")]
109    Ohlc,
110    #[serde(rename = "spread")]
111    #[strum(serialize = "spread")]
112    Spread,
113    // Private channels
114    #[serde(rename = "executions")]
115    #[strum(serialize = "executions")]
116    Executions,
117    #[serde(rename = "balances")]
118    #[strum(serialize = "balances")]
119    Balances,
120    #[serde(rename = "level3")]
121    #[strum(serialize = "level3")]
122    Level3,
123}
124
125#[derive(
126    Clone,
127    Copy,
128    Debug,
129    Display,
130    AsRefStr,
131    EnumString,
132    FromRepr,
133    PartialEq,
134    Eq,
135    Hash,
136    Serialize,
137    Deserialize,
138)]
139#[cfg_attr(
140    feature = "python",
141    pyo3::pyclass(
142        module = "nautilus_trader.core.nautilus_pyo3.kraken",
143        eq,
144        eq_int,
145        from_py_object
146    )
147)]
148#[cfg_attr(
149    feature = "python",
150    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.kraken")
151)]
152#[serde(rename_all = "lowercase")]
153#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
154pub enum KrakenWsMessageType {
155    Heartbeat,
156    Status,
157    Subscribe,
158    Unsubscribe,
159    Update,
160    Snapshot,
161    Error,
162}
163
164/// Execution type from the Kraken executions channel.
165#[derive(
166    Clone,
167    Copy,
168    Debug,
169    Display,
170    AsRefStr,
171    EnumString,
172    FromRepr,
173    PartialEq,
174    Eq,
175    Hash,
176    Serialize,
177    Deserialize,
178)]
179#[serde(rename_all = "snake_case")]
180#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
181pub enum KrakenExecType {
182    /// Order is pending submission to the exchange.
183    #[serde(rename = "pending_new")]
184    #[strum(serialize = "pending_new")]
185    PendingNew,
186    /// Order has been accepted by the exchange.
187    New,
188    /// Order has been partially or fully filled.
189    Trade,
190    /// Order has been completely filled.
191    Filled,
192    /// Iceberg order refill.
193    #[serde(rename = "iceberg_refill")]
194    #[strum(serialize = "iceberg_refill")]
195    IcebergRefill,
196    /// Order has been canceled.
197    Canceled,
198    /// Order has expired.
199    Expired,
200    /// Order has been amended (user-initiated modification).
201    Amended,
202    /// Order has been restated (engine-initiated adjustment).
203    Restated,
204    /// Order status update without state change.
205    Status,
206}
207
208/// Order status from the Kraken WebSocket v2 executions channel.
209#[derive(
210    Clone,
211    Copy,
212    Debug,
213    Display,
214    AsRefStr,
215    EnumString,
216    FromRepr,
217    PartialEq,
218    Eq,
219    Hash,
220    Serialize,
221    Deserialize,
222)]
223#[serde(rename_all = "snake_case")]
224#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
225pub enum KrakenWsOrderStatus {
226    /// Order is pending submission.
227    #[serde(rename = "pending_new")]
228    #[strum(serialize = "pending_new")]
229    PendingNew,
230    /// Order has been accepted.
231    New,
232    /// Order has been partially filled.
233    #[serde(rename = "partially_filled")]
234    #[strum(serialize = "partially_filled")]
235    PartiallyFilled,
236    /// Order has been completely filled.
237    Filled,
238    /// Order has been canceled.
239    Canceled,
240    /// Order has expired.
241    Expired,
242    /// Conditional order has been triggered.
243    Triggered,
244}
245
246/// Liquidity indicator from trade executions.
247#[derive(
248    Clone,
249    Copy,
250    Debug,
251    Display,
252    AsRefStr,
253    EnumString,
254    FromRepr,
255    PartialEq,
256    Eq,
257    Hash,
258    Serialize,
259    Deserialize,
260)]
261#[serde(rename_all = "lowercase")]
262#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
263pub enum KrakenLiquidityInd {
264    /// Maker (limit order that added liquidity).
265    #[serde(rename = "m")]
266    #[strum(serialize = "m")]
267    Maker,
268    /// Taker (order that removed liquidity).
269    #[serde(rename = "t")]
270    #[strum(serialize = "t")]
271    Taker,
272}
273
274impl From<KrakenWsOrderStatus> for OrderStatus {
275    fn from(value: KrakenWsOrderStatus) -> Self {
276        match value {
277            KrakenWsOrderStatus::PendingNew => Self::Submitted,
278            KrakenWsOrderStatus::New => Self::Accepted,
279            KrakenWsOrderStatus::PartiallyFilled => Self::PartiallyFilled,
280            KrakenWsOrderStatus::Filled => Self::Filled,
281            KrakenWsOrderStatus::Canceled => Self::Canceled,
282            KrakenWsOrderStatus::Expired => Self::Expired,
283            KrakenWsOrderStatus::Triggered => Self::Triggered,
284        }
285    }
286}
287
288impl From<KrakenLiquidityInd> for LiquiditySide {
289    fn from(value: KrakenLiquidityInd) -> Self {
290        match value {
291            KrakenLiquidityInd::Maker => Self::Maker,
292            KrakenLiquidityInd::Taker => Self::Taker,
293        }
294    }
295}
296
297#[cfg(test)]
298mod tests {
299    use rstest::rstest;
300
301    use super::*;
302
303    #[rstest]
304    #[case(KrakenWsMethod::AddOrder, "\"add_order\"")]
305    #[case(KrakenWsMethod::AmendOrder, "\"amend_order\"")]
306    #[case(KrakenWsMethod::CancelOrder, "\"cancel_order\"")]
307    #[case(KrakenWsMethod::BatchAdd, "\"batch_add\"")]
308    fn test_ws_method_order_variants_serde(#[case] m: KrakenWsMethod, #[case] expected: &str) {
309        let json = serde_json::to_string(&m).unwrap();
310        assert_eq!(json, expected);
311        let back: KrakenWsMethod = serde_json::from_str(&json).unwrap();
312        assert_eq!(back, m);
313    }
314
315    #[rstest]
316    fn test_ws_channel_level3_serde() {
317        let json = serde_json::to_string(&KrakenWsChannel::Level3).unwrap();
318        assert_eq!(json, "\"level3\"");
319        let back: KrakenWsChannel = serde_json::from_str(&json).unwrap();
320        assert_eq!(back, KrakenWsChannel::Level3);
321    }
322}