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