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 ustr::Ustr;
35
36use super::parse::{display_fromstr, display_fromstr_opt};
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#[derive(Debug, Clone, Serialize, Deserialize)]
52#[serde(rename_all = "camelCase")]
53pub struct PerpetualMarket {
54 #[serde(with = "display_fromstr")]
56 pub clob_pair_id: u32,
57 pub ticker: Ustr,
59 pub status: DydxMarketStatus,
61 #[serde(default)]
63 pub base_asset: Option<Ustr>,
64 #[serde(default)]
66 pub quote_asset: Option<Ustr>,
67 #[serde(with = "display_fromstr")]
69 pub step_size: Decimal,
70 #[serde(with = "display_fromstr")]
72 pub tick_size: Decimal,
73 #[serde(default)]
75 #[serde(with = "display_fromstr_opt")]
76 pub index_price: Option<Decimal>,
77 #[serde(default)]
79 #[serde(with = "display_fromstr_opt")]
80 pub oracle_price: Option<Decimal>,
81 #[serde(rename = "priceChange24H")]
83 #[serde(with = "display_fromstr")]
84 pub price_change_24h: Decimal,
85 #[serde(with = "display_fromstr")]
87 pub next_funding_rate: Decimal,
88 #[serde(default)]
90 pub next_funding_at: Option<DateTime<Utc>>,
91 #[serde(default)]
93 #[serde(with = "display_fromstr_opt")]
94 pub min_order_size: Option<Decimal>,
95 #[serde(rename = "type", default)]
97 pub market_type: Option<DydxTickerType>,
98 #[serde(with = "display_fromstr")]
100 pub initial_margin_fraction: Decimal,
101 #[serde(with = "display_fromstr")]
103 pub maintenance_margin_fraction: Decimal,
104 #[serde(default)]
106 #[serde(with = "display_fromstr_opt")]
107 pub base_position_notional: Option<Decimal>,
108 #[serde(default)]
110 #[serde(with = "display_fromstr_opt")]
111 pub incremental_position_size: Option<Decimal>,
112 #[serde(default)]
114 #[serde(with = "display_fromstr_opt")]
115 pub incremental_initial_margin_fraction: Option<Decimal>,
116 #[serde(default)]
118 #[serde(with = "display_fromstr_opt")]
119 pub max_position_size: Option<Decimal>,
120 #[serde(with = "display_fromstr")]
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#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct OrderbookLevel {
148 #[serde(with = "display_fromstr")]
150 pub price: Decimal,
151 #[serde(with = "display_fromstr")]
153 pub size: Decimal,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize)]
158pub struct TradesResponse {
159 pub trades: Vec<Trade>,
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
165#[serde(rename_all = "camelCase")]
166pub struct Trade {
167 pub id: String,
169 pub side: OrderSide,
171 #[serde(with = "display_fromstr")]
173 pub size: Decimal,
174 #[serde(with = "display_fromstr")]
176 pub price: Decimal,
177 pub created_at: DateTime<Utc>,
179 #[serde(with = "display_fromstr")]
181 pub created_at_height: u64,
182 #[serde(rename = "type")]
184 pub trade_type: DydxTradeType,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct CandlesResponse {
190 pub candles: Vec<Candle>,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
196#[serde(rename_all = "camelCase")]
197pub struct Candle {
198 pub started_at: DateTime<Utc>,
200 pub ticker: Ustr,
202 pub resolution: DydxCandleResolution,
204 #[serde(with = "display_fromstr")]
206 pub open: Decimal,
207 #[serde(with = "display_fromstr")]
209 pub high: Decimal,
210 #[serde(with = "display_fromstr")]
212 pub low: Decimal,
213 #[serde(with = "display_fromstr")]
215 pub close: Decimal,
216 #[serde(with = "display_fromstr")]
218 pub base_token_volume: Decimal,
219 #[serde(with = "display_fromstr")]
221 pub usd_volume: Decimal,
222 pub trades: u64,
224 #[serde(with = "display_fromstr")]
226 pub starting_open_interest: Decimal,
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct SubaccountResponse {
232 pub subaccount: Subaccount,
234}
235
236#[derive(Debug, Clone, Serialize, Deserialize)]
238#[serde(rename_all = "camelCase")]
239pub struct Subaccount {
240 pub address: String,
242 pub subaccount_number: u32,
244 #[serde(with = "display_fromstr")]
246 pub equity: Decimal,
247 #[serde(with = "display_fromstr")]
249 pub free_collateral: Decimal,
250 #[serde(default)]
252 pub open_perpetual_positions: HashMap<String, PerpetualPosition>,
253 #[serde(default)]
255 pub asset_positions: HashMap<String, AssetPosition>,
256 #[serde(default)]
258 pub margin_enabled: bool,
259 #[serde(with = "display_fromstr")]
261 pub updated_at_height: u64,
262 #[serde(default)]
264 #[serde(with = "display_fromstr_opt")]
265 pub latest_processed_block_height: Option<u64>,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
270#[serde(rename_all = "camelCase")]
271pub struct PerpetualPosition {
272 pub market: Ustr,
274 pub status: DydxPositionStatus,
276 pub side: DydxPositionSide,
278 #[serde(with = "display_fromstr")]
280 pub size: Decimal,
281 #[serde(with = "display_fromstr")]
283 pub max_size: Decimal,
284 #[serde(with = "display_fromstr")]
286 pub entry_price: Decimal,
287 #[serde(
289 default,
290 with = "display_fromstr_opt",
291 skip_serializing_if = "Option::is_none"
292 )]
293 pub exit_price: Option<Decimal>,
294 #[serde(with = "display_fromstr")]
296 pub realized_pnl: Decimal,
297 #[serde(with = "display_fromstr")]
299 pub created_at_height: u64,
300 pub created_at: DateTime<Utc>,
302 #[serde(with = "display_fromstr")]
304 pub sum_open: Decimal,
305 #[serde(with = "display_fromstr")]
307 pub sum_close: Decimal,
308 #[serde(with = "display_fromstr")]
310 pub net_funding: Decimal,
311 #[serde(with = "display_fromstr")]
313 pub unrealized_pnl: Decimal,
314 #[serde(skip_serializing_if = "Option::is_none")]
316 pub closed_at: Option<DateTime<Utc>>,
317}
318
319#[derive(Debug, Clone, Serialize, Deserialize)]
321#[serde(rename_all = "camelCase")]
322pub struct AssetPosition {
323 pub symbol: Ustr,
325 pub side: DydxPositionSide,
327 #[serde(with = "display_fromstr")]
329 pub size: Decimal,
330 pub asset_id: String,
332 #[serde(default)]
334 pub subaccount_number: u32,
335}
336
337pub type OrdersResponse = Vec<Order>;
339
340#[derive(Debug, Clone, Serialize, Deserialize)]
342#[serde(rename_all = "camelCase")]
343pub struct Order {
344 pub id: String,
346 pub subaccount_id: String,
348 pub client_id: String,
350 #[serde(with = "display_fromstr")]
352 pub clob_pair_id: u32,
353 pub side: OrderSide,
355 #[serde(with = "display_fromstr")]
357 pub size: Decimal,
358 #[serde(with = "display_fromstr")]
360 pub total_filled: Decimal,
361 #[serde(with = "display_fromstr")]
363 pub price: Decimal,
364 pub status: DydxOrderStatus,
366 #[serde(rename = "type")]
368 pub order_type: DydxOrderType,
369 pub time_in_force: DydxTimeInForce,
371 pub reduce_only: bool,
373 pub post_only: bool,
375 #[serde(with = "display_fromstr")]
377 pub order_flags: u32,
378 #[serde(
380 default,
381 with = "display_fromstr_opt",
382 skip_serializing_if = "Option::is_none"
383 )]
384 pub good_til_block: Option<u64>,
385 #[serde(skip_serializing_if = "Option::is_none")]
387 pub good_til_block_time: Option<DateTime<Utc>>,
388 #[serde(
390 default,
391 with = "display_fromstr_opt",
392 skip_serializing_if = "Option::is_none"
393 )]
394 pub created_at_height: Option<u64>,
395 #[serde(with = "display_fromstr")]
397 pub client_metadata: u32,
398 #[serde(
400 default,
401 with = "display_fromstr_opt",
402 skip_serializing_if = "Option::is_none"
403 )]
404 pub trigger_price: Option<Decimal>,
405 #[serde(skip_serializing_if = "Option::is_none")]
407 pub condition_type: Option<DydxConditionType>,
408 #[serde(
410 default,
411 with = "display_fromstr_opt",
412 skip_serializing_if = "Option::is_none"
413 )]
414 pub conditional_order_trigger_subticks: Option<u64>,
415 #[serde(skip_serializing_if = "Option::is_none")]
417 pub execution: Option<DydxOrderExecution>,
418 #[serde(skip_serializing_if = "Option::is_none")]
420 pub updated_at: Option<DateTime<Utc>>,
421 #[serde(
423 default,
424 with = "display_fromstr_opt",
425 skip_serializing_if = "Option::is_none"
426 )]
427 pub updated_at_height: Option<u64>,
428 #[serde(skip_serializing_if = "Option::is_none")]
430 pub ticker: Option<Ustr>,
431 #[serde(default)]
433 pub subaccount_number: u32,
434 #[serde(default, deserialize_with = "deserialize_empty_string_as_none")]
436 #[serde(skip_serializing_if = "Option::is_none")]
437 pub order_router_address: Option<String>,
438}
439
440#[derive(Debug, Clone, Serialize, Deserialize)]
442#[serde(rename_all = "camelCase")]
443pub struct FillsResponse {
444 pub fills: Vec<Fill>,
446}
447
448#[derive(Debug, Clone, Serialize, Deserialize)]
450#[serde(rename_all = "camelCase")]
451pub struct Fill {
452 pub id: String,
454 pub side: OrderSide,
456 pub liquidity: DydxLiquidity,
458 #[serde(rename = "type")]
460 pub fill_type: DydxFillType,
461 pub market: Ustr,
463 pub market_type: DydxTickerType,
465 #[serde(with = "display_fromstr")]
467 pub price: Decimal,
468 #[serde(with = "display_fromstr")]
470 pub size: Decimal,
471 #[serde(with = "display_fromstr")]
473 pub fee: Decimal,
474 pub created_at: DateTime<Utc>,
476 #[serde(with = "display_fromstr")]
478 pub created_at_height: u64,
479 pub order_id: String,
481 #[serde(with = "display_fromstr")]
483 pub client_metadata: u32,
484}
485
486#[derive(Debug, Clone, Serialize, Deserialize)]
488pub struct TransfersResponse {
489 pub transfers: Vec<Transfer>,
491}
492
493#[derive(Debug, Clone, Serialize, Deserialize)]
495#[serde(rename_all = "camelCase")]
496pub struct Transfer {
497 pub id: String,
499 #[serde(rename = "type")]
501 pub transfer_type: DydxTransferType,
502 pub sender: TransferAccount,
504 pub recipient: TransferAccount,
506 pub asset: String,
508 #[serde(with = "display_fromstr")]
510 pub amount: Decimal,
511 pub created_at: DateTime<Utc>,
513 #[serde(with = "display_fromstr")]
515 pub created_at_height: u64,
516 pub transaction_hash: String,
518}
519
520#[derive(Debug, Clone, Serialize, Deserialize)]
522#[serde(rename_all = "camelCase")]
523pub struct TransferAccount {
524 pub address: String,
526 pub subaccount_number: u32,
528}
529
530#[derive(Debug, Clone, Serialize, Deserialize)]
532#[serde(rename_all = "camelCase")]
533pub struct HistoricalFundingResponse {
534 pub historical_funding: Vec<HistoricalFunding>,
536}
537
538#[derive(Debug, Clone, Serialize, Deserialize)]
540#[serde(rename_all = "camelCase")]
541pub struct HistoricalFunding {
542 pub ticker: Ustr,
544 #[serde(with = "display_fromstr")]
546 pub rate: Decimal,
547 #[serde(with = "display_fromstr")]
549 pub price: Decimal,
550 #[serde(with = "display_fromstr")]
552 pub effective_at_height: u64,
553 pub effective_at: DateTime<Utc>,
555}
556
557#[derive(Debug, Clone, Serialize, Deserialize)]
559pub struct TimeResponse {
560 pub iso: DateTime<Utc>,
562 #[serde(rename = "epoch")]
564 pub epoch_ms: i64,
565}
566
567#[derive(Debug, Clone, Serialize, Deserialize)]
569pub struct HeightResponse {
570 #[serde(with = "display_fromstr")]
572 pub height: u64,
573 pub time: DateTime<Utc>,
575}
576
577#[derive(Debug, Clone, Serialize, Deserialize)]
579#[serde(rename_all = "camelCase")]
580pub struct PlaceOrderRequest {
581 pub subaccount: SubaccountId,
583 pub client_id: u32,
585 pub order_flags: String,
587 pub clob_pair_id: u32,
589 pub side: OrderSide,
591 pub quantums: u64,
593 pub subticks: u64,
595 pub time_in_force: DydxTimeInForce,
597 #[serde(skip_serializing_if = "Option::is_none")]
599 pub good_til_block: Option<u32>,
600 #[serde(skip_serializing_if = "Option::is_none")]
602 pub good_til_block_time: Option<u32>,
603 pub reduce_only: bool,
605 #[serde(skip_serializing_if = "Option::is_none")]
607 pub authenticator_ids: Option<Vec<u64>>,
608}
609
610#[derive(Debug, Clone, Serialize, Deserialize)]
612pub struct SubaccountId {
613 pub owner: String,
615 pub number: u32,
617}
618
619#[derive(Debug, Clone, Serialize, Deserialize)]
621#[serde(rename_all = "camelCase")]
622pub struct CancelOrderRequest {
623 pub subaccount_id: SubaccountId,
625 pub client_id: u32,
627 pub clob_pair_id: u32,
629 pub order_flags: String,
631 pub good_til_block: Option<u32>,
633 pub good_til_block_time: Option<u32>,
634}
635
636#[derive(Debug, Clone, Serialize, Deserialize)]
638pub struct TransactionResponse {
639 pub tx_hash: String,
641 #[serde(with = "display_fromstr")]
643 pub height: u64,
644 pub code: u32,
646 pub raw_log: String,
648}