nautilus_dydx/websocket/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//! Enums for dYdX WebSocket operations, channels, and message types.
17
18use chrono::{DateTime, Utc};
19use serde::{Deserialize, Serialize};
20use serde_json::Value;
21use strum::{AsRefStr, Display, EnumString, FromRepr};
22
23use super::{
24 error::DydxWebSocketError,
25 messages::{
26 DydxCandle, DydxMarketsContents, DydxOrderbookContents, DydxOrderbookSnapshotContents,
27 DydxTradeContents, DydxWsConnectedMsg, DydxWsSubaccountsChannelData,
28 DydxWsSubaccountsSubscribed, DydxWsSubscriptionMsg,
29 },
30};
31
32/// WebSocket operation types for dYdX.
33#[derive(
34 Clone,
35 Copy,
36 Debug,
37 PartialEq,
38 Eq,
39 Hash,
40 Display,
41 AsRefStr,
42 EnumString,
43 FromRepr,
44 Serialize,
45 Deserialize,
46)]
47#[serde(rename_all = "snake_case")]
48#[strum(serialize_all = "snake_case")]
49pub enum DydxWsOperation {
50 /// Subscribes to a channel.
51 Subscribe,
52 /// Unsubscribes from a channel.
53 Unsubscribe,
54 /// Ping keepalive message.
55 Ping,
56 /// Pong response to ping.
57 Pong,
58}
59
60/// dYdX WebSocket channel identifiers.
61///
62/// # References
63///
64/// <https://docs.dydx.trade/developers/indexer/websockets>
65#[derive(
66 Clone,
67 Copy,
68 Debug,
69 Default,
70 PartialEq,
71 Eq,
72 Hash,
73 Display,
74 AsRefStr,
75 EnumString,
76 FromRepr,
77 Serialize,
78 Deserialize,
79)]
80#[serde(rename_all = "snake_case")]
81#[strum(serialize_all = "snake_case")]
82pub enum DydxWsChannel {
83 /// Market data for all markets.
84 #[serde(rename = "v4_markets")]
85 #[strum(serialize = "v4_markets")]
86 Markets,
87 /// Trade stream for specific market.
88 #[serde(rename = "v4_trades")]
89 #[strum(serialize = "v4_trades")]
90 Trades,
91 /// Order book snapshots and updates.
92 #[serde(rename = "v4_orderbook")]
93 #[strum(serialize = "v4_orderbook")]
94 Orderbook,
95 /// Candlestick/kline data.
96 #[serde(rename = "v4_candles")]
97 #[strum(serialize = "v4_candles")]
98 Candles,
99 /// Subaccount updates (orders, fills, positions).
100 #[serde(rename = "v4_subaccounts")]
101 #[strum(serialize = "v4_subaccounts")]
102 Subaccounts,
103 /// Parent subaccount updates (for isolated positions).
104 #[serde(rename = "v4_parent_subaccounts")]
105 #[strum(serialize = "v4_parent_subaccounts")]
106 ParentSubaccounts,
107 /// Block height updates from chain.
108 #[serde(rename = "v4_block_height")]
109 #[strum(serialize = "v4_block_height")]
110 BlockHeight,
111 /// Unknown/unrecognized channel type (default when field is missing).
112 #[default]
113 #[serde(other)]
114 #[strum(to_string = "unknown")]
115 Unknown,
116}
117
118impl DydxWsChannel {
119 /// Returns `true` if this is a private channel requiring authentication.
120 #[must_use]
121 pub const fn is_private(&self) -> bool {
122 matches!(self, Self::Subaccounts | Self::ParentSubaccounts)
123 }
124
125 /// Returns `true` if this is a public channel.
126 #[must_use]
127 pub const fn is_public(&self) -> bool {
128 !self.is_private()
129 }
130
131 /// Returns `true` if this is an unknown/unrecognized channel type.
132 #[must_use]
133 pub const fn is_unknown(&self) -> bool {
134 matches!(self, Self::Unknown)
135 }
136}
137
138/// WebSocket message types for dYdX.
139#[derive(
140 Clone,
141 Copy,
142 Debug,
143 Default,
144 PartialEq,
145 Eq,
146 Hash,
147 Display,
148 AsRefStr,
149 EnumString,
150 FromRepr,
151 Serialize,
152 Deserialize,
153)]
154#[serde(rename_all = "snake_case")]
155#[strum(serialize_all = "snake_case")]
156pub enum DydxWsMessageType {
157 /// Connection established.
158 Connected,
159 /// Subscription confirmed.
160 Subscribed,
161 /// Unsubscription confirmed.
162 Unsubscribed,
163 /// Channel data update (default for missing type field).
164 #[default]
165 ChannelData,
166 /// Batch channel data update.
167 ChannelBatchData,
168 /// Error message.
169 Error,
170 /// Unknown/unrecognized message type.
171 #[serde(other)]
172 #[strum(to_string = "unknown")]
173 Unknown,
174}
175
176/// Control messages for the fallback parsing path.
177///
178/// Channel data is handled directly via `DydxWsFeedMessage` in `handle_feed_message()`.
179#[derive(Debug, Clone)]
180pub enum DydxWsMessage {
181 /// Subscription acknowledgement.
182 Subscribed(DydxWsSubscriptionMsg),
183 /// Unsubscription acknowledgement.
184 Unsubscribed(DydxWsSubscriptionMsg),
185 /// Subaccounts subscription with initial account state.
186 SubaccountsSubscribed(DydxWsSubaccountsSubscribed),
187 /// Connected acknowledgement with connection_id.
188 Connected(DydxWsConnectedMsg),
189 /// Error received from the venue or client lifecycle.
190 Error(DydxWebSocketError),
191 /// Raw message payload that does not yet have a typed representation.
192 Raw(Value),
193 /// Notification that the underlying connection reconnected.
194 Reconnected,
195 /// Explicit pong event (text-based heartbeat acknowledgement).
196 Pong,
197}
198
199/// Venue-specific message emitted by the handler to consumers.
200///
201/// The handler deserializes raw WebSocket JSON into these typed variants
202/// without converting to Nautilus domain types. Consumers (data client,
203/// execution client, Python bindings) perform the final conversion using
204/// their own instrument caches.
205#[derive(Debug, Clone)]
206pub enum DydxWsOutputMessage {
207 /// Trade data for a market.
208 Trades {
209 id: String,
210 contents: DydxTradeContents,
211 },
212 /// Order book snapshot (initial subscription).
213 OrderbookSnapshot {
214 id: String,
215 contents: DydxOrderbookSnapshotContents,
216 },
217 /// Order book delta update.
218 OrderbookUpdate {
219 id: String,
220 contents: DydxOrderbookContents,
221 },
222 /// Order book batch update (multiple deltas).
223 OrderbookBatch {
224 id: String,
225 updates: Vec<DydxOrderbookContents>,
226 },
227 /// Candle data for a market.
228 Candles { id: String, contents: DydxCandle },
229 /// Markets channel data (oracle prices, trading, instrument status).
230 Markets(DydxMarketsContents),
231 /// Subaccount subscription with initial account state.
232 SubaccountSubscribed(Box<DydxWsSubaccountsSubscribed>),
233 /// Subaccount channel data (orders, fills).
234 SubaccountsChannelData(Box<DydxWsSubaccountsChannelData>),
235 /// Block height update from chain.
236 BlockHeight { height: u64, time: DateTime<Utc> },
237 /// Error from the venue or handler.
238 Error(DydxWebSocketError),
239 /// Reconnection notification.
240 Reconnected,
241}