Skip to main content

nautilus_binance/futures/websocket/
messages.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Binance Futures WebSocket message types.
17//!
18//! Futures streams use standard JSON encoding (not SBE like Spot).
19//!
20//! Message types are separated into data (public market data) and execution
21//! (private user data stream) concerns:
22//! - [`NautilusDataWsMessage`] - Market data for data clients.
23//! - [`NautilusExecWsMessage`] - User data for execution clients.
24//! - [`NautilusWsMessage`] - Wrapper enum containing both.
25
26use nautilus_model::{
27    data::{Data, OrderBookDeltas},
28    events::{
29        AccountState, OrderAccepted, OrderCanceled, OrderFilled, OrderRejected, OrderUpdated,
30    },
31    identifiers::{ClientOrderId, InstrumentId, StrategyId, TraderId, VenueOrderId},
32    instruments::InstrumentAny,
33};
34use nautilus_network::websocket::WebSocketClient;
35use serde::{Deserialize, Serialize};
36use ustr::Ustr;
37
38use crate::{
39    common::enums::{
40        BinanceAlgoStatus, BinanceAlgoType, BinanceFuturesOrderType, BinanceKlineInterval,
41        BinanceMarginType, BinanceOrderStatus, BinancePositionSide, BinanceSide,
42        BinanceTimeInForce, BinanceWorkingType, BinanceWsMethod,
43    },
44    futures::http::BinanceFuturesInstrument,
45};
46
47/// Output message from the Futures WebSocket handler.
48///
49/// Wraps data and execution message types, allowing the single handler to
50/// produce messages for both data and execution clients.
51#[derive(Debug, Clone)]
52pub enum NautilusWsMessage {
53    /// Public market data message (normalized Nautilus types).
54    Data(NautilusDataWsMessage),
55    /// Private user data stream message (normalized Nautilus events).
56    Exec(Box<NautilusExecWsMessage>),
57    /// Raw user data stream message (for internal processing by exec handler).
58    ExecRaw(BinanceFuturesExecWsMessage),
59    /// Error from the server.
60    Error(BinanceFuturesWsErrorMsg),
61    /// WebSocket reconnected - subscriptions should be restored.
62    Reconnected,
63}
64
65/// Market data message from Binance Futures WebSocket.
66///
67/// These are public messages that don't require authentication.
68#[derive(Debug, Clone)]
69pub enum NautilusDataWsMessage {
70    /// Market data (trades, quotes, etc.).
71    Data(Vec<Data>),
72    /// Order book deltas with Binance-specific sequence metadata for validation.
73    DepthUpdate {
74        deltas: OrderBookDeltas,
75        first_update_id: u64,
76        prev_final_update_id: u64,
77    },
78    /// Instrument update.
79    Instrument(Box<InstrumentAny>),
80    /// Raw JSON message (for debugging or unhandled types).
81    RawJson(serde_json::Value),
82}
83
84/// Normalized execution event from Binance Futures.
85///
86/// These are normalized Nautilus events produced by the execution handler
87/// from raw WebSocket messages. The handler correlates updates with
88/// the original order context (strategy_id, etc.) using pending order maps.
89#[derive(Debug, Clone)]
90pub enum NautilusExecWsMessage {
91    /// Account state update (balance changes).
92    AccountUpdate(AccountState),
93    /// Order accepted by the exchange.
94    OrderAccepted(OrderAccepted),
95    /// Order canceled.
96    OrderCanceled(OrderCanceled),
97    /// Order rejected.
98    OrderRejected(OrderRejected),
99    /// Order filled (partial or full).
100    OrderFilled(OrderFilled),
101    /// Order modified/amended.
102    OrderUpdated(OrderUpdated),
103    /// Listen key expired - need to reconnect user data stream.
104    ListenKeyExpired,
105    /// WebSocket reconnected - subscriptions should be restored.
106    Reconnected,
107}
108
109/// Raw user data stream message from Binance Futures WebSocket.
110///
111/// These are raw messages from the user data stream that require
112/// a listen key for authentication. The execution handler processes these
113/// and emits normalized Nautilus events via [`NautilusExecWsMessage`].
114#[derive(Debug, Clone)]
115pub enum BinanceFuturesExecWsMessage {
116    /// Account update (balance/position changes).
117    AccountUpdate(BinanceFuturesAccountUpdateMsg),
118    /// Order/trade update.
119    OrderUpdate(Box<BinanceFuturesOrderUpdateMsg>),
120    /// Algo order update (conditional orders via Algo Service).
121    AlgoUpdate(Box<BinanceFuturesAlgoUpdateMsg>),
122    /// Margin call warning.
123    MarginCall(BinanceFuturesMarginCallMsg),
124    /// Account configuration change (leverage, etc.).
125    AccountConfigUpdate(BinanceFuturesAccountConfigMsg),
126    /// Listen key expired - need to reconnect user data stream.
127    ListenKeyExpired,
128}
129
130/// Error message from Binance Futures WebSocket.
131#[derive(Debug, Clone)]
132pub struct BinanceFuturesWsErrorMsg {
133    /// Error code from Binance.
134    pub code: i64,
135    /// Error message.
136    pub msg: String,
137}
138
139/// Handler command for data client-handler communication.
140#[derive(Debug)]
141#[allow(
142    clippy::large_enum_variant,
143    reason = "Commands are ephemeral and immediately consumed"
144)]
145pub enum DataHandlerCommand {
146    /// Set the WebSocket client reference.
147    SetClient(WebSocketClient),
148    /// Disconnect from the WebSocket.
149    Disconnect,
150    /// Initialize instruments in the handler cache.
151    InitializeInstruments(Vec<InstrumentAny>),
152    /// Update a single instrument in the handler cache.
153    UpdateInstrument(InstrumentAny),
154    /// Subscribe to streams.
155    Subscribe { streams: Vec<String> },
156    /// Unsubscribe from streams.
157    Unsubscribe { streams: Vec<String> },
158}
159
160/// Handler command for execution client-handler communication.
161#[derive(Debug)]
162#[allow(
163    clippy::large_enum_variant,
164    reason = "Commands are ephemeral and immediately consumed"
165)]
166pub enum ExecHandlerCommand {
167    /// Set the WebSocket client reference.
168    SetClient(WebSocketClient),
169    /// Disconnect from the WebSocket.
170    Disconnect,
171    /// Initialize instruments in the handler cache.
172    InitializeInstruments(Vec<BinanceFuturesInstrument>),
173    /// Update a single instrument in the handler cache.
174    UpdateInstrument(BinanceFuturesInstrument),
175    /// Subscribe to user data stream.
176    Subscribe { streams: Vec<String> },
177    /// Register an order for context tracking.
178    RegisterOrder {
179        client_order_id: ClientOrderId,
180        trader_id: TraderId,
181        strategy_id: StrategyId,
182        instrument_id: InstrumentId,
183    },
184    /// Register a cancel request for context tracking.
185    RegisterCancel {
186        client_order_id: ClientOrderId,
187        trader_id: TraderId,
188        strategy_id: StrategyId,
189        instrument_id: InstrumentId,
190        venue_order_id: Option<VenueOrderId>,
191    },
192    /// Register a modify request for context tracking.
193    RegisterModify {
194        client_order_id: ClientOrderId,
195        trader_id: TraderId,
196        strategy_id: StrategyId,
197        instrument_id: InstrumentId,
198        venue_order_id: Option<VenueOrderId>,
199    },
200}
201
202/// Aggregate trade stream message.
203#[derive(Debug, Clone, Deserialize)]
204pub struct BinanceFuturesAggTradeMsg {
205    /// Event type.
206    #[serde(rename = "e")]
207    pub event_type: String,
208    /// Event time in milliseconds.
209    #[serde(rename = "E")]
210    pub event_time: i64,
211    /// Symbol.
212    #[serde(rename = "s")]
213    pub symbol: Ustr,
214    /// Aggregate trade ID.
215    #[serde(rename = "a")]
216    pub agg_trade_id: u64,
217    /// Price.
218    #[serde(rename = "p")]
219    pub price: String,
220    /// Quantity.
221    #[serde(rename = "q")]
222    pub quantity: String,
223    /// First trade ID.
224    #[serde(rename = "f")]
225    pub first_trade_id: u64,
226    /// Last trade ID.
227    #[serde(rename = "l")]
228    pub last_trade_id: u64,
229    /// Trade time in milliseconds.
230    #[serde(rename = "T")]
231    pub trade_time: i64,
232    /// Is buyer the market maker.
233    #[serde(rename = "m")]
234    pub is_buyer_maker: bool,
235}
236
237/// Trade stream message.
238#[derive(Debug, Clone, Deserialize)]
239pub struct BinanceFuturesTradeMsg {
240    /// Event type.
241    #[serde(rename = "e")]
242    pub event_type: String,
243    /// Event time in milliseconds.
244    #[serde(rename = "E")]
245    pub event_time: i64,
246    /// Symbol.
247    #[serde(rename = "s")]
248    pub symbol: Ustr,
249    /// Trade ID.
250    #[serde(rename = "t")]
251    pub trade_id: u64,
252    /// Price.
253    #[serde(rename = "p")]
254    pub price: String,
255    /// Quantity.
256    #[serde(rename = "q")]
257    pub quantity: String,
258    /// Trade time in milliseconds.
259    #[serde(rename = "T")]
260    pub trade_time: i64,
261    /// Is buyer the market maker.
262    #[serde(rename = "m")]
263    pub is_buyer_maker: bool,
264}
265
266/// Order book depth update stream message.
267#[derive(Debug, Clone, Deserialize)]
268pub struct BinanceFuturesDepthUpdateMsg {
269    /// Event type.
270    #[serde(rename = "e")]
271    pub event_type: String,
272    /// Event time in milliseconds.
273    #[serde(rename = "E")]
274    pub event_time: i64,
275    /// Transaction time in milliseconds.
276    #[serde(rename = "T")]
277    pub transaction_time: i64,
278    /// Symbol.
279    #[serde(rename = "s")]
280    pub symbol: Ustr,
281    /// First update ID.
282    #[serde(rename = "U")]
283    pub first_update_id: u64,
284    /// Final update ID.
285    #[serde(rename = "u")]
286    pub final_update_id: u64,
287    /// Previous final update ID.
288    #[serde(rename = "pu")]
289    pub prev_final_update_id: u64,
290    /// Bids [price, quantity].
291    #[serde(rename = "b")]
292    pub bids: Vec<[String; 2]>,
293    /// Asks [price, quantity].
294    #[serde(rename = "a")]
295    pub asks: Vec<[String; 2]>,
296}
297
298/// Mark price stream message.
299#[derive(Debug, Clone, Deserialize)]
300pub struct BinanceFuturesMarkPriceMsg {
301    /// Event type.
302    #[serde(rename = "e")]
303    pub event_type: String,
304    /// Event time in milliseconds.
305    #[serde(rename = "E")]
306    pub event_time: i64,
307    /// Symbol.
308    #[serde(rename = "s")]
309    pub symbol: Ustr,
310    /// Mark price.
311    #[serde(rename = "p")]
312    pub mark_price: String,
313    /// Index price.
314    #[serde(rename = "i")]
315    pub index_price: String,
316    /// Estimated settle price.
317    #[serde(rename = "P")]
318    pub estimated_settle_price: String,
319    /// Funding rate.
320    #[serde(rename = "r")]
321    pub funding_rate: String,
322    /// Next funding time in milliseconds.
323    #[serde(rename = "T")]
324    pub next_funding_time: i64,
325}
326
327/// Book ticker stream message.
328#[derive(Debug, Clone, Deserialize)]
329pub struct BinanceFuturesBookTickerMsg {
330    /// Event type.
331    #[serde(rename = "e")]
332    pub event_type: String,
333    /// Update ID.
334    #[serde(rename = "u")]
335    pub update_id: u64,
336    /// Event time in milliseconds.
337    #[serde(rename = "E")]
338    pub event_time: i64,
339    /// Transaction time in milliseconds.
340    #[serde(rename = "T")]
341    pub transaction_time: i64,
342    /// Symbol.
343    #[serde(rename = "s")]
344    pub symbol: Ustr,
345    /// Best bid price.
346    #[serde(rename = "b")]
347    pub best_bid_price: String,
348    /// Best bid quantity.
349    #[serde(rename = "B")]
350    pub best_bid_qty: String,
351    /// Best ask price.
352    #[serde(rename = "a")]
353    pub best_ask_price: String,
354    /// Best ask quantity.
355    #[serde(rename = "A")]
356    pub best_ask_qty: String,
357}
358
359/// Kline/candlestick stream message.
360#[derive(Debug, Clone, Deserialize)]
361pub struct BinanceFuturesKlineMsg {
362    /// Event type.
363    #[serde(rename = "e")]
364    pub event_type: String,
365    /// Event time in milliseconds.
366    #[serde(rename = "E")]
367    pub event_time: i64,
368    /// Symbol.
369    #[serde(rename = "s")]
370    pub symbol: Ustr,
371    /// Kline data.
372    #[serde(rename = "k")]
373    pub kline: BinanceFuturesKlineData,
374}
375
376/// Kline data within kline message.
377#[derive(Debug, Clone, Deserialize)]
378pub struct BinanceFuturesKlineData {
379    /// Kline start time.
380    #[serde(rename = "t")]
381    pub start_time: i64,
382    /// Kline close time.
383    #[serde(rename = "T")]
384    pub close_time: i64,
385    /// Symbol.
386    #[serde(rename = "s")]
387    pub symbol: Ustr,
388    /// Kline interval.
389    #[serde(rename = "i")]
390    pub interval: BinanceKlineInterval,
391    /// First trade ID.
392    #[serde(rename = "f")]
393    pub first_trade_id: i64,
394    /// Last trade ID.
395    #[serde(rename = "L")]
396    pub last_trade_id: i64,
397    /// Open price.
398    #[serde(rename = "o")]
399    pub open: String,
400    /// Close price.
401    #[serde(rename = "c")]
402    pub close: String,
403    /// High price.
404    #[serde(rename = "h")]
405    pub high: String,
406    /// Low price.
407    #[serde(rename = "l")]
408    pub low: String,
409    /// Base asset volume.
410    #[serde(rename = "v")]
411    pub volume: String,
412    /// Number of trades.
413    #[serde(rename = "n")]
414    pub num_trades: i64,
415    /// Is this kline closed.
416    #[serde(rename = "x")]
417    pub is_closed: bool,
418    /// Quote asset volume.
419    #[serde(rename = "q")]
420    pub quote_volume: String,
421    /// Taker buy base asset volume.
422    #[serde(rename = "V")]
423    pub taker_buy_volume: String,
424    /// Taker buy quote asset volume.
425    #[serde(rename = "Q")]
426    pub taker_buy_quote_volume: String,
427}
428
429/// Liquidation order stream message.
430#[derive(Debug, Clone, Deserialize)]
431pub struct BinanceFuturesLiquidationMsg {
432    /// Event type.
433    #[serde(rename = "e")]
434    pub event_type: String,
435    /// Event time in milliseconds.
436    #[serde(rename = "E")]
437    pub event_time: i64,
438    /// Order data.
439    #[serde(rename = "o")]
440    pub order: BinanceFuturesLiquidationOrder,
441}
442
443/// Liquidation order details.
444#[derive(Debug, Clone, Deserialize)]
445pub struct BinanceFuturesLiquidationOrder {
446    /// Symbol.
447    #[serde(rename = "s")]
448    pub symbol: Ustr,
449    /// Order side.
450    #[serde(rename = "S")]
451    pub side: BinanceSide,
452    /// Order type.
453    #[serde(rename = "o")]
454    pub order_type: BinanceFuturesOrderType,
455    /// Time in force.
456    #[serde(rename = "f")]
457    pub time_in_force: BinanceTimeInForce,
458    /// Original quantity.
459    #[serde(rename = "q")]
460    pub original_qty: String,
461    /// Price.
462    #[serde(rename = "p")]
463    pub price: String,
464    /// Average price.
465    #[serde(rename = "ap")]
466    pub average_price: String,
467    /// Order status.
468    #[serde(rename = "X")]
469    pub status: BinanceOrderStatus,
470    /// Last filled quantity.
471    #[serde(rename = "l")]
472    pub last_filled_qty: String,
473    /// Accumulated filled quantity.
474    #[serde(rename = "z")]
475    pub accumulated_qty: String,
476    /// Trade time in milliseconds.
477    #[serde(rename = "T")]
478    pub trade_time: i64,
479}
480
481/// WebSocket subscription request.
482#[derive(Debug, Clone, Serialize)]
483pub struct BinanceFuturesWsSubscribeRequest {
484    /// Request method.
485    pub method: BinanceWsMethod,
486    /// Stream names to subscribe.
487    pub params: Vec<String>,
488    /// Request ID.
489    pub id: u64,
490}
491
492/// WebSocket subscription response.
493#[derive(Debug, Clone, Deserialize)]
494pub struct BinanceFuturesWsSubscribeResponse {
495    /// Response result (null on success).
496    pub result: Option<serde_json::Value>,
497    /// Request ID echoed back.
498    pub id: u64,
499}
500
501/// WebSocket error response.
502#[derive(Debug, Clone, Deserialize)]
503pub struct BinanceFuturesWsErrorResponse {
504    /// Error code.
505    pub code: i64,
506    /// Error message.
507    pub msg: String,
508    /// Request ID if available.
509    pub id: Option<u64>,
510}
511
512/// Account update event from user data stream.
513#[derive(Debug, Clone, Deserialize)]
514pub struct BinanceFuturesAccountUpdateMsg {
515    /// Event type.
516    #[serde(rename = "e")]
517    pub event_type: String,
518    /// Event time in milliseconds.
519    #[serde(rename = "E")]
520    pub event_time: i64,
521    /// Transaction time in milliseconds.
522    #[serde(rename = "T")]
523    pub transaction_time: i64,
524    /// Account update data.
525    #[serde(rename = "a")]
526    pub account: AccountUpdateData,
527}
528
529/// Account update data payload.
530#[derive(Debug, Clone, Deserialize)]
531pub struct AccountUpdateData {
532    /// Reason for account update.
533    #[serde(rename = "m")]
534    pub reason: AccountUpdateReason,
535    /// Balance updates.
536    #[serde(rename = "B", default)]
537    pub balances: Vec<BalanceUpdate>,
538    /// Position updates.
539    #[serde(rename = "P", default)]
540    pub positions: Vec<PositionUpdate>,
541}
542
543/// Account update reason type.
544#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
545#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
546pub enum AccountUpdateReason {
547    Deposit,
548    Withdraw,
549    Order,
550    FundingFee,
551    WithdrawReject,
552    Adjustment,
553    InsuranceClear,
554    AdminDeposit,
555    AdminWithdraw,
556    MarginTransfer,
557    MarginTypeChange,
558    AssetTransfer,
559    OptionsPremiumFee,
560    OptionsSettleProfit,
561    AutoExchange,
562    CoinSwapDeposit,
563    CoinSwapWithdraw,
564    #[serde(other)]
565    Unknown,
566}
567
568/// Balance update within account update.
569#[derive(Debug, Clone, Deserialize)]
570pub struct BalanceUpdate {
571    /// Asset name.
572    #[serde(rename = "a")]
573    pub asset: Ustr,
574    /// Wallet balance.
575    #[serde(rename = "wb")]
576    pub wallet_balance: String,
577    /// Cross wallet balance.
578    #[serde(rename = "cw")]
579    pub cross_wallet_balance: String,
580    /// Balance change (except for PnL and commission).
581    #[serde(rename = "bc", default)]
582    pub balance_change: Option<String>,
583}
584
585/// Position update within account update.
586#[derive(Debug, Clone, Deserialize)]
587pub struct PositionUpdate {
588    /// Symbol.
589    #[serde(rename = "s")]
590    pub symbol: Ustr,
591    /// Position amount.
592    #[serde(rename = "pa")]
593    pub position_amount: String,
594    /// Entry price.
595    #[serde(rename = "ep")]
596    pub entry_price: String,
597    /// Break-even price.
598    #[serde(rename = "bep", default)]
599    pub break_even_price: Option<String>,
600    /// Accumulated realized (pre-fee).
601    #[serde(rename = "cr")]
602    pub accumulated_realized: String,
603    /// Unrealized PnL.
604    #[serde(rename = "up")]
605    pub unrealized_pnl: String,
606    /// Margin type.
607    #[serde(rename = "mt")]
608    pub margin_type: BinanceMarginType,
609    /// Isolated wallet (if isolated position).
610    #[serde(rename = "iw")]
611    pub isolated_wallet: String,
612    /// Position side.
613    #[serde(rename = "ps")]
614    pub position_side: BinancePositionSide,
615}
616
617/// Order/trade update event from user data stream.
618#[derive(Debug, Clone, Deserialize)]
619pub struct BinanceFuturesOrderUpdateMsg {
620    /// Event type.
621    #[serde(rename = "e")]
622    pub event_type: String,
623    /// Event time in milliseconds.
624    #[serde(rename = "E")]
625    pub event_time: i64,
626    /// Transaction time in milliseconds.
627    #[serde(rename = "T")]
628    pub transaction_time: i64,
629    /// Order data.
630    #[serde(rename = "o")]
631    pub order: OrderUpdateData,
632}
633
634/// Order update data payload.
635#[derive(Debug, Clone, Deserialize)]
636pub struct OrderUpdateData {
637    /// Symbol.
638    #[serde(rename = "s")]
639    pub symbol: Ustr,
640    /// Client order ID.
641    #[serde(rename = "c")]
642    pub client_order_id: String,
643    /// Order side.
644    #[serde(rename = "S")]
645    pub side: BinanceSide,
646    /// Order type.
647    #[serde(rename = "o")]
648    pub order_type: BinanceFuturesOrderType,
649    /// Time in force.
650    #[serde(rename = "f")]
651    pub time_in_force: BinanceTimeInForce,
652    /// Original quantity.
653    #[serde(rename = "q")]
654    pub original_qty: String,
655    /// Original price.
656    #[serde(rename = "p")]
657    pub original_price: String,
658    /// Average price.
659    #[serde(rename = "ap")]
660    pub average_price: String,
661    /// Stop price.
662    #[serde(rename = "sp")]
663    pub stop_price: String,
664    /// Execution type.
665    #[serde(rename = "x")]
666    pub execution_type: BinanceExecutionType,
667    /// Order status.
668    #[serde(rename = "X")]
669    pub order_status: BinanceOrderStatus,
670    /// Order ID.
671    #[serde(rename = "i")]
672    pub order_id: i64,
673    /// Last executed quantity.
674    #[serde(rename = "l")]
675    pub last_filled_qty: String,
676    /// Cumulative filled quantity.
677    #[serde(rename = "z")]
678    pub cumulative_filled_qty: String,
679    /// Last executed price.
680    #[serde(rename = "L")]
681    pub last_filled_price: String,
682    /// Commission asset.
683    #[serde(rename = "N", default)]
684    pub commission_asset: Option<Ustr>,
685    /// Commission amount.
686    #[serde(rename = "n", default)]
687    pub commission: Option<String>,
688    /// Order trade time.
689    #[serde(rename = "T")]
690    pub trade_time: i64,
691    /// Trade ID.
692    #[serde(rename = "t")]
693    pub trade_id: i64,
694    /// Bids notional.
695    #[serde(rename = "b", default)]
696    pub bids_notional: Option<String>,
697    /// Asks notional.
698    #[serde(rename = "a", default)]
699    pub asks_notional: Option<String>,
700    /// Is maker.
701    #[serde(rename = "m")]
702    pub is_maker: bool,
703    /// Is reduce only.
704    #[serde(rename = "R")]
705    pub is_reduce_only: bool,
706    /// Working type.
707    #[serde(rename = "wt")]
708    pub working_type: BinanceWorkingType,
709    /// Original order type.
710    #[serde(rename = "ot")]
711    pub original_order_type: BinanceFuturesOrderType,
712    /// Position side.
713    #[serde(rename = "ps")]
714    pub position_side: BinancePositionSide,
715    /// Close all (for stop orders).
716    #[serde(rename = "cp", default)]
717    pub close_position: Option<bool>,
718    /// Activation price (for trailing stop).
719    #[serde(rename = "AP", default)]
720    pub activation_price: Option<String>,
721    /// Callback rate (for trailing stop).
722    #[serde(rename = "cr", default)]
723    pub callback_rate: Option<String>,
724    /// Price protection.
725    #[serde(rename = "pP", default)]
726    pub price_protect: Option<bool>,
727    /// Realized profit.
728    #[serde(rename = "rp")]
729    pub realized_profit: String,
730    /// Self-trade prevention mode.
731    #[serde(rename = "V", default)]
732    pub stp_mode: Option<String>,
733    /// Price match mode.
734    #[serde(rename = "pm", default)]
735    pub price_match: Option<String>,
736    /// Good till date for GTD orders.
737    #[serde(rename = "gtd", default)]
738    pub good_till_date: Option<i64>,
739}
740
741impl OrderUpdateData {
742    /// Returns true if this is a liquidation order.
743    #[must_use]
744    pub fn is_liquidation(&self) -> bool {
745        self.client_order_id.starts_with("autoclose-")
746    }
747
748    /// Returns true if this is an ADL (Auto-Deleveraging) order.
749    #[must_use]
750    pub fn is_adl(&self) -> bool {
751        self.client_order_id.starts_with("adl_autoclose")
752    }
753
754    /// Returns true if this is a settlement order.
755    #[must_use]
756    pub fn is_settlement(&self) -> bool {
757        self.client_order_id.starts_with("settlement_autoclose-")
758    }
759
760    /// Returns true if this is an exchange-generated order.
761    #[must_use]
762    pub fn is_exchange_generated(&self) -> bool {
763        self.is_liquidation() || self.is_adl() || self.is_settlement()
764    }
765}
766
767/// Execution type for order updates.
768#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
769#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
770pub enum BinanceExecutionType {
771    /// New order accepted.
772    New,
773    /// Order canceled.
774    Canceled,
775    /// Calculated (liquidation, ADL).
776    Calculated,
777    /// Order expired.
778    Expired,
779    /// Trade (partial or full fill).
780    Trade,
781    /// Amendment (order modified).
782    Amendment,
783}
784
785/// Margin call event from user data stream.
786#[derive(Debug, Clone, Deserialize)]
787pub struct BinanceFuturesMarginCallMsg {
788    /// Event type.
789    #[serde(rename = "e")]
790    pub event_type: String,
791    /// Event time in milliseconds.
792    #[serde(rename = "E")]
793    pub event_time: i64,
794    /// Cross wallet balance.
795    #[serde(rename = "cw")]
796    pub cross_wallet_balance: String,
797    /// Positions at risk.
798    #[serde(rename = "p")]
799    pub positions: Vec<MarginCallPosition>,
800}
801
802/// Position at risk in margin call.
803#[derive(Debug, Clone, Deserialize)]
804pub struct MarginCallPosition {
805    /// Symbol.
806    #[serde(rename = "s")]
807    pub symbol: Ustr,
808    /// Position side.
809    #[serde(rename = "ps")]
810    pub position_side: BinancePositionSide,
811    /// Position amount.
812    #[serde(rename = "pa")]
813    pub position_amount: String,
814    /// Margin type.
815    #[serde(rename = "mt")]
816    pub margin_type: BinanceMarginType,
817    /// Isolated wallet (if any).
818    #[serde(rename = "iw")]
819    pub isolated_wallet: String,
820    /// Mark price.
821    #[serde(rename = "mp")]
822    pub mark_price: String,
823    /// Unrealized PnL.
824    #[serde(rename = "up")]
825    pub unrealized_pnl: String,
826    /// Maintenance margin required.
827    #[serde(rename = "mm")]
828    pub maintenance_margin: String,
829}
830
831/// Account configuration update event.
832#[derive(Debug, Clone, Deserialize)]
833pub struct BinanceFuturesAccountConfigMsg {
834    /// Event type.
835    #[serde(rename = "e")]
836    pub event_type: String,
837    /// Event time in milliseconds.
838    #[serde(rename = "E")]
839    pub event_time: i64,
840    /// Transaction time in milliseconds.
841    #[serde(rename = "T")]
842    pub transaction_time: i64,
843    /// Leverage configuration data.
844    #[serde(rename = "ac", default)]
845    pub leverage_config: Option<LeverageConfig>,
846    /// Asset index price data (for multi-assets mode).
847    #[serde(rename = "ai", default)]
848    pub asset_index: Option<AssetIndexConfig>,
849}
850
851/// Leverage configuration change.
852#[derive(Debug, Clone, Deserialize)]
853pub struct LeverageConfig {
854    /// Symbol.
855    #[serde(rename = "s")]
856    pub symbol: Ustr,
857    /// New leverage value.
858    #[serde(rename = "l")]
859    pub leverage: u32,
860}
861
862/// Asset index configuration (multi-assets mode).
863#[derive(Debug, Clone, Deserialize)]
864pub struct AssetIndexConfig {
865    /// Symbol.
866    #[serde(rename = "s")]
867    pub symbol: Ustr,
868}
869
870/// Algo order update event from user data stream (Binance Futures Algo Service).
871///
872/// This event is triggered for conditional orders (STOP_MARKET, STOP_LIMIT,
873/// TAKE_PROFIT, TAKE_PROFIT_MARKET, TRAILING_STOP_MARKET) managed by the
874/// Algo Service.
875///
876/// # References
877///
878/// - <https://developers.binance.com/docs/derivatives/usds-margined-futures/user-data-streams/Event-Algo-Order-Update>
879#[derive(Debug, Clone, Deserialize)]
880pub struct BinanceFuturesAlgoUpdateMsg {
881    /// Event type ("ALGO_UPDATE").
882    #[serde(rename = "e")]
883    pub event_type: String,
884    /// Event time in milliseconds.
885    #[serde(rename = "E")]
886    pub event_time: i64,
887    /// Transaction time in milliseconds.
888    #[serde(rename = "T")]
889    pub transaction_time: i64,
890    /// Algo order data.
891    #[serde(rename = "ao")]
892    pub algo_order: AlgoOrderUpdateData,
893}
894
895/// Algo order update data payload.
896#[derive(Debug, Clone, Deserialize)]
897pub struct AlgoOrderUpdateData {
898    /// Client algo order ID.
899    #[serde(rename = "caid")]
900    pub client_algo_id: String,
901    /// Algo order ID.
902    #[serde(rename = "aid")]
903    pub algo_id: i64,
904    /// Algo type (currently only `Conditional`).
905    #[serde(rename = "at")]
906    pub algo_type: BinanceAlgoType,
907    /// Order type (STOP_MARKET, STOP, TAKE_PROFIT, TAKE_PROFIT_MARKET, TRAILING_STOP_MARKET).
908    #[serde(rename = "o")]
909    pub order_type: BinanceFuturesOrderType,
910    /// Symbol.
911    #[serde(rename = "s")]
912    pub symbol: Ustr,
913    /// Order side.
914    #[serde(rename = "S")]
915    pub side: BinanceSide,
916    /// Position side.
917    #[serde(rename = "ps")]
918    pub position_side: BinancePositionSide,
919    /// Time in force.
920    #[serde(rename = "f")]
921    pub time_in_force: BinanceTimeInForce,
922    /// Order quantity.
923    #[serde(rename = "q")]
924    pub quantity: String,
925    /// Algo order status (NEW, TRIGGERING, TRIGGERED, FINISHED, CANCELED, EXPIRED, REJECTED).
926    #[serde(rename = "X")]
927    pub algo_status: BinanceAlgoStatus,
928    /// Trigger price.
929    #[serde(rename = "tp")]
930    pub trigger_price: String,
931    /// Limit price.
932    #[serde(rename = "p")]
933    pub price: String,
934    /// Working type for trigger price calculation.
935    #[serde(rename = "wt")]
936    pub working_type: BinanceWorkingType,
937    /// Price match mode.
938    #[serde(rename = "pm", default)]
939    pub price_match: Option<String>,
940    /// Close position flag.
941    #[serde(rename = "cp", default)]
942    pub close_position: Option<bool>,
943    /// Price protection flag.
944    #[serde(rename = "pP", default)]
945    pub price_protect: Option<bool>,
946    /// Reduce-only flag.
947    #[serde(rename = "R", default)]
948    pub reduce_only: Option<bool>,
949    /// Trigger time in milliseconds.
950    #[serde(rename = "tt", default)]
951    pub trigger_time: Option<i64>,
952    /// Good till date in milliseconds.
953    #[serde(rename = "gtd", default)]
954    pub good_till_date: Option<i64>,
955    /// Order ID in matching engine (populated when triggered).
956    #[serde(rename = "ai", default)]
957    pub actual_order_id: Option<String>,
958    /// Average fill price in matching engine (populated when triggered).
959    #[serde(rename = "ap", default)]
960    pub avg_price: Option<String>,
961    /// Executed quantity in matching engine (populated when triggered).
962    #[serde(rename = "aq", default)]
963    pub executed_qty: Option<String>,
964    /// Actual order type in matching engine (populated when triggered).
965    #[serde(rename = "act", default)]
966    pub actual_order_type: Option<String>,
967    /// Callback rate for trailing stop (0.1 to 10, where 1 = 1%).
968    #[serde(rename = "cr", default)]
969    pub callback_rate: Option<String>,
970    /// Self-trade prevention mode.
971    #[serde(rename = "V", default)]
972    pub stp_mode: Option<String>,
973}
974
975/// Listen key expired event.
976#[derive(Debug, Clone, Deserialize)]
977pub struct BinanceFuturesListenKeyExpiredMsg {
978    /// Event type.
979    #[serde(rename = "e")]
980    pub event_type: String,
981    /// Event time in milliseconds.
982    #[serde(rename = "E")]
983    pub event_time: i64,
984}