1use std::collections::HashMap;
28
29use chrono::{DateTime, Utc};
30use nautilus_model::enums::OrderSide;
31use rust_decimal::Decimal;
32use serde::{Deserialize, Serialize};
33use serde_with::{DisplayFromStr, serde_as};
34use ustr::Ustr;
35
36use crate::common::enums::{
37 DydxCandleResolution, DydxConditionType, DydxFillType, DydxLiquidity, DydxMarketStatus,
38 DydxOrderExecution, DydxOrderStatus, DydxPositionStatus, DydxTickerType, DydxTimeInForce,
39 DydxTradeType,
40};
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct MarketsResponse {
49 pub markets: HashMap<String, PerpetualMarket>,
51}
52
53#[serde_as]
55#[derive(Debug, Clone, Serialize, Deserialize)]
56#[serde(rename_all = "camelCase")]
57pub struct PerpetualMarket {
58 #[serde_as(as = "DisplayFromStr")]
60 pub clob_pair_id: u32,
61 pub ticker: String,
63 pub status: DydxMarketStatus,
65 #[serde(default)]
67 pub base_asset: Option<String>,
68 #[serde(default)]
70 pub quote_asset: Option<String>,
71 #[serde_as(as = "DisplayFromStr")]
73 pub step_size: Decimal,
74 #[serde_as(as = "DisplayFromStr")]
76 pub tick_size: Decimal,
77 #[serde(default)]
79 #[serde_as(as = "Option<DisplayFromStr>")]
80 pub index_price: Option<Decimal>,
81 #[serde_as(as = "DisplayFromStr")]
83 pub oracle_price: Decimal,
84 #[serde(rename = "priceChange24H")]
86 #[serde_as(as = "DisplayFromStr")]
87 pub price_change_24h: Decimal,
88 #[serde_as(as = "DisplayFromStr")]
90 pub next_funding_rate: Decimal,
91 #[serde(default)]
93 pub next_funding_at: Option<DateTime<Utc>>,
94 #[serde(default)]
96 #[serde_as(as = "Option<DisplayFromStr>")]
97 pub min_order_size: Option<Decimal>,
98 #[serde(rename = "type", default)]
100 pub market_type: Option<DydxTickerType>,
101 #[serde_as(as = "DisplayFromStr")]
103 pub initial_margin_fraction: Decimal,
104 #[serde_as(as = "DisplayFromStr")]
106 pub maintenance_margin_fraction: Decimal,
107 #[serde(default)]
109 #[serde_as(as = "Option<DisplayFromStr>")]
110 pub base_position_notional: Option<Decimal>,
111 #[serde(default)]
113 #[serde_as(as = "Option<DisplayFromStr>")]
114 pub incremental_position_size: Option<Decimal>,
115 #[serde(default)]
117 #[serde_as(as = "Option<DisplayFromStr>")]
118 pub incremental_initial_margin_fraction: Option<Decimal>,
119 #[serde(default)]
121 #[serde_as(as = "Option<DisplayFromStr>")]
122 pub max_position_size: Option<Decimal>,
123 #[serde_as(as = "DisplayFromStr")]
125 pub open_interest: Decimal,
126 pub atomic_resolution: i32,
128 pub quantum_conversion_exponent: i32,
130 pub subticks_per_tick: u32,
132 pub step_base_quantums: u64,
134 #[serde(default)]
136 pub is_reduce_only: bool,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct OrderbookResponse {
142 pub bids: Vec<OrderbookLevel>,
144 pub asks: Vec<OrderbookLevel>,
146}
147
148#[serde_as]
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct OrderbookLevel {
152 #[serde_as(as = "DisplayFromStr")]
154 pub price: Decimal,
155 #[serde_as(as = "DisplayFromStr")]
157 pub size: Decimal,
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct TradesResponse {
163 pub trades: Vec<Trade>,
165}
166
167#[serde_as]
169#[derive(Debug, Clone, Serialize, Deserialize)]
170#[serde(rename_all = "camelCase")]
171pub struct Trade {
172 pub id: String,
174 pub side: OrderSide,
176 #[serde_as(as = "DisplayFromStr")]
178 pub size: Decimal,
179 #[serde_as(as = "DisplayFromStr")]
181 pub price: Decimal,
182 pub created_at: DateTime<Utc>,
184 #[serde_as(as = "DisplayFromStr")]
186 pub created_at_height: u64,
187 #[serde(rename = "type")]
189 pub trade_type: DydxTradeType,
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct CandlesResponse {
195 pub candles: Vec<Candle>,
197}
198
199#[serde_as]
201#[derive(Debug, Clone, Serialize, Deserialize)]
202#[serde(rename_all = "camelCase")]
203pub struct Candle {
204 pub started_at: DateTime<Utc>,
206 pub ticker: String,
208 pub resolution: DydxCandleResolution,
210 #[serde_as(as = "DisplayFromStr")]
212 pub open: Decimal,
213 #[serde_as(as = "DisplayFromStr")]
215 pub high: Decimal,
216 #[serde_as(as = "DisplayFromStr")]
218 pub low: Decimal,
219 #[serde_as(as = "DisplayFromStr")]
221 pub close: Decimal,
222 #[serde_as(as = "DisplayFromStr")]
224 pub base_token_volume: Decimal,
225 #[serde_as(as = "DisplayFromStr")]
227 pub usd_volume: Decimal,
228 pub trades: u64,
230 #[serde_as(as = "DisplayFromStr")]
232 pub starting_open_interest: Decimal,
233}
234
235#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct SubaccountResponse {
242 pub subaccount: Subaccount,
244}
245
246#[serde_as]
248#[derive(Debug, Clone, Serialize, Deserialize)]
249#[serde(rename_all = "camelCase")]
250pub struct Subaccount {
251 pub address: String,
253 pub subaccount_number: u32,
255 #[serde_as(as = "DisplayFromStr")]
257 pub equity: Decimal,
258 #[serde_as(as = "DisplayFromStr")]
260 pub free_collateral: Decimal,
261 #[serde(default)]
263 pub open_perpetual_positions: HashMap<String, PerpetualPosition>,
264 #[serde(default)]
266 pub asset_positions: HashMap<String, AssetPosition>,
267 #[serde(default)]
269 pub margin_enabled: bool,
270 #[serde_as(as = "DisplayFromStr")]
272 pub updated_at_height: u64,
273}
274
275#[serde_as]
277#[derive(Debug, Clone, Serialize, Deserialize)]
278#[serde(rename_all = "camelCase")]
279pub struct PerpetualPosition {
280 pub market: String,
282 pub status: DydxPositionStatus,
284 pub side: OrderSide,
286 #[serde_as(as = "DisplayFromStr")]
288 pub size: Decimal,
289 #[serde_as(as = "DisplayFromStr")]
291 pub max_size: Decimal,
292 #[serde_as(as = "DisplayFromStr")]
294 pub entry_price: Decimal,
295 #[serde_as(as = "Option<DisplayFromStr>")]
297 #[serde(skip_serializing_if = "Option::is_none")]
298 pub exit_price: Option<Decimal>,
299 #[serde_as(as = "DisplayFromStr")]
301 pub realized_pnl: Decimal,
302 #[serde_as(as = "DisplayFromStr")]
304 pub created_at_height: u64,
305 pub created_at: DateTime<Utc>,
307 #[serde_as(as = "DisplayFromStr")]
309 pub sum_open: Decimal,
310 #[serde_as(as = "DisplayFromStr")]
312 pub sum_close: Decimal,
313 #[serde_as(as = "DisplayFromStr")]
315 pub net_funding: Decimal,
316 #[serde_as(as = "DisplayFromStr")]
318 pub unrealized_pnl: Decimal,
319 #[serde(skip_serializing_if = "Option::is_none")]
321 pub closed_at: Option<DateTime<Utc>>,
322}
323
324#[serde_as]
326#[derive(Debug, Clone, Serialize, Deserialize)]
327#[serde(rename_all = "camelCase")]
328pub struct AssetPosition {
329 pub symbol: Ustr,
331 pub side: OrderSide,
333 #[serde_as(as = "DisplayFromStr")]
335 pub size: Decimal,
336 pub asset_id: String,
338}
339
340#[derive(Debug, Clone, Serialize, Deserialize)]
342pub struct OrdersResponse {
343 pub orders: Vec<Order>,
345}
346
347#[serde_as]
349#[derive(Debug, Clone, Serialize, Deserialize)]
350#[serde(rename_all = "camelCase")]
351pub struct Order {
352 pub id: String,
354 pub subaccount_id: String,
356 pub client_id: String,
358 #[serde_as(as = "DisplayFromStr")]
360 pub clob_pair_id: u32,
361 pub side: OrderSide,
363 #[serde_as(as = "DisplayFromStr")]
365 pub size: Decimal,
366 #[serde_as(as = "DisplayFromStr")]
368 pub remaining_size: Decimal,
369 #[serde_as(as = "DisplayFromStr")]
371 pub price: Decimal,
372 pub status: DydxOrderStatus,
374 #[serde(rename = "type")]
376 pub order_type: String,
377 pub time_in_force: DydxTimeInForce,
379 pub reduce_only: bool,
381 pub post_only: bool,
383 pub order_flags: u32,
385 #[serde_as(as = "Option<DisplayFromStr>")]
387 #[serde(skip_serializing_if = "Option::is_none")]
388 pub good_til_block: Option<u64>,
389 #[serde(skip_serializing_if = "Option::is_none")]
391 pub good_til_block_time: Option<DateTime<Utc>>,
392 #[serde_as(as = "DisplayFromStr")]
394 pub created_at_height: u64,
395 pub client_metadata: u32,
397 #[serde_as(as = "Option<DisplayFromStr>")]
399 #[serde(skip_serializing_if = "Option::is_none")]
400 pub trigger_price: Option<Decimal>,
401 #[serde(skip_serializing_if = "Option::is_none")]
403 pub condition_type: Option<DydxConditionType>,
404 #[serde_as(as = "Option<DisplayFromStr>")]
406 #[serde(skip_serializing_if = "Option::is_none")]
407 pub conditional_order_trigger_subticks: Option<u64>,
408 #[serde(skip_serializing_if = "Option::is_none")]
410 pub execution: Option<DydxOrderExecution>,
411 pub updated_at: DateTime<Utc>,
413 #[serde_as(as = "DisplayFromStr")]
415 pub updated_at_height: u64,
416}
417
418#[derive(Debug, Clone, Serialize, Deserialize)]
420pub struct FillsResponse {
421 pub fills: Vec<Fill>,
423}
424
425#[serde_as]
427#[derive(Debug, Clone, Serialize, Deserialize)]
428#[serde(rename_all = "camelCase")]
429pub struct Fill {
430 pub id: String,
432 pub side: OrderSide,
434 pub liquidity: DydxLiquidity,
436 #[serde(rename = "type")]
438 pub fill_type: DydxFillType,
439 pub market: String,
441 pub market_type: DydxTickerType,
443 #[serde_as(as = "DisplayFromStr")]
445 pub price: Decimal,
446 #[serde_as(as = "DisplayFromStr")]
448 pub size: Decimal,
449 #[serde_as(as = "DisplayFromStr")]
451 pub fee: Decimal,
452 pub created_at: DateTime<Utc>,
454 #[serde_as(as = "DisplayFromStr")]
456 pub created_at_height: u64,
457 pub order_id: String,
459 pub client_metadata: u32,
461}
462
463#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct TransfersResponse {
466 pub transfers: Vec<Transfer>,
468}
469
470#[serde_as]
472#[derive(Debug, Clone, Serialize, Deserialize)]
473#[serde(rename_all = "camelCase")]
474pub struct Transfer {
475 pub id: String,
477 #[serde(rename = "type")]
479 pub transfer_type: String,
480 pub sender: TransferAccount,
482 pub recipient: TransferAccount,
484 pub asset: String,
486 #[serde_as(as = "DisplayFromStr")]
488 pub amount: Decimal,
489 pub created_at: DateTime<Utc>,
491 #[serde_as(as = "DisplayFromStr")]
493 pub created_at_height: u64,
494 pub transaction_hash: String,
496}
497
498#[derive(Debug, Clone, Serialize, Deserialize)]
500#[serde(rename_all = "camelCase")]
501pub struct TransferAccount {
502 pub address: String,
504 pub subaccount_number: u32,
506}
507
508#[derive(Debug, Clone, Serialize, Deserialize)]
514pub struct TimeResponse {
515 pub iso: DateTime<Utc>,
517 #[serde(rename = "epoch")]
519 pub epoch_ms: i64,
520}
521
522#[serde_as]
524#[derive(Debug, Clone, Serialize, Deserialize)]
525pub struct HeightResponse {
526 #[serde_as(as = "DisplayFromStr")]
528 pub height: u64,
529 pub time: DateTime<Utc>,
531}
532
533#[serde_as]
539#[derive(Debug, Clone, Serialize, Deserialize)]
540#[serde(rename_all = "camelCase")]
541pub struct PlaceOrderRequest {
542 pub subaccount: SubaccountId,
544 pub client_id: u32,
546 pub order_flags: u32,
548 pub clob_pair_id: u32,
550 pub side: OrderSide,
552 pub quantums: u64,
554 pub subticks: u64,
556 pub time_in_force: DydxTimeInForce,
558 #[serde(skip_serializing_if = "Option::is_none")]
560 pub good_til_block: Option<u32>,
561 #[serde(skip_serializing_if = "Option::is_none")]
563 pub good_til_block_time: Option<u32>,
564 pub reduce_only: bool,
566 #[serde(skip_serializing_if = "Option::is_none")]
568 pub authenticator_ids: Option<Vec<u64>>,
569}
570
571#[derive(Debug, Clone, Serialize, Deserialize)]
573pub struct SubaccountId {
574 pub owner: String,
576 pub number: u32,
578}
579
580#[derive(Debug, Clone, Serialize, Deserialize)]
582#[serde(rename_all = "camelCase")]
583pub struct CancelOrderRequest {
584 pub subaccount_id: SubaccountId,
586 pub client_id: u32,
588 pub clob_pair_id: u32,
590 pub order_flags: u32,
592 pub good_til_block: Option<u32>,
594 pub good_til_block_time: Option<u32>,
595}
596
597#[serde_as]
599#[derive(Debug, Clone, Serialize, Deserialize)]
600pub struct TransactionResponse {
601 pub tx_hash: String,
603 #[serde_as(as = "DisplayFromStr")]
605 pub height: u64,
606 pub code: u32,
608 pub raw_log: String,
610}