1use 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#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct BitmexAuthentication {
43 pub op: BitmexWsAuthAction,
44 pub args: (String, i64, String),
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct BitmexSubscription {
50 pub op: BitmexWsOperation,
51 pub args: Vec<String>,
52}
53
54#[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#[derive(Debug, Display, Deserialize)]
69#[serde(untagged)]
70pub enum BitmexWsMessage {
71 Table(BitmexTableMessage),
73 Welcome {
75 info: String,
77 version: String,
79 timestamp: DateTime<Utc>,
81 docs: String,
83 #[serde(rename = "heartbeatEnabled")]
85 heartbeat_enabled: bool,
86 limit: BitmexRateLimit,
88 },
89 Subscription {
91 success: bool,
93 subscribe: Option<String>,
95 error: Option<String>,
97 },
98 Error {
100 status: u16,
101 error: String,
102 meta: HashMap<String, String>,
103 request: BitmexHttpRequest,
104 },
105 #[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#[derive(Debug, Deserialize)]
118pub struct BitmexRateLimit {
119 pub remaining: i32,
121}
122
123#[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#[derive(Clone, Debug, Deserialize)]
205#[serde(rename_all = "camelCase")]
206pub struct BitmexOrderBookMsg {
207 pub symbol: Ustr,
209 pub id: u64,
211 pub side: BitmexSide,
213 pub size: Option<u64>,
215 pub price: f64,
217 pub timestamp: DateTime<Utc>,
219 pub transact_time: DateTime<Utc>,
221}
222
223#[derive(Clone, Debug, Deserialize)]
225#[serde(rename_all = "camelCase")]
226pub struct BitmexOrderBook10Msg {
227 pub symbol: Ustr,
229 pub bids: Vec<[f64; 2]>,
231 pub asks: Vec<[f64; 2]>,
233 pub timestamp: DateTime<Utc>,
235}
236
237#[derive(Clone, Debug, Deserialize)]
239#[serde(rename_all = "camelCase")]
240pub struct BitmexQuoteMsg {
241 pub symbol: Ustr,
243 pub bid_price: Option<f64>,
245 pub bid_size: Option<u64>,
247 pub ask_price: Option<f64>,
249 pub ask_size: Option<u64>,
251 pub timestamp: DateTime<Utc>,
253}
254
255#[derive(Clone, Debug, Deserialize)]
257#[serde(rename_all = "camelCase")]
258pub struct BitmexTradeMsg {
259 pub timestamp: DateTime<Utc>,
261 pub symbol: Ustr,
263 pub side: BitmexSide,
265 pub size: u64,
267 pub price: f64,
269 pub tick_direction: BitmexTickDirection,
271 #[serde(rename = "trdMatchID")]
273 pub trd_match_id: Option<Uuid>,
274 pub gross_value: Option<i64>,
276 pub home_notional: Option<f64>,
278 pub foreign_notional: Option<f64>,
280 #[serde(rename = "trdType")]
282 pub trade_type: Ustr, }
284
285#[derive(Clone, Debug, Deserialize)]
286#[serde(rename_all = "camelCase")]
287pub struct BitmexTradeBinMsg {
288 pub timestamp: DateTime<Utc>,
290 pub symbol: Ustr,
292 pub open: f64,
294 pub high: f64,
296 pub low: f64,
298 pub close: f64,
300 pub trades: i64,
302 pub volume: i64,
304 pub vwap: f64,
306 pub last_size: i64,
308 pub turnover: i64,
310 pub home_notional: f64,
312 pub foreign_notional: f64,
314}
315
316#[derive(Clone, Debug, Deserialize)]
318#[serde(rename_all = "camelCase")]
319pub struct BitmexInstrumentMsg {
320 pub symbol: Ustr,
322 pub last_price: Option<f64>,
324 pub last_tick_direction: Option<BitmexTickDirection>,
326 pub mark_price: Option<f64>,
328 pub index_price: Option<f64>,
330 pub indicative_settle_price: Option<f64>,
332 pub open_interest: Option<i64>,
334 pub open_value: Option<i64>,
336 pub fair_basis: Option<f64>,
338 pub fair_basis_rate: Option<f64>,
340 pub fair_price: Option<f64>,
342 pub mark_method: Option<Ustr>,
344 pub indicative_tax_rate: Option<f64>,
346 pub timestamp: DateTime<Utc>,
348}
349
350#[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#[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#[derive(Clone, Debug)]
412pub enum OrderData {
413 Full(BitmexOrderMsg),
414 Update(BitmexOrderUpdateMsg),
415}
416
417fn 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 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#[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#[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#[derive(Clone, Debug, Deserialize)]
621#[serde(rename_all = "camelCase")]
622pub struct BitmexMarginMsg {
623 pub account: i64,
625 pub currency: Ustr,
627 pub risk_limit: Option<i64>,
629 pub amount: Option<i64>,
631 pub prev_realised_pnl: Option<i64>,
633 pub gross_comm: Option<i64>,
635 pub gross_open_cost: Option<i64>,
637 pub gross_open_premium: Option<i64>,
639 pub gross_exec_cost: Option<i64>,
641 pub gross_mark_value: Option<i64>,
643 pub risk_value: Option<i64>,
645 pub init_margin: Option<i64>,
647 pub maint_margin: Option<i64>,
649 pub target_excess_margin: Option<i64>,
651 pub realised_pnl: Option<i64>,
653 pub unrealised_pnl: Option<i64>,
655 pub wallet_balance: Option<i64>,
657 pub margin_balance: Option<i64>,
659 pub margin_leverage: Option<f64>,
661 pub margin_used_pcnt: Option<f64>,
663 pub excess_margin: Option<i64>,
665 pub available_margin: Option<i64>,
667 pub withdrawable_margin: Option<i64>,
669 pub maker_fee_discount: Option<f64>,
671 pub taker_fee_discount: Option<f64>,
673 pub timestamp: DateTime<Utc>,
675 pub foreign_margin_balance: Option<i64>,
677 pub foreign_requirement: Option<i64>,
679}
680
681#[derive(Clone, Debug, Deserialize)]
683#[serde(rename_all = "camelCase")]
684pub struct BitmexFundingMsg {
685 pub timestamp: DateTime<Utc>,
687 pub symbol: Ustr,
689 pub funding_rate: f64,
691 pub funding_rate_daily: f64,
693}
694
695#[derive(Clone, Debug, Deserialize)]
697#[serde(rename_all = "camelCase")]
698pub struct BitmexInsuranceMsg {
699 pub currency: Ustr,
701 pub timestamp: DateTime<Utc>,
703 pub wallet_balance: i64,
705}
706
707#[derive(Clone, Debug, Deserialize)]
709#[serde(rename_all = "camelCase")]
710pub struct BitmexLiquidationMsg {
711 pub order_id: Ustr,
713 pub symbol: Ustr,
715 pub side: BitmexSide,
717 pub price: f64,
719 pub leaves_qty: i64,
721}