1use 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;
27
28use crate::{
29 schemas::ws::DydxWsMessageType,
30 websocket::{
31 enums::{DydxWsChannel, DydxWsOperation},
32 error::DydxWebSocketError,
33 },
34};
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct DydxSubscription {
43 #[serde(rename = "type")]
45 pub op: DydxWsOperation,
46 pub channel: DydxWsChannel,
48 #[serde(skip_serializing_if = "Option::is_none")]
50 pub id: Option<String>,
51}
52
53#[derive(Debug, Clone)]
55pub enum DydxWsMessage {
56 Subscribed(DydxWsSubscriptionMsg),
58 Unsubscribed(DydxWsSubscriptionMsg),
60 SubaccountsSubscribed(crate::schemas::ws::DydxWsSubaccountsSubscribed),
62 Connected(DydxWsConnectedMsg),
64 ChannelData(DydxWsChannelDataMsg),
66 ChannelBatchData(DydxWsChannelBatchDataMsg),
68 Error(DydxWebSocketError),
70 Raw(Value),
72 Reconnected,
74 Pong,
76}
77
78#[derive(Debug, Clone)]
83pub enum NautilusWsMessage {
84 Data(Vec<Data>),
86 Deltas(Box<OrderBookDeltas>),
88 Order(Box<OrderStatusReport>),
90 Fill(Box<FillReport>),
92 Position(Box<PositionStatusReport>),
94 AccountState(Box<AccountState>),
96 SubaccountSubscribed(Box<crate::schemas::ws::DydxWsSubaccountsSubscribed>),
98 SubaccountsChannelData(Box<crate::schemas::ws::DydxWsSubaccountsChannelData>),
100 OraclePrices(HashMap<String, crate::websocket::types::DydxOraclePriceMarket>),
102 Error(DydxWebSocketError),
104 Reconnected,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct DydxWsSubscriptionMsg {
111 #[serde(rename = "type")]
113 pub msg_type: DydxWsMessageType,
114 pub connection_id: String,
116 pub message_id: u64,
118 pub channel: DydxWsChannel,
120 #[serde(default, skip_serializing_if = "Option::is_none")]
122 pub id: Option<String>,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct DydxWsConnectedMsg {
128 #[serde(rename = "type")]
130 pub msg_type: DydxWsMessageType,
131 pub connection_id: String,
133 pub message_id: u64,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct DydxWsChannelDataMsg {
140 #[serde(rename = "type")]
142 pub msg_type: DydxWsMessageType,
143 pub connection_id: String,
145 pub message_id: u64,
147 pub channel: DydxWsChannel,
149 #[serde(default, skip_serializing_if = "Option::is_none")]
151 pub id: Option<String>,
152 pub contents: Value,
154 #[serde(default, skip_serializing_if = "Option::is_none")]
156 pub version: Option<String>,
157}
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct DydxWsChannelBatchDataMsg {
162 #[serde(rename = "type")]
164 pub msg_type: DydxWsMessageType,
165 pub connection_id: String,
167 pub message_id: u64,
169 pub channel: DydxWsChannel,
171 #[serde(default, skip_serializing_if = "Option::is_none")]
173 pub id: Option<String>,
174 pub contents: Value,
176 #[serde(default, skip_serializing_if = "Option::is_none")]
178 pub version: Option<String>,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct DydxWsGenericMsg {
184 #[serde(rename = "type")]
186 pub msg_type: DydxWsMessageType,
187 #[serde(default, skip_serializing_if = "Option::is_none")]
189 pub connection_id: Option<String>,
190 #[serde(default, skip_serializing_if = "Option::is_none")]
192 pub message_id: Option<u64>,
193 #[serde(default, skip_serializing_if = "Option::is_none")]
195 pub channel: Option<DydxWsChannel>,
196 #[serde(default, skip_serializing_if = "Option::is_none")]
198 pub id: Option<String>,
199 #[serde(default, skip_serializing_if = "Option::is_none")]
201 pub message: Option<String>,
202}
203
204impl DydxWsGenericMsg {
205 #[must_use]
207 pub fn is_error(&self) -> bool {
208 self.msg_type == DydxWsMessageType::Error
209 }
210
211 #[must_use]
213 pub fn is_subscribed(&self) -> bool {
214 self.msg_type == DydxWsMessageType::Subscribed
215 }
216
217 #[must_use]
219 pub fn is_unsubscribed(&self) -> bool {
220 self.msg_type == DydxWsMessageType::Unsubscribed
221 }
222
223 #[must_use]
225 pub fn is_connected(&self) -> bool {
226 self.msg_type == DydxWsMessageType::Connected
227 }
228
229 #[must_use]
231 pub fn is_channel_data(&self) -> bool {
232 self.msg_type == DydxWsMessageType::ChannelData
233 }
234
235 #[must_use]
237 pub fn is_channel_batch_data(&self) -> bool {
238 self.msg_type == DydxWsMessageType::ChannelBatchData
239 }
240}
241
242use chrono::{DateTime, Utc};
247use nautilus_model::enums::OrderSide;
248
249#[derive(Debug, Clone, Serialize, Deserialize)]
251#[serde(rename_all = "camelCase")]
252pub struct DydxTrade {
253 pub id: String,
255 pub side: OrderSide,
257 pub size: String,
259 pub price: String,
261 pub created_at: DateTime<Utc>,
263 #[serde(rename = "type")]
265 pub order_type: String,
266 #[serde(skip_serializing_if = "Option::is_none")]
268 pub created_at_height: Option<String>,
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize)]
273pub struct DydxTradeContents {
274 pub trades: Vec<DydxTrade>,
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize)]
280#[serde(rename_all = "camelCase")]
281pub struct DydxCandle {
282 pub base_token_volume: String,
284 pub close: String,
286 pub high: String,
288 pub low: String,
290 pub open: String,
292 pub resolution: String,
294 pub started_at: DateTime<Utc>,
296 pub starting_open_interest: String,
298 pub ticker: String,
300 pub trades: i64,
302 pub usd_volume: String,
304 #[serde(skip_serializing_if = "Option::is_none")]
306 pub orderbook_mid_price_close: Option<String>,
307 #[serde(skip_serializing_if = "Option::is_none")]
309 pub orderbook_mid_price_open: Option<String>,
310}
311
312pub type PriceLevel = (String, String);
314
315#[derive(Debug, Clone, Serialize, Deserialize)]
317pub struct DydxOrderbookContents {
318 #[serde(skip_serializing_if = "Option::is_none")]
320 pub bids: Option<Vec<PriceLevel>>,
321 #[serde(skip_serializing_if = "Option::is_none")]
323 pub asks: Option<Vec<PriceLevel>>,
324}
325
326#[derive(Debug, Clone, Serialize, Deserialize)]
328pub struct DydxPriceLevel {
329 pub price: String,
331 pub size: String,
333}
334
335#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct DydxOrderbookSnapshotContents {
338 #[serde(skip_serializing_if = "Option::is_none")]
340 pub bids: Option<Vec<DydxPriceLevel>>,
341 #[serde(skip_serializing_if = "Option::is_none")]
343 pub asks: Option<Vec<DydxPriceLevel>>,
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize)]
348#[serde(rename_all = "camelCase")]
349pub struct DydxOraclePriceMarket {
350 pub oracle_price: String,
352}
353
354#[derive(Debug, Clone, Serialize, Deserialize)]
356#[serde(rename_all = "camelCase")]
357pub struct DydxMarketsContents {
358 #[serde(skip_serializing_if = "Option::is_none")]
360 pub oracle_prices: Option<HashMap<String, DydxOraclePriceMarket>>,
361}