1use chrono::{DateTime, Utc};
19use serde::{Deserialize, Serialize};
20use ustr::Ustr;
21use uuid::Uuid;
22
23use crate::common::enums::{
24 BitmexContingencyType, BitmexExecInstruction, BitmexExecType, BitmexFairMethod,
25 BitmexInstrumentState, BitmexInstrumentType, BitmexLiquidityIndicator, BitmexMarkMethod,
26 BitmexOrderStatus, BitmexOrderType, BitmexPegPriceType, BitmexSide, BitmexTickDirection,
27 BitmexTimeInForce,
28};
29
30fn deserialize_exec_instructions<'de, D>(
32 deserializer: D,
33) -> Result<Option<Vec<BitmexExecInstruction>>, D::Error>
34where
35 D: serde::Deserializer<'de>,
36{
37 let s: Option<String> = Option::deserialize(deserializer)?;
38 match s {
39 None => Ok(None),
40 Some(ref s) if s.is_empty() => Ok(None),
41 Some(s) => {
42 let instructions: Result<Vec<BitmexExecInstruction>, _> = s
43 .split(',')
44 .map(|inst| {
45 let trimmed = inst.trim();
46 match trimmed {
47 "ParticipateDoNotInitiate" => {
48 Ok(BitmexExecInstruction::ParticipateDoNotInitiate)
49 }
50 "AllOrNone" => Ok(BitmexExecInstruction::AllOrNone),
51 "MarkPrice" => Ok(BitmexExecInstruction::MarkPrice),
52 "IndexPrice" => Ok(BitmexExecInstruction::IndexPrice),
53 "LastPrice" => Ok(BitmexExecInstruction::LastPrice),
54 "Close" => Ok(BitmexExecInstruction::Close),
55 "ReduceOnly" => Ok(BitmexExecInstruction::ReduceOnly),
56 "Fixed" => Ok(BitmexExecInstruction::Fixed),
57 "" => Ok(BitmexExecInstruction::Unknown),
58 _ => Err(serde::de::Error::custom(format!(
59 "Unknown ExecInstruction: {trimmed}"
60 ))),
61 }
62 })
63 .collect();
64 instructions.map(Some)
65 }
66 }
67}
68
69#[derive(Clone, Debug, Serialize, Deserialize)]
70#[serde(rename_all = "camelCase")]
71pub struct BitmexInstrument {
72 pub symbol: Ustr,
73 pub root_symbol: Ustr,
74 pub state: BitmexInstrumentState,
75 #[serde(rename = "typ")]
76 pub instrument_type: BitmexInstrumentType,
77 pub listing: Option<DateTime<Utc>>,
78 pub front: Option<DateTime<Utc>>,
79 pub expiry: Option<DateTime<Utc>>,
80 pub settle: Option<DateTime<Utc>>,
81 pub listed_settle: Option<DateTime<Utc>>,
82 pub position_currency: Option<Ustr>,
83 pub underlying: Ustr,
84 pub quote_currency: Ustr,
85 pub underlying_symbol: Option<Ustr>,
86 pub reference: Option<Ustr>,
87 pub reference_symbol: Option<Ustr>,
88 pub calc_interval: Option<DateTime<Utc>>,
89 pub publish_interval: Option<DateTime<Utc>>,
90 pub publish_time: Option<DateTime<Utc>>,
91 pub max_order_qty: Option<f64>,
92 pub max_price: Option<f64>,
93 pub lot_size: Option<f64>,
94 pub tick_size: f64,
95 pub multiplier: f64,
96 pub settl_currency: Option<Ustr>,
97 pub underlying_to_position_multiplier: Option<f64>,
98 pub underlying_to_settle_multiplier: Option<f64>,
99 pub quote_to_settle_multiplier: Option<f64>,
100 pub is_quanto: bool,
101 pub is_inverse: bool,
102 pub init_margin: Option<f64>,
103 pub maint_margin: Option<f64>,
104 pub risk_limit: Option<f64>,
105 pub risk_step: Option<f64>,
106 pub limit: Option<f64>,
107 pub taxed: Option<bool>,
108 pub deleverage: Option<bool>,
109 pub maker_fee: Option<f64>,
110 pub taker_fee: Option<f64>,
111 pub settlement_fee: Option<f64>,
112 pub funding_base_symbol: Option<Ustr>,
113 pub funding_quote_symbol: Option<Ustr>,
114 pub funding_premium_symbol: Option<Ustr>,
115 pub funding_timestamp: Option<DateTime<Utc>>,
116 pub funding_interval: Option<DateTime<Utc>>,
117 pub funding_rate: Option<f64>,
118 pub indicative_funding_rate: Option<f64>,
119 pub rebalance_timestamp: Option<DateTime<Utc>>,
120 pub rebalance_interval: Option<DateTime<Utc>>,
121 pub prev_close_price: Option<f64>,
122 pub limit_down_price: Option<f64>,
123 pub limit_up_price: Option<f64>,
124 pub prev_total_volume: Option<f64>,
125 pub total_volume: Option<f64>,
126 pub volume: Option<f64>,
127 #[serde(rename = "volume24h")]
128 pub volume_24h: Option<f64>,
129 pub prev_total_turnover: Option<f64>,
130 pub total_turnover: Option<f64>,
131 pub turnover: Option<f64>,
132 #[serde(rename = "turnover24h")]
133 pub turnover_24h: Option<f64>,
134 #[serde(rename = "homeNotional24h")]
135 pub home_notional_24h: Option<f64>,
136 #[serde(rename = "foreignNotional24h")]
137 pub foreign_notional_24h: Option<f64>,
138 #[serde(rename = "prevPrice24h")]
139 pub prev_price_24h: Option<f64>,
140 pub vwap: Option<f64>,
141 pub high_price: Option<f64>,
142 pub low_price: Option<f64>,
143 pub last_price: Option<f64>,
144 pub last_price_protected: Option<f64>,
145 pub last_tick_direction: Option<BitmexTickDirection>,
146 pub last_change_pcnt: Option<f64>,
147 pub bid_price: Option<f64>,
148 pub mid_price: Option<f64>,
149 pub ask_price: Option<f64>,
150 pub impact_bid_price: Option<f64>,
151 pub impact_mid_price: Option<f64>,
152 pub impact_ask_price: Option<f64>,
153 pub has_liquidity: Option<bool>,
154 pub open_interest: Option<f64>,
155 pub open_value: Option<f64>,
156 pub fair_method: Option<BitmexFairMethod>,
157 pub fair_basis_rate: Option<f64>,
158 pub fair_basis: Option<f64>,
159 pub fair_price: Option<f64>,
160 pub mark_method: Option<BitmexMarkMethod>,
161 pub mark_price: Option<f64>,
162 pub indicative_settle_price: Option<f64>,
163 pub settled_price_adjustment_rate: Option<f64>,
164 pub settled_price: Option<f64>,
165 pub instant_pnl: bool,
166 pub min_tick: Option<f64>,
167 pub funding_base_rate: Option<f64>,
168 pub funding_quote_rate: Option<f64>,
169 pub capped: Option<bool>,
170 pub opening_timestamp: Option<DateTime<Utc>>,
171 pub closing_timestamp: Option<DateTime<Utc>>,
172 pub timestamp: DateTime<Utc>,
173}
174
175#[derive(Clone, Debug, Serialize, Deserialize)]
177#[serde(rename_all = "camelCase")]
178pub struct BitmexExecution {
179 #[serde(rename = "execID")]
180 pub exec_id: Uuid,
181 #[serde(rename = "orderID")]
182 pub order_id: Option<Uuid>,
183 #[serde(rename = "clOrdID")]
184 pub cl_ord_id: Option<Ustr>,
185 #[serde(rename = "clOrdLinkID")]
186 pub cl_ord_link_id: Option<Ustr>,
187 pub account: i64,
188 pub symbol: Option<Ustr>,
189 pub side: Option<BitmexSide>,
190 pub last_qty: i64,
191 pub last_px: f64,
192 pub underlying_last_px: Option<f64>,
193 pub last_mkt: Option<Ustr>,
194 pub last_liquidity_ind: Option<BitmexLiquidityIndicator>,
195 pub order_qty: Option<i64>,
196 pub price: Option<f64>,
197 pub display_qty: Option<i64>,
198 pub stop_px: Option<f64>,
199 pub peg_offset_value: Option<f64>,
200 pub peg_price_type: Option<BitmexPegPriceType>,
201 pub currency: Option<Ustr>,
202 pub settl_currency: Option<Ustr>,
203 pub exec_type: BitmexExecType,
204 pub ord_type: BitmexOrderType,
205 pub time_in_force: BitmexTimeInForce,
206 #[serde(default, deserialize_with = "deserialize_exec_instructions")]
207 pub exec_inst: Option<Vec<BitmexExecInstruction>>,
208 pub contingency_type: Option<BitmexContingencyType>,
209 pub ex_destination: Option<Ustr>,
210 pub ord_status: Option<BitmexOrderStatus>,
211 pub triggered: Option<Ustr>,
212 pub working_indicator: Option<bool>,
213 pub ord_rej_reason: Option<Ustr>,
214 pub leaves_qty: Option<i64>,
215 pub cum_qty: Option<i64>,
216 pub avg_px: Option<f64>,
217 pub commission: Option<f64>,
218 pub trade_publish_indicator: Option<Ustr>,
219 pub multi_leg_reporting_type: Option<Ustr>,
220 pub text: Option<Ustr>,
221 pub trd_match_id: Option<Uuid>,
222 pub exec_cost: Option<i64>,
223 pub exec_comm: Option<i64>,
224 pub home_notional: Option<f64>,
225 pub foreign_notional: Option<f64>,
226 pub transact_time: Option<DateTime<Utc>>,
227 pub timestamp: Option<DateTime<Utc>>,
228}
229
230#[derive(Clone, Debug, Serialize, Deserialize)]
232#[serde(rename_all = "camelCase")]
233pub struct BitmexFunding {
234 pub timestamp: DateTime<Utc>,
235 pub symbol: Ustr,
236 pub funding_interval: Option<DateTime<Utc>>,
237 pub funding_rate: Option<f64>,
238 pub funding_rate_daily: Option<f64>,
239}
240
241#[derive(Clone, Debug, Serialize, Deserialize, Default)]
242#[serde(rename_all = "camelCase")]
243pub struct BitmexInstrumentInterval {
244 pub intervals: Vec<String>,
245 pub symbols: Vec<String>,
246}
247
248#[derive(Clone, Debug, Serialize, Deserialize)]
249#[serde(rename_all = "camelCase")]
250pub struct BitmexIndexComposite {
251 pub timestamp: DateTime<Utc>,
252 pub symbol: Option<String>,
253 pub index_symbol: Option<String>,
254 pub reference: Option<String>,
255 pub last_price: Option<f64>,
256 pub weight: Option<f64>,
257 pub logged: Option<DateTime<Utc>>,
258}
259
260#[derive(Clone, Debug, Serialize, Deserialize)]
262#[serde(rename_all = "camelCase")]
263pub struct BitmexInsurance {
264 pub currency: Ustr,
265 pub timestamp: DateTime<Utc>,
266 pub wallet_balance: Option<i64>,
267}
268
269#[derive(Clone, Debug, Serialize, Deserialize)]
271#[serde(rename_all = "camelCase")]
272pub struct BitmexLiquidation {
273 #[serde(rename = "orderID")]
274 pub order_id: Uuid,
275 pub symbol: Option<String>,
276 pub side: Option<BitmexSide>,
277 pub price: Option<f64>,
278 pub leaves_qty: Option<i64>,
279}
280
281#[derive(Clone, Debug, Serialize, Deserialize)]
283#[serde(rename_all = "camelCase")]
284pub struct BitmexOrder {
285 #[serde(rename = "orderID")]
286 pub order_id: Uuid,
287 #[serde(rename = "clOrdID")]
288 pub cl_ord_id: Option<Ustr>,
289 #[serde(rename = "clOrdLinkID")]
290 pub cl_ord_link_id: Option<Ustr>,
291 pub account: i64,
292 pub symbol: Option<Ustr>,
293 pub side: Option<BitmexSide>,
294 pub order_qty: Option<i64>,
295 pub price: Option<f64>,
296 pub display_qty: Option<i64>,
297 pub stop_px: Option<f64>,
298 pub peg_offset_value: Option<f64>,
299 pub peg_price_type: Option<BitmexPegPriceType>,
300 pub currency: Option<Ustr>,
301 pub settl_currency: Option<Ustr>,
302 pub ord_type: Option<BitmexOrderType>,
303 pub time_in_force: Option<BitmexTimeInForce>,
304 #[serde(default, deserialize_with = "deserialize_exec_instructions")]
305 pub exec_inst: Option<Vec<BitmexExecInstruction>>,
306 pub contingency_type: Option<BitmexContingencyType>,
307 pub ex_destination: Option<Ustr>,
308 pub ord_status: Option<BitmexOrderStatus>,
309 pub triggered: Option<Ustr>,
310 pub working_indicator: Option<bool>,
311 pub ord_rej_reason: Option<Ustr>,
312 pub leaves_qty: Option<i64>,
313 pub cum_qty: Option<i64>,
314 pub avg_px: Option<f64>,
315 pub multi_leg_reporting_type: Option<Ustr>,
316 pub text: Option<Ustr>,
317 pub transact_time: Option<DateTime<Utc>>,
318 pub timestamp: Option<DateTime<Utc>>,
319}
320
321#[derive(Clone, Debug, Serialize, Deserialize)]
322#[serde(rename_all = "camelCase")]
323pub struct BitmexOrderBookL2 {
324 pub symbol: Ustr,
325 pub id: i64,
326 pub side: BitmexSide,
327 pub size: Option<i64>,
328 pub price: Option<f64>,
329}
330
331#[derive(Clone, Debug, Serialize, Deserialize)]
333#[serde(rename_all = "camelCase")]
334pub struct BitmexPosition {
335 pub account: i64,
336 pub symbol: Ustr,
337 pub currency: Option<Ustr>,
338 pub underlying: Option<Ustr>,
339 pub quote_currency: Option<Ustr>,
340 pub commission: Option<f64>,
341 pub init_margin_req: Option<f64>,
342 pub maint_margin_req: Option<f64>,
343 pub risk_limit: Option<i64>,
344 pub leverage: Option<f64>,
345 pub cross_margin: Option<bool>,
346 pub deleverage_percentile: Option<f64>,
347 pub rebalanced_pnl: Option<i64>,
348 pub prev_realised_pnl: Option<i64>,
349 pub prev_unrealised_pnl: Option<i64>,
350 pub prev_close_price: Option<f64>,
351 pub opening_timestamp: Option<DateTime<Utc>>,
352 pub opening_qty: Option<i64>,
353 pub opening_cost: Option<i64>,
354 pub opening_comm: Option<i64>,
355 pub open_order_buy_qty: Option<i64>,
356 pub open_order_buy_cost: Option<i64>,
357 pub open_order_buy_premium: Option<i64>,
358 pub open_order_sell_qty: Option<i64>,
359 pub open_order_sell_cost: Option<i64>,
360 pub open_order_sell_premium: Option<i64>,
361 pub exec_buy_qty: Option<i64>,
362 pub exec_buy_cost: Option<i64>,
363 pub exec_sell_qty: Option<i64>,
364 pub exec_sell_cost: Option<i64>,
365 pub exec_qty: Option<i64>,
366 pub exec_cost: Option<i64>,
367 pub exec_comm: Option<i64>,
368 pub current_timestamp: Option<DateTime<Utc>>,
369 pub current_qty: Option<i64>,
370 pub current_cost: Option<i64>,
371 pub current_comm: Option<i64>,
372 pub realised_cost: Option<i64>,
373 pub unrealised_cost: Option<i64>,
374 pub gross_open_cost: Option<i64>,
375 pub gross_open_premium: Option<i64>,
376 pub gross_exec_cost: Option<i64>,
377 pub is_open: Option<bool>,
378 pub mark_price: Option<f64>,
379 pub mark_value: Option<i64>,
380 pub risk_value: Option<i64>,
381 pub home_notional: Option<f64>,
382 pub foreign_notional: Option<f64>,
383 pub pos_state: Option<Ustr>,
384 pub pos_cost: Option<i64>,
385 pub pos_cost2: Option<i64>,
386 pub pos_cross: Option<i64>,
387 pub pos_init: Option<i64>,
388 pub pos_comm: Option<i64>,
389 pub pos_loss: Option<i64>,
390 pub pos_margin: Option<i64>,
391 pub pos_maint: Option<i64>,
392 pub pos_allowance: Option<i64>,
393 pub taxable_margin: Option<i64>,
394 pub init_margin: Option<i64>,
395 pub maint_margin: Option<i64>,
396 pub session_margin: Option<i64>,
397 pub target_excess_margin: Option<i64>,
398 pub var_margin: Option<i64>,
399 pub realised_gross_pnl: Option<i64>,
400 pub realised_tax: Option<i64>,
401 pub realised_pnl: Option<i64>,
402 pub unrealised_gross_pnl: Option<i64>,
403 pub long_bankrupt: Option<i64>,
404 pub short_bankrupt: Option<i64>,
405 pub tax_base: Option<i64>,
406 pub indicative_tax_rate: Option<f64>,
407 pub indicative_tax: Option<i64>,
408 pub unrealised_tax: Option<i64>,
409 pub unrealised_pnl: Option<i64>,
410 pub unrealised_pnl_pcnt: Option<f64>,
411 pub unrealised_roe_pcnt: Option<f64>,
412 pub avg_cost_price: Option<f64>,
413 pub avg_entry_price: Option<f64>,
414 pub break_even_price: Option<f64>,
415 pub margin_call_price: Option<f64>,
416 pub liquidation_price: Option<f64>,
417 pub bankrupt_price: Option<f64>,
418 pub timestamp: Option<DateTime<Utc>>,
419 pub last_price: Option<f64>,
420 pub last_value: Option<i64>,
421}
422
423#[derive(Clone, Debug, Deserialize)]
425#[serde(rename_all = "camelCase")]
426pub struct BitmexQuote {
427 pub timestamp: DateTime<Utc>,
428 pub symbol: Ustr,
429 pub bid_size: Option<i64>,
430 pub bid_price: Option<f64>,
431 pub ask_price: Option<f64>,
432 pub ask_size: Option<i64>,
433}
434
435#[derive(Clone, Debug, Deserialize)]
437#[serde(rename_all = "camelCase")]
438pub struct BitmexSettlement {
439 pub timestamp: DateTime<Utc>,
440 pub symbol: Ustr,
441 pub settlement_type: Option<String>,
442 pub settled_price: Option<f64>,
443 pub option_strike_price: Option<f64>,
444 pub option_underlying_price: Option<f64>,
445 pub bankrupt: Option<i64>,
446 pub tax_base: Option<i64>,
447 pub tax_rate: Option<f64>,
448}
449
450#[derive(Clone, Debug, Deserialize)]
452#[serde(rename_all = "camelCase")]
453pub struct BitmexStats {
454 pub root_symbol: Ustr,
455 pub currency: Option<String>,
456 pub volume24h: Option<i64>,
457 pub turnover24h: Option<i64>,
458 pub open_interest: Option<i64>,
459 pub open_value: Option<i64>,
460}
461
462#[derive(Clone, Debug, Deserialize)]
463#[serde(rename_all = "camelCase")]
464pub struct BitmexStatsHistory {
465 pub date: DateTime<Utc>,
466 pub root_symbol: Ustr,
467 pub currency: Option<String>,
468 pub volume: Option<i64>,
469 pub turnover: Option<i64>,
470}
471
472#[derive(Clone, Debug, Deserialize)]
473#[serde(rename_all = "camelCase")]
474pub struct BitmexStatsUSD {
475 pub root_symbol: Ustr,
476 pub currency: Option<String>,
477 pub turnover24h: Option<i64>,
478 pub turnover30d: Option<i64>,
479 pub turnover365d: Option<i64>,
480 pub turnover: Option<i64>,
481}
482
483#[derive(Clone, Debug, Deserialize)]
485#[serde(rename_all = "camelCase")]
486pub struct BitmexTrade {
487 pub timestamp: DateTime<Utc>,
488 pub symbol: Ustr,
489 pub side: Option<BitmexSide>,
490 pub size: i64,
491 pub price: f64,
492 pub tick_direction: Option<String>,
493 #[serde(rename = "trdMatchID")]
494 pub trd_match_id: Option<Uuid>,
495 pub gross_value: Option<i64>,
496 pub home_notional: Option<f64>,
497 pub foreign_notional: Option<f64>,
498}
499
500#[derive(Clone, Debug, Deserialize)]
501#[serde(rename_all = "camelCase")]
502pub struct BitmexTradeBin {
503 pub timestamp: DateTime<Utc>,
504 pub symbol: Ustr,
505 pub open: Option<f64>,
506 pub high: Option<f64>,
507 pub low: Option<f64>,
508 pub close: Option<f64>,
509 pub trades: Option<i64>,
510 pub volume: Option<i64>,
511 pub vwap: Option<f64>,
512 pub last_size: Option<i64>,
513 pub turnover: Option<i64>,
514 pub home_notional: Option<f64>,
515 pub foreign_notional: Option<f64>,
516}
517
518#[derive(Clone, Debug, Deserialize)]
519#[serde(rename_all = "camelCase")]
520pub struct BitmexWallet {
521 pub account: i64,
522 pub currency: Ustr,
523 pub prev_deposited: Option<i64>,
524 pub prev_withdrawn: Option<i64>,
525 pub prev_transfer_in: Option<i64>,
526 pub prev_transfer_out: Option<i64>,
527 pub prev_amount: Option<i64>,
528 pub prev_timestamp: Option<DateTime<Utc>>,
529 pub delta_deposited: Option<i64>,
530 pub delta_withdrawn: Option<i64>,
531 pub delta_transfer_in: Option<i64>,
532 pub delta_transfer_out: Option<i64>,
533 pub delta_amount: Option<i64>,
534 pub deposited: Option<i64>,
535 pub withdrawn: Option<i64>,
536 pub transfer_in: Option<i64>,
537 pub transfer_out: Option<i64>,
538 pub amount: Option<i64>,
539 pub pending_credit: Option<i64>,
540 pub pending_debit: Option<i64>,
541 pub confirmed_debit: Option<i64>,
542 pub timestamp: Option<DateTime<Utc>>,
543 pub addr: Option<Ustr>,
544 pub script: Option<Ustr>,
545 pub withdrawal_lock: Option<Vec<Ustr>>,
546}
547
548#[derive(Clone, Debug, Deserialize, Default)]
549#[serde(rename_all = "camelCase")]
550pub struct BitmexTransaction {
551 pub transact_id: Option<Uuid>,
552 pub account: Option<i64>,
553 pub currency: Option<Ustr>,
554 pub transact_type: Option<Ustr>,
555 pub amount: Option<i64>,
556 pub fee: Option<i64>,
557 pub transact_status: Option<Ustr>,
558 pub address: Option<Ustr>,
559 pub tx: Option<Ustr>,
560 pub text: Option<Ustr>,
561 pub transact_time: Option<DateTime<Utc>>,
562 pub timestamp: Option<DateTime<Utc>>,
563}
564
565#[derive(Clone, Debug, Deserialize)]
567#[serde(rename_all = "camelCase")]
568pub struct BitmexAnnouncement {
569 pub id: i32,
570 pub link: Option<String>,
571 pub title: Option<String>,
572 pub content: Option<String>,
573 pub date: Option<DateTime<Utc>>,
574}
575
576#[derive(Clone, Debug, Deserialize)]
578#[serde(rename_all = "camelCase")]
579pub struct BitmexAPIKey {
580 pub id: String,
581 pub secret: Option<String>,
582 pub name: String,
583 pub nonce: i64,
584 pub cidr: Option<String>,
585 pub permissions: Vec<serde_json::Value>,
586 pub enabled: Option<bool>,
587 pub user_id: i32,
588 pub created: Option<DateTime<Utc>>,
589}
590
591#[derive(Clone, Debug, Deserialize)]
593#[serde(rename_all = "camelCase")]
594pub struct BitmexGlobalNotification {
595 pub id: Option<i32>,
596 pub date: DateTime<Utc>,
597 pub title: String,
598 pub body: String,
599 pub ttl: i32,
600 pub r#type: Option<String>,
601 pub closable: Option<bool>,
602 pub persist: Option<bool>,
603 pub wait_for_visibility: Option<bool>,
604 pub sound: Option<String>,
605}
606
607#[derive(Clone, Debug, Deserialize)]
608#[serde(rename_all = "camelCase")]
609pub struct BitmexAccessToken {
610 pub id: String,
611 pub ttl: Option<f64>,
613 pub created: Option<DateTime<Utc>>,
614 pub user_id: Option<f64>,
615}
616
617#[derive(Clone, Debug, Deserialize)]
619#[serde(rename_all = "camelCase")]
620pub struct BitmexQuoteFillRatio {
621 pub date: DateTime<Utc>,
622 pub account: Option<f64>,
623 pub quote_count: Option<f64>,
624 pub dealt_count: Option<f64>,
625 pub quotes_mavg7: Option<f64>,
626 pub dealt_mavg7: Option<f64>,
627 pub quote_fill_ratio_mavg7: Option<f64>,
628}
629
630#[derive(Clone, Debug, Deserialize)]
632#[serde(rename_all = "camelCase")]
633pub struct BitmexUser {
634 pub id: Option<i32>,
635 pub owner_id: Option<i32>,
636 pub firstname: Option<String>,
637 pub lastname: Option<String>,
638 pub username: String,
639 pub email: String,
640 pub phone: Option<String>,
641 pub created: Option<DateTime<Utc>>,
642 pub last_updated: Option<DateTime<Utc>>,
643 pub preferences: BitmexUserPreferences,
644 #[serde(rename = "TFAEnabled")]
645 pub tfa_enabled: Option<String>,
646 #[serde(rename = "affiliateID")]
647 pub affiliate_id: Option<String>,
648 pub pgp_pub_key: Option<String>,
649 pub country: Option<String>,
650 pub geoip_country: Option<String>,
651 pub geoip_region: Option<String>,
652 pub typ: Option<String>,
653}
654
655#[derive(Clone, Debug, Deserialize)]
656#[serde(rename_all = "camelCase")]
657pub struct BitmexMargin {
658 pub account: i64,
659 pub currency: Ustr,
660 pub risk_limit: Option<i64>,
661 pub prev_state: Option<String>,
662 pub state: Option<String>,
663 pub action: Option<String>,
664 pub amount: Option<i64>,
665 pub pending_credit: Option<i64>,
666 pub pending_debit: Option<i64>,
667 pub confirmed_debit: Option<i64>,
668 pub prev_realised_pnl: Option<i64>,
669 pub prev_unrealised_pnl: Option<i64>,
670 pub gross_comm: Option<i64>,
671 pub gross_open_cost: Option<i64>,
672 pub gross_open_premium: Option<i64>,
673 pub gross_exec_cost: Option<i64>,
674 pub gross_mark_value: Option<i64>,
675 pub risk_value: Option<i64>,
676 pub taxable_margin: Option<i64>,
677 pub init_margin: Option<i64>,
678 pub maint_margin: Option<i64>,
679 pub session_margin: Option<i64>,
680 pub target_excess_margin: Option<i64>,
681 pub var_margin: Option<i64>,
682 pub realised_pnl: Option<i64>,
683 pub unrealised_pnl: Option<i64>,
684 pub indicative_tax: Option<i64>,
685 pub unrealised_profit: Option<i64>,
686 pub synthetic_margin: Option<i64>,
687 pub wallet_balance: Option<i64>,
688 pub margin_balance: Option<i64>,
689 pub margin_balance_pcnt: Option<f64>,
690 pub margin_leverage: Option<f64>,
691 pub margin_used_pcnt: Option<f64>,
692 pub excess_margin: Option<i64>,
693 pub excess_margin_pcnt: Option<f64>,
694 pub available_margin: Option<i64>,
695 pub withdrawable_margin: Option<i64>,
696 pub timestamp: Option<DateTime<Utc>>,
697 pub gross_last_value: Option<i64>,
698 pub commission: Option<f64>,
699}
700
701#[derive(Clone, Debug, Deserialize)]
703#[serde(rename_all = "camelCase")]
704pub struct BitmexCommunicationToken {
705 pub id: String,
706 #[serde(rename = "userId")]
707 pub user_id: i32,
708 #[serde(rename = "deviceToken")]
709 pub device_token: String,
710 pub channel: String,
711}
712
713#[derive(Clone, Debug, Deserialize)]
715#[serde(rename_all = "camelCase")]
716pub struct BitmexUserEvent {
717 pub id: Option<f64>,
718 #[serde(rename = "type")]
719 pub r#type: String,
720 pub status: String,
721 #[serde(rename = "userId")]
722 pub user_id: f64,
723 #[serde(rename = "createdById")]
724 pub created_by_id: Option<f64>,
725 pub ip: Option<String>,
726 #[serde(rename = "geoipCountry")]
727 pub geoip_country: Option<String>,
728 #[serde(rename = "geoipRegion")]
729 pub geoip_region: Option<String>,
730 #[serde(rename = "geoipSubRegion")]
731 pub geoip_sub_region: Option<String>,
732 #[serde(rename = "eventMeta")]
733 pub event_meta: Option<BitmexEventMetaEventMeta>,
734 pub created: DateTime<Utc>,
735}
736
737#[derive(Clone, Debug, Deserialize, Default)]
738#[allow(dead_code)]
739pub struct BitmexEventMetaEventMeta(serde_json::Value);
740
741#[derive(Clone, Debug, Deserialize, Default)]
742#[serde(rename_all = "camelCase")]
743pub struct BitmexUserPreferences {
744 pub alert_on_liquidations: Option<bool>,
745 pub animations_enabled: Option<bool>,
746 pub announcements_last_seen: Option<DateTime<Utc>>,
747 pub chat_channel_id: Option<f64>,
748 pub color_theme: Option<String>,
749 pub currency: Option<Ustr>,
750 pub debug: Option<bool>,
751 pub disable_emails: Option<Vec<String>>,
752 pub disable_push: Option<Vec<String>>,
753 pub hide_confirm_dialogs: Option<Vec<String>>,
754 pub hide_connection_modal: Option<bool>,
755 pub hide_from_leaderboard: Option<bool>,
756 pub hide_name_from_leaderboard: Option<bool>,
757 pub hide_notifications: Option<Vec<String>>,
758 pub locale: Option<String>,
759 pub msgs_seen: Option<Vec<String>>,
760 pub order_book_binning: Option<BitmexOrderBookBinning>,
761 pub order_book_type: Option<String>,
762 pub order_clear_immediate: Option<bool>,
763 pub order_controls_plus_minus: Option<bool>,
764 pub show_locale_numbers: Option<bool>,
765 pub sounds: Option<Vec<String>>,
766 #[serde(rename = "strictIPCheck")]
767 pub strict_ip_check: Option<bool>,
768 pub strict_timeout: Option<bool>,
769 pub ticker_group: Option<String>,
770 pub ticker_pinned: Option<bool>,
771 pub trade_layout: Option<String>,
772}
773
774#[derive(Clone, Debug, Deserialize, Default)]
775#[allow(dead_code)]
776pub struct BitmexOrderBookBinning(serde_json::Value);
777
778#[derive(Clone, Debug, Deserialize)]
780#[serde(rename_all = "camelCase")]
781pub struct BitmexApiInfo {
782 pub name: String,
784 pub version: String,
786 pub timestamp: u64,
788}
789
790#[cfg(test)]
795mod tests {
796 use rstest::rstest;
797 use serde_json::json;
798
799 use super::*;
800
801 #[rstest]
802 #[case(json!(null), None)]
803 #[case(json!(""), None)]
804 #[case(json!("ParticipateDoNotInitiate"), Some(vec![BitmexExecInstruction::ParticipateDoNotInitiate]))]
805 #[case(json!("ReduceOnly"), Some(vec![BitmexExecInstruction::ReduceOnly]))]
806 #[case(json!("LastPrice,Close"), Some(vec![BitmexExecInstruction::LastPrice, BitmexExecInstruction::Close]))]
807 #[case(
808 json!("ParticipateDoNotInitiate,ReduceOnly"),
809 Some(vec![BitmexExecInstruction::ParticipateDoNotInitiate, BitmexExecInstruction::ReduceOnly])
810 )]
811 #[case(
812 json!("MarkPrice,IndexPrice,AllOrNone"),
813 Some(vec![BitmexExecInstruction::MarkPrice, BitmexExecInstruction::IndexPrice, BitmexExecInstruction::AllOrNone])
814 )]
815 #[case(json!("Fixed"), Some(vec![BitmexExecInstruction::Fixed]))]
816 fn test_deserialize_exec_instructions(
817 #[case] input: serde_json::Value,
818 #[case] expected: Option<Vec<BitmexExecInstruction>>,
819 ) {
820 #[derive(Deserialize)]
821 struct TestStruct {
822 #[serde(default, deserialize_with = "deserialize_exec_instructions")]
823 exec_inst: Option<Vec<BitmexExecInstruction>>,
824 }
825
826 let test_json = json!({
827 "exec_inst": input
828 });
829
830 let result: TestStruct = serde_json::from_value(test_json).unwrap();
831 assert_eq!(result.exec_inst, expected);
832 }
833
834 #[rstest]
835 fn test_deserialize_exec_instructions_with_spaces() {
836 #[derive(Deserialize)]
837 struct TestStruct {
838 #[serde(default, deserialize_with = "deserialize_exec_instructions")]
839 exec_inst: Option<Vec<BitmexExecInstruction>>,
840 }
841
842 let test_json = json!({
843 "exec_inst": "LastPrice , Close , ReduceOnly"
844 });
845
846 let result: TestStruct = serde_json::from_value(test_json).unwrap();
847 assert_eq!(
848 result.exec_inst,
849 Some(vec![
850 BitmexExecInstruction::LastPrice,
851 BitmexExecInstruction::Close,
852 BitmexExecInstruction::ReduceOnly,
853 ])
854 );
855 }
856
857 #[rstest]
858 fn test_deserialize_order_with_exec_instructions() {
859 let order_json = json!({
860 "account": 123456,
861 "symbol": "XBTUSD",
862 "orderID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
863 "side": "Buy",
864 "ordType": "Limit",
865 "timeInForce": "GoodTillCancel",
866 "ordStatus": "New",
867 "orderQty": 100,
868 "cumQty": 0,
869 "price": 50000.0,
870 "execInst": "ParticipateDoNotInitiate,ReduceOnly",
871 "transactTime": "2024-01-01T00:00:00.000Z",
872 "timestamp": "2024-01-01T00:00:00.000Z"
873 });
874
875 let order: BitmexOrder = serde_json::from_value(order_json).unwrap();
876 assert_eq!(
877 order.exec_inst,
878 Some(vec![
879 BitmexExecInstruction::ParticipateDoNotInitiate,
880 BitmexExecInstruction::ReduceOnly,
881 ])
882 );
883 }
884}