binance/
model.rs

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/// 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(|| 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// https://binance-docs.github.io/apidocs/delivery/en/#index-kline-candlestick-streams
1167#[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/// Response to the Savings API get all coins request
1252#[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/// Part of the Savings API get all coins response
1279#[derive(Debug, Serialize, Deserialize, Clone)]
1280#[serde(rename_all = "camelCase")]
1281pub struct Network {
1282    pub address_regex: String,
1283    pub coin: String,
1284    /// shown only when "depositEnable" is false.
1285    pub deposit_desc: Option<String>,
1286    pub deposit_enable: bool,
1287    pub is_default: bool,
1288    pub memo_regex: String,
1289    /// min number for balance confirmation
1290    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    /// confirmation number for balance unlock
1296    pub un_lock_confirm: u32,
1297    /// shown only when "withdrawEnable" is false.
1298    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 insert_time: Option<u64>, //commented out for now, because they are not inside the actual response (only the api doc example)
1305    // pub update_time: Option<u64>,
1306    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    /// false if ALL of networks' are false
1315    pub deposit_status: bool,
1316    #[serde(with = "string_or_float")]
1317    pub withdraw_fee: f64,
1318    /// false if ALL of networks' are false
1319    pub withdraw_status: bool,
1320    /// reason
1321    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    //let event =  from_value::<AccountUpdateEvent>(json).unwrap();
1638}