nautilus_dydx/websocket/
enums.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 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//! Enums for dYdX WebSocket operations, channels, and message types.
17
18use std::collections::HashMap;
19
20use nautilus_model::{
21    data::{Data, OrderBookDeltas},
22    events::AccountState,
23    reports::{FillReport, OrderStatusReport, PositionStatusReport},
24};
25use serde::{Deserialize, Serialize};
26use serde_json::Value;
27use strum::{AsRefStr, Display, EnumString, FromRepr};
28
29use super::{
30    error::DydxWebSocketError,
31    messages::{
32        DydxOraclePriceMarket, DydxWsChannelBatchDataMsg, DydxWsChannelDataMsg, DydxWsConnectedMsg,
33        DydxWsSubaccountsChannelData, DydxWsSubaccountsSubscribed, DydxWsSubscriptionMsg,
34    },
35};
36
37/// WebSocket operation types for dYdX.
38#[derive(
39    Clone,
40    Copy,
41    Debug,
42    PartialEq,
43    Eq,
44    Hash,
45    Display,
46    AsRefStr,
47    EnumString,
48    FromRepr,
49    Serialize,
50    Deserialize,
51)]
52#[serde(rename_all = "snake_case")]
53#[strum(serialize_all = "snake_case")]
54pub enum DydxWsOperation {
55    /// Subscribe to a channel.
56    Subscribe,
57    /// Unsubscribe from a channel.
58    Unsubscribe,
59    /// Ping keepalive message.
60    Ping,
61    /// Pong response to ping.
62    Pong,
63}
64
65/// dYdX WebSocket channel identifiers.
66///
67/// # References
68///
69/// <https://docs.dydx.trade/developers/indexer/websockets>
70#[derive(
71    Clone,
72    Copy,
73    Debug,
74    PartialEq,
75    Eq,
76    Hash,
77    Display,
78    AsRefStr,
79    EnumString,
80    FromRepr,
81    Serialize,
82    Deserialize,
83)]
84#[serde(rename_all = "snake_case")]
85#[strum(serialize_all = "snake_case")]
86pub enum DydxWsChannel {
87    /// Market data for all markets.
88    #[serde(rename = "v4_markets")]
89    #[strum(serialize = "v4_markets")]
90    Markets,
91    /// Trade stream for specific market.
92    #[serde(rename = "v4_trades")]
93    #[strum(serialize = "v4_trades")]
94    Trades,
95    /// Order book snapshots and updates.
96    #[serde(rename = "v4_orderbook")]
97    #[strum(serialize = "v4_orderbook")]
98    Orderbook,
99    /// Candlestick/kline data.
100    #[serde(rename = "v4_candles")]
101    #[strum(serialize = "v4_candles")]
102    Candles,
103    /// Subaccount updates (orders, fills, positions).
104    #[serde(rename = "v4_subaccounts")]
105    #[strum(serialize = "v4_subaccounts")]
106    Subaccounts,
107    /// Parent subaccount updates (for isolated positions).
108    #[serde(rename = "v4_parent_subaccounts")]
109    #[strum(serialize = "v4_parent_subaccounts")]
110    ParentSubaccounts,
111    /// Block height updates from chain.
112    #[serde(rename = "v4_block_height")]
113    #[strum(serialize = "v4_block_height")]
114    BlockHeight,
115    /// Unknown/unrecognized channel type.
116    #[serde(other)]
117    #[strum(to_string = "unknown")]
118    Unknown,
119}
120
121impl DydxWsChannel {
122    /// Returns `true` if this is a private channel requiring authentication.
123    #[must_use]
124    pub const fn is_private(&self) -> bool {
125        matches!(self, Self::Subaccounts | Self::ParentSubaccounts)
126    }
127
128    /// Returns `true` if this is a public channel.
129    #[must_use]
130    pub const fn is_public(&self) -> bool {
131        !self.is_private()
132    }
133
134    /// Returns `true` if this is an unknown/unrecognized channel type.
135    #[must_use]
136    pub const fn is_unknown(&self) -> bool {
137        matches!(self, Self::Unknown)
138    }
139}
140
141/// WebSocket message types for dYdX.
142#[derive(
143    Clone,
144    Copy,
145    Debug,
146    PartialEq,
147    Eq,
148    Hash,
149    Display,
150    AsRefStr,
151    EnumString,
152    FromRepr,
153    Serialize,
154    Deserialize,
155)]
156#[serde(rename_all = "snake_case")]
157#[strum(serialize_all = "snake_case")]
158pub enum DydxWsMessageType {
159    /// Connection established.
160    Connected,
161    /// Subscription confirmed.
162    Subscribed,
163    /// Unsubscription confirmed.
164    Unsubscribed,
165    /// Channel data update.
166    ChannelData,
167    /// Batch channel data update.
168    ChannelBatchData,
169    /// Error message.
170    Error,
171    /// Unknown/unrecognized message type.
172    #[serde(other)]
173    #[strum(to_string = "unknown")]
174    Unknown,
175}
176
177/// High level message emitted by the dYdX WebSocket client.
178#[derive(Debug, Clone)]
179pub enum DydxWsMessage {
180    /// Subscription acknowledgement.
181    Subscribed(DydxWsSubscriptionMsg),
182    /// Unsubscription acknowledgement.
183    Unsubscribed(DydxWsSubscriptionMsg),
184    /// Subaccounts subscription with initial account state.
185    SubaccountsSubscribed(DydxWsSubaccountsSubscribed),
186    /// Connected acknowledgement with connection_id.
187    Connected(DydxWsConnectedMsg),
188    /// Channel data update.
189    ChannelData(DydxWsChannelDataMsg),
190    /// Batch of channel data updates.
191    ChannelBatchData(DydxWsChannelBatchDataMsg),
192    /// Error received from the venue or client lifecycle.
193    Error(DydxWebSocketError),
194    /// Raw message payload that does not yet have a typed representation.
195    Raw(Value),
196    /// Notification that the underlying connection reconnected.
197    Reconnected,
198    /// Explicit pong event (text-based heartbeat acknowledgement).
199    Pong,
200}
201
202/// Nautilus domain message emitted after parsing dYdX WebSocket events.
203///
204/// This enum contains fully-parsed Nautilus domain objects ready for consumption
205/// by the Python layer without additional processing.
206#[derive(Debug, Clone)]
207pub enum NautilusWsMessage {
208    /// Market data (trades, quotes, bars).
209    Data(Vec<Data>),
210    /// Order book deltas.
211    Deltas(Box<OrderBookDeltas>),
212    /// Order status reports from subaccount stream.
213    Order(Box<OrderStatusReport>),
214    /// Fill reports from subaccount stream.
215    Fill(Box<FillReport>),
216    /// Position status reports from subaccount stream.
217    Position(Box<PositionStatusReport>),
218    /// Account state updates from subaccount stream.
219    AccountState(Box<AccountState>),
220    /// Raw subaccount subscription with full state (for execution client parsing).
221    SubaccountSubscribed(Box<DydxWsSubaccountsSubscribed>),
222    /// Raw subaccounts channel data (orders/fills) for execution client parsing.
223    SubaccountsChannelData(Box<DydxWsSubaccountsChannelData>),
224    /// Oracle price updates from markets channel (for execution client).
225    OraclePrices(HashMap<String, DydxOraclePriceMarket>),
226    /// Error message.
227    Error(DydxWebSocketError),
228    /// Reconnection notification.
229    Reconnected,
230}