1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::{from_value, Value};
5use crate::errors::{Error, ErrorKind, Result};
6
7#[derive(Deserialize, Clone)]
8pub struct Empty {}
9
10#[derive(Serialize, Deserialize, Clone)]
11#[serde(rename_all = "camelCase")]
12pub struct ServerTime {
13 pub server_time: u64,
14}
15
16#[derive(Debug, Serialize, Deserialize, Clone)]
17#[serde(rename_all = "camelCase")]
18pub struct ExchangeInformation {
19 pub timezone: String,
20 pub server_time: u64,
21 pub rate_limits: Vec<RateLimit>,
22 pub symbols: Vec<Symbol>,
23}
24
25#[derive(Debug, Serialize, Deserialize, Clone)]
26#[serde(rename_all = "camelCase")]
27pub struct RateLimit {
28 pub rate_limit_type: String,
29 pub interval: String,
30 pub interval_num: u16,
31 pub limit: u64,
32}
33
34#[derive(Debug, Serialize, Deserialize, Clone)]
35#[serde(rename_all = "camelCase")]
36pub struct Symbol {
37 pub symbol: String,
38 pub status: String,
39 pub base_asset: String,
40 pub base_asset_precision: u64,
41 pub quote_asset: String,
42 pub quote_precision: u64,
43 pub order_types: Vec<String>,
44 pub iceberg_allowed: bool,
45 pub is_spot_trading_allowed: bool,
46 pub is_margin_trading_allowed: bool,
47 pub filters: Vec<Filters>,
48}
49
50#[derive(Debug, Serialize, Deserialize, Clone)]
51#[serde(tag = "filterType")]
52pub enum Filters {
53 #[serde(rename = "PRICE_FILTER")]
54 #[serde(rename_all = "camelCase")]
55 PriceFilter {
56 min_price: String,
57 max_price: String,
58 tick_size: String,
59 },
60 #[serde(rename = "PERCENT_PRICE")]
61 #[serde(rename_all = "camelCase")]
62 PercentPrice {
63 multiplier_up: String,
64 multiplier_down: String,
65 avg_price_mins: Option<f64>,
66 },
67 #[serde(rename = "PERCENT_PRICE_BY_SIDE")]
68 #[serde(rename_all = "camelCase")]
69 PercentPriceBySide {
70 bid_multiplier_up: String,
71 bid_multiplier_down: String,
72 ask_multiplier_up: String,
73 ask_multiplier_down: String,
74 avg_price_mins: Option<f64>,
75 },
76 #[serde(rename = "LOT_SIZE")]
77 #[serde(rename_all = "camelCase")]
78 LotSize {
79 min_qty: String,
80 max_qty: String,
81 step_size: String,
82 },
83 #[serde(rename = "MIN_NOTIONAL")]
84 #[serde(rename_all = "camelCase")]
85 MinNotional {
86 notional: Option<String>,
87 min_notional: Option<String>,
88 apply_to_market: Option<bool>,
89 avg_price_mins: Option<f64>,
90 },
91 #[serde(rename = "NOTIONAL")]
92 #[serde(rename_all = "camelCase")]
93 Notional {
94 notional: Option<String>,
95 min_notional: Option<String>,
96 apply_to_market: Option<bool>,
97 avg_price_mins: Option<f64>,
98 },
99 #[serde(rename = "ICEBERG_PARTS")]
100 #[serde(rename_all = "camelCase")]
101 IcebergParts { limit: Option<u16> },
102 #[serde(rename = "MAX_NUM_ORDERS")]
103 #[serde(rename_all = "camelCase")]
104 MaxNumOrders { max_num_orders: Option<u16> },
105 #[serde(rename = "MAX_NUM_ALGO_ORDERS")]
106 #[serde(rename_all = "camelCase")]
107 MaxNumAlgoOrders { max_num_algo_orders: Option<u16> },
108 #[serde(rename = "MAX_NUM_ICEBERG_ORDERS")]
109 #[serde(rename_all = "camelCase")]
110 MaxNumIcebergOrders { max_num_iceberg_orders: u16 },
111 #[serde(rename = "MAX_POSITION")]
112 #[serde(rename_all = "camelCase")]
113 MaxPosition { max_position: String },
114 #[serde(rename = "MARKET_LOT_SIZE")]
115 #[serde(rename_all = "camelCase")]
116 MarketLotSize {
117 min_qty: String,
118 max_qty: String,
119 step_size: String,
120 },
121 #[serde(rename = "TRAILING_DELTA")]
122 #[serde(rename_all = "camelCase")]
123 TrailingData {
124 min_trailing_above_delta: Option<u16>,
125 max_trailing_above_delta: Option<u16>,
126 min_trailing_below_delta: Option<u16>,
127 max_trailing_below_delta: Option<u16>,
128 },
129}
130
131#[derive(Debug, Serialize, Deserialize, Clone)]
132#[serde(rename_all = "camelCase")]
133pub struct AccountInformation {
134 pub maker_commission: f32,
135 pub taker_commission: f32,
136 pub buyer_commission: f32,
137 pub seller_commission: f32,
138 pub can_trade: bool,
139 pub can_withdraw: bool,
140 pub can_deposit: bool,
141 pub balances: Vec<Balance>,
142}
143
144#[derive(Debug, Serialize, Deserialize, Clone)]
145#[serde(rename_all = "camelCase")]
146pub struct Balance {
147 pub asset: String,
148 pub free: String,
149 pub locked: String,
150}
151
152#[derive(Debug, Serialize, Deserialize, Clone)]
153#[serde(rename_all = "camelCase")]
154pub struct Order {
155 pub symbol: String,
156 pub order_id: u64,
157 pub order_list_id: i64,
158 pub client_order_id: String,
159 #[serde(with = "string_or_float")]
160 pub price: f64,
161 pub orig_qty: String,
162 pub executed_qty: String,
163 pub cummulative_quote_qty: String,
164 pub status: String,
165 pub time_in_force: String,
166 #[serde(rename = "type")]
167 pub type_name: String,
168 pub side: String,
169 #[serde(with = "string_or_float")]
170 pub stop_price: f64,
171 pub iceberg_qty: String,
172 pub time: u64,
173 pub update_time: u64,
174 pub is_working: bool,
175 pub orig_quote_order_qty: String,
176}
177
178#[derive(Debug, Serialize, Deserialize, Clone)]
179#[serde(rename_all = "camelCase")]
180pub struct OrderCanceled {
181 pub symbol: String,
182 pub orig_client_order_id: Option<String>,
183 pub order_id: Option<u64>,
184 pub client_order_id: Option<String>,
185}
186#[derive(Debug, Serialize, Deserialize, Clone)]
187#[serde(rename_all = "camelCase")]
188pub enum SpotFuturesTransferType {
189 SpotToUsdtFutures = 1,
190 UsdtFuturesToSpot = 2,
191 SpotToCoinFutures = 3,
192 CoinFuturesToSpot = 4,
193}
194
195#[derive(Debug, Serialize, Deserialize, Clone)]
196#[serde(rename_all = "camelCase")]
197pub struct TransactionId {
198 pub tran_id: u64,
199}
200
201#[derive(Debug, Serialize, Deserialize, Clone)]
202#[serde(rename_all = "camelCase")]
203pub struct Transaction {
204 pub symbol: String,
205 pub order_id: u64,
206 pub order_list_id: Option<i64>,
207 pub client_order_id: String,
208 pub transact_time: u64,
209 #[serde(with = "string_or_float")]
210 pub price: f64,
211 #[serde(with = "string_or_float")]
212 pub orig_qty: f64,
213 #[serde(with = "string_or_float")]
214 pub executed_qty: f64,
215 #[serde(with = "string_or_float")]
216 pub cummulative_quote_qty: f64,
217 #[serde(with = "string_or_float", default = "default_stop_price")]
218 pub stop_price: f64,
219 pub status: String,
220 pub time_in_force: String,
221 #[serde(rename = "type")]
222 pub type_name: String,
223 pub side: String,
224 pub fills: Option<Vec<FillInfo>>,
225}
226
227fn default_stop_price() -> f64 {
228 0.0
229}
230
231#[derive(Debug, Serialize, Deserialize, Clone)]
232#[serde(rename_all = "camelCase")]
233pub struct FillInfo {
234 #[serde(with = "string_or_float")]
235 pub price: f64,
236 #[serde(with = "string_or_float")]
237 pub qty: f64,
238 #[serde(with = "string_or_float")]
239 pub commission: f64,
240 pub commission_asset: String,
241 pub trade_id: Option<u64>,
242}
243#[derive(Debug, Serialize, Deserialize, Clone)]
248#[serde(rename_all = "camelCase")]
249pub struct TestResponse {}
250
251#[derive(Debug, Serialize, Deserialize, Clone)]
252#[serde(rename_all = "camelCase")]
253pub struct OrderBook {
254 pub last_update_id: u64,
255 pub bids: Vec<Bids>,
256 pub asks: Vec<Asks>,
257}
258
259#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
260pub struct Bids {
261 #[serde(with = "string_or_float")]
262 pub price: f64,
263 #[serde(with = "string_or_float")]
264 pub qty: f64,
265}
266
267impl Bids {
268 pub fn new(price: f64, qty: f64) -> Bids {
269 Bids { price, qty }
270 }
271}
272
273#[derive(Debug, Serialize, Deserialize, Clone)]
274pub struct Asks {
275 #[serde(with = "string_or_float")]
276 pub price: f64,
277 #[serde(with = "string_or_float")]
278 pub qty: f64,
279}
280
281#[derive(Debug, Serialize, Deserialize, Clone)]
282#[serde(rename_all = "camelCase")]
283pub struct UserDataStream {
284 pub listen_key: String,
285}
286
287#[derive(Debug, Serialize, Deserialize, Clone)]
288pub struct Success {}
289
290#[derive(Debug, Serialize, Deserialize, Clone)]
291#[serde(rename_all = "camelCase")]
292#[serde(untagged)]
293pub enum Prices {
294 AllPrices(Vec<SymbolPrice>),
295}
296
297#[derive(Debug, Serialize, Deserialize, Clone)]
298pub struct SymbolPrice {
299 pub symbol: String,
300 #[serde(with = "string_or_float")]
301 pub price: f64,
302}
303
304#[derive(Debug, Serialize, Deserialize, Clone)]
305pub struct AveragePrice {
306 pub mins: u64,
307 #[serde(with = "string_or_float")]
308 pub price: f64,
309}
310
311#[derive(Debug, Serialize, Deserialize, Clone)]
312#[serde(rename_all = "camelCase")]
313#[serde(untagged)]
314pub enum BookTickers {
315 AllBookTickers(Vec<Tickers>),
316}
317
318#[derive(Debug, Serialize, Deserialize, Clone)]
319pub enum KlineSummaries {
320 AllKlineSummaries(Vec<KlineSummary>),
321}
322
323#[derive(Debug, Serialize, Deserialize, Clone)]
324#[serde(rename_all = "camelCase")]
325pub struct Tickers {
326 pub symbol: String,
327 #[serde(with = "string_or_float")]
328 pub bid_price: f64,
329 #[serde(with = "string_or_float")]
330 pub bid_qty: f64,
331 #[serde(with = "string_or_float")]
332 pub ask_price: f64,
333 #[serde(with = "string_or_float")]
334 pub ask_qty: f64,
335}
336
337#[derive(Debug, Serialize, Deserialize, Clone)]
338#[serde(rename_all = "camelCase")]
339pub struct TradeHistory {
340 pub id: u64,
341 #[serde(with = "string_or_float")]
342 pub price: f64,
343 #[serde(with = "string_or_float")]
344 pub qty: f64,
345 pub commission: String,
346 pub commission_asset: String,
347 pub time: u64,
348 pub is_buyer: bool,
349 pub is_maker: bool,
350 pub is_best_match: bool,
351}
352
353#[derive(Debug, Serialize, Deserialize, Clone)]
354#[serde(rename_all = "camelCase")]
355pub struct PriceStats {
356 pub symbol: String,
357 pub price_change: String,
358 pub price_change_percent: String,
359 pub weighted_avg_price: String,
360 #[serde(with = "string_or_float")]
361 pub prev_close_price: f64,
362 #[serde(with = "string_or_float")]
363 pub last_price: f64,
364 #[serde(with = "string_or_float")]
365 pub bid_price: f64,
366 #[serde(with = "string_or_float")]
367 pub ask_price: f64,
368 #[serde(with = "string_or_float")]
369 pub open_price: f64,
370 #[serde(with = "string_or_float")]
371 pub high_price: f64,
372 #[serde(with = "string_or_float")]
373 pub low_price: f64,
374 #[serde(with = "string_or_float")]
375 pub volume: f64,
376 pub open_time: u64,
377 pub close_time: u64,
378 pub first_id: i64,
379 pub last_id: i64,
380 pub count: u64,
381}
382
383#[derive(Debug, Serialize, Deserialize, Clone)]
384pub struct AggTrade {
385 #[serde(rename = "T")]
386 pub time: u64,
387 #[serde(rename = "a")]
388 pub agg_id: u64,
389 #[serde(rename = "f")]
390 pub first_id: u64,
391 #[serde(rename = "l")]
392 pub last_id: u64,
393 #[serde(rename = "m")]
394 pub maker: bool,
395 #[serde(rename = "M")]
396 pub best_match: bool,
397 #[serde(rename = "p", with = "string_or_float")]
398 pub price: f64,
399 #[serde(rename = "q", with = "string_or_float")]
400 pub qty: f64,
401}
402
403#[derive(Debug, Serialize, Deserialize, Clone)]
404#[serde(rename_all = "camelCase")]
405pub struct UserDataStreamExpiredEvent {
406 #[serde(rename = "e")]
407 pub event_type: String,
408
409 #[serde(rename = "E")]
410 pub event_time: u64,
411}
412
413#[derive(Debug, Serialize, Deserialize, Clone)]
414#[serde(rename_all = "camelCase")]
415pub struct AccountUpdateEvent {
416 #[serde(rename = "e")]
417 pub event_type: String,
418
419 #[serde(rename = "E")]
420 pub event_time: u64,
421
422 #[serde(rename = "a")]
423 pub data: AccountUpdateDataEvent,
424}
425
426#[derive(Debug, Serialize, Deserialize, Clone)]
427#[serde(rename_all = "camelCase")]
428pub struct AccountUpdateDataEvent {
429 #[serde(rename = "m")]
430 pub reason: String,
431
432 #[serde(rename = "B")]
433 pub balances: Vec<EventBalance>,
434
435 #[serde(rename = "P")]
436 pub positions: Vec<EventPosition>,
437}
438
439#[derive(Debug, Serialize, Deserialize, Clone)]
440#[serde(rename_all = "camelCase")]
441pub struct EventBalance {
442 #[serde(rename = "a")]
443 pub asset: String,
444 #[serde(rename = "wb")]
445 pub wallet_balance: String,
446 #[serde(rename = "cw")]
447 pub cross_wallet_balance: String,
448 #[serde(rename = "bc")]
449 pub balance_change: String, }
451
452#[derive(Debug, Serialize, Deserialize, Clone)]
453#[serde(rename_all = "camelCase")]
454pub struct EventPosition {
455 #[serde(rename = "s")]
456 pub symbol: String,
457 #[serde(rename = "pa")]
458 pub position_amount: String,
459 #[serde(rename = "ep")]
460 pub entry_price: String,
461 #[serde(rename = "cr")]
462 pub accumulated_realized: String, #[serde(rename = "up")]
464 pub unrealized_pnl: String,
465 #[serde(rename = "mt")]
466 pub margin_type: String,
467 #[serde(rename = "iw")]
468 pub isolated_wallet: String,
469 #[serde(rename = "ps")]
470 pub position_side: String,
471}
472
473#[derive(Debug, Serialize, Deserialize, Clone)]
474#[serde(rename_all = "camelCase")]
475pub struct BalanceUpdateEvent {
476 #[serde(rename = "B")]
477 pub balance: Vec<EventBalance>,
478
479 #[serde(rename = "e")]
480 pub event_type: String,
481
482 #[serde(rename = "E")]
483 pub event_time: u64,
484
485 #[serde(rename = "u")]
486 pub last_account_update_time: u64,
487}
488
489#[derive(Debug, Serialize, Deserialize, Clone)]
490#[serde(rename_all = "camelCase")]
491pub struct OrderTradeEvent {
492 #[serde(rename = "e")]
493 pub event_type: String,
494
495 #[serde(rename = "E")]
496 pub event_time: u64,
497
498 #[serde(rename = "s")]
499 pub symbol: String,
500
501 #[serde(rename = "c")]
502 pub new_client_order_id: String,
503
504 #[serde(rename = "S")]
505 pub side: String,
506
507 #[serde(rename = "o")]
508 pub order_type: String,
509
510 #[serde(rename = "f")]
511 pub time_in_force: String,
512
513 #[serde(rename = "q")]
514 pub qty: String,
515
516 #[serde(rename = "p")]
517 pub price: String,
518
519 #[serde(skip, rename = "P")]
520 pub p_ignore: String,
521
522 #[serde(skip, rename = "F")]
523 pub f_ignore: String,
524
525 #[serde(skip)]
526 pub g: i32,
527
528 #[serde(skip, rename = "C")]
529 pub c_ignore: Option<String>,
530
531 #[serde(rename = "x")]
532 pub execution_type: String,
533
534 #[serde(rename = "X")]
535 pub order_status: String,
536
537 #[serde(rename = "r")]
538 pub order_reject_reason: String,
539
540 #[serde(rename = "i")]
541 pub order_id: u64,
542
543 #[serde(rename = "l")]
544 pub qty_last_filled_trade: String,
545
546 #[serde(rename = "z")]
547 pub accumulated_qty_filled_trades: String,
548
549 #[serde(rename = "L")]
550 pub price_last_filled_trade: String,
551
552 #[serde(rename = "n")]
553 pub commission: String,
554
555 #[serde(skip, rename = "N")]
556 pub asset_commisioned: Option<String>,
557
558 #[serde(rename = "T")]
559 pub trade_order_time: u64,
560
561 #[serde(rename = "t")]
562 pub trade_id: i64,
563
564 #[serde(skip, rename = "I")]
565 pub i_ignore: u64,
566
567 #[serde(skip)]
568 pub w: bool,
569
570 #[serde(rename = "m")]
571 pub is_buyer_maker: bool,
572
573 #[serde(skip, rename = "M")]
574 pub m_ignore: bool,
575}
576
577#[derive(Debug, Serialize, Deserialize, Clone)]
585#[serde(rename_all = "camelCase")]
586pub struct AggrTradesEvent {
587 #[serde(rename = "e")]
588 pub event_type: String,
589
590 #[serde(rename = "E")]
591 pub event_time: u64,
592
593 #[serde(rename = "s")]
594 pub symbol: String,
595
596 #[serde(rename = "a")]
597 pub aggregated_trade_id: u64,
598
599 #[serde(rename = "p")]
600 pub price: String,
601
602 #[serde(rename = "q")]
603 pub qty: String,
604
605 #[serde(rename = "f")]
606 pub first_break_trade_id: u64,
607
608 #[serde(rename = "l")]
609 pub last_break_trade_id: u64,
610
611 #[serde(rename = "T")]
612 pub trade_order_time: u64,
613
614 #[serde(rename = "m")]
615 pub is_buyer_maker: bool,
616
617 #[serde(skip, rename = "M")]
618 pub m_ignore: bool,
619}
620
621#[derive(Debug, Serialize, Deserialize, Clone)]
629#[serde(rename_all = "camelCase")]
630pub struct TradeEvent {
631 #[serde(rename = "e")]
632 pub event_type: String,
633
634 #[serde(rename = "E")]
635 pub event_time: u64,
636
637 #[serde(rename = "s")]
638 pub symbol: String,
639
640 #[serde(rename = "t")]
641 pub trade_id: u64,
642
643 #[serde(rename = "p")]
644 pub price: String,
645
646 #[serde(rename = "q")]
647 pub qty: String,
648
649 #[serde(rename = "b")]
650 pub buyer_order_id: u64,
651
652 #[serde(rename = "a")]
653 pub seller_order_id: u64,
654
655 #[serde(rename = "T")]
656 pub trade_order_time: u64,
657
658 #[serde(rename = "m")]
659 pub is_buyer_maker: bool,
660
661 #[serde(skip, rename = "M")]
662 pub m_ignore: bool,
663}
664
665#[derive(Debug, Serialize, Deserialize, Clone)]
666#[serde(rename_all = "camelCase")]
667pub struct IndexPriceEvent {
668 #[serde(rename = "e")]
669 pub event_type: String,
670
671 #[serde(rename = "E")]
672 pub event_time: u64,
673
674 #[serde(rename = "i")]
675 pub pair: String,
676
677 #[serde(rename = "p")]
678 pub price: String,
679}
680#[derive(Debug, Serialize, Deserialize, Clone)]
683#[serde(rename_all = "camelCase")]
684pub struct MarkPriceEvent {
685 #[serde(rename = "E")]
686 pub event_time: u64,
687
688 #[serde(rename = "P")]
689 pub estimate_settle_price: String,
690
691 #[serde(rename = "T")]
692 pub next_funding_time: u64,
693
694 #[serde(rename = "e")]
695 pub event_type: String,
696
697 #[serde(rename = "i")]
698 pub index_price: Option<String>,
699
700 #[serde(rename = "p")]
701 pub mark_price: String,
702
703 #[serde(rename = "r")]
704 pub funding_rate: String,
705
706 #[serde(rename = "s")]
707 pub symbol: String,
708}
709
710#[derive(Debug, Serialize, Deserialize, Clone)]
714#[serde(rename_all = "camelCase")]
715pub struct LiquidationEvent {
716 #[serde(rename = "e")]
717 pub event_type: String,
718
719 #[serde(rename = "E")]
720 pub event_time: u64,
721
722 #[serde(rename = "o")]
723 pub liquidation_order: LiquidationOrder,
724}
725
726#[derive(Debug, Serialize, Deserialize, Clone)]
727#[serde(rename_all = "camelCase")]
728pub struct LiquidationOrder {
729 #[serde(rename = "s")]
730 pub symbol: String,
731
732 #[serde(rename = "S")]
733 pub side: String,
734
735 #[serde(rename = "o")]
736 pub order_type: String,
737
738 #[serde(rename = "f")]
739 pub time_in_force: String,
740
741 #[serde(rename = "q")]
742 pub original_quantity: String,
743
744 #[serde(rename = "p")]
745 pub price: String,
746
747 #[serde(rename = "ap")]
748 pub average_price: String,
749
750 #[serde(rename = "X")]
751 pub order_status: String,
752
753 #[serde(rename = "l")]
754 pub order_last_filled_quantity: String,
755
756 #[serde(rename = "z")]
757 pub order_filled_accumulated_quantity: String,
758
759 #[serde(rename = "T")]
760 pub order_trade_time: u64,
761}
762
763#[derive(Debug, Serialize, Deserialize, Clone)]
764#[serde(rename_all = "camelCase")]
765pub struct BookTickerEvent {
766 #[serde(rename = "u")]
767 pub update_id: u64,
768
769 #[serde(rename = "s")]
770 pub symbol: String,
771
772 #[serde(rename = "b")]
773 pub best_bid: String,
774
775 #[serde(rename = "B")]
776 pub best_bid_qty: String,
777
778 #[serde(rename = "a")]
779 pub best_ask: String,
780
781 #[serde(rename = "A")]
782 pub best_ask_qty: String,
783}
784
785#[derive(Debug, Serialize, Deserialize, Clone)]
786#[serde(rename_all = "camelCase")]
787pub struct DayTickerEvent {
788 #[serde(rename = "e")]
789 pub event_type: String,
790
791 #[serde(rename = "E")]
792 pub event_time: u64,
793
794 #[serde(rename = "s")]
795 pub symbol: String,
796
797 #[serde(rename = "p")]
798 pub price_change: String,
799
800 #[serde(rename = "P")]
801 pub price_change_percent: String,
802
803 #[serde(rename = "w")]
804 pub average_price: String,
805
806 #[serde(rename = "x")]
807 pub prev_close: String,
808
809 #[serde(rename = "c")]
810 pub current_close: String,
811
812 #[serde(rename = "Q")]
813 pub current_close_qty: String,
814
815 #[serde(rename = "b")]
816 pub best_bid: String,
817
818 #[serde(rename = "B")]
819 pub best_bid_qty: String,
820
821 #[serde(rename = "a")]
822 pub best_ask: String,
823
824 #[serde(rename = "A")]
825 pub best_ask_qty: String,
826
827 #[serde(rename = "o")]
828 pub open: String,
829
830 #[serde(rename = "h")]
831 pub high: String,
832
833 #[serde(rename = "l")]
834 pub low: String,
835
836 #[serde(rename = "v")]
837 pub volume: String,
838
839 #[serde(rename = "q")]
840 pub quote_volume: String,
841
842 #[serde(rename = "O")]
843 pub open_time: u64,
844
845 #[serde(rename = "C")]
846 pub close_time: u64,
847
848 #[serde(rename = "F")]
849 pub first_trade_id: i64,
850
851 #[serde(rename = "L")]
852 pub last_trade_id: i64,
853
854 #[serde(rename = "n")]
855 pub num_trades: u64,
856}
857
858#[derive(Debug, Serialize, Deserialize, Clone)]
859#[serde(rename_all = "camelCase")]
860pub struct WindowTickerEvent {
861 #[serde(rename = "e")]
862 pub event_type: String,
863
864 #[serde(rename = "E")]
865 pub event_time: u64,
866
867 #[serde(rename = "s")]
868 pub symbol: String,
869
870 #[serde(rename = "p")]
871 pub price_change: String,
872
873 #[serde(rename = "P")]
874 pub price_change_percent: String,
875
876 #[serde(rename = "o")]
877 pub open: String,
878
879 #[serde(rename = "h")]
880 pub high: String,
881
882 #[serde(rename = "l")]
883 pub low: String,
884
885 #[serde(rename = "c")]
886 pub current_close: String,
887
888 #[serde(rename = "w")]
889 pub average_price: String,
890
891 #[serde(rename = "v")]
892 pub volume: String,
893
894 #[serde(rename = "q")]
895 pub quote_volume: String,
896
897 #[serde(rename = "O")]
898 pub open_time: u64,
899
900 #[serde(rename = "C")]
901 pub close_time: u64,
902
903 #[serde(rename = "F")]
904 pub first_trade_id: i64,
905
906 #[serde(rename = "L")]
907 pub last_trade_id: i64,
908
909 #[serde(rename = "n")]
910 pub num_trades: u64,
911}
912
913#[derive(Debug, Serialize, Deserialize, Clone)]
914#[serde(rename_all = "camelCase")]
915pub struct MiniTickerEvent {
916 #[serde(rename = "e")]
917 pub event_type: String,
918
919 #[serde(rename = "E")]
920 pub event_time: u64,
921
922 #[serde(rename = "s")]
923 pub symbol: String,
924
925 #[serde(rename = "c")]
926 pub close: String,
927
928 #[serde(rename = "o")]
929 pub open: String,
930
931 #[serde(rename = "h")]
932 pub high: String,
933
934 #[serde(rename = "l")]
935 pub low: String,
936
937 #[serde(rename = "v")]
938 pub volume: String,
939
940 #[serde(rename = "q")]
941 pub quote_volume: String,
942}
943
944#[derive(Debug, Serialize, Deserialize, Clone)]
945#[serde(rename_all = "camelCase")]
946pub struct KlineEvent {
947 #[serde(rename = "e")]
948 pub event_type: String,
949
950 #[serde(rename = "E")]
951 pub event_time: u64,
952
953 #[serde(rename = "s")]
954 pub symbol: String,
955
956 #[serde(rename = "k")]
957 pub kline: Kline,
958}
959
960#[derive(Debug, Serialize, Deserialize, Clone)]
963#[serde(rename_all = "camelCase")]
964pub struct ContinuousKlineEvent {
965 #[serde(rename = "e")]
966 pub event_type: String,
967
968 #[serde(rename = "E")]
969 pub event_time: u64,
970
971 #[serde(rename = "ps")]
972 pub pair: String,
973
974 #[serde(rename = "ct")]
975 pub contract_type: String,
976
977 #[serde(rename = "k")]
978 pub kline: ContinuousKline,
979}
980
981#[derive(Debug, Serialize, Deserialize, Clone)]
984#[serde(rename_all = "camelCase")]
985pub struct IndexKlineEvent {
986 #[serde(rename = "e")]
987 pub event_type: String,
988
989 #[serde(rename = "E")]
990 pub event_time: u64,
991
992 #[serde(rename = "ps")]
993 pub pair: String,
994
995 #[serde(rename = "k")]
996 pub kline: IndexKline,
997}
998
999#[derive(Debug, Serialize, Deserialize, Clone)]
1000pub struct KlineSummary {
1001 pub open_time: i64,
1002
1003 pub open: String,
1004
1005 pub high: String,
1006
1007 pub low: String,
1008
1009 pub close: String,
1010
1011 pub volume: String,
1012
1013 pub close_time: i64,
1014
1015 pub quote_asset_volume: String,
1016
1017 pub number_of_trades: i64,
1018
1019 pub taker_buy_base_asset_volume: String,
1020
1021 pub taker_buy_quote_asset_volume: String,
1022}
1023
1024fn get_value(row: &[Value], index: usize, name: &'static str) -> Result<Value> {
1025 Ok(row
1026 .get(index)
1027 .ok_or_else(|| ErrorKind::KlineValueMissingError(index, name))?
1028 .clone())
1029}
1030
1031impl TryFrom<&Vec<Value>> for KlineSummary {
1032 type Error = Error;
1033
1034 fn try_from(row: &Vec<Value>) -> Result<Self> {
1035 Ok(Self {
1036 open_time: from_value(get_value(row, 0, "open_time")?)?,
1037 open: from_value(get_value(row, 1, "open")?)?,
1038 high: from_value(get_value(row, 2, "high")?)?,
1039 low: from_value(get_value(row, 3, "low")?)?,
1040 close: from_value(get_value(row, 4, "close")?)?,
1041 volume: from_value(get_value(row, 5, "volume")?)?,
1042 close_time: from_value(get_value(row, 6, "close_time")?)?,
1043 quote_asset_volume: from_value(get_value(row, 7, "quote_asset_volume")?)?,
1044 number_of_trades: from_value(get_value(row, 8, "number_of_trades")?)?,
1045 taker_buy_base_asset_volume: from_value(get_value(
1046 row,
1047 9,
1048 "taker_buy_base_asset_volume",
1049 )?)?,
1050 taker_buy_quote_asset_volume: from_value(get_value(
1051 row,
1052 10,
1053 "taker_buy_quote_asset_volume",
1054 )?)?,
1055 })
1056 }
1057}
1058
1059#[derive(Debug, Serialize, Deserialize, Clone)]
1060#[serde(rename_all = "camelCase")]
1061pub struct Kline {
1062 #[serde(rename = "t")]
1063 pub open_time: i64,
1064
1065 #[serde(rename = "T")]
1066 pub close_time: i64,
1067
1068 #[serde(rename = "s")]
1069 pub symbol: String,
1070
1071 #[serde(rename = "i")]
1072 pub interval: String,
1073
1074 #[serde(rename = "f")]
1075 pub first_trade_id: i64,
1076
1077 #[serde(rename = "L")]
1078 pub last_trade_id: i64,
1079
1080 #[serde(rename = "o")]
1081 pub open: String,
1082
1083 #[serde(rename = "c")]
1084 pub close: String,
1085
1086 #[serde(rename = "h")]
1087 pub high: String,
1088
1089 #[serde(rename = "l")]
1090 pub low: String,
1091
1092 #[serde(rename = "v")]
1093 pub volume: String,
1094
1095 #[serde(rename = "n")]
1096 pub number_of_trades: i64,
1097
1098 #[serde(rename = "x")]
1099 pub is_final_bar: bool,
1100
1101 #[serde(rename = "q")]
1102 pub quote_asset_volume: String,
1103
1104 #[serde(rename = "V")]
1105 pub taker_buy_base_asset_volume: String,
1106
1107 #[serde(rename = "Q")]
1108 pub taker_buy_quote_asset_volume: String,
1109
1110 #[serde(skip, rename = "B")]
1111 pub ignore_me: String,
1112}
1113
1114#[derive(Debug, Serialize, Deserialize, Clone)]
1115#[serde(rename_all = "camelCase")]
1116pub struct ContinuousKline {
1117 #[serde(rename = "t")]
1118 pub start_time: i64,
1119
1120 #[serde(rename = "T")]
1121 pub end_time: i64,
1122
1123 #[serde(rename = "i")]
1124 pub interval: String,
1125
1126 #[serde(rename = "f")]
1127 pub first_trade_id: i64,
1128
1129 #[serde(rename = "L")]
1130 pub last_trade_id: i64,
1131
1132 #[serde(rename = "o")]
1133 pub open: String,
1134
1135 #[serde(rename = "c")]
1136 pub close: String,
1137
1138 #[serde(rename = "h")]
1139 pub high: String,
1140
1141 #[serde(rename = "l")]
1142 pub low: String,
1143
1144 #[serde(rename = "v")]
1145 pub volume: String,
1146
1147 #[serde(rename = "n")]
1148 pub number_of_trades: i64,
1149
1150 #[serde(rename = "x")]
1151 pub is_final_bar: bool,
1152
1153 #[serde(rename = "q")]
1154 pub quote_volume: String,
1155
1156 #[serde(rename = "V")]
1157 pub active_buy_volume: String,
1158
1159 #[serde(rename = "Q")]
1160 pub active_volume_buy_quote: String,
1161
1162 #[serde(skip, rename = "B")]
1163 pub ignore_me: String,
1164}
1165
1166#[derive(Debug, Serialize, Deserialize, Clone)]
1168#[serde(rename_all = "camelCase")]
1169pub struct IndexKline {
1170 #[serde(rename = "t")]
1171 pub start_time: i64,
1172
1173 #[serde(rename = "T")]
1174 pub end_time: i64,
1175
1176 #[serde(skip, rename = "s")]
1177 pub ignore_me: String,
1178
1179 #[serde(rename = "i")]
1180 pub interval: String,
1181
1182 #[serde(rename = "f")]
1183 pub first_trade_id: i64,
1184
1185 #[serde(rename = "L")]
1186 pub last_trade_id: i64,
1187
1188 #[serde(rename = "o")]
1189 pub open: String,
1190
1191 #[serde(rename = "c")]
1192 pub close: String,
1193
1194 #[serde(rename = "h")]
1195 pub high: String,
1196
1197 #[serde(rename = "l")]
1198 pub low: String,
1199
1200 #[serde(rename = "v")]
1201 pub volume: String,
1202
1203 #[serde(rename = "n")]
1204 pub number_of_trades: i64,
1205
1206 #[serde(rename = "x")]
1207 pub is_final_bar: bool,
1208
1209 #[serde(skip, rename = "q")]
1210 pub ignore_me2: String,
1211
1212 #[serde(skip, rename = "V")]
1213 pub ignore_me3: String,
1214
1215 #[serde(skip, rename = "Q")]
1216 pub ignore_me4: String,
1217
1218 #[serde(skip, rename = "B")]
1219 pub ignore_me5: String,
1220}
1221
1222#[derive(Debug, Serialize, Deserialize, Clone)]
1223#[serde(rename_all = "camelCase")]
1224pub struct DepthOrderBookEvent {
1225 #[serde(rename = "e")]
1226 pub event_type: String,
1227
1228 #[serde(rename = "E")]
1229 pub event_time: u64,
1230
1231 #[serde(rename = "s")]
1232 pub symbol: String,
1233
1234 #[serde(rename = "U")]
1235 pub first_update_id: u64,
1236
1237 #[serde(rename = "u")]
1238 pub final_update_id: u64,
1239
1240 #[serde(rename = "pu")]
1241 #[serde(default)]
1242 pub previous_final_update_id: Option<u64>,
1243
1244 #[serde(rename = "b")]
1245 pub bids: Vec<Bids>,
1246
1247 #[serde(rename = "a")]
1248 pub asks: Vec<Asks>,
1249}
1250
1251#[derive(Debug, Serialize, Deserialize, Clone)]
1253#[serde(rename_all = "camelCase")]
1254pub struct CoinInfo {
1255 pub coin: String,
1256 pub deposit_all_enable: bool,
1257 #[serde(with = "string_or_float")]
1258 pub free: f64,
1259 #[serde(with = "string_or_float")]
1260 pub freeze: f64,
1261 #[serde(with = "string_or_float")]
1262 pub ipoable: f64,
1263 #[serde(with = "string_or_float")]
1264 pub ipoing: f64,
1265 pub is_legal_money: bool,
1266 #[serde(with = "string_or_float")]
1267 pub locked: f64,
1268 pub name: String,
1269 pub network_list: Vec<Network>,
1270 #[serde(with = "string_or_float")]
1271 pub storage: f64,
1272 pub trading: bool,
1273 pub withdraw_all_enable: bool,
1274 #[serde(with = "string_or_float")]
1275 pub withdrawing: f64,
1276}
1277
1278#[derive(Debug, Serialize, Deserialize, Clone)]
1280#[serde(rename_all = "camelCase")]
1281pub struct Network {
1282 pub address_regex: String,
1283 pub coin: String,
1284 pub deposit_desc: Option<String>,
1286 pub deposit_enable: bool,
1287 pub is_default: bool,
1288 pub memo_regex: String,
1289 pub min_confirm: u32,
1291 pub name: String,
1292 pub network: String,
1293 pub reset_address_status: bool,
1294 pub special_tips: Option<String>,
1295 pub un_lock_confirm: u32,
1297 pub withdraw_desc: Option<String>,
1299 pub withdraw_enable: bool,
1300 #[serde(with = "string_or_float")]
1301 pub withdraw_fee: f64,
1302 #[serde(with = "string_or_float")]
1303 pub withdraw_min: f64,
1304 pub withdraw_integer_multiple: Option<String>,
1307}
1308
1309#[derive(Debug, Serialize, Deserialize, Clone)]
1310#[serde(rename_all = "camelCase")]
1311pub struct AssetDetail {
1312 #[serde(with = "string_or_float")]
1313 pub min_withdraw_amount: f64,
1314 pub deposit_status: bool,
1316 #[serde(with = "string_or_float")]
1317 pub withdraw_fee: f64,
1318 pub withdraw_status: bool,
1320 pub deposit_tip: Option<String>,
1322}
1323
1324#[derive(Debug, Serialize, Deserialize, Clone)]
1325pub struct DepositAddress {
1326 pub address: String,
1327 pub coin: String,
1328 pub tag: String,
1329 pub url: String,
1330}
1331
1332#[derive(Debug, Serialize, Deserialize, Clone)]
1333pub struct PaginatedResponse<T> {
1334 #[serde(rename = "rows")]
1335 pub data: Vec<T>,
1336 pub total: usize,
1337}
1338#[derive(Debug, Serialize, Deserialize, Clone)]
1339#[serde(rename_all = "camelCase")]
1340pub struct FlexibleProductInfo {
1341 #[serde(with = "string_or_float")]
1342 pub total_amount: f64,
1343
1344 #[serde(default)]
1345 pub tier_annual_percentage_rate: HashMap<String, String>,
1346
1347 #[serde(with = "string_or_float")]
1348 pub latest_annual_percentage_rate: f64,
1349
1350 pub asset: String,
1351 pub can_redeem: bool,
1352
1353 #[serde(with = "string_or_float")]
1354 pub collateral_amount: f64,
1355
1356 pub product_id: String,
1357
1358 #[serde(with = "string_or_float")]
1359 pub yesterday_real_time_rewards: f64,
1360
1361 #[serde(with = "string_or_float")]
1362 pub cumulative_bonus_rewards: f64,
1363
1364 #[serde(with = "string_or_float")]
1365 pub cumulative_real_time_rewards: f64,
1366
1367 #[serde(with = "string_or_float")]
1368 pub cumulative_total_rewards: f64,
1369
1370 pub auto_subscribe: bool,
1371
1372 #[serde(default)]
1373 pub yesterday_airdrop_percentage_rate: Option<f64>,
1374
1375 #[serde(default)]
1376 pub air_drop_asset: Option<String>,
1377}
1378#[derive(Debug, Serialize, Deserialize, Clone)]
1379#[serde(rename_all = "camelCase")]
1380pub struct LockedProductInfo {
1381 pub position_id: u64,
1382 pub parent_position_id: u64,
1383 pub project_id: String,
1384 pub asset: String,
1385
1386 #[serde(with = "string_or_float")]
1387 pub amount: f64,
1388
1389 pub purchase_time: String,
1390 pub duration: String,
1391 pub accrual_days: String,
1392 pub reward_asset: String,
1393
1394 #[serde(with = "string_or_float")]
1395 #[serde(default, rename = "APY")]
1396 pub apy: f64,
1397
1398 #[serde(rename = "rewardAmt", with = "string_or_float")]
1399 pub reward_amt: f64,
1400
1401 #[serde(default)]
1402 pub extra_reward_asset: Option<String>,
1403
1404 #[serde(rename = "extraRewardAPR", with = "string_or_float_opt")]
1405 #[serde(default)]
1406 pub extra_reward_apr: Option<f64>,
1407
1408 #[serde(rename = "estExtraRewardAmt", with = "string_or_float_opt")]
1409 #[serde(default)]
1410 pub est_extra_reward_amt: Option<f64>,
1411
1412 #[serde(default)]
1413 pub boost_reward_asset: Option<String>,
1414
1415 #[serde(rename = "boostApr", with = "string_or_float_opt")]
1416 #[serde(default)]
1417 pub boost_apr: Option<f64>,
1418
1419 #[serde(rename = "totalBoostRewardAmt", with = "string_or_float_opt")]
1420 #[serde(default)]
1421 pub total_boost_reward_amt: Option<f64>,
1422
1423 #[serde(rename = "nextPay", with = "string_or_float_opt")]
1424 #[serde(default)]
1425 pub next_pay: Option<f64>,
1426
1427 #[serde(default)]
1428 pub next_pay_date: Option<String>,
1429
1430 #[serde(default)]
1431 pub pay_period: Option<String>,
1432
1433 #[serde(rename = "redeemAmountEarly", with = "string_or_float_opt")]
1434 #[serde(default)]
1435 pub redeem_amount_early: Option<f64>,
1436
1437 #[serde(default)]
1438 pub rewards_end_date: Option<String>,
1439
1440 #[serde(default)]
1441 pub deliver_date: Option<String>,
1442
1443 #[serde(default)]
1444 pub redeem_period: Option<String>,
1445
1446 #[serde(rename = "redeemingAmt", with = "string_or_float_opt")]
1447 #[serde(default)]
1448 pub redeeming_amt: Option<f64>,
1449
1450 #[serde(default)]
1451 pub redeem_to: Option<String>,
1452
1453 #[serde(default)]
1454 pub partial_amt_deliver_date: Option<String>,
1455
1456 #[serde(default)]
1457 pub can_redeem_early: Option<bool>,
1458
1459 #[serde(default)]
1460 pub can_fast_redemption: Option<bool>,
1461
1462 #[serde(default)]
1463 pub auto_subscribe: Option<bool>,
1464
1465 #[serde(rename = "type")]
1466 pub order_type: String,
1467
1468 pub status: String,
1469
1470 #[serde(default)]
1471 pub can_re_stake: Option<bool>,
1472}
1473
1474pub(crate) mod string_or_float {
1475 use std::fmt;
1476
1477 use serde::{de, Serializer, Deserialize, Deserializer};
1478
1479 pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
1480 where
1481 T: fmt::Display,
1482 S: Serializer,
1483 {
1484 serializer.collect_str(value)
1485 }
1486
1487 pub fn deserialize<'de, D>(deserializer: D) -> Result<f64, D::Error>
1488 where
1489 D: Deserializer<'de>,
1490 {
1491 #[derive(Deserialize)]
1492 #[serde(untagged)]
1493 enum StringOrFloat {
1494 String(String),
1495 Float(f64),
1496 }
1497
1498 match StringOrFloat::deserialize(deserializer)? {
1499 StringOrFloat::String(s) => {
1500 if s == "INF" {
1501 Ok(f64::INFINITY)
1502 } else {
1503 s.parse().map_err(de::Error::custom)
1504 }
1505 }
1506 StringOrFloat::Float(i) => Ok(i),
1507 }
1508 }
1509}
1510
1511pub(crate) mod string_or_float_opt {
1512 use std::fmt;
1513
1514 use serde::{Serializer, Deserialize, Deserializer};
1515
1516 pub fn serialize<T, S>(value: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
1517 where
1518 T: fmt::Display,
1519 S: Serializer,
1520 {
1521 match value {
1522 Some(v) => crate::model::string_or_float::serialize(v, serializer),
1523 None => serializer.serialize_none(),
1524 }
1525 }
1526
1527 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
1528 where
1529 D: Deserializer<'de>,
1530 {
1531 #[derive(Deserialize)]
1532 #[serde(untagged)]
1533 enum StringOrFloat {
1534 String(String),
1535 Float(f64),
1536 }
1537
1538 Ok(Some(crate::model::string_or_float::deserialize(
1539 deserializer,
1540 )?))
1541 }
1542}
1543
1544pub(crate) mod string_or_bool {
1545 use std::fmt;
1546
1547 use serde::{de, Serializer, Deserialize, Deserializer};
1548
1549 pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
1550 where
1551 T: fmt::Display,
1552 S: Serializer,
1553 {
1554 serializer.collect_str(value)
1555 }
1556
1557 pub fn deserialize<'de, D>(deserializer: D) -> Result<bool, D::Error>
1558 where
1559 D: Deserializer<'de>,
1560 {
1561 #[derive(Deserialize)]
1562 #[serde(untagged)]
1563 enum StringOrFloat {
1564 String(String),
1565 Bool(bool),
1566 }
1567
1568 match StringOrFloat::deserialize(deserializer)? {
1569 StringOrFloat::String(s) => s.parse().map_err(de::Error::custom),
1570 StringOrFloat::Bool(i) => Ok(i),
1571 }
1572 }
1573}
1574
1575#[test]
1576fn test_account_update_event() {
1577 let json = r#"
1578 {
1579 "e": "ACCOUNT_UPDATE",
1580 "E": 1564745798939,
1581 "T": 1564745798938,
1582 "a": {
1583 "m": "ORDER",
1584 "B": [
1585 {
1586 "a": "USDT",
1587 "wb": "122624.12345678",
1588 "cw": "100.12345678",
1589 "bc": "50.12345678"
1590 },
1591 {
1592 "a": "BUSD",
1593 "wb": "1.00000000",
1594 "cw": "0.00000000",
1595 "bc": "-49.12345678"
1596 }
1597 ],
1598 "P": [
1599 {
1600 "s": "BTCUSDT",
1601 "pa": "0",
1602 "ep": "0.00000",
1603 "cr": "200",
1604 "up": "0",
1605 "mt": "isolated",
1606 "iw": "0.00000000",
1607 "ps": "BOTH"
1608 },
1609 {
1610 "s": "BTCUSDT",
1611 "pa": "20",
1612 "ep": "6563.66500",
1613 "cr": "0",
1614 "up": "2850.21200",
1615 "mt": "isolated",
1616 "iw": "13200.70726908",
1617 "ps": "LONG"
1618 },
1619 {
1620 "s": "BTCUSDT",
1621 "pa": "-10",
1622 "ep": "6563.86000",
1623 "cr": "-45.04000000",
1624 "up": "-1423.15600",
1625 "mt": "isolated",
1626 "iw": "6570.42511771",
1627 "ps": "SHORT"
1628 }
1629 ]
1630 }
1631}
1632 "#;
1633
1634 let res = r#"AccountUpdateEvent { event_type: "ACCOUNT_UPDATE", event_time: 1564745798939, data: AccountUpdateDataEvent { reason: "ORDER", balances: [EventBalance { asset: "USDT", wallet_balance: "122624.12345678", cross_wallet_balance: "100.12345678", balance_change: "50.12345678" }, EventBalance { asset: "BUSD", wallet_balance: "1.00000000", cross_wallet_balance: "0.00000000", balance_change: "-49.12345678" }], positions: [EventPosition { symbol: "BTCUSDT", position_amount: "0", entry_price: "0.00000", accumulated_realized: "200", unrealized_pnl: "0", margin_type: "isolated", isolated_wallet: "0.00000000", position_side: "BOTH" }, EventPosition { symbol: "BTCUSDT", position_amount: "20", entry_price: "6563.66500", accumulated_realized: "0", unrealized_pnl: "2850.21200", margin_type: "isolated", isolated_wallet: "13200.70726908", position_side: "LONG" }, EventPosition { symbol: "BTCUSDT", position_amount: "-10", entry_price: "6563.86000", accumulated_realized: "-45.04000000", unrealized_pnl: "-1423.15600", margin_type: "isolated", isolated_wallet: "6570.42511771", position_side: "SHORT" }] } }"#;
1635 let v: AccountUpdateEvent = serde_json::from_str(json).unwrap();
1636 assert_eq!(format!("{:?}", v), res);
1637 }