1use nautilus_core::serialization::{
24 deserialize_decimal_from_str, deserialize_optional_decimal_from_str,
25};
26use nautilus_model::identifiers::{
27 ClientOrderId, InstrumentId, StrategyId, TraderId, VenueOrderId,
28};
29use nautilus_network::websocket::WebSocketClient;
30use rust_decimal::Decimal;
31use serde::{Deserialize, Serialize};
32use ustr::Ustr;
33
34use crate::{
35 common::enums::{
36 BinanceAlgoStatus, BinanceAlgoType, BinanceFuturesOrderType, BinanceKlineInterval,
37 BinanceMarginType, BinanceOrderStatus, BinancePositionSide, BinancePriceMatch,
38 BinanceSelfTradePreventionMode, BinanceSide, BinanceTimeInForce, BinanceWorkingType,
39 BinanceWsMethod,
40 },
41 futures::http::BinanceFuturesInstrument,
42};
43
44#[derive(Debug, Clone)]
50pub enum BinanceFuturesWsStreamsMessage {
51 AggTrade(BinanceFuturesAggTradeMsg),
53 Trade(BinanceFuturesTradeMsg),
55 BookTicker(BinanceFuturesBookTickerMsg),
57 DepthUpdate(BinanceFuturesDepthUpdateMsg),
59 MarkPrice(BinanceFuturesMarkPriceMsg),
61 Kline(BinanceFuturesKlineMsg),
63 ForceOrder(BinanceFuturesLiquidationMsg),
65 Ticker(BinanceFuturesTickerMsg),
67 AccountUpdate(BinanceFuturesAccountUpdateMsg),
69 OrderUpdate(Box<BinanceFuturesOrderUpdateMsg>),
71 TradeLite(Box<BinanceFuturesTradeLiteMsg>),
73 AlgoUpdate(Box<BinanceFuturesAlgoUpdateMsg>),
75 MarginCall(BinanceFuturesMarginCallMsg),
77 AccountConfigUpdate(BinanceFuturesAccountConfigMsg),
79 ListenKeyExpired,
81 Error(BinanceFuturesWsErrorMsg),
83 Reconnected,
85}
86
87#[derive(Debug, Clone)]
89pub struct BinanceFuturesWsErrorMsg {
90 pub code: i64,
92 pub msg: String,
94}
95
96#[derive(Debug)]
98pub enum BinanceFuturesWsStreamsCommand {
99 SetClient(WebSocketClient),
101 Disconnect,
103 Subscribe { streams: Vec<String> },
105 Unsubscribe { streams: Vec<String> },
107}
108
109#[derive(Debug)]
111#[expect(
112 clippy::large_enum_variant,
113 reason = "Commands are ephemeral and immediately consumed"
114)]
115pub enum ExecHandlerCommand {
116 SetClient(WebSocketClient),
118 Disconnect,
120 InitializeInstruments(Vec<BinanceFuturesInstrument>),
122 UpdateInstrument(BinanceFuturesInstrument),
124 Subscribe { streams: Vec<String> },
126 RegisterOrder {
128 client_order_id: ClientOrderId,
129 trader_id: TraderId,
130 strategy_id: StrategyId,
131 instrument_id: InstrumentId,
132 },
133 RegisterCancel {
135 client_order_id: ClientOrderId,
136 trader_id: TraderId,
137 strategy_id: StrategyId,
138 instrument_id: InstrumentId,
139 venue_order_id: Option<VenueOrderId>,
140 },
141 RegisterModify {
143 client_order_id: ClientOrderId,
144 trader_id: TraderId,
145 strategy_id: StrategyId,
146 instrument_id: InstrumentId,
147 venue_order_id: Option<VenueOrderId>,
148 },
149}
150
151#[derive(Debug, Clone, Deserialize)]
153pub struct BinanceFuturesAggTradeMsg {
154 #[serde(rename = "e")]
156 pub event_type: String,
157 #[serde(rename = "E")]
159 pub event_time: i64,
160 #[serde(rename = "s")]
162 pub symbol: Ustr,
163 #[serde(rename = "a")]
165 pub agg_trade_id: u64,
166 #[serde(rename = "p")]
168 pub price: String,
169 #[serde(rename = "q")]
171 pub quantity: String,
172 #[serde(rename = "f")]
174 pub first_trade_id: u64,
175 #[serde(rename = "l")]
177 pub last_trade_id: u64,
178 #[serde(rename = "T")]
180 pub trade_time: i64,
181 #[serde(rename = "m")]
183 pub is_buyer_maker: bool,
184}
185
186#[derive(Debug, Clone, Deserialize)]
188pub struct BinanceFuturesTradeMsg {
189 #[serde(rename = "e")]
191 pub event_type: String,
192 #[serde(rename = "E")]
194 pub event_time: i64,
195 #[serde(rename = "s")]
197 pub symbol: Ustr,
198 #[serde(rename = "t")]
200 pub trade_id: u64,
201 #[serde(rename = "p")]
203 pub price: String,
204 #[serde(rename = "q")]
206 pub quantity: String,
207 #[serde(rename = "T")]
209 pub trade_time: i64,
210 #[serde(rename = "m")]
212 pub is_buyer_maker: bool,
213}
214
215#[derive(Debug, Clone, Deserialize)]
217pub struct BinanceFuturesDepthUpdateMsg {
218 #[serde(rename = "e")]
220 pub event_type: String,
221 #[serde(rename = "E")]
223 pub event_time: i64,
224 #[serde(rename = "T")]
226 pub transaction_time: i64,
227 #[serde(rename = "s")]
229 pub symbol: Ustr,
230 #[serde(rename = "U")]
232 pub first_update_id: u64,
233 #[serde(rename = "u")]
235 pub final_update_id: u64,
236 #[serde(rename = "pu")]
238 pub prev_final_update_id: u64,
239 #[serde(rename = "b")]
241 pub bids: Vec<[String; 2]>,
242 #[serde(rename = "a")]
244 pub asks: Vec<[String; 2]>,
245}
246
247#[derive(Debug, Clone, Deserialize)]
249pub struct BinanceFuturesMarkPriceMsg {
250 #[serde(rename = "e")]
252 pub event_type: String,
253 #[serde(rename = "E")]
255 pub event_time: i64,
256 #[serde(rename = "s")]
258 pub symbol: Ustr,
259 #[serde(rename = "p")]
261 pub mark_price: String,
262 #[serde(rename = "ap", default)]
264 pub mark_price_moving_avg: Option<String>,
265 #[serde(rename = "i")]
267 pub index_price: String,
268 #[serde(rename = "P")]
270 pub estimated_settle_price: String,
271 #[serde(rename = "r")]
273 pub funding_rate: String,
274 #[serde(rename = "T")]
276 pub next_funding_time: i64,
277}
278
279#[derive(Debug, Clone, Deserialize)]
281pub struct BinanceFuturesBookTickerMsg {
282 #[serde(rename = "e")]
284 pub event_type: String,
285 #[serde(rename = "u")]
287 pub update_id: u64,
288 #[serde(rename = "E")]
290 pub event_time: i64,
291 #[serde(rename = "T")]
293 pub transaction_time: i64,
294 #[serde(rename = "s")]
296 pub symbol: Ustr,
297 #[serde(rename = "b")]
299 pub best_bid_price: String,
300 #[serde(rename = "B")]
302 pub best_bid_qty: String,
303 #[serde(rename = "a")]
305 pub best_ask_price: String,
306 #[serde(rename = "A")]
308 pub best_ask_qty: String,
309}
310
311#[derive(Debug, Clone, Deserialize)]
313pub struct BinanceFuturesKlineMsg {
314 #[serde(rename = "e")]
316 pub event_type: String,
317 #[serde(rename = "E")]
319 pub event_time: i64,
320 #[serde(rename = "s")]
322 pub symbol: Ustr,
323 #[serde(rename = "k")]
325 pub kline: BinanceFuturesKlineData,
326}
327
328#[derive(Debug, Clone, Deserialize)]
330pub struct BinanceFuturesKlineData {
331 #[serde(rename = "t")]
333 pub start_time: i64,
334 #[serde(rename = "T")]
336 pub close_time: i64,
337 #[serde(rename = "s")]
339 pub symbol: Ustr,
340 #[serde(rename = "i")]
342 pub interval: BinanceKlineInterval,
343 #[serde(rename = "f")]
345 pub first_trade_id: i64,
346 #[serde(rename = "L")]
348 pub last_trade_id: i64,
349 #[serde(rename = "o")]
351 pub open: String,
352 #[serde(rename = "c")]
354 pub close: String,
355 #[serde(rename = "h")]
357 pub high: String,
358 #[serde(rename = "l")]
360 pub low: String,
361 #[serde(rename = "v")]
363 pub volume: String,
364 #[serde(rename = "n")]
366 pub num_trades: i64,
367 #[serde(rename = "x")]
369 pub is_closed: bool,
370 #[serde(rename = "q")]
372 pub quote_volume: String,
373 #[serde(rename = "V")]
375 pub taker_buy_volume: String,
376 #[serde(rename = "Q")]
378 pub taker_buy_quote_volume: String,
379}
380
381#[derive(Debug, Clone, Deserialize)]
383pub struct BinanceFuturesLiquidationMsg {
384 #[serde(rename = "e")]
386 pub event_type: String,
387 #[serde(rename = "E")]
389 pub event_time: i64,
390 #[serde(rename = "o")]
392 pub order: BinanceFuturesLiquidationOrder,
393}
394
395#[derive(Debug, Clone, Deserialize)]
397pub struct BinanceFuturesLiquidationOrder {
398 #[serde(rename = "s")]
400 pub symbol: Ustr,
401 #[serde(rename = "S")]
403 pub side: BinanceSide,
404 #[serde(rename = "o")]
406 pub order_type: BinanceFuturesOrderType,
407 #[serde(rename = "f")]
409 pub time_in_force: BinanceTimeInForce,
410 #[serde(rename = "q")]
412 pub original_qty: String,
413 #[serde(rename = "p")]
415 pub price: String,
416 #[serde(rename = "ap")]
418 pub average_price: String,
419 #[serde(rename = "X")]
421 pub status: BinanceOrderStatus,
422 #[serde(rename = "l")]
424 pub last_filled_qty: String,
425 #[serde(rename = "z")]
427 pub accumulated_qty: String,
428 #[serde(rename = "T")]
430 pub trade_time: i64,
431}
432
433#[derive(Debug, Clone, Deserialize)]
435pub struct BinanceFuturesTickerMsg {
436 #[serde(rename = "e")]
438 pub event_type: String,
439 #[serde(rename = "E")]
441 pub event_time: i64,
442 #[serde(rename = "s")]
444 pub symbol: Ustr,
445 #[serde(rename = "p")]
447 pub price_change: String,
448 #[serde(rename = "P")]
450 pub price_change_percent: String,
451 #[serde(rename = "w")]
453 pub weighted_avg_price: String,
454 #[serde(rename = "c")]
456 pub last_price: String,
457 #[serde(rename = "Q")]
459 pub last_qty: String,
460 #[serde(rename = "o")]
462 pub open_price: String,
463 #[serde(rename = "h")]
465 pub high_price: String,
466 #[serde(rename = "l")]
468 pub low_price: String,
469 #[serde(rename = "v")]
471 pub volume: String,
472 #[serde(rename = "q")]
474 pub quote_volume: String,
475 #[serde(rename = "O")]
477 pub open_time: i64,
478 #[serde(rename = "C")]
480 pub close_time: i64,
481 #[serde(rename = "F")]
483 pub first_trade_id: i64,
484 #[serde(rename = "L")]
486 pub last_trade_id: i64,
487 #[serde(rename = "n")]
489 pub num_trades: i64,
490}
491
492#[derive(Debug, Clone, Serialize)]
494pub struct BinanceFuturesWsSubscribeRequest {
495 pub method: BinanceWsMethod,
497 pub params: Vec<String>,
499 pub id: u64,
501}
502
503#[derive(Debug, Clone, Deserialize)]
505pub struct BinanceFuturesWsSubscribeResponse {
506 pub result: Option<serde_json::Value>,
508 pub id: u64,
510}
511
512#[derive(Debug, Clone, Deserialize)]
514pub struct BinanceFuturesWsErrorResponse {
515 pub code: i64,
517 pub msg: String,
519 pub id: Option<u64>,
521}
522
523#[derive(Debug, Clone, Deserialize)]
525pub struct BinanceFuturesAccountUpdateMsg {
526 #[serde(rename = "e")]
528 pub event_type: String,
529 #[serde(rename = "E")]
531 pub event_time: i64,
532 #[serde(rename = "T")]
534 pub transaction_time: i64,
535 #[serde(rename = "a")]
537 pub account: AccountUpdateData,
538}
539
540#[derive(Debug, Clone, Deserialize)]
542pub struct AccountUpdateData {
543 #[serde(rename = "m")]
545 pub reason: AccountUpdateReason,
546 #[serde(rename = "B", default)]
548 pub balances: Vec<BalanceUpdate>,
549 #[serde(rename = "P", default)]
551 pub positions: Vec<PositionUpdate>,
552}
553
554#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
556#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
557pub enum AccountUpdateReason {
558 Deposit,
559 Withdraw,
560 Order,
561 FundingFee,
562 WithdrawReject,
563 Adjustment,
564 InsuranceClear,
565 AdminDeposit,
566 AdminWithdraw,
567 MarginTransfer,
568 MarginTypeChange,
569 AssetTransfer,
570 OptionsPremiumFee,
571 OptionsSettleProfit,
572 AutoExchange,
573 Adl,
574 CoinSwapDeposit,
575 CoinSwapWithdraw,
576 #[serde(other)]
577 Unknown,
578}
579
580#[derive(Debug, Clone, Deserialize)]
582pub struct BalanceUpdate {
583 #[serde(rename = "a")]
585 pub asset: Ustr,
586 #[serde(rename = "wb", deserialize_with = "deserialize_decimal_from_str")]
588 pub wallet_balance: Decimal,
589 #[serde(rename = "cw", deserialize_with = "deserialize_decimal_from_str")]
591 pub cross_wallet_balance: Decimal,
592 #[serde(
594 rename = "bc",
595 default,
596 deserialize_with = "deserialize_optional_decimal_from_str"
597 )]
598 pub balance_change: Option<Decimal>,
599}
600
601#[derive(Debug, Clone, Deserialize)]
603pub struct PositionUpdate {
604 #[serde(rename = "s")]
606 pub symbol: Ustr,
607 #[serde(rename = "pa")]
609 pub position_amount: String,
610 #[serde(rename = "ep")]
612 pub entry_price: String,
613 #[serde(rename = "bep", default)]
615 pub break_even_price: Option<String>,
616 #[serde(rename = "cr")]
618 pub accumulated_realized: String,
619 #[serde(rename = "up")]
621 pub unrealized_pnl: String,
622 #[serde(rename = "mt")]
624 pub margin_type: BinanceMarginType,
625 #[serde(rename = "iw")]
627 pub isolated_wallet: String,
628 #[serde(rename = "ps")]
630 pub position_side: BinancePositionSide,
631}
632
633#[derive(Debug, Clone, Deserialize)]
635pub struct BinanceFuturesOrderUpdateMsg {
636 #[serde(rename = "e")]
638 pub event_type: String,
639 #[serde(rename = "E")]
641 pub event_time: i64,
642 #[serde(rename = "T")]
644 pub transaction_time: i64,
645 #[serde(rename = "o")]
647 pub order: OrderUpdateData,
648}
649
650#[derive(Debug, Clone, Deserialize)]
652pub struct OrderUpdateData {
653 #[serde(rename = "s")]
655 pub symbol: Ustr,
656 #[serde(rename = "c")]
658 pub client_order_id: String,
659 #[serde(rename = "S")]
661 pub side: BinanceSide,
662 #[serde(rename = "o")]
664 pub order_type: BinanceFuturesOrderType,
665 #[serde(rename = "f")]
667 pub time_in_force: BinanceTimeInForce,
668 #[serde(rename = "q")]
670 pub original_qty: String,
671 #[serde(rename = "p")]
673 pub original_price: String,
674 #[serde(rename = "ap")]
676 pub average_price: String,
677 #[serde(rename = "sp")]
679 pub stop_price: String,
680 #[serde(rename = "x")]
682 pub execution_type: BinanceExecutionType,
683 #[serde(rename = "X")]
685 pub order_status: BinanceOrderStatus,
686 #[serde(rename = "i")]
688 pub order_id: i64,
689 #[serde(rename = "l")]
691 pub last_filled_qty: String,
692 #[serde(rename = "z")]
694 pub cumulative_filled_qty: String,
695 #[serde(rename = "L")]
697 pub last_filled_price: String,
698 #[serde(rename = "N", default)]
700 pub commission_asset: Option<Ustr>,
701 #[serde(rename = "n", default)]
703 pub commission: Option<String>,
704 #[serde(rename = "T")]
706 pub trade_time: i64,
707 #[serde(rename = "t")]
709 pub trade_id: i64,
710 #[serde(rename = "b", default)]
712 pub bids_notional: Option<String>,
713 #[serde(rename = "a", default)]
715 pub asks_notional: Option<String>,
716 #[serde(rename = "m")]
718 pub is_maker: bool,
719 #[serde(rename = "R")]
721 pub is_reduce_only: bool,
722 #[serde(rename = "wt")]
724 pub working_type: BinanceWorkingType,
725 #[serde(rename = "ot")]
727 pub original_order_type: BinanceFuturesOrderType,
728 #[serde(rename = "ps")]
730 pub position_side: BinancePositionSide,
731 #[serde(rename = "cp", default)]
733 pub close_position: Option<bool>,
734 #[serde(rename = "AP", default)]
736 pub activation_price: Option<String>,
737 #[serde(rename = "cr", default)]
739 pub callback_rate: Option<String>,
740 #[serde(rename = "pP", default)]
742 pub price_protect: Option<bool>,
743 #[serde(rename = "rp")]
745 pub realized_profit: String,
746 #[serde(rename = "V", default)]
748 pub stp_mode: Option<BinanceSelfTradePreventionMode>,
749 #[serde(rename = "pm", default)]
751 pub price_match: Option<BinancePriceMatch>,
752 #[serde(rename = "gtd", default)]
754 pub good_till_date: Option<i64>,
755}
756
757impl OrderUpdateData {
758 #[must_use]
760 pub fn is_liquidation(&self) -> bool {
761 self.client_order_id.starts_with("autoclose-")
762 }
763
764 #[must_use]
766 pub fn is_adl(&self) -> bool {
767 self.client_order_id.starts_with("adl_autoclose")
768 }
769
770 #[must_use]
776 pub fn is_settlement(&self) -> bool {
777 self.client_order_id.starts_with("settlement_autoclose-")
778 || self.client_order_id.starts_with("delivery_autoclose-")
779 }
780
781 #[must_use]
783 pub fn is_exchange_generated(&self) -> bool {
784 self.is_liquidation() || self.is_adl() || self.is_settlement()
785 }
786}
787
788#[derive(Debug, Clone, Deserialize)]
795pub struct BinanceFuturesTradeLiteMsg {
796 #[serde(rename = "e")]
798 pub event_type: String,
799 #[serde(rename = "E")]
801 pub event_time: i64,
802 #[serde(rename = "T")]
804 pub transaction_time: i64,
805 #[serde(rename = "s")]
807 pub symbol: Ustr,
808 #[serde(rename = "c")]
810 pub client_order_id: String,
811 #[serde(rename = "S")]
813 pub side: BinanceSide,
814 #[serde(rename = "q")]
816 pub original_qty: String,
817 #[serde(rename = "p")]
819 pub original_price: String,
820 #[serde(rename = "i")]
822 pub order_id: i64,
823 #[serde(rename = "l")]
825 pub last_filled_qty: String,
826 #[serde(rename = "L")]
828 pub last_filled_price: String,
829 #[serde(rename = "t")]
831 pub trade_id: i64,
832 #[serde(rename = "m")]
834 pub is_maker: bool,
835}
836
837#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
839#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
840pub enum BinanceExecutionType {
841 New,
843 Canceled,
845 Calculated,
847 Expired,
849 Trade,
851 Amendment,
853}
854
855#[derive(Debug, Clone, Deserialize)]
857pub struct BinanceFuturesMarginCallMsg {
858 #[serde(rename = "e")]
860 pub event_type: String,
861 #[serde(rename = "E")]
863 pub event_time: i64,
864 #[serde(rename = "cw")]
866 pub cross_wallet_balance: String,
867 #[serde(rename = "p")]
869 pub positions: Vec<MarginCallPosition>,
870}
871
872#[derive(Debug, Clone, Deserialize)]
874pub struct MarginCallPosition {
875 #[serde(rename = "s")]
877 pub symbol: Ustr,
878 #[serde(rename = "ps")]
880 pub position_side: BinancePositionSide,
881 #[serde(rename = "pa")]
883 pub position_amount: String,
884 #[serde(rename = "mt")]
886 pub margin_type: BinanceMarginType,
887 #[serde(rename = "iw")]
889 pub isolated_wallet: String,
890 #[serde(rename = "mp")]
892 pub mark_price: String,
893 #[serde(rename = "up")]
895 pub unrealized_pnl: String,
896 #[serde(rename = "mm")]
898 pub maintenance_margin: String,
899}
900
901#[derive(Debug, Clone, Deserialize)]
903pub struct BinanceFuturesAccountConfigMsg {
904 #[serde(rename = "e")]
906 pub event_type: String,
907 #[serde(rename = "E")]
909 pub event_time: i64,
910 #[serde(rename = "T")]
912 pub transaction_time: i64,
913 #[serde(rename = "ac", default)]
915 pub leverage_config: Option<LeverageConfig>,
916 #[serde(rename = "ai", default)]
918 pub asset_index: Option<AssetIndexConfig>,
919}
920
921#[derive(Debug, Clone, Deserialize)]
923pub struct LeverageConfig {
924 #[serde(rename = "s")]
926 pub symbol: Ustr,
927 #[serde(rename = "l")]
929 pub leverage: u32,
930}
931
932#[derive(Debug, Clone, Deserialize)]
934pub struct AssetIndexConfig {
935 #[serde(rename = "s")]
937 pub symbol: Ustr,
938}
939
940#[derive(Debug, Clone, Deserialize)]
950pub struct BinanceFuturesAlgoUpdateMsg {
951 #[serde(rename = "e")]
953 pub event_type: String,
954 #[serde(rename = "E")]
956 pub event_time: i64,
957 #[serde(rename = "T")]
959 pub transaction_time: i64,
960 #[serde(rename = "o", alias = "ao")]
962 pub algo_order: AlgoOrderUpdateData,
963}
964
965#[derive(Debug, Clone, Deserialize)]
967pub struct AlgoOrderUpdateData {
968 #[serde(rename = "caid")]
970 pub client_algo_id: String,
971 #[serde(rename = "aid")]
973 pub algo_id: i64,
974 #[serde(rename = "at")]
976 pub algo_type: BinanceAlgoType,
977 #[serde(rename = "o")]
979 pub order_type: BinanceFuturesOrderType,
980 #[serde(rename = "s")]
982 pub symbol: Ustr,
983 #[serde(rename = "S")]
985 pub side: BinanceSide,
986 #[serde(rename = "ps")]
988 pub position_side: BinancePositionSide,
989 #[serde(rename = "f")]
991 pub time_in_force: BinanceTimeInForce,
992 #[serde(rename = "q")]
994 pub quantity: String,
995 #[serde(rename = "X")]
997 pub algo_status: BinanceAlgoStatus,
998 #[serde(rename = "tp")]
1000 pub trigger_price: String,
1001 #[serde(rename = "p")]
1003 pub price: String,
1004 #[serde(rename = "wt")]
1006 pub working_type: BinanceWorkingType,
1007 #[serde(rename = "pm", default)]
1009 pub price_match: Option<BinancePriceMatch>,
1010 #[serde(rename = "cp", default)]
1012 pub close_position: Option<bool>,
1013 #[serde(rename = "pP", default)]
1015 pub price_protect: Option<bool>,
1016 #[serde(rename = "R", default)]
1018 pub reduce_only: Option<bool>,
1019 #[serde(rename = "tt", default)]
1021 pub trigger_time: Option<i64>,
1022 #[serde(rename = "gtd", default)]
1024 pub good_till_date: Option<i64>,
1025 #[serde(rename = "ai", default)]
1027 pub actual_order_id: Option<String>,
1028 #[serde(rename = "ap", default)]
1030 pub avg_price: Option<String>,
1031 #[serde(rename = "aq", default)]
1033 pub executed_qty: Option<String>,
1034 #[serde(rename = "act", default)]
1036 pub actual_order_type: Option<String>,
1037 #[serde(rename = "cr", default)]
1039 pub callback_rate: Option<String>,
1040 #[serde(rename = "V", default)]
1042 pub stp_mode: Option<BinanceSelfTradePreventionMode>,
1043}
1044
1045#[derive(Debug, Clone, Deserialize)]
1047pub struct BinanceFuturesListenKeyExpiredMsg {
1048 #[serde(rename = "e")]
1050 pub event_type: String,
1051 #[serde(rename = "E")]
1053 pub event_time: i64,
1054}
1055
1056#[cfg(test)]
1057mod tests {
1058 use rstest::rstest;
1059
1060 use super::*;
1061
1062 #[rstest]
1063 fn test_account_update_reason_adl_deserializes() {
1064 let value: AccountUpdateReason = serde_json::from_str("\"ADL\"").unwrap();
1065 assert_eq!(value, AccountUpdateReason::Adl);
1066 }
1067
1068 #[rstest]
1069 fn test_account_update_reason_unknown_fallback() {
1070 let value: AccountUpdateReason = serde_json::from_str("\"SOMETHING_NEW\"").unwrap();
1071 assert_eq!(value, AccountUpdateReason::Unknown);
1072 }
1073}