Skip to main content

binance/
model.rs

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/// Response to a test order (endpoint /api/v3/order/test).
244///
245/// Currently, the API responds {} on a successfull test transaction,
246/// hence this struct has no fields.
247#[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, // Balance Change except PnL and Commission
450}
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, // (Pre-fee) Accumulated Realized
463    #[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/// The Aggregate Trade Streams push trade information that is aggregated for a single taker order.
578///
579/// Stream Name: \<symbol\>@aggTrade
580///
581/// Update Speed: Real-time
582///
583/// <https://github.com/binance/binance-spot-api-docs/blob/master/web-socket-streams.md#aggregate-trade-streams>
584#[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/// The Trade Streams push raw trade information; each trade has a unique buyer and seller.
622///
623/// Stream Name: \<symbol\>@trade
624///
625/// Update Speed: Real-time
626///
627/// <https://github.com/binance/binance-spot-api-docs/blob/master/web-socket-streams.md#trade-streams>
628#[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// https://binance-docs.github.io/apidocs/futures/en/#mark-price-stream
681// https://binance-docs.github.io/apidocs/delivery/en/#mark-price-stream
682#[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// Object({"E": Number(1626118018407), "e": String("forceOrder"), "o": Object({"S": String("SELL"), "T": Number(1626118018404), "X": String("FILLED"), "ap": String("33028.07"), "f": String("IOC"), "l": String("0.010"), "o": String("LIMIT"), "p": String("32896.00"), "q": String("0.010"), "s": String("BTCUSDT"), "z": String("0.010")})})
711// https://binance-docs.github.io/apidocs/futures/en/#liquidation-order-streams
712
713#[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// https://binance-docs.github.io/apidocs/futures/en/#continuous-contract-kline-candlestick-streams
961
962#[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// https://binance-docs.github.io/apidocs/delivery/en/#index-kline-candlestick-streams
982
983#[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// https://binance-docs.github.io/apidocs/delivery/en/#index-kline-candlestick-streams
1170#[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/// Response to the Savings API get all coins request
1255#[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/// Part of the Savings API get all coins response
1282#[derive(Debug, Serialize, Deserialize, Clone)]
1283#[serde(rename_all = "camelCase")]
1284pub struct Network {
1285    pub address_regex: String,
1286    pub coin: String,
1287    /// shown only when "depositEnable" is false.
1288    pub deposit_desc: Option<String>,
1289    pub deposit_enable: bool,
1290    pub is_default: bool,
1291    pub memo_regex: String,
1292    /// min number for balance confirmation
1293    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    /// confirmation number for balance unlock
1299    pub un_lock_confirm: u32,
1300    /// shown only when "withdrawEnable" is false.
1301    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 insert_time: Option<u64>, //commented out for now, because they are not inside the actual response (only the api doc example)
1308    // pub update_time: Option<u64>,
1309    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    /// false if ALL of networks' are false
1318    pub deposit_status: bool,
1319    #[serde(with = "string_or_float")]
1320    pub withdraw_fee: f64,
1321    /// false if ALL of networks' are false
1322    pub withdraw_status: bool,
1323    /// reason
1324    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    //let event =  from_value::<AccountUpdateEvent>(json).unwrap();
1669}