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