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 = "i")]
264 pub index_price: String,
265 #[serde(rename = "P")]
267 pub estimated_settle_price: String,
268 #[serde(rename = "r")]
270 pub funding_rate: String,
271 #[serde(rename = "T")]
273 pub next_funding_time: i64,
274}
275
276#[derive(Debug, Clone, Deserialize)]
278pub struct BinanceFuturesBookTickerMsg {
279 #[serde(rename = "e")]
281 pub event_type: String,
282 #[serde(rename = "u")]
284 pub update_id: u64,
285 #[serde(rename = "E")]
287 pub event_time: i64,
288 #[serde(rename = "T")]
290 pub transaction_time: i64,
291 #[serde(rename = "s")]
293 pub symbol: Ustr,
294 #[serde(rename = "b")]
296 pub best_bid_price: String,
297 #[serde(rename = "B")]
299 pub best_bid_qty: String,
300 #[serde(rename = "a")]
302 pub best_ask_price: String,
303 #[serde(rename = "A")]
305 pub best_ask_qty: String,
306}
307
308#[derive(Debug, Clone, Deserialize)]
310pub struct BinanceFuturesKlineMsg {
311 #[serde(rename = "e")]
313 pub event_type: String,
314 #[serde(rename = "E")]
316 pub event_time: i64,
317 #[serde(rename = "s")]
319 pub symbol: Ustr,
320 #[serde(rename = "k")]
322 pub kline: BinanceFuturesKlineData,
323}
324
325#[derive(Debug, Clone, Deserialize)]
327pub struct BinanceFuturesKlineData {
328 #[serde(rename = "t")]
330 pub start_time: i64,
331 #[serde(rename = "T")]
333 pub close_time: i64,
334 #[serde(rename = "s")]
336 pub symbol: Ustr,
337 #[serde(rename = "i")]
339 pub interval: BinanceKlineInterval,
340 #[serde(rename = "f")]
342 pub first_trade_id: i64,
343 #[serde(rename = "L")]
345 pub last_trade_id: i64,
346 #[serde(rename = "o")]
348 pub open: String,
349 #[serde(rename = "c")]
351 pub close: String,
352 #[serde(rename = "h")]
354 pub high: String,
355 #[serde(rename = "l")]
357 pub low: String,
358 #[serde(rename = "v")]
360 pub volume: String,
361 #[serde(rename = "n")]
363 pub num_trades: i64,
364 #[serde(rename = "x")]
366 pub is_closed: bool,
367 #[serde(rename = "q")]
369 pub quote_volume: String,
370 #[serde(rename = "V")]
372 pub taker_buy_volume: String,
373 #[serde(rename = "Q")]
375 pub taker_buy_quote_volume: String,
376}
377
378#[derive(Debug, Clone, Deserialize)]
380pub struct BinanceFuturesLiquidationMsg {
381 #[serde(rename = "e")]
383 pub event_type: String,
384 #[serde(rename = "E")]
386 pub event_time: i64,
387 #[serde(rename = "o")]
389 pub order: BinanceFuturesLiquidationOrder,
390}
391
392#[derive(Debug, Clone, Deserialize)]
394pub struct BinanceFuturesLiquidationOrder {
395 #[serde(rename = "s")]
397 pub symbol: Ustr,
398 #[serde(rename = "S")]
400 pub side: BinanceSide,
401 #[serde(rename = "o")]
403 pub order_type: BinanceFuturesOrderType,
404 #[serde(rename = "f")]
406 pub time_in_force: BinanceTimeInForce,
407 #[serde(rename = "q")]
409 pub original_qty: String,
410 #[serde(rename = "p")]
412 pub price: String,
413 #[serde(rename = "ap")]
415 pub average_price: String,
416 #[serde(rename = "X")]
418 pub status: BinanceOrderStatus,
419 #[serde(rename = "l")]
421 pub last_filled_qty: String,
422 #[serde(rename = "z")]
424 pub accumulated_qty: String,
425 #[serde(rename = "T")]
427 pub trade_time: i64,
428}
429
430#[derive(Debug, Clone, Deserialize)]
432pub struct BinanceFuturesTickerMsg {
433 #[serde(rename = "e")]
435 pub event_type: String,
436 #[serde(rename = "E")]
438 pub event_time: i64,
439 #[serde(rename = "s")]
441 pub symbol: Ustr,
442 #[serde(rename = "p")]
444 pub price_change: String,
445 #[serde(rename = "P")]
447 pub price_change_percent: String,
448 #[serde(rename = "w")]
450 pub weighted_avg_price: String,
451 #[serde(rename = "c")]
453 pub last_price: String,
454 #[serde(rename = "Q")]
456 pub last_qty: String,
457 #[serde(rename = "o")]
459 pub open_price: String,
460 #[serde(rename = "h")]
462 pub high_price: String,
463 #[serde(rename = "l")]
465 pub low_price: String,
466 #[serde(rename = "v")]
468 pub volume: String,
469 #[serde(rename = "q")]
471 pub quote_volume: String,
472 #[serde(rename = "O")]
474 pub open_time: i64,
475 #[serde(rename = "C")]
477 pub close_time: i64,
478 #[serde(rename = "F")]
480 pub first_trade_id: i64,
481 #[serde(rename = "L")]
483 pub last_trade_id: i64,
484 #[serde(rename = "n")]
486 pub num_trades: i64,
487}
488
489#[derive(Debug, Clone, Serialize)]
491pub struct BinanceFuturesWsSubscribeRequest {
492 pub method: BinanceWsMethod,
494 pub params: Vec<String>,
496 pub id: u64,
498}
499
500#[derive(Debug, Clone, Deserialize)]
502pub struct BinanceFuturesWsSubscribeResponse {
503 pub result: Option<serde_json::Value>,
505 pub id: u64,
507}
508
509#[derive(Debug, Clone, Deserialize)]
511pub struct BinanceFuturesWsErrorResponse {
512 pub code: i64,
514 pub msg: String,
516 pub id: Option<u64>,
518}
519
520#[derive(Debug, Clone, Deserialize)]
522pub struct BinanceFuturesAccountUpdateMsg {
523 #[serde(rename = "e")]
525 pub event_type: String,
526 #[serde(rename = "E")]
528 pub event_time: i64,
529 #[serde(rename = "T")]
531 pub transaction_time: i64,
532 #[serde(rename = "a")]
534 pub account: AccountUpdateData,
535}
536
537#[derive(Debug, Clone, Deserialize)]
539pub struct AccountUpdateData {
540 #[serde(rename = "m")]
542 pub reason: AccountUpdateReason,
543 #[serde(rename = "B", default)]
545 pub balances: Vec<BalanceUpdate>,
546 #[serde(rename = "P", default)]
548 pub positions: Vec<PositionUpdate>,
549}
550
551#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
553#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
554pub enum AccountUpdateReason {
555 Deposit,
556 Withdraw,
557 Order,
558 FundingFee,
559 WithdrawReject,
560 Adjustment,
561 InsuranceClear,
562 AdminDeposit,
563 AdminWithdraw,
564 MarginTransfer,
565 MarginTypeChange,
566 AssetTransfer,
567 OptionsPremiumFee,
568 OptionsSettleProfit,
569 AutoExchange,
570 Adl,
571 CoinSwapDeposit,
572 CoinSwapWithdraw,
573 #[serde(other)]
574 Unknown,
575}
576
577#[derive(Debug, Clone, Deserialize)]
579pub struct BalanceUpdate {
580 #[serde(rename = "a")]
582 pub asset: Ustr,
583 #[serde(rename = "wb", deserialize_with = "deserialize_decimal_from_str")]
585 pub wallet_balance: Decimal,
586 #[serde(rename = "cw", deserialize_with = "deserialize_decimal_from_str")]
588 pub cross_wallet_balance: Decimal,
589 #[serde(
591 rename = "bc",
592 default,
593 deserialize_with = "deserialize_optional_decimal_from_str"
594 )]
595 pub balance_change: Option<Decimal>,
596}
597
598#[derive(Debug, Clone, Deserialize)]
600pub struct PositionUpdate {
601 #[serde(rename = "s")]
603 pub symbol: Ustr,
604 #[serde(rename = "pa")]
606 pub position_amount: String,
607 #[serde(rename = "ep")]
609 pub entry_price: String,
610 #[serde(rename = "bep", default)]
612 pub break_even_price: Option<String>,
613 #[serde(rename = "cr")]
615 pub accumulated_realized: String,
616 #[serde(rename = "up")]
618 pub unrealized_pnl: String,
619 #[serde(rename = "mt")]
621 pub margin_type: BinanceMarginType,
622 #[serde(rename = "iw")]
624 pub isolated_wallet: String,
625 #[serde(rename = "ps")]
627 pub position_side: BinancePositionSide,
628}
629
630#[derive(Debug, Clone, Deserialize)]
632pub struct BinanceFuturesOrderUpdateMsg {
633 #[serde(rename = "e")]
635 pub event_type: String,
636 #[serde(rename = "E")]
638 pub event_time: i64,
639 #[serde(rename = "T")]
641 pub transaction_time: i64,
642 #[serde(rename = "o")]
644 pub order: OrderUpdateData,
645}
646
647#[derive(Debug, Clone, Deserialize)]
649pub struct OrderUpdateData {
650 #[serde(rename = "s")]
652 pub symbol: Ustr,
653 #[serde(rename = "c")]
655 pub client_order_id: String,
656 #[serde(rename = "S")]
658 pub side: BinanceSide,
659 #[serde(rename = "o")]
661 pub order_type: BinanceFuturesOrderType,
662 #[serde(rename = "f")]
664 pub time_in_force: BinanceTimeInForce,
665 #[serde(rename = "q")]
667 pub original_qty: String,
668 #[serde(rename = "p")]
670 pub original_price: String,
671 #[serde(rename = "ap")]
673 pub average_price: String,
674 #[serde(rename = "sp")]
676 pub stop_price: String,
677 #[serde(rename = "x")]
679 pub execution_type: BinanceExecutionType,
680 #[serde(rename = "X")]
682 pub order_status: BinanceOrderStatus,
683 #[serde(rename = "i")]
685 pub order_id: i64,
686 #[serde(rename = "l")]
688 pub last_filled_qty: String,
689 #[serde(rename = "z")]
691 pub cumulative_filled_qty: String,
692 #[serde(rename = "L")]
694 pub last_filled_price: String,
695 #[serde(rename = "N", default)]
697 pub commission_asset: Option<Ustr>,
698 #[serde(rename = "n", default)]
700 pub commission: Option<String>,
701 #[serde(rename = "T")]
703 pub trade_time: i64,
704 #[serde(rename = "t")]
706 pub trade_id: i64,
707 #[serde(rename = "b", default)]
709 pub bids_notional: Option<String>,
710 #[serde(rename = "a", default)]
712 pub asks_notional: Option<String>,
713 #[serde(rename = "m")]
715 pub is_maker: bool,
716 #[serde(rename = "R")]
718 pub is_reduce_only: bool,
719 #[serde(rename = "wt")]
721 pub working_type: BinanceWorkingType,
722 #[serde(rename = "ot")]
724 pub original_order_type: BinanceFuturesOrderType,
725 #[serde(rename = "ps")]
727 pub position_side: BinancePositionSide,
728 #[serde(rename = "cp", default)]
730 pub close_position: Option<bool>,
731 #[serde(rename = "AP", default)]
733 pub activation_price: Option<String>,
734 #[serde(rename = "cr", default)]
736 pub callback_rate: Option<String>,
737 #[serde(rename = "pP", default)]
739 pub price_protect: Option<bool>,
740 #[serde(rename = "rp")]
742 pub realized_profit: String,
743 #[serde(rename = "V", default)]
745 pub stp_mode: Option<BinanceSelfTradePreventionMode>,
746 #[serde(rename = "pm", default)]
748 pub price_match: Option<BinancePriceMatch>,
749 #[serde(rename = "gtd", default)]
751 pub good_till_date: Option<i64>,
752}
753
754impl OrderUpdateData {
755 #[must_use]
757 pub fn is_liquidation(&self) -> bool {
758 self.client_order_id.starts_with("autoclose-")
759 }
760
761 #[must_use]
763 pub fn is_adl(&self) -> bool {
764 self.client_order_id.starts_with("adl_autoclose")
765 }
766
767 #[must_use]
773 pub fn is_settlement(&self) -> bool {
774 self.client_order_id.starts_with("settlement_autoclose-")
775 || self.client_order_id.starts_with("delivery_autoclose-")
776 }
777
778 #[must_use]
780 pub fn is_exchange_generated(&self) -> bool {
781 self.is_liquidation() || self.is_adl() || self.is_settlement()
782 }
783}
784
785#[derive(Debug, Clone, Deserialize)]
792pub struct BinanceFuturesTradeLiteMsg {
793 #[serde(rename = "e")]
795 pub event_type: String,
796 #[serde(rename = "E")]
798 pub event_time: i64,
799 #[serde(rename = "T")]
801 pub transaction_time: i64,
802 #[serde(rename = "s")]
804 pub symbol: Ustr,
805 #[serde(rename = "c")]
807 pub client_order_id: String,
808 #[serde(rename = "S")]
810 pub side: BinanceSide,
811 #[serde(rename = "q")]
813 pub original_qty: String,
814 #[serde(rename = "p")]
816 pub original_price: String,
817 #[serde(rename = "i")]
819 pub order_id: i64,
820 #[serde(rename = "l")]
822 pub last_filled_qty: String,
823 #[serde(rename = "L")]
825 pub last_filled_price: String,
826 #[serde(rename = "t")]
828 pub trade_id: i64,
829 #[serde(rename = "m")]
831 pub is_maker: bool,
832}
833
834#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
836#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
837pub enum BinanceExecutionType {
838 New,
840 Canceled,
842 Calculated,
844 Expired,
846 Trade,
848 Amendment,
850}
851
852#[derive(Debug, Clone, Deserialize)]
854pub struct BinanceFuturesMarginCallMsg {
855 #[serde(rename = "e")]
857 pub event_type: String,
858 #[serde(rename = "E")]
860 pub event_time: i64,
861 #[serde(rename = "cw")]
863 pub cross_wallet_balance: String,
864 #[serde(rename = "p")]
866 pub positions: Vec<MarginCallPosition>,
867}
868
869#[derive(Debug, Clone, Deserialize)]
871pub struct MarginCallPosition {
872 #[serde(rename = "s")]
874 pub symbol: Ustr,
875 #[serde(rename = "ps")]
877 pub position_side: BinancePositionSide,
878 #[serde(rename = "pa")]
880 pub position_amount: String,
881 #[serde(rename = "mt")]
883 pub margin_type: BinanceMarginType,
884 #[serde(rename = "iw")]
886 pub isolated_wallet: String,
887 #[serde(rename = "mp")]
889 pub mark_price: String,
890 #[serde(rename = "up")]
892 pub unrealized_pnl: String,
893 #[serde(rename = "mm")]
895 pub maintenance_margin: String,
896}
897
898#[derive(Debug, Clone, Deserialize)]
900pub struct BinanceFuturesAccountConfigMsg {
901 #[serde(rename = "e")]
903 pub event_type: String,
904 #[serde(rename = "E")]
906 pub event_time: i64,
907 #[serde(rename = "T")]
909 pub transaction_time: i64,
910 #[serde(rename = "ac", default)]
912 pub leverage_config: Option<LeverageConfig>,
913 #[serde(rename = "ai", default)]
915 pub asset_index: Option<AssetIndexConfig>,
916}
917
918#[derive(Debug, Clone, Deserialize)]
920pub struct LeverageConfig {
921 #[serde(rename = "s")]
923 pub symbol: Ustr,
924 #[serde(rename = "l")]
926 pub leverage: u32,
927}
928
929#[derive(Debug, Clone, Deserialize)]
931pub struct AssetIndexConfig {
932 #[serde(rename = "s")]
934 pub symbol: Ustr,
935}
936
937#[derive(Debug, Clone, Deserialize)]
947pub struct BinanceFuturesAlgoUpdateMsg {
948 #[serde(rename = "e")]
950 pub event_type: String,
951 #[serde(rename = "E")]
953 pub event_time: i64,
954 #[serde(rename = "T")]
956 pub transaction_time: i64,
957 #[serde(rename = "o", alias = "ao")]
959 pub algo_order: AlgoOrderUpdateData,
960}
961
962#[derive(Debug, Clone, Deserialize)]
964pub struct AlgoOrderUpdateData {
965 #[serde(rename = "caid")]
967 pub client_algo_id: String,
968 #[serde(rename = "aid")]
970 pub algo_id: i64,
971 #[serde(rename = "at")]
973 pub algo_type: BinanceAlgoType,
974 #[serde(rename = "o")]
976 pub order_type: BinanceFuturesOrderType,
977 #[serde(rename = "s")]
979 pub symbol: Ustr,
980 #[serde(rename = "S")]
982 pub side: BinanceSide,
983 #[serde(rename = "ps")]
985 pub position_side: BinancePositionSide,
986 #[serde(rename = "f")]
988 pub time_in_force: BinanceTimeInForce,
989 #[serde(rename = "q")]
991 pub quantity: String,
992 #[serde(rename = "X")]
994 pub algo_status: BinanceAlgoStatus,
995 #[serde(rename = "tp")]
997 pub trigger_price: String,
998 #[serde(rename = "p")]
1000 pub price: String,
1001 #[serde(rename = "wt")]
1003 pub working_type: BinanceWorkingType,
1004 #[serde(rename = "pm", default)]
1006 pub price_match: Option<BinancePriceMatch>,
1007 #[serde(rename = "cp", default)]
1009 pub close_position: Option<bool>,
1010 #[serde(rename = "pP", default)]
1012 pub price_protect: Option<bool>,
1013 #[serde(rename = "R", default)]
1015 pub reduce_only: Option<bool>,
1016 #[serde(rename = "tt", default)]
1018 pub trigger_time: Option<i64>,
1019 #[serde(rename = "gtd", default)]
1021 pub good_till_date: Option<i64>,
1022 #[serde(rename = "ai", default)]
1024 pub actual_order_id: Option<String>,
1025 #[serde(rename = "ap", default)]
1027 pub avg_price: Option<String>,
1028 #[serde(rename = "aq", default)]
1030 pub executed_qty: Option<String>,
1031 #[serde(rename = "act", default)]
1033 pub actual_order_type: Option<String>,
1034 #[serde(rename = "cr", default)]
1036 pub callback_rate: Option<String>,
1037 #[serde(rename = "V", default)]
1039 pub stp_mode: Option<BinanceSelfTradePreventionMode>,
1040}
1041
1042#[derive(Debug, Clone, Deserialize)]
1044pub struct BinanceFuturesListenKeyExpiredMsg {
1045 #[serde(rename = "e")]
1047 pub event_type: String,
1048 #[serde(rename = "E")]
1050 pub event_time: i64,
1051}
1052
1053#[cfg(test)]
1054mod tests {
1055 use rstest::rstest;
1056
1057 use super::*;
1058
1059 #[rstest]
1060 fn test_account_update_reason_adl_deserializes() {
1061 let value: AccountUpdateReason = serde_json::from_str("\"ADL\"").unwrap();
1062 assert_eq!(value, AccountUpdateReason::Adl);
1063 }
1064
1065 #[rstest]
1066 fn test_account_update_reason_unknown_fallback() {
1067 let value: AccountUpdateReason = serde_json::from_str("\"SOMETHING_NEW\"").unwrap();
1068 assert_eq!(value, AccountUpdateReason::Unknown);
1069 }
1070}