1use std::collections::HashMap;
28
29use chrono::{DateTime, Utc};
30use nautilus_core::serialization::deserialize_empty_string_as_none;
31use nautilus_model::enums::OrderSide;
32use rust_decimal::Decimal;
33use serde::{Deserialize, Serialize};
34use serde_with::{DisplayFromStr, serde_as};
35use ustr::Ustr;
36
37use crate::common::enums::{
38 DydxCandleResolution, DydxConditionType, DydxFillType, DydxLiquidity, DydxMarketStatus,
39 DydxOrderExecution, DydxOrderStatus, DydxOrderType, DydxPositionSide, DydxPositionStatus,
40 DydxTickerType, DydxTimeInForce, DydxTradeType, DydxTransferType,
41};
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct MarketsResponse {
46 pub markets: HashMap<String, PerpetualMarket>,
48}
49
50#[serde_as]
52#[derive(Debug, Clone, Serialize, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub struct PerpetualMarket {
55 #[serde_as(as = "DisplayFromStr")]
57 pub clob_pair_id: u32,
58 pub ticker: String,
60 pub status: DydxMarketStatus,
62 #[serde(default)]
64 pub base_asset: Option<String>,
65 #[serde(default)]
67 pub quote_asset: Option<String>,
68 #[serde_as(as = "DisplayFromStr")]
70 pub step_size: Decimal,
71 #[serde_as(as = "DisplayFromStr")]
73 pub tick_size: Decimal,
74 #[serde(default)]
76 #[serde_as(as = "Option<DisplayFromStr>")]
77 pub index_price: Option<Decimal>,
78 #[serde_as(as = "DisplayFromStr")]
80 pub oracle_price: Decimal,
81 #[serde(rename = "priceChange24H")]
83 #[serde_as(as = "DisplayFromStr")]
84 pub price_change_24h: Decimal,
85 #[serde_as(as = "DisplayFromStr")]
87 pub next_funding_rate: Decimal,
88 #[serde(default)]
90 pub next_funding_at: Option<DateTime<Utc>>,
91 #[serde(default)]
93 #[serde_as(as = "Option<DisplayFromStr>")]
94 pub min_order_size: Option<Decimal>,
95 #[serde(rename = "type", default)]
97 pub market_type: Option<DydxTickerType>,
98 #[serde_as(as = "DisplayFromStr")]
100 pub initial_margin_fraction: Decimal,
101 #[serde_as(as = "DisplayFromStr")]
103 pub maintenance_margin_fraction: Decimal,
104 #[serde(default)]
106 #[serde_as(as = "Option<DisplayFromStr>")]
107 pub base_position_notional: Option<Decimal>,
108 #[serde(default)]
110 #[serde_as(as = "Option<DisplayFromStr>")]
111 pub incremental_position_size: Option<Decimal>,
112 #[serde(default)]
114 #[serde_as(as = "Option<DisplayFromStr>")]
115 pub incremental_initial_margin_fraction: Option<Decimal>,
116 #[serde(default)]
118 #[serde_as(as = "Option<DisplayFromStr>")]
119 pub max_position_size: Option<Decimal>,
120 #[serde_as(as = "DisplayFromStr")]
122 pub open_interest: Decimal,
123 pub atomic_resolution: i32,
125 pub quantum_conversion_exponent: i32,
127 pub subticks_per_tick: u32,
129 pub step_base_quantums: u64,
131 #[serde(default)]
133 pub is_reduce_only: bool,
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct OrderbookResponse {
139 pub bids: Vec<OrderbookLevel>,
141 pub asks: Vec<OrderbookLevel>,
143}
144
145#[serde_as]
147#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct OrderbookLevel {
149 #[serde_as(as = "DisplayFromStr")]
151 pub price: Decimal,
152 #[serde_as(as = "DisplayFromStr")]
154 pub size: Decimal,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct TradesResponse {
160 pub trades: Vec<Trade>,
162}
163
164#[serde_as]
166#[derive(Debug, Clone, Serialize, Deserialize)]
167#[serde(rename_all = "camelCase")]
168pub struct Trade {
169 pub id: String,
171 pub side: OrderSide,
173 #[serde_as(as = "DisplayFromStr")]
175 pub size: Decimal,
176 #[serde_as(as = "DisplayFromStr")]
178 pub price: Decimal,
179 pub created_at: DateTime<Utc>,
181 #[serde_as(as = "DisplayFromStr")]
183 pub created_at_height: u64,
184 #[serde(rename = "type")]
186 pub trade_type: DydxTradeType,
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize)]
191pub struct CandlesResponse {
192 pub candles: Vec<Candle>,
194}
195
196#[serde_as]
198#[derive(Debug, Clone, Serialize, Deserialize)]
199#[serde(rename_all = "camelCase")]
200pub struct Candle {
201 pub started_at: DateTime<Utc>,
203 pub ticker: String,
205 pub resolution: DydxCandleResolution,
207 #[serde_as(as = "DisplayFromStr")]
209 pub open: Decimal,
210 #[serde_as(as = "DisplayFromStr")]
212 pub high: Decimal,
213 #[serde_as(as = "DisplayFromStr")]
215 pub low: Decimal,
216 #[serde_as(as = "DisplayFromStr")]
218 pub close: Decimal,
219 #[serde_as(as = "DisplayFromStr")]
221 pub base_token_volume: Decimal,
222 #[serde_as(as = "DisplayFromStr")]
224 pub usd_volume: Decimal,
225 pub trades: u64,
227 #[serde_as(as = "DisplayFromStr")]
229 pub starting_open_interest: Decimal,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize)]
234pub struct SubaccountResponse {
235 pub subaccount: Subaccount,
237}
238
239#[serde_as]
241#[derive(Debug, Clone, Serialize, Deserialize)]
242#[serde(rename_all = "camelCase")]
243pub struct Subaccount {
244 pub address: String,
246 pub subaccount_number: u32,
248 #[serde_as(as = "DisplayFromStr")]
250 pub equity: Decimal,
251 #[serde_as(as = "DisplayFromStr")]
253 pub free_collateral: Decimal,
254 #[serde(default)]
256 pub open_perpetual_positions: HashMap<String, PerpetualPosition>,
257 #[serde(default)]
259 pub asset_positions: HashMap<String, AssetPosition>,
260 #[serde(default)]
262 pub margin_enabled: bool,
263 #[serde_as(as = "DisplayFromStr")]
265 pub updated_at_height: u64,
266 #[serde(default)]
268 #[serde_as(as = "Option<DisplayFromStr>")]
269 pub latest_processed_block_height: Option<u64>,
270}
271
272#[serde_as]
274#[derive(Debug, Clone, Serialize, Deserialize)]
275#[serde(rename_all = "camelCase")]
276pub struct PerpetualPosition {
277 pub market: String,
279 pub status: DydxPositionStatus,
281 pub side: OrderSide,
283 #[serde_as(as = "DisplayFromStr")]
285 pub size: Decimal,
286 #[serde_as(as = "DisplayFromStr")]
288 pub max_size: Decimal,
289 #[serde_as(as = "DisplayFromStr")]
291 pub entry_price: Decimal,
292 #[serde_as(as = "Option<DisplayFromStr>")]
294 #[serde(skip_serializing_if = "Option::is_none")]
295 pub exit_price: Option<Decimal>,
296 #[serde_as(as = "DisplayFromStr")]
298 pub realized_pnl: Decimal,
299 #[serde_as(as = "DisplayFromStr")]
301 pub created_at_height: u64,
302 pub created_at: DateTime<Utc>,
304 #[serde_as(as = "DisplayFromStr")]
306 pub sum_open: Decimal,
307 #[serde_as(as = "DisplayFromStr")]
309 pub sum_close: Decimal,
310 #[serde_as(as = "DisplayFromStr")]
312 pub net_funding: Decimal,
313 #[serde_as(as = "DisplayFromStr")]
315 pub unrealized_pnl: Decimal,
316 #[serde(skip_serializing_if = "Option::is_none")]
318 pub closed_at: Option<DateTime<Utc>>,
319}
320
321#[serde_as]
323#[derive(Debug, Clone, Serialize, Deserialize)]
324#[serde(rename_all = "camelCase")]
325pub struct AssetPosition {
326 pub symbol: Ustr,
328 pub side: DydxPositionSide,
330 #[serde_as(as = "DisplayFromStr")]
332 pub size: Decimal,
333 pub asset_id: String,
335 #[serde(default)]
337 pub subaccount_number: u32,
338}
339
340pub type OrdersResponse = Vec<Order>;
342
343#[serde_as]
345#[derive(Debug, Clone, Serialize, Deserialize)]
346#[serde(rename_all = "camelCase")]
347pub struct Order {
348 pub id: String,
350 pub subaccount_id: String,
352 pub client_id: String,
354 #[serde_as(as = "DisplayFromStr")]
356 pub clob_pair_id: u32,
357 pub side: OrderSide,
359 #[serde_as(as = "DisplayFromStr")]
361 pub size: Decimal,
362 #[serde_as(as = "DisplayFromStr")]
364 pub total_filled: Decimal,
365 #[serde_as(as = "DisplayFromStr")]
367 pub price: Decimal,
368 pub status: DydxOrderStatus,
370 #[serde(rename = "type")]
372 pub order_type: DydxOrderType,
373 pub time_in_force: DydxTimeInForce,
375 pub reduce_only: bool,
377 pub post_only: bool,
379 #[serde_as(as = "DisplayFromStr")]
381 pub order_flags: u32,
382 #[serde_as(as = "Option<DisplayFromStr>")]
384 #[serde(skip_serializing_if = "Option::is_none")]
385 pub good_til_block: Option<u64>,
386 #[serde(skip_serializing_if = "Option::is_none")]
388 pub good_til_block_time: Option<DateTime<Utc>>,
389 #[serde_as(as = "Option<DisplayFromStr>")]
391 #[serde(skip_serializing_if = "Option::is_none")]
392 pub created_at_height: Option<u64>,
393 #[serde_as(as = "DisplayFromStr")]
395 pub client_metadata: u32,
396 #[serde_as(as = "Option<DisplayFromStr>")]
398 #[serde(skip_serializing_if = "Option::is_none")]
399 pub trigger_price: Option<Decimal>,
400 #[serde(skip_serializing_if = "Option::is_none")]
402 pub condition_type: Option<DydxConditionType>,
403 #[serde_as(as = "Option<DisplayFromStr>")]
405 #[serde(skip_serializing_if = "Option::is_none")]
406 pub conditional_order_trigger_subticks: Option<u64>,
407 #[serde(skip_serializing_if = "Option::is_none")]
409 pub execution: Option<DydxOrderExecution>,
410 #[serde(skip_serializing_if = "Option::is_none")]
412 pub updated_at: Option<DateTime<Utc>>,
413 #[serde_as(as = "Option<DisplayFromStr>")]
415 #[serde(skip_serializing_if = "Option::is_none")]
416 pub updated_at_height: Option<u64>,
417 #[serde(skip_serializing_if = "Option::is_none")]
419 pub ticker: Option<String>,
420 #[serde(default)]
422 pub subaccount_number: u32,
423 #[serde(default, deserialize_with = "deserialize_empty_string_as_none")]
425 #[serde(skip_serializing_if = "Option::is_none")]
426 pub order_router_address: Option<String>,
427}
428
429#[derive(Debug, Clone, Serialize, Deserialize)]
431#[serde(rename_all = "camelCase")]
432pub struct FillsResponse {
433 pub fills: Vec<Fill>,
435}
436
437#[serde_as]
439#[derive(Debug, Clone, Serialize, Deserialize)]
440#[serde(rename_all = "camelCase")]
441pub struct Fill {
442 pub id: String,
444 pub side: OrderSide,
446 pub liquidity: DydxLiquidity,
448 #[serde(rename = "type")]
450 pub fill_type: DydxFillType,
451 pub market: String,
453 pub market_type: DydxTickerType,
455 #[serde_as(as = "DisplayFromStr")]
457 pub price: Decimal,
458 #[serde_as(as = "DisplayFromStr")]
460 pub size: Decimal,
461 #[serde_as(as = "DisplayFromStr")]
463 pub fee: Decimal,
464 pub created_at: DateTime<Utc>,
466 #[serde_as(as = "DisplayFromStr")]
468 pub created_at_height: u64,
469 pub order_id: String,
471 #[serde_as(as = "DisplayFromStr")]
473 pub client_metadata: u32,
474}
475
476#[derive(Debug, Clone, Serialize, Deserialize)]
478pub struct TransfersResponse {
479 pub transfers: Vec<Transfer>,
481}
482
483#[serde_as]
485#[derive(Debug, Clone, Serialize, Deserialize)]
486#[serde(rename_all = "camelCase")]
487pub struct Transfer {
488 pub id: String,
490 #[serde(rename = "type")]
492 pub transfer_type: DydxTransferType,
493 pub sender: TransferAccount,
495 pub recipient: TransferAccount,
497 pub asset: String,
499 #[serde_as(as = "DisplayFromStr")]
501 pub amount: Decimal,
502 pub created_at: DateTime<Utc>,
504 #[serde_as(as = "DisplayFromStr")]
506 pub created_at_height: u64,
507 pub transaction_hash: String,
509}
510
511#[derive(Debug, Clone, Serialize, Deserialize)]
513#[serde(rename_all = "camelCase")]
514pub struct TransferAccount {
515 pub address: String,
517 pub subaccount_number: u32,
519}
520
521#[derive(Debug, Clone, Serialize, Deserialize)]
523pub struct TimeResponse {
524 pub iso: DateTime<Utc>,
526 #[serde(rename = "epoch")]
528 pub epoch_ms: i64,
529}
530
531#[serde_as]
533#[derive(Debug, Clone, Serialize, Deserialize)]
534pub struct HeightResponse {
535 #[serde_as(as = "DisplayFromStr")]
537 pub height: u64,
538 pub time: DateTime<Utc>,
540}
541
542#[serde_as]
544#[derive(Debug, Clone, Serialize, Deserialize)]
545#[serde(rename_all = "camelCase")]
546pub struct PlaceOrderRequest {
547 pub subaccount: SubaccountId,
549 pub client_id: u32,
551 pub order_flags: String,
553 pub clob_pair_id: u32,
555 pub side: OrderSide,
557 pub quantums: u64,
559 pub subticks: u64,
561 pub time_in_force: DydxTimeInForce,
563 #[serde(skip_serializing_if = "Option::is_none")]
565 pub good_til_block: Option<u32>,
566 #[serde(skip_serializing_if = "Option::is_none")]
568 pub good_til_block_time: Option<u32>,
569 pub reduce_only: bool,
571 #[serde(skip_serializing_if = "Option::is_none")]
573 pub authenticator_ids: Option<Vec<u64>>,
574}
575
576#[derive(Debug, Clone, Serialize, Deserialize)]
578pub struct SubaccountId {
579 pub owner: String,
581 pub number: u32,
583}
584
585#[derive(Debug, Clone, Serialize, Deserialize)]
587#[serde(rename_all = "camelCase")]
588pub struct CancelOrderRequest {
589 pub subaccount_id: SubaccountId,
591 pub client_id: u32,
593 pub clob_pair_id: u32,
595 pub order_flags: String,
597 pub good_til_block: Option<u32>,
599 pub good_til_block_time: Option<u32>,
600}
601
602#[serde_as]
604#[derive(Debug, Clone, Serialize, Deserialize)]
605pub struct TransactionResponse {
606 pub tx_hash: String,
608 #[serde_as(as = "DisplayFromStr")]
610 pub height: u64,
611 pub code: u32,
613 pub raw_log: String,
615}