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