1use rust_decimal::{Decimal, serde::str_option::deserialize as option_decimal};
2use serde::{Deserialize, Serialize};
3use serde_aux::prelude::{
4 deserialize_number_from_string as number,
5 deserialize_option_number_from_string as option_number,
6};
7
8use crate::{
9 ContractType, CopyTrading, CurAuctionPhase, Side, Status, Timestamp,
10 enums::{Category, Interval},
11 serde::{empty_string_as_none, string_to_bool},
12};
13
14#[derive(Debug, Serialize, Clone)]
15pub struct GetKLinesParams {
16 pub category: Category,
17 pub symbol: String,
18 pub interval: Interval,
19 pub start: Option<Timestamp>,
20 pub end: Option<Timestamp>,
21 pub limit: Option<u64>,
22}
23
24#[derive(Debug, Deserialize, PartialEq)]
25#[serde(tag = "category")]
26pub enum KLine {
27 #[serde(rename = "inverse")]
28 Inverse { symbol: String, list: Vec<KLineRow> },
29 #[serde(rename = "linear")]
30 Linear { symbol: String, list: Vec<KLineRow> },
31 #[serde(rename = "option")]
32 Option { symbol: String, list: Vec<KLineRow> },
33 #[serde(rename = "spot")]
34 Spot { symbol: String, list: Vec<KLineRow> },
35}
36
37#[derive(Debug, Deserialize, PartialEq)]
38pub struct KLineRow {
39 #[serde(rename = "startTime", deserialize_with = "number")]
41 pub start_time: Timestamp,
42 #[serde(rename = "openPrice")]
44 pub open_price: Decimal,
45 #[serde(rename = "highPrice")]
47 pub high_price: Decimal,
48 #[serde(rename = "lowPrice")]
50 pub low_price: Decimal,
51 #[serde(rename = "closePrice")]
53 pub close_price: Decimal,
54 #[serde(rename = "volume")]
56 pub volume: Decimal,
57 #[serde(rename = "turnover")]
59 pub turnover: Decimal,
60}
61
62#[derive(Debug, Serialize, Clone)]
63pub struct GetTickersParams {
64 pub category: Category,
65 pub symbol: Option<String>,
66 pub base_coin: Option<String>,
67 pub exp_date: Option<String>,
68}
69
70#[derive(Debug, Deserialize, PartialEq)]
71#[serde(tag = "category")]
72pub enum Ticker {
73 #[serde(rename = "inverse")]
74 Inverse { list: Vec<LinearInverseTicker> },
75 #[serde(rename = "linear")]
76 Linear { list: Vec<LinearInverseTicker> },
77 #[serde(rename = "option")]
78 Option { list: Vec<OptionTicker> },
79 #[serde(rename = "spot")]
80 Spot { list: Vec<SpotTicker> },
81}
82
83#[derive(Debug, Deserialize, PartialEq)]
84#[serde(rename_all = "camelCase")]
85pub struct LinearInverseTicker {
86 pub symbol: String,
88 pub last_price: Decimal,
90 pub mark_price: Decimal,
92 pub index_price: Decimal,
94 pub prev_price24h: Decimal,
96 pub price24h_pcnt: Decimal,
98 pub high_price24h: Decimal,
100 pub low_price24h: Decimal,
102 pub prev_price1h: Decimal,
104 pub open_interest: Decimal,
106 pub open_interest_value: Decimal,
108 pub turnover24h: Decimal,
110 pub volume24h: Decimal,
112 #[serde(default, deserialize_with = "option_decimal")]
114 pub funding_rate: Option<Decimal>,
115 #[serde(deserialize_with = "number")]
117 pub next_funding_time: Timestamp,
118 #[serde(default, deserialize_with = "option_decimal")]
120 pub predicted_delivery_price: Option<Decimal>,
121 #[serde(default, deserialize_with = "option_decimal")]
123 pub basis_rate: Option<Decimal>,
124 #[serde(default, deserialize_with = "option_decimal")]
126 pub basis: Option<Decimal>,
127 #[serde(default, deserialize_with = "option_decimal")]
129 pub delivery_fee_rate: Option<Decimal>,
130 #[serde(deserialize_with = "option_number")]
132 pub delivery_time: Option<Timestamp>,
133 pub bid1_price: Decimal,
135 pub bid1_size: Decimal,
137 pub ask1_price: Decimal,
139 pub ask1_size: Decimal,
141 #[serde(default, deserialize_with = "option_decimal")]
143 pub pre_open_price: Option<Decimal>,
144 #[serde(default, deserialize_with = "option_decimal")]
146 pub pre_qty: Option<Decimal>,
147 #[serde(default, deserialize_with = "empty_string_as_none")]
149 pub cur_pre_listing_phase: Option<CurAuctionPhase>,
150}
151
152#[derive(Debug, Deserialize, PartialEq)]
153#[serde(rename_all = "camelCase")]
154pub struct OptionTicker {
155 pub symbol: String,
157 pub bid1_price: Decimal,
159 pub bid1_size: Decimal,
161 pub bid1_iv: Decimal,
163 pub ask1_price: Decimal,
165 pub ask1_size: Decimal,
167 pub ask1_iv: Decimal,
169 pub last_price: Decimal,
171 pub high_price24h: Decimal,
173 pub low_price24h: Decimal,
175 pub mark_price: Decimal,
177 pub index_price: Decimal,
179 pub mark_iv: Decimal,
181 pub underlying_price: Decimal,
183 pub open_interest: Decimal,
185 pub turnover24h: Decimal,
187 pub volume24h: Decimal,
189 pub total_volume: Decimal,
191 pub total_turnover: Decimal,
193 pub delta: Decimal,
195 pub gamma: Decimal,
197 pub vega: Decimal,
199 pub theta: Decimal,
201 pub predicted_delivery_price: Decimal,
203 pub change24h: Decimal,
205}
206
207#[derive(Debug, Deserialize, PartialEq)]
208#[serde(rename_all = "camelCase")]
209pub struct SpotTicker {
210 pub symbol: String,
212 pub bid1_price: Decimal,
214 pub bid1_size: Decimal,
216 pub ask1_price: Decimal,
218 pub ask1_size: Decimal,
220 pub last_price: Decimal,
222 pub prev_price24h: Decimal,
224 pub price24h_pcnt: Decimal,
226 pub high_price24h: Decimal,
228 pub low_price24h: Decimal,
230 pub turnover24h: Decimal,
232 pub volume24h: Decimal,
234 #[serde(default, deserialize_with = "option_decimal")]
239 pub usd_index_price: Option<Decimal>,
240}
241
242#[derive(Debug, Serialize, Clone)]
243pub struct GetOrderbookParams {
244 pub category: Category,
245 pub symbol: String,
246 pub limit: Option<u64>,
251}
252
253#[derive(Debug, Deserialize, PartialEq)]
254pub struct Orderbook {
255 #[serde(rename = "s")]
257 pub symbol: String,
258 #[serde(rename = "b")]
260 pub bids: Vec<OrderbookLevel>,
261 #[serde(rename = "a")]
263 pub asks: Vec<OrderbookLevel>,
264 pub ts: Timestamp,
266 #[serde(rename = "u")]
269 pub update_id: i64,
270 pub seq: i64,
273 #[serde(default)]
275 pub cts: Option<Timestamp>,
276}
277
278#[derive(Debug, Deserialize, PartialEq)]
279pub struct OrderbookLevel {
280 pub price: Decimal,
282 pub size: Decimal,
284}
285
286#[derive(Debug, Serialize, Clone)]
287#[serde(rename_all = "camelCase")]
288pub struct GetTradesParams {
289 pub category: Category,
290 pub symbol: Option<String>,
293 pub base_coin: Option<String>,
296 pub option_type: Option<u64>,
298 pub limit: Option<u64>,
301}
302
303#[derive(Debug, Deserialize, PartialEq)]
304#[serde(tag = "category")]
305pub enum Trade {
306 #[serde(rename = "inverse")]
307 Inverse { list: Vec<InverseLinearSpotTrade> },
308 #[serde(rename = "linear")]
309 Linear { list: Vec<InverseLinearSpotTrade> },
310 #[serde(rename = "option")]
311 Option { list: Vec<OptionTrade> },
312 #[serde(rename = "spot")]
313 Spot { list: Vec<InverseLinearSpotTrade> },
314}
315
316#[derive(Debug, Deserialize, PartialEq)]
317#[serde(rename_all = "camelCase")]
318pub struct InverseLinearSpotTrade {
319 pub exec_id: String,
321 pub symbol: String,
323 pub price: Decimal,
325 pub size: Decimal,
327 pub side: Side,
329 #[serde(deserialize_with = "number")]
331 pub time: Timestamp,
332 pub is_block_trade: bool,
334 #[serde(rename = "isRPITrade")]
336 pub is_rpi_trade: bool,
337}
338
339#[derive(Debug, Deserialize, PartialEq)]
340#[serde(rename_all = "camelCase")]
341pub struct OptionTrade {
342 pub exec_id: String,
344 pub symbol: String,
346 pub price: Decimal,
348 pub size: Decimal,
350 pub side: Side,
352 #[serde(deserialize_with = "number")]
354 pub time: Timestamp,
355 pub is_block_trade: bool,
357 #[serde(rename = "isRPITrade")]
359 pub is_rpi_trade: bool,
360 #[serde(rename = "mP")]
362 pub mark_price: Decimal,
363 #[serde(rename = "iP")]
365 pub index_price: Decimal,
366 #[serde(rename = "mIv")]
368 pub mark_iv: Decimal,
369 #[serde(rename = "iv")]
371 pub iv: Decimal,
372}
373
374#[derive(Debug, Deserialize, PartialEq)]
375#[serde(rename_all = "camelCase")]
376pub struct ServerTime {
377 #[serde(deserialize_with = "number")]
379 pub time_second: u64,
380 #[serde(deserialize_with = "number")]
382 pub time_nano: u64,
383}
384
385#[derive(Debug, Serialize, Clone)]
386pub struct GetInstrumentsInfoParams {
387 pub category: Category,
388 pub symbol: Option<String>,
389 pub status: Option<Status>,
390 pub base_coin: Option<String>,
391 pub limit: Option<i64>,
392 pub cursor: Option<String>,
393}
394
395#[derive(Debug, Deserialize, PartialEq)]
396#[serde(tag = "category")]
397pub enum InstrumentsInfo {
398 #[serde(rename = "inverse", rename_all = "camelCase")]
399 Inverse {
400 next_page_cursor: String,
401 list: Vec<InverseLinearInstrumentsInfo>,
402 },
403 #[serde(rename = "linear", rename_all = "camelCase")]
404 Linear {
405 next_page_cursor: String,
406 list: Vec<InverseLinearInstrumentsInfo>,
407 },
408 #[serde(rename = "option", rename_all = "camelCase")]
409 Option {
410 next_page_cursor: String,
411 list: Vec<OptionInstrumentsInfo>,
412 },
413 #[serde(rename = "spot", rename_all = "camelCase")]
414 Spot {
415 #[serde(default, deserialize_with = "empty_string_as_none")]
416 next_page_cursor: Option<String>,
417 list: Vec<SpotInstrumentsInfo>,
418 },
419}
420
421#[derive(Debug, Deserialize, PartialEq)]
422#[serde(rename_all = "camelCase")]
423pub struct InverseLinearInstrumentsInfo {
424 pub symbol: String,
425 pub contract_type: ContractType,
426 pub status: Status,
427 pub base_coin: String,
428 pub quote_coin: String,
429 #[serde(deserialize_with = "number")]
430 pub launch_time: Timestamp,
431 #[serde(deserialize_with = "number")]
432 pub delivery_time: Timestamp,
433 #[serde(deserialize_with = "option_decimal")]
434 pub delivery_fee_rate: Option<Decimal>,
435 #[serde(deserialize_with = "number")]
436 pub price_scale: i64,
437 pub leverage_filter: LeverageFilter,
438 pub price_filter: PriceFilter,
439 pub lot_size_filter: LotSizeFilter,
440 pub unified_margin_trade: bool,
441 pub funding_interval: i64,
442 pub settle_coin: String,
443 pub copy_trading: CopyTrading,
444 pub upper_funding_rate: Decimal,
445 pub lower_funding_rate: Decimal,
446 pub risk_parameters: RiskParameters,
447 pub is_pre_listing: bool,
448 pub pre_listing_info: Option<PreListingInfo>,
449}
450
451#[derive(Debug, Deserialize, PartialEq)]
452#[serde(rename_all = "camelCase")]
453pub struct OptionInstrumentsInfo {
454 pub symbol: String,
455 pub contract_type: ContractType,
456 pub status: Status,
457 pub base_coin: String,
458 pub quote_coin: String,
459 #[serde(deserialize_with = "number")]
460 pub launch_time: i64,
461 #[serde(deserialize_with = "number")]
462 pub delivery_time: i64,
463 #[serde(deserialize_with = "option_decimal")]
464 pub delivery_fee_rate: Option<Decimal>,
465 #[serde(deserialize_with = "number")]
466 pub price_scale: i64,
467 pub leverage_filter: LeverageFilter,
468 pub price_filter: PriceFilter,
469 pub lot_size_filter: LotSizeFilter,
470 pub unified_margin_trade: bool,
471 pub funding_interval: i64,
472 pub settle_coin: String,
473 pub copy_trading: CopyTrading,
474 pub upper_funding_rate: Decimal,
475 pub lower_funding_rate: Decimal,
476 pub risk_parameters: RiskParameters,
477 pub is_pre_listing: bool,
478 pub pre_listing_info: Option<PreListingInfo>,
479}
480
481#[derive(Debug, Deserialize, PartialEq)]
482#[serde(rename_all = "camelCase")]
483pub struct SpotInstrumentsInfo {
484 pub symbol: String,
486 pub base_coin: String,
488 pub quote_coin: String,
490 #[serde(deserialize_with = "string_to_bool")]
492 pub innovation: bool,
493 pub status: Status,
495 pub margin_trading: String,
499 #[serde(deserialize_with = "string_to_bool")]
501 pub st_tag: bool,
502 pub lot_size_filter: SpotLotSizeFilter,
504 pub price_filter: SpotPriceFilter,
506 pub risk_parameters: RiskParameters,
508}
509
510#[derive(Debug, Deserialize, PartialEq)]
511#[serde(rename_all = "camelCase")]
512pub struct LeverageFilter {
513 pub min_leverage: Decimal,
514 pub max_leverage: Decimal,
515 pub leverage_step: Decimal,
516}
517
518#[derive(Debug, Deserialize, PartialEq)]
519#[serde(rename_all = "camelCase")]
520pub struct PriceFilter {
521 pub min_price: Decimal,
522 pub max_price: Decimal,
523 pub tick_size: Decimal,
524}
525
526#[derive(Debug, Deserialize, PartialEq)]
527#[serde(rename_all = "camelCase")]
528pub struct SpotPriceFilter {
529 pub tick_size: Decimal,
531}
532
533#[derive(Debug, Deserialize, PartialEq)]
534#[serde(rename_all = "camelCase")]
535pub struct LotSizeFilter {
536 pub min_notional_value: Decimal,
537 pub max_order_qty: Decimal,
538 pub max_mkt_order_qty: Decimal,
539 pub min_order_qty: Decimal,
540 pub qty_step: Decimal,
541 pub post_only_max_order_qty: Decimal,
542}
543
544#[derive(Debug, Deserialize, PartialEq)]
545#[serde(rename_all = "camelCase")]
546pub struct SpotLotSizeFilter {
547 pub base_precision: Decimal,
549 pub quote_precision: Decimal,
551 pub min_order_qty: Decimal,
553 pub max_order_qty: Decimal,
555 pub min_order_amt: Decimal,
557 pub max_order_amt: Decimal,
559}
560
561#[derive(Debug, Deserialize, PartialEq)]
562#[serde(rename_all = "camelCase")]
563pub struct RiskParameters {
564 pub price_limit_ratio_x: Decimal,
565 pub price_limit_ratio_y: Decimal,
566}
567
568#[derive(Debug, Deserialize, PartialEq)]
569#[serde(rename_all = "camelCase")]
570pub struct PreListingInfo {
571 pub cur_auction_phase: CurAuctionPhase,
572 pub phases: Vec<Phase>,
573 pub auction_fee_info: AuctionFeeInfo,
574}
575
576#[derive(Debug, Deserialize, PartialEq)]
577#[serde(rename_all = "camelCase")]
578pub struct Phase {
579 pub phase: CurAuctionPhase,
580 #[serde(deserialize_with = "option_number")]
581 pub start_time: Option<Timestamp>,
582 #[serde(deserialize_with = "option_number")]
583 pub end_time: Option<Timestamp>,
584}
585
586#[derive(Debug, Deserialize, PartialEq)]
587#[serde(rename_all = "camelCase")]
588pub struct AuctionFeeInfo {
589 pub auction_fee_rate: Decimal,
590 pub taker_fee_rate: Decimal,
591 pub maker_fee_rate: Decimal,
592}