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