nautilus_bitmex/websocket/
messages.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 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
16use std::collections::HashMap;
17
18use chrono::{DateTime, Utc};
19use nautilus_model::{
20    data::{Data, funding::FundingRateUpdate},
21    reports::{FillReport, OrderStatusReport, PositionStatusReport},
22};
23use serde::{Deserialize, Serialize};
24use strum::Display;
25use ustr::Ustr;
26use uuid::Uuid;
27
28use super::enums::{
29    BitmexAction, BitmexSide, BitmexTickDirection, BitmexWsAuthAction, BitmexWsOperation,
30};
31use crate::common::enums::{
32    BitmexContingencyType, BitmexExecInstruction, BitmexExecType, BitmexLiquidityIndicator,
33    BitmexOrderStatus, BitmexOrderType, BitmexPegPriceType, BitmexTimeInForce,
34};
35
36/// BitMEX WebSocket authentication message.
37///
38/// The args array contains [api_key, expires/nonce, signature].
39/// The second element must be a number (not a string) for proper authentication.
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct BitmexAuthentication {
42    pub op: BitmexWsAuthAction,
43    pub args: (String, i64, String),
44}
45
46/// BitMEX WebSocket subscription message.
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct BitmexSubscription {
49    pub op: BitmexWsOperation,
50    pub args: Vec<String>,
51}
52
53/// Unified WebSocket message type for BitMEX.
54#[derive(Clone, Debug)]
55pub enum NautilusWsMessage {
56    Data(Vec<Data>),
57    OrderStatusReports(Vec<OrderStatusReport>),
58    FillReports(Vec<FillReport>),
59    PositionStatusReport(Box<PositionStatusReport>),
60    FundingRateUpdates(Vec<FundingRateUpdate>),
61    AccountState(Box<nautilus_model::events::AccountState>),
62    Reconnected,
63}
64
65/// Represents all possible message types from the BitMEX WebSocket API.
66#[derive(Debug, Display, Deserialize)]
67#[serde(untagged)]
68pub enum BitmexWsMessage {
69    /// Table websocket message.
70    Table(BitmexTableMessage),
71    /// Initial welcome message received when connecting to the WebSocket.
72    Welcome {
73        /// Welcome message text.
74        info: String,
75        /// API version string.
76        version: String,
77        /// Server timestamp.
78        timestamp: DateTime<Utc>,
79        /// Link to API documentation.
80        docs: String,
81        /// Whether heartbeat is enabled for this connection.
82        #[serde(rename = "heartbeatEnabled")]
83        heartbeat_enabled: bool,
84        /// Rate limit information.
85        limit: BitmexRateLimit,
86    },
87    /// Subscription response messages.
88    Subscription {
89        /// Whether the subscription request was successful.
90        success: bool,
91        /// The subscription topic if successful.
92        subscribe: Option<String>,
93        /// Error message if subscription failed.
94        error: Option<String>,
95    },
96    /// WebSocket error message.
97    Error {
98        status: u16,
99        error: String,
100        meta: HashMap<String, String>,
101        request: BitmexHttpRequest,
102    },
103    /// Indicates a WebSocket reconnection has occurred.
104    #[serde(skip)]
105    Reconnected,
106}
107
108#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
109pub struct BitmexHttpRequest {
110    pub op: String,
111    pub args: Vec<String>,
112}
113
114/// Rate limit information from BitMEX API.
115#[derive(Debug, Deserialize)]
116pub struct BitmexRateLimit {
117    /// Number of requests remaining in the current time window.
118    pub remaining: i32,
119}
120
121/// Represents table-based messages.
122#[derive(Debug, Display, Deserialize)]
123#[serde(rename_all = "camelCase")]
124#[serde(tag = "table")]
125pub enum BitmexTableMessage {
126    OrderBookL2 {
127        action: BitmexAction,
128        data: Vec<BitmexOrderBookMsg>,
129    },
130    OrderBookL2_25 {
131        action: BitmexAction,
132        data: Vec<BitmexOrderBookMsg>,
133    },
134    OrderBook10 {
135        action: BitmexAction,
136        data: Vec<BitmexOrderBook10Msg>,
137    },
138    Quote {
139        action: BitmexAction,
140        data: Vec<BitmexQuoteMsg>,
141    },
142    Trade {
143        action: BitmexAction,
144        data: Vec<BitmexTradeMsg>,
145    },
146    TradeBin1m {
147        action: BitmexAction,
148        data: Vec<BitmexTradeBinMsg>,
149    },
150    TradeBin5m {
151        action: BitmexAction,
152        data: Vec<BitmexTradeBinMsg>,
153    },
154    TradeBin1h {
155        action: BitmexAction,
156        data: Vec<BitmexTradeBinMsg>,
157    },
158    TradeBin1d {
159        action: BitmexAction,
160        data: Vec<BitmexTradeBinMsg>,
161    },
162    Instrument {
163        action: BitmexAction,
164        data: Vec<BitmexInstrumentMsg>,
165    },
166    Order {
167        action: BitmexAction,
168        data: Vec<BitmexOrderMsg>,
169    },
170    Execution {
171        action: BitmexAction,
172        data: Vec<BitmexExecutionMsg>,
173    },
174    Position {
175        action: BitmexAction,
176        data: Vec<BitmexPositionMsg>,
177    },
178    Wallet {
179        action: BitmexAction,
180        data: Vec<BitmexWalletMsg>,
181    },
182    Margin {
183        action: BitmexAction,
184        data: Vec<BitmexMarginMsg>,
185    },
186    Funding {
187        action: BitmexAction,
188        data: Vec<BitmexFundingMsg>,
189    },
190    Insurance {
191        action: BitmexAction,
192        data: Vec<BitmexInsuranceMsg>,
193    },
194    Liquidation {
195        action: BitmexAction,
196        data: Vec<BitmexLiquidationMsg>,
197    },
198}
199
200/// Represents a single order book entry in the BitMEX order book.
201#[derive(Clone, Debug, Deserialize)]
202#[serde(rename_all = "camelCase")]
203pub struct BitmexOrderBookMsg {
204    /// The instrument symbol (e.g., "XBTUSD").
205    pub symbol: Ustr,
206    /// Unique order ID.
207    pub id: u64,
208    /// Side of the order ("Buy" or "Sell").
209    pub side: BitmexSide,
210    /// Size of the order, can be None for deletes.
211    pub size: Option<u64>,
212    /// Price level of the order.
213    pub price: f64,
214    /// Timestamp of the update.
215    pub timestamp: DateTime<Utc>,
216    /// Timestamp of the transaction.
217    pub transact_time: DateTime<Utc>,
218}
219
220/// Represents a single order book entry in the BitMEX order book.
221#[derive(Clone, Debug, Deserialize)]
222#[serde(rename_all = "camelCase")]
223pub struct BitmexOrderBook10Msg {
224    /// The instrument symbol (e.g., "XBTUSD").
225    pub symbol: Ustr,
226    /// Array of bid levels, each containing [price, size].
227    pub bids: Vec<[f64; 2]>,
228    /// Array of ask levels, each containing [price, size].
229    pub asks: Vec<[f64; 2]>,
230    /// Timestamp of the orderbook snapshot.
231    pub timestamp: DateTime<Utc>,
232}
233
234/// Represents a top-of-book quote.
235#[derive(Clone, Debug, Deserialize)]
236#[serde(rename_all = "camelCase")]
237pub struct BitmexQuoteMsg {
238    /// The instrument symbol (e.g., "XBTUSD").
239    pub symbol: Ustr,
240    /// Price of best bid.
241    pub bid_price: Option<f64>,
242    /// Size of best bid.
243    pub bid_size: Option<u64>,
244    /// Price of best ask.
245    pub ask_price: Option<f64>,
246    /// Size of best ask.
247    pub ask_size: Option<u64>,
248    /// Timestamp of the quote.
249    pub timestamp: DateTime<Utc>,
250}
251
252/// Represents a single trade execution on BitMEX.
253#[derive(Clone, Debug, Deserialize)]
254#[serde(rename_all = "camelCase")]
255pub struct BitmexTradeMsg {
256    /// Timestamp of the trade.
257    pub timestamp: DateTime<Utc>,
258    /// The instrument symbol.
259    pub symbol: Ustr,
260    /// Side of the trade ("Buy" or "Sell").
261    pub side: BitmexSide,
262    /// Size of the trade.
263    pub size: u64,
264    /// Price the trade executed at.
265    pub price: f64,
266    /// Direction of the tick ("`PlusTick`", "`MinusTick`", "`ZeroPlusTick`", "`ZeroMinusTick`").
267    pub tick_direction: BitmexTickDirection,
268    /// Unique trade match ID.
269    #[serde(rename = "trdMatchID")]
270    pub trd_match_id: Option<Uuid>,
271    /// Gross value of the trade in satoshis.
272    pub gross_value: Option<i64>,
273    /// Home currency value of the trade.
274    pub home_notional: Option<f64>,
275    /// Foreign currency value of the trade.
276    pub foreign_notional: Option<f64>,
277    /// Trade type.
278    #[serde(rename = "trdType")]
279    pub trade_type: Ustr, // TODO: Add enum
280}
281
282#[derive(Clone, Debug, Deserialize)]
283#[serde(rename_all = "camelCase")]
284pub struct BitmexTradeBinMsg {
285    /// Start time of the bin
286    pub timestamp: DateTime<Utc>,
287    /// Trading instrument symbol
288    pub symbol: Ustr,
289    /// Opening price for the period
290    pub open: f64,
291    /// Highest price for the period
292    pub high: f64,
293    /// Lowest price for the period
294    pub low: f64,
295    /// Closing price for the period
296    pub close: f64,
297    /// Number of trades in the period
298    pub trades: i64,
299    /// Volume traded in the period
300    pub volume: i64,
301    /// Volume weighted average price
302    pub vwap: f64,
303    /// Size of the last trade in the period
304    pub last_size: i64,
305    /// Turnover in satoshis
306    pub turnover: i64,
307    /// Home currency volume
308    pub home_notional: f64,
309    /// Foreign currency volume
310    pub foreign_notional: f64,
311}
312
313/// Represents a single order book entry in the BitMEX order book.
314#[derive(Clone, Debug, Deserialize)]
315#[serde(rename_all = "camelCase")]
316pub struct BitmexInstrumentMsg {
317    /// The instrument symbol (e.g., "XBTUSD").
318    pub symbol: Ustr,
319    /// Last traded price for the instrument.
320    pub last_price: Option<f64>,
321    /// Last tick direction for the instrument.
322    pub last_tick_direction: Option<BitmexTickDirection>,
323    /// Mark price.
324    pub mark_price: Option<f64>,
325    /// Index price.
326    pub index_price: Option<f64>,
327    /// Indicative settlement price.
328    pub indicative_settle_price: Option<f64>,
329    /// Open interest for the instrument.
330    pub open_interest: Option<i64>,
331    /// Open value for the instrument.
332    pub open_value: Option<i64>,
333    /// Fair basis.
334    pub fair_basis: Option<f64>,
335    /// Fair basis rate.
336    pub fair_basis_rate: Option<f64>,
337    /// Fair price.
338    pub fair_price: Option<f64>,
339    /// Mark method.
340    pub mark_method: Option<Ustr>,
341    /// Indicative tax rate.
342    pub indicative_tax_rate: Option<f64>,
343    /// Timestamp of the update.
344    pub timestamp: DateTime<Utc>,
345}
346
347/// Represents an order update from the WebSocket stream
348#[derive(Clone, Debug, Deserialize)]
349#[serde(rename_all = "camelCase")]
350pub struct BitmexOrderMsg {
351    #[serde(rename = "orderID")]
352    pub order_id: Uuid,
353    #[serde(rename = "clOrdID")]
354    pub cl_ord_id: Option<Ustr>,
355    #[serde(rename = "clOrdLinkID")]
356    pub cl_ord_link_id: Option<Ustr>,
357    pub account: i64,
358    pub symbol: Ustr,
359    pub side: BitmexSide,
360    pub order_qty: i64,
361    pub price: Option<f64>,
362    pub display_qty: Option<i64>,
363    pub stop_px: Option<f64>,
364    pub peg_offset_value: Option<f64>,
365    pub peg_price_type: Option<BitmexPegPriceType>,
366    pub currency: Ustr,
367    pub settl_currency: Ustr,
368    pub ord_type: BitmexOrderType,
369    pub time_in_force: BitmexTimeInForce,
370    pub exec_inst: Option<BitmexExecInstruction>,
371    pub contingency_type: Option<BitmexContingencyType>,
372    pub ord_status: BitmexOrderStatus,
373    pub triggered: Option<Ustr>,
374    pub working_indicator: bool,
375    pub ord_rej_reason: Option<Ustr>,
376    pub leaves_qty: i64,
377    pub cum_qty: i64,
378    pub avg_px: Option<f64>,
379    pub text: Option<Ustr>,
380    pub transact_time: DateTime<Utc>,
381    pub timestamp: DateTime<Utc>,
382}
383
384/// Raw Order and Balance Data.
385#[derive(Clone, Debug, Deserialize)]
386#[serde(rename_all = "camelCase")]
387pub struct BitmexExecutionMsg {
388    #[serde(rename = "execID")]
389    pub exec_id: Uuid,
390    #[serde(rename = "orderID")]
391    pub order_id: Option<Uuid>,
392    #[serde(rename = "clOrdID")]
393    pub cl_ord_id: Option<Ustr>,
394    #[serde(rename = "clOrdLinkID")]
395    pub cl_ord_link_id: Option<Ustr>,
396    pub account: Option<i64>,
397    pub symbol: Option<Ustr>,
398    pub side: Option<BitmexSide>,
399    pub last_qty: Option<i64>,
400    pub last_px: Option<f64>,
401    pub underlying_last_px: Option<f64>,
402    pub last_mkt: Option<Ustr>,
403    pub last_liquidity_ind: Option<BitmexLiquidityIndicator>,
404    pub order_qty: Option<i64>,
405    pub price: Option<f64>,
406    pub display_qty: Option<i64>,
407    pub stop_px: Option<f64>,
408    pub peg_offset_value: Option<f64>,
409    pub peg_price_type: Option<BitmexPegPriceType>,
410    pub currency: Option<Ustr>,
411    pub settl_currency: Option<Ustr>,
412    pub exec_type: Option<BitmexExecType>,
413    pub ord_type: Option<BitmexOrderType>,
414    pub time_in_force: Option<BitmexTimeInForce>,
415    pub exec_inst: Option<BitmexExecInstruction>,
416    pub contingency_type: Option<BitmexContingencyType>,
417    pub ex_destination: Option<Ustr>,
418    pub ord_status: Option<BitmexOrderStatus>,
419    pub triggered: Option<Ustr>,
420    pub working_indicator: Option<bool>,
421    pub ord_rej_reason: Option<Ustr>,
422    pub leaves_qty: Option<i64>,
423    pub cum_qty: Option<i64>,
424    pub avg_px: Option<f64>,
425    pub commission: Option<f64>,
426    pub trade_publish_indicator: Option<Ustr>,
427    pub multi_leg_reporting_type: Option<Ustr>,
428    pub text: Option<Ustr>,
429    #[serde(rename = "trdMatchID")]
430    pub trd_match_id: Option<Uuid>,
431    pub exec_cost: Option<i64>,
432    pub exec_comm: Option<i64>,
433    pub home_notional: Option<f64>,
434    pub foreign_notional: Option<f64>,
435    pub transact_time: Option<DateTime<Utc>>,
436    pub timestamp: Option<DateTime<Utc>>,
437}
438
439/// Position status.
440#[derive(Clone, Debug, Deserialize)]
441#[serde(rename_all = "camelCase")]
442pub struct BitmexPositionMsg {
443    pub account: i64,
444    pub symbol: Ustr,
445    pub currency: Option<Ustr>,
446    pub underlying: Option<Ustr>,
447    pub quote_currency: Option<Ustr>,
448    pub commission: Option<f64>,
449    pub init_margin_req: Option<f64>,
450    pub maint_margin_req: Option<f64>,
451    pub risk_limit: Option<i64>,
452    pub leverage: Option<f64>,
453    pub cross_margin: Option<bool>,
454    pub deleverage_percentile: Option<f64>,
455    pub rebalanced_pnl: Option<i64>,
456    pub prev_realised_pnl: Option<i64>,
457    pub prev_unrealised_pnl: Option<i64>,
458    pub prev_close_price: Option<f64>,
459    pub opening_timestamp: Option<DateTime<Utc>>,
460    pub opening_qty: Option<i64>,
461    pub opening_cost: Option<i64>,
462    pub opening_comm: Option<i64>,
463    pub open_order_buy_qty: Option<i64>,
464    pub open_order_buy_cost: Option<i64>,
465    pub open_order_buy_premium: Option<i64>,
466    pub open_order_sell_qty: Option<i64>,
467    pub open_order_sell_cost: Option<i64>,
468    pub open_order_sell_premium: Option<i64>,
469    pub exec_buy_qty: Option<i64>,
470    pub exec_buy_cost: Option<i64>,
471    pub exec_sell_qty: Option<i64>,
472    pub exec_sell_cost: Option<i64>,
473    pub exec_qty: Option<i64>,
474    pub exec_cost: Option<i64>,
475    pub exec_comm: Option<i64>,
476    pub current_timestamp: Option<DateTime<Utc>>,
477    pub current_qty: Option<i64>,
478    pub current_cost: Option<i64>,
479    pub current_comm: Option<i64>,
480    pub realised_cost: Option<i64>,
481    pub unrealised_cost: Option<i64>,
482    pub gross_open_cost: Option<i64>,
483    pub gross_open_premium: Option<i64>,
484    pub gross_exec_cost: Option<i64>,
485    pub is_open: Option<bool>,
486    pub mark_price: Option<f64>,
487    pub mark_value: Option<i64>,
488    pub risk_value: Option<i64>,
489    pub home_notional: Option<f64>,
490    pub foreign_notional: Option<f64>,
491    pub pos_state: Option<Ustr>,
492    pub pos_cost: Option<i64>,
493    pub pos_cost2: Option<i64>,
494    pub pos_cross: Option<i64>,
495    pub pos_init: Option<i64>,
496    pub pos_comm: Option<i64>,
497    pub pos_loss: Option<i64>,
498    pub pos_margin: Option<i64>,
499    pub pos_maint: Option<i64>,
500    pub pos_allowance: Option<i64>,
501    pub taxable_margin: Option<i64>,
502    pub init_margin: Option<i64>,
503    pub maint_margin: Option<i64>,
504    pub session_margin: Option<i64>,
505    pub target_excess_margin: Option<i64>,
506    pub var_margin: Option<i64>,
507    pub realised_gross_pnl: Option<i64>,
508    pub realised_tax: Option<i64>,
509    pub realised_pnl: Option<i64>,
510    pub unrealised_gross_pnl: Option<i64>,
511    pub long_bankrupt: Option<i64>,
512    pub short_bankrupt: Option<i64>,
513    pub tax_base: Option<i64>,
514    pub indicative_tax_rate: Option<f64>,
515    pub indicative_tax: Option<i64>,
516    pub unrealised_tax: Option<i64>,
517    pub unrealised_pnl: Option<i64>,
518    pub unrealised_pnl_pcnt: Option<f64>,
519    pub unrealised_roe_pcnt: Option<f64>,
520    pub avg_cost_price: Option<f64>,
521    pub avg_entry_price: Option<f64>,
522    pub break_even_price: Option<f64>,
523    pub margin_call_price: Option<f64>,
524    pub liquidation_price: Option<f64>,
525    pub bankrupt_price: Option<f64>,
526    pub timestamp: Option<DateTime<Utc>>,
527    pub last_price: Option<f64>,
528    pub last_value: Option<i64>,
529}
530
531#[derive(Clone, Debug, Deserialize)]
532#[serde(rename_all = "camelCase")]
533pub struct BitmexWalletMsg {
534    pub account: i64,
535    pub currency: Ustr,
536    pub prev_deposited: Option<i64>,
537    pub prev_withdrawn: Option<i64>,
538    pub prev_transfer_in: Option<i64>,
539    pub prev_transfer_out: Option<i64>,
540    pub prev_amount: Option<i64>,
541    pub prev_timestamp: Option<DateTime<Utc>>,
542    pub delta_deposited: Option<i64>,
543    pub delta_withdrawn: Option<i64>,
544    pub delta_transfer_in: Option<i64>,
545    pub delta_transfer_out: Option<i64>,
546    pub delta_amount: Option<i64>,
547    pub deposited: Option<i64>,
548    pub withdrawn: Option<i64>,
549    pub transfer_in: Option<i64>,
550    pub transfer_out: Option<i64>,
551    pub amount: Option<i64>,
552    pub pending_credit: Option<i64>,
553    pub pending_debit: Option<i64>,
554    pub confirmed_debit: Option<i64>,
555    pub timestamp: Option<DateTime<Utc>>,
556    pub addr: Option<Ustr>,
557    pub script: Option<Ustr>,
558    pub withdrawal_lock: Option<Vec<Ustr>>,
559}
560
561/// Represents margin account information
562#[derive(Clone, Debug, Deserialize)]
563#[serde(rename_all = "camelCase")]
564pub struct BitmexMarginMsg {
565    /// Account identifier
566    pub account: i64,
567    /// Currency of the margin account
568    pub currency: Ustr,
569    /// Risk limit for the account
570    pub risk_limit: Option<i64>,
571    /// Current amount in the account
572    pub amount: Option<i64>,
573    /// Previously realized PnL
574    pub prev_realised_pnl: Option<i64>,
575    /// Gross commission
576    pub gross_comm: Option<i64>,
577    /// Gross open cost
578    pub gross_open_cost: Option<i64>,
579    /// Gross open premium
580    pub gross_open_premium: Option<i64>,
581    /// Gross execution cost
582    pub gross_exec_cost: Option<i64>,
583    /// Gross mark value
584    pub gross_mark_value: Option<i64>,
585    /// Risk value
586    pub risk_value: Option<i64>,
587    /// Initial margin requirement
588    pub init_margin: Option<i64>,
589    /// Maintenance margin requirement
590    pub maint_margin: Option<i64>,
591    /// Target excess margin
592    pub target_excess_margin: Option<i64>,
593    /// Realized profit and loss
594    pub realised_pnl: Option<i64>,
595    /// Unrealized profit and loss
596    pub unrealised_pnl: Option<i64>,
597    /// Wallet balance
598    pub wallet_balance: Option<i64>,
599    /// Margin balance
600    pub margin_balance: Option<i64>,
601    /// Margin leverage
602    pub margin_leverage: Option<f64>,
603    /// Margin used percentage
604    pub margin_used_pcnt: Option<f64>,
605    /// Excess margin
606    pub excess_margin: Option<i64>,
607    /// Available margin
608    pub available_margin: Option<i64>,
609    /// Withdrawable margin
610    pub withdrawable_margin: Option<i64>,
611    /// Maker fee discount
612    pub maker_fee_discount: Option<f64>,
613    /// Taker fee discount
614    pub taker_fee_discount: Option<f64>,
615    /// Timestamp of the margin update
616    pub timestamp: DateTime<Utc>,
617    /// Foreign margin balance
618    pub foreign_margin_balance: Option<i64>,
619    /// Foreign margin requirement
620    pub foreign_requirement: Option<i64>,
621}
622
623/// Represents a funding rate update.
624#[derive(Clone, Debug, Deserialize)]
625#[serde(rename_all = "camelCase")]
626pub struct BitmexFundingMsg {
627    /// Timestamp of the funding update.
628    pub timestamp: DateTime<Utc>,
629    /// The instrument symbol the funding applies to.
630    pub symbol: Ustr,
631    /// The funding rate for this interval.
632    pub funding_rate: f64,
633    /// The daily funding rate.
634    pub funding_rate_daily: f64,
635}
636
637/// Represents an insurance fund update.
638#[derive(Clone, Debug, Deserialize)]
639#[serde(rename_all = "camelCase")]
640pub struct BitmexInsuranceMsg {
641    /// The currency of the insurance fund.
642    pub currency: Ustr,
643    /// Timestamp of the update.
644    pub timestamp: DateTime<Utc>,
645    /// Current balance of the insurance wallet.
646    pub wallet_balance: i64,
647}
648
649/// Represents a liquidation order.
650#[derive(Clone, Debug, Deserialize)]
651#[serde(rename_all = "camelCase")]
652pub struct BitmexLiquidationMsg {
653    /// Unique order ID of the liquidation.
654    pub order_id: Ustr,
655    /// The instrument symbol being liquidated.
656    pub symbol: Ustr,
657    /// Side of the liquidation ("Buy" or "Sell").
658    pub side: BitmexSide,
659    /// Price of the liquidation order.
660    pub price: f64,
661    /// Remaining quantity to be executed.
662    pub leaves_qty: i64,
663}