1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::{from_value, Value};
5use crate::errors::{SdkError, 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(|| SdkError::KlineValueMissingError {
1028 name: name.to_string(),
1029 index,
1030 })?
1031 .clone())
1032}
1033
1034impl TryFrom<&Vec<Value>> for KlineSummary {
1035 type Error = SdkError;
1036
1037 fn try_from(row: &Vec<Value>) -> Result<Self> {
1038 Ok(Self {
1039 open_time: from_value(get_value(row, 0, "open_time")?)?,
1040 open: from_value(get_value(row, 1, "open")?)?,
1041 high: from_value(get_value(row, 2, "high")?)?,
1042 low: from_value(get_value(row, 3, "low")?)?,
1043 close: from_value(get_value(row, 4, "close")?)?,
1044 volume: from_value(get_value(row, 5, "volume")?)?,
1045 close_time: from_value(get_value(row, 6, "close_time")?)?,
1046 quote_asset_volume: from_value(get_value(row, 7, "quote_asset_volume")?)?,
1047 number_of_trades: from_value(get_value(row, 8, "number_of_trades")?)?,
1048 taker_buy_base_asset_volume: from_value(get_value(
1049 row,
1050 9,
1051 "taker_buy_base_asset_volume",
1052 )?)?,
1053 taker_buy_quote_asset_volume: from_value(get_value(
1054 row,
1055 10,
1056 "taker_buy_quote_asset_volume",
1057 )?)?,
1058 })
1059 }
1060}
1061
1062#[derive(Debug, Serialize, Deserialize, Clone)]
1063#[serde(rename_all = "camelCase")]
1064pub struct Kline {
1065 #[serde(rename = "t")]
1066 pub open_time: i64,
1067
1068 #[serde(rename = "T")]
1069 pub close_time: i64,
1070
1071 #[serde(rename = "s")]
1072 pub symbol: String,
1073
1074 #[serde(rename = "i")]
1075 pub interval: String,
1076
1077 #[serde(rename = "f")]
1078 pub first_trade_id: i64,
1079
1080 #[serde(rename = "L")]
1081 pub last_trade_id: i64,
1082
1083 #[serde(rename = "o")]
1084 pub open: String,
1085
1086 #[serde(rename = "c")]
1087 pub close: String,
1088
1089 #[serde(rename = "h")]
1090 pub high: String,
1091
1092 #[serde(rename = "l")]
1093 pub low: String,
1094
1095 #[serde(rename = "v")]
1096 pub volume: String,
1097
1098 #[serde(rename = "n")]
1099 pub number_of_trades: i64,
1100
1101 #[serde(rename = "x")]
1102 pub is_final_bar: bool,
1103
1104 #[serde(rename = "q")]
1105 pub quote_asset_volume: String,
1106
1107 #[serde(rename = "V")]
1108 pub taker_buy_base_asset_volume: String,
1109
1110 #[serde(rename = "Q")]
1111 pub taker_buy_quote_asset_volume: String,
1112
1113 #[serde(skip, rename = "B")]
1114 pub ignore_me: String,
1115}
1116
1117#[derive(Debug, Serialize, Deserialize, Clone)]
1118#[serde(rename_all = "camelCase")]
1119pub struct ContinuousKline {
1120 #[serde(rename = "t")]
1121 pub start_time: i64,
1122
1123 #[serde(rename = "T")]
1124 pub end_time: i64,
1125
1126 #[serde(rename = "i")]
1127 pub interval: String,
1128
1129 #[serde(rename = "f")]
1130 pub first_trade_id: i64,
1131
1132 #[serde(rename = "L")]
1133 pub last_trade_id: i64,
1134
1135 #[serde(rename = "o")]
1136 pub open: String,
1137
1138 #[serde(rename = "c")]
1139 pub close: String,
1140
1141 #[serde(rename = "h")]
1142 pub high: String,
1143
1144 #[serde(rename = "l")]
1145 pub low: String,
1146
1147 #[serde(rename = "v")]
1148 pub volume: String,
1149
1150 #[serde(rename = "n")]
1151 pub number_of_trades: i64,
1152
1153 #[serde(rename = "x")]
1154 pub is_final_bar: bool,
1155
1156 #[serde(rename = "q")]
1157 pub quote_volume: String,
1158
1159 #[serde(rename = "V")]
1160 pub active_buy_volume: String,
1161
1162 #[serde(rename = "Q")]
1163 pub active_volume_buy_quote: String,
1164
1165 #[serde(skip, rename = "B")]
1166 pub ignore_me: String,
1167}
1168
1169#[derive(Debug, Serialize, Deserialize, Clone)]
1171#[serde(rename_all = "camelCase")]
1172pub struct IndexKline {
1173 #[serde(rename = "t")]
1174 pub start_time: i64,
1175
1176 #[serde(rename = "T")]
1177 pub end_time: i64,
1178
1179 #[serde(skip, rename = "s")]
1180 pub ignore_me: String,
1181
1182 #[serde(rename = "i")]
1183 pub interval: String,
1184
1185 #[serde(rename = "f")]
1186 pub first_trade_id: i64,
1187
1188 #[serde(rename = "L")]
1189 pub last_trade_id: i64,
1190
1191 #[serde(rename = "o")]
1192 pub open: String,
1193
1194 #[serde(rename = "c")]
1195 pub close: String,
1196
1197 #[serde(rename = "h")]
1198 pub high: String,
1199
1200 #[serde(rename = "l")]
1201 pub low: String,
1202
1203 #[serde(rename = "v")]
1204 pub volume: String,
1205
1206 #[serde(rename = "n")]
1207 pub number_of_trades: i64,
1208
1209 #[serde(rename = "x")]
1210 pub is_final_bar: bool,
1211
1212 #[serde(skip, rename = "q")]
1213 pub ignore_me2: String,
1214
1215 #[serde(skip, rename = "V")]
1216 pub ignore_me3: String,
1217
1218 #[serde(skip, rename = "Q")]
1219 pub ignore_me4: String,
1220
1221 #[serde(skip, rename = "B")]
1222 pub ignore_me5: String,
1223}
1224
1225#[derive(Debug, Serialize, Deserialize, Clone)]
1226#[serde(rename_all = "camelCase")]
1227pub struct DepthOrderBookEvent {
1228 #[serde(rename = "e")]
1229 pub event_type: String,
1230
1231 #[serde(rename = "E")]
1232 pub event_time: u64,
1233
1234 #[serde(rename = "s")]
1235 pub symbol: String,
1236
1237 #[serde(rename = "U")]
1238 pub first_update_id: u64,
1239
1240 #[serde(rename = "u")]
1241 pub final_update_id: u64,
1242
1243 #[serde(rename = "pu")]
1244 #[serde(default)]
1245 pub previous_final_update_id: Option<u64>,
1246
1247 #[serde(rename = "b")]
1248 pub bids: Vec<Bids>,
1249
1250 #[serde(rename = "a")]
1251 pub asks: Vec<Asks>,
1252}
1253
1254#[derive(Debug, Serialize, Deserialize, Clone)]
1256#[serde(rename_all = "camelCase")]
1257pub struct CoinInfo {
1258 pub coin: String,
1259 pub deposit_all_enable: bool,
1260 #[serde(with = "string_or_float")]
1261 pub free: f64,
1262 #[serde(with = "string_or_float")]
1263 pub freeze: f64,
1264 #[serde(with = "string_or_float")]
1265 pub ipoable: f64,
1266 #[serde(with = "string_or_float")]
1267 pub ipoing: f64,
1268 pub is_legal_money: bool,
1269 #[serde(with = "string_or_float")]
1270 pub locked: f64,
1271 pub name: String,
1272 pub network_list: Vec<Network>,
1273 #[serde(with = "string_or_float")]
1274 pub storage: f64,
1275 pub trading: bool,
1276 pub withdraw_all_enable: bool,
1277 #[serde(with = "string_or_float")]
1278 pub withdrawing: f64,
1279}
1280
1281#[derive(Debug, Serialize, Deserialize, Clone)]
1283#[serde(rename_all = "camelCase")]
1284pub struct Network {
1285 pub address_regex: String,
1286 pub coin: String,
1287 pub deposit_desc: Option<String>,
1289 pub deposit_enable: bool,
1290 pub is_default: bool,
1291 pub memo_regex: String,
1292 pub min_confirm: u32,
1294 pub name: String,
1295 pub network: String,
1296 pub reset_address_status: bool,
1297 pub special_tips: Option<String>,
1298 pub un_lock_confirm: u32,
1300 pub withdraw_desc: Option<String>,
1302 pub withdraw_enable: bool,
1303 #[serde(with = "string_or_float")]
1304 pub withdraw_fee: f64,
1305 #[serde(with = "string_or_float")]
1306 pub withdraw_min: f64,
1307 pub withdraw_integer_multiple: Option<String>,
1310}
1311
1312#[derive(Debug, Serialize, Deserialize, Clone)]
1313#[serde(rename_all = "camelCase")]
1314pub struct AssetDetail {
1315 #[serde(with = "string_or_float")]
1316 pub min_withdraw_amount: f64,
1317 pub deposit_status: bool,
1319 #[serde(with = "string_or_float")]
1320 pub withdraw_fee: f64,
1321 pub withdraw_status: bool,
1323 pub deposit_tip: Option<String>,
1325}
1326
1327#[derive(Debug, Serialize, Deserialize, Clone)]
1328pub struct DepositAddress {
1329 pub address: String,
1330 pub coin: String,
1331 pub tag: String,
1332 pub url: String,
1333}
1334
1335#[derive(Debug, Serialize, Deserialize, Clone)]
1336pub struct PaginatedResponse<T> {
1337 #[serde(rename = "rows")]
1338 pub data: Vec<T>,
1339 pub total: usize,
1340}
1341#[derive(Debug, Serialize, Deserialize, Clone)]
1342#[serde(rename_all = "camelCase")]
1343pub struct FlexibleProductInfo {
1344 #[serde(with = "string_or_float")]
1345 pub total_amount: f64,
1346
1347 #[serde(default)]
1348 #[serde(with = "string_or_float_hashmap")]
1349 pub tier_annual_percentage_rate: HashMap<String, f64>,
1350
1351 #[serde(with = "string_or_float")]
1352 pub latest_annual_percentage_rate: f64,
1353
1354 pub asset: String,
1355 pub can_redeem: bool,
1356
1357 #[serde(with = "string_or_float")]
1358 pub collateral_amount: f64,
1359
1360 pub product_id: String,
1361
1362 #[serde(with = "string_or_float")]
1363 pub yesterday_real_time_rewards: f64,
1364
1365 #[serde(with = "string_or_float")]
1366 pub cumulative_bonus_rewards: f64,
1367
1368 #[serde(with = "string_or_float")]
1369 pub cumulative_real_time_rewards: f64,
1370
1371 #[serde(with = "string_or_float")]
1372 pub cumulative_total_rewards: f64,
1373
1374 pub auto_subscribe: bool,
1375
1376 #[serde(default)]
1377 pub yesterday_airdrop_percentage_rate: Option<f64>,
1378
1379 #[serde(default)]
1380 pub air_drop_asset: Option<String>,
1381}
1382#[derive(Debug, Serialize, Deserialize, Clone)]
1383#[serde(rename_all = "camelCase")]
1384pub struct LockedProductInfo {
1385 pub position_id: u64,
1386 pub parent_position_id: Option<u64>,
1387 pub project_id: String,
1388 pub asset: String,
1389
1390 #[serde(with = "string_or_float")]
1391 pub amount: f64,
1392
1393 pub purchase_time: u64,
1394 pub duration: u64,
1395 pub accrual_days: u64,
1396 pub reward_asset: String,
1397
1398 #[serde(with = "string_or_float")]
1399 #[serde(default, rename = "APY")]
1400 pub apy: f64,
1401
1402 #[serde(rename = "rewardAmt", with = "string_or_float")]
1403 pub reward_amt: f64,
1404
1405 #[serde(default)]
1406 pub extra_reward_asset: Option<String>,
1407
1408 #[serde(rename = "extraRewardAPR", with = "string_or_float_opt")]
1409 #[serde(default)]
1410 pub extra_reward_apr: Option<f64>,
1411
1412 #[serde(rename = "estExtraRewardAmt", with = "string_or_float_opt")]
1413 #[serde(default)]
1414 pub est_extra_reward_amt: Option<f64>,
1415
1416 #[serde(default)]
1417 pub boost_reward_asset: Option<String>,
1418
1419 #[serde(rename = "boostApr", with = "string_or_float_opt")]
1420 #[serde(default)]
1421 pub boost_apr: Option<f64>,
1422
1423 #[serde(rename = "totalBoostRewardAmt", with = "string_or_float_opt")]
1424 #[serde(default)]
1425 pub total_boost_reward_amt: Option<f64>,
1426
1427 #[serde(rename = "nextPay", with = "string_or_float_opt")]
1428 #[serde(default)]
1429 pub next_pay: Option<f64>,
1430
1431 #[serde(default)]
1432 pub next_pay_date: Option<u64>,
1433
1434 #[serde(default)]
1435 pub pay_period: Option<u64>,
1436
1437 #[serde(rename = "redeemAmountEarly", with = "string_or_float_opt")]
1438 #[serde(default)]
1439 pub redeem_amount_early: Option<f64>,
1440
1441 #[serde(default)]
1442 pub rewards_end_date: Option<u64>,
1443
1444 #[serde(default)]
1445 pub deliver_date: Option<u64>,
1446
1447 #[serde(default)]
1448 pub redeem_period: Option<u64>,
1449
1450 #[serde(rename = "redeemingAmt", with = "string_or_float_opt")]
1451 #[serde(default)]
1452 pub redeeming_amt: Option<f64>,
1453
1454 #[serde(default)]
1455 pub redeem_to: Option<String>,
1456
1457 #[serde(default)]
1458 pub partial_amt_deliver_date: Option<u64>,
1459
1460 #[serde(default)]
1461 pub can_redeem_early: Option<bool>,
1462
1463 #[serde(default)]
1464 pub can_fast_redemption: Option<bool>,
1465
1466 #[serde(default)]
1467 pub auto_subscribe: Option<bool>,
1468
1469 #[serde(rename = "type")]
1470 pub order_type: String,
1471
1472 pub status: String,
1473
1474 #[serde(default)]
1475 pub can_re_stake: Option<bool>,
1476}
1477
1478pub(crate) mod string_or_float {
1479 use std::fmt;
1480
1481 use serde::{de, Serializer, Deserialize, Deserializer};
1482
1483 pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
1484 where
1485 T: fmt::Display,
1486 S: Serializer,
1487 {
1488 serializer.collect_str(value)
1489 }
1490
1491 pub fn deserialize<'de, D>(deserializer: D) -> Result<f64, D::Error>
1492 where
1493 D: Deserializer<'de>,
1494 {
1495 #[derive(Deserialize)]
1496 #[serde(untagged)]
1497 enum StringOrFloat {
1498 String(String),
1499 Float(f64),
1500 }
1501
1502 match StringOrFloat::deserialize(deserializer)? {
1503 StringOrFloat::String(s) => {
1504 if s == "INF" {
1505 Ok(f64::INFINITY)
1506 } else {
1507 s.parse().map_err(de::Error::custom)
1508 }
1509 }
1510 StringOrFloat::Float(i) => Ok(i),
1511 }
1512 }
1513}
1514
1515pub(crate) mod string_or_float_opt {
1516 use std::fmt;
1517
1518 use serde::{Serializer, Deserialize, Deserializer};
1519
1520 pub fn serialize<T, S>(value: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
1521 where
1522 T: fmt::Display,
1523 S: Serializer,
1524 {
1525 match value {
1526 Some(v) => crate::model::string_or_float::serialize(v, serializer),
1527 None => serializer.serialize_none(),
1528 }
1529 }
1530
1531 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
1532 where
1533 D: Deserializer<'de>,
1534 {
1535 #[allow(dead_code)]
1536 #[derive(Deserialize)]
1537 #[serde(untagged)]
1538 enum StringOrFloat {
1539 String(String),
1540 Float(f64),
1541 }
1542
1543 Ok(Some(crate::model::string_or_float::deserialize(
1544 deserializer,
1545 )?))
1546 }
1547}
1548
1549pub(crate) mod string_or_bool {
1550 use std::fmt;
1551
1552 use serde::{de, Serializer, Deserialize, Deserializer};
1553
1554 pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
1555 where
1556 T: fmt::Display,
1557 S: Serializer,
1558 {
1559 serializer.collect_str(value)
1560 }
1561
1562 pub fn deserialize<'de, D>(deserializer: D) -> Result<bool, D::Error>
1563 where
1564 D: Deserializer<'de>,
1565 {
1566 #[derive(Deserialize)]
1567 #[serde(untagged)]
1568 enum StringOrFloat {
1569 String(String),
1570 Bool(bool),
1571 }
1572
1573 match StringOrFloat::deserialize(deserializer)? {
1574 StringOrFloat::String(s) => s.parse().map_err(de::Error::custom),
1575 StringOrFloat::Bool(i) => Ok(i),
1576 }
1577 }
1578}
1579
1580pub(crate) mod string_or_float_hashmap {
1581 use std::collections::HashMap;
1582 use serde::{Serialize, Deserialize, Serializer, Deserializer};
1583 use super::string_or_float;
1584
1585 #[derive(Serialize, Deserialize)]
1586 struct Helper(#[serde(with = "string_or_float")] f64);
1587
1588 pub fn serialize<S>(map: &HashMap<String, f64>, serializer: S) -> Result<S::Ok, S::Error>
1589 where
1590 S: Serializer,
1591 {
1592 let helper_map: HashMap<String, Helper> =
1593 map.iter().map(|(k, v)| (k.clone(), Helper(*v))).collect();
1594 helper_map.serialize(serializer)
1595 }
1596
1597 pub fn deserialize<'de, D>(deserializer: D) -> Result<HashMap<String, f64>, D::Error>
1598 where
1599 D: Deserializer<'de>,
1600 {
1601 let map: HashMap<String, Helper> = HashMap::deserialize(deserializer)?;
1602 Ok(map.into_iter().map(|(k, Helper(v))| (k, v)).collect())
1603 }
1604}
1605
1606#[test]
1607fn test_account_update_event() {
1608 let json = r#"
1609 {
1610 "e": "ACCOUNT_UPDATE",
1611 "E": 1564745798939,
1612 "T": 1564745798938,
1613 "a": {
1614 "m": "ORDER",
1615 "B": [
1616 {
1617 "a": "USDT",
1618 "wb": "122624.12345678",
1619 "cw": "100.12345678",
1620 "bc": "50.12345678"
1621 },
1622 {
1623 "a": "BUSD",
1624 "wb": "1.00000000",
1625 "cw": "0.00000000",
1626 "bc": "-49.12345678"
1627 }
1628 ],
1629 "P": [
1630 {
1631 "s": "BTCUSDT",
1632 "pa": "0",
1633 "ep": "0.00000",
1634 "cr": "200",
1635 "up": "0",
1636 "mt": "isolated",
1637 "iw": "0.00000000",
1638 "ps": "BOTH"
1639 },
1640 {
1641 "s": "BTCUSDT",
1642 "pa": "20",
1643 "ep": "6563.66500",
1644 "cr": "0",
1645 "up": "2850.21200",
1646 "mt": "isolated",
1647 "iw": "13200.70726908",
1648 "ps": "LONG"
1649 },
1650 {
1651 "s": "BTCUSDT",
1652 "pa": "-10",
1653 "ep": "6563.86000",
1654 "cr": "-45.04000000",
1655 "up": "-1423.15600",
1656 "mt": "isolated",
1657 "iw": "6570.42511771",
1658 "ps": "SHORT"
1659 }
1660 ]
1661 }
1662}
1663 "#;
1664
1665 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" }] } }"#;
1666 let v: AccountUpdateEvent = serde_json::from_str(json).unwrap();
1667 assert_eq!(format!("{:?}", v), res);
1668 }