1use rust_decimal::Decimal;
7use serde::{Deserialize, Serialize};
8
9use crate::types::common::BuySell;
10
11
12#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(rename_all = "lowercase")]
18pub enum ContractType {
19 #[default]
21 Perpetual,
22 #[serde(alias = "futures_inverse", alias = "futures_vanilla")]
24 FixedMaturity,
25 #[serde(alias = "spot index")]
27 Index,
28}
29
30#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
32#[serde(rename_all = "snake_case")]
33pub enum FuturesOrderType {
34 #[serde(alias = "lmt")]
36 #[default]
37 Limit,
38 #[serde(alias = "mkt")]
40 Market,
41 #[serde(alias = "stp")]
43 Stop,
44 TakeProfit,
46 #[serde(alias = "ioc")]
48 ImmediateOrCancel,
49 PostOnly,
51}
52
53#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
55#[serde(rename_all = "lowercase")]
56pub enum FuturesOrderStatus {
57 #[serde(alias = "untouched")]
59 #[default]
60 Open,
61 #[serde(alias = "partiallyFilled")]
63 PartiallyFilled,
64 Filled,
66 Cancelled,
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
72#[serde(rename_all = "lowercase")]
73pub enum FillType {
74 Maker,
76 Taker,
78 Liquidation,
80 Assignee,
82 Assignor,
84}
85
86
87#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub enum AccountType {
94 #[serde(alias = "cashAccount")]
96 #[default]
97 Cash,
98 #[serde(alias = "marginAccount")]
100 Margin,
101 #[serde(alias = "multiCollateralMarginAccount")]
103 MultiCollateral,
104 FlexFutures,
106}
107
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
114#[serde(rename_all = "camelCase")]
115pub struct FuturesPosition {
116 pub symbol: String,
118 pub side: BuySell,
120 pub size: Decimal,
122 #[serde(alias = "price")]
124 pub entry_price: Decimal,
125 #[serde(default)]
127 pub mark_price: Option<Decimal>,
128 #[serde(default)]
130 pub liquidation_threshold: Option<Decimal>,
131 #[serde(default)]
133 pub unrealized_pnl: Option<Decimal>,
134 #[serde(default, alias = "unrealizedFunding")]
136 pub unrealized_funding: Option<Decimal>,
137 #[serde(default)]
139 pub initial_margin: Option<Decimal>,
140 #[serde(default)]
142 pub maintenance_margin: Option<Decimal>,
143 #[serde(default)]
145 pub effective_leverage: Option<Decimal>,
146 #[serde(default)]
148 pub return_on_equity: Option<Decimal>,
149 #[serde(default)]
151 pub pnl_currency: Option<String>,
152 #[serde(default, alias = "maxFixedLeverage")]
154 pub max_fixed_leverage: Option<Decimal>,
155 #[serde(default, alias = "fillTime")]
157 pub fill_time: Option<String>,
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize)]
162#[serde(rename_all = "camelCase")]
163pub struct FuturesOrder {
164 #[serde(alias = "order_id")]
166 pub order_id: String,
167 #[serde(default, alias = "cliOrdId")]
169 pub cli_ord_id: Option<String>,
170 pub symbol: String,
172 pub side: BuySell,
174 #[serde(alias = "orderType")]
176 pub order_type: FuturesOrderType,
177 pub status: FuturesOrderStatus,
179 #[serde(alias = "quantity", alias = "qty")]
181 pub size: Decimal,
182 #[serde(default, alias = "filledSize")]
184 pub filled_size: Decimal,
185 #[serde(default, alias = "unfilledSize")]
187 pub unfilled_size: Decimal,
188 #[serde(default, alias = "limitPrice")]
190 pub limit_price: Option<Decimal>,
191 #[serde(default, alias = "stopPrice")]
193 pub stop_price: Option<Decimal>,
194 #[serde(default, alias = "reduceOnly")]
196 pub reduce_only: bool,
197 #[serde(default, alias = "receivedTime")]
199 pub received_time: Option<String>,
200 #[serde(default, alias = "lastUpdateTime")]
202 pub last_update_time: Option<String>,
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
207#[serde(rename_all = "camelCase")]
208pub struct FuturesFill {
209 #[serde(alias = "fill_id")]
211 pub fill_id: String,
212 #[serde(alias = "order_id")]
214 pub order_id: String,
215 #[serde(default, alias = "cliOrdId")]
217 pub cli_ord_id: Option<String>,
218 pub symbol: String,
220 pub side: BuySell,
222 pub size: Decimal,
224 pub price: Decimal,
226 #[serde(alias = "fillType")]
228 pub fill_type: FillType,
229 #[serde(alias = "fillTime")]
231 pub fill_time: String,
232}
233
234
235#[derive(Debug, Clone, Serialize, Deserialize)]
240#[serde(rename_all = "camelCase")]
241pub struct FuturesAccount {
242 #[serde(alias = "type")]
244 pub account_type: AccountType,
245 #[serde(default)]
247 pub currency: Option<String>,
248 #[serde(default)]
250 pub balances: Option<std::collections::HashMap<String, Decimal>>,
251 #[serde(default)]
253 pub margin_requirements: Option<MarginRequirements>,
254 #[serde(default)]
256 pub trigger_estimates: Option<TriggerEstimates>,
257 #[serde(default)]
259 pub auxiliary: Option<AuxiliaryInfo>,
260}
261
262#[derive(Debug, Clone, Serialize, Deserialize)]
264pub struct MarginRequirements {
265 pub im: Decimal,
267 pub mm: Decimal,
269 pub lt: Decimal,
271 pub tt: Decimal,
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct TriggerEstimates {
278 pub im: Decimal,
280 pub mm: Decimal,
282 pub lt: Decimal,
284 pub tt: Decimal,
286}
287
288#[derive(Debug, Clone, Serialize, Deserialize)]
290pub struct AuxiliaryInfo {
291 pub af: Decimal,
293 #[serde(default)]
295 pub funding: Option<Decimal>,
296 pub pnl: Decimal,
298 pub pv: Decimal,
300 #[serde(default)]
302 pub usd: Option<Decimal>,
303}
304
305#[derive(Debug, Clone, Serialize, Deserialize)]
307#[serde(rename_all = "camelCase")]
308pub struct FlexAccountInfo {
309 pub currencies: std::collections::HashMap<String, FlexCurrencyBalance>,
311 pub balance_value: Decimal,
313 pub portfolio_value: Decimal,
315 pub collateral_value: Decimal,
317 pub initial_margin: Decimal,
319 pub maintenance_margin: Decimal,
321 pub pnl: Decimal,
323 #[serde(default)]
325 pub unrealized_funding: Option<Decimal>,
326 pub available_margin: Decimal,
328 pub margin_equity: Decimal,
330}
331
332#[derive(Debug, Clone, Serialize, Deserialize)]
334#[serde(rename_all = "camelCase")]
335pub struct FlexCurrencyBalance {
336 pub quantity: Decimal,
338 pub value: Decimal,
340 #[serde(alias = "collateral_value")]
342 pub collateral_value: Decimal,
343 pub available: Decimal,
345 #[serde(default)]
347 pub haircut: Option<Decimal>,
348 #[serde(default)]
350 pub conversion_spread: Option<Decimal>,
351}
352
353
354#[derive(Debug, Clone, Serialize, Deserialize)]
359#[serde(rename_all = "camelCase")]
360pub struct FuturesInstrument {
361 pub symbol: String,
363 #[serde(default)]
365 pub pair: Option<String>,
366 #[serde(default, alias = "type")]
368 pub contract_type: Option<ContractType>,
369 #[serde(default)]
371 pub tradeable: Option<bool>,
372 #[serde(default, alias = "tickSize")]
374 pub tick_size: Option<Decimal>,
375 #[serde(default, alias = "contractSize")]
377 pub contract_size: Option<Decimal>,
378 #[serde(default)]
380 pub leverage: Option<String>,
381 #[serde(default, alias = "marginLevels")]
383 pub margin_levels: Option<Vec<MarginLevel>>,
384 #[serde(default, alias = "lastTradingTime")]
386 pub maturity_time: Option<String>,
387 #[serde(default, alias = "openingDate")]
389 pub opening_date: Option<String>,
390 #[serde(default)]
392 pub tag: Option<String>,
393 #[serde(default, alias = "postOnly")]
395 pub post_only: Option<bool>,
396}
397
398#[derive(Debug, Clone, Serialize, Deserialize)]
400#[serde(rename_all = "camelCase")]
401pub struct MarginLevel {
402 pub contracts: Decimal,
404 #[serde(alias = "initialMargin")]
406 pub initial_margin: Decimal,
407 #[serde(alias = "maintenanceMargin")]
409 pub maintenance_margin: Decimal,
410}
411
412
413#[derive(Debug, Clone, Serialize, Deserialize)]
418#[serde(rename_all = "camelCase")]
419pub struct FuturesTicker {
420 pub symbol: String,
422 #[serde(default)]
424 pub pair: Option<String>,
425 pub last: Decimal,
427 #[serde(default)]
429 pub bid: Option<Decimal>,
430 #[serde(default, alias = "bidSize")]
432 pub bid_size: Option<Decimal>,
433 #[serde(default)]
435 pub ask: Option<Decimal>,
436 #[serde(default, alias = "askSize")]
438 pub ask_size: Option<Decimal>,
439 #[serde(default)]
441 pub volume: Option<Decimal>,
442 #[serde(default, alias = "volumeQuote")]
444 pub volume_quote: Option<Decimal>,
445 #[serde(default, alias = "openInterest")]
447 pub open_interest: Option<Decimal>,
448 #[serde(default)]
450 pub open: Option<Decimal>,
451 #[serde(default)]
453 pub high: Option<Decimal>,
454 #[serde(default)]
456 pub low: Option<Decimal>,
457 #[serde(default)]
459 pub change: Option<Decimal>,
460 #[serde(default, alias = "markPrice")]
462 pub mark_price: Option<Decimal>,
463 #[serde(default, alias = "index")]
465 pub index_price: Option<Decimal>,
466 #[serde(default, alias = "fundingRate")]
468 pub funding_rate: Option<Decimal>,
469 #[serde(default, alias = "fundingRatePrediction")]
471 pub funding_rate_prediction: Option<Decimal>,
472 #[serde(default, alias = "nextFundingRateTime")]
474 pub next_funding_rate_time: Option<i64>,
475 #[serde(default)]
477 pub dtm: Option<i32>,
478 #[serde(default, alias = "maturityTime")]
480 pub maturity_time: Option<i64>,
481 #[serde(default)]
483 pub tag: Option<String>,
484 #[serde(default)]
486 pub suspended: Option<bool>,
487 #[serde(default, alias = "postOnly")]
489 pub post_only: Option<bool>,
490 #[serde(default)]
492 pub time: Option<i64>,
493}
494
495
496#[derive(Debug, Clone, Serialize, Deserialize)]
501#[serde(rename_all = "camelCase")]
502pub struct FuturesOrderBook {
503 pub symbol: String,
505 pub bids: Vec<BookLevel>,
507 pub asks: Vec<BookLevel>,
509 #[serde(default, alias = "serverTime")]
511 pub server_time: Option<String>,
512}
513
514#[derive(Debug, Clone, Serialize, Deserialize)]
516pub struct BookLevel {
517 pub price: Decimal,
519 #[serde(alias = "qty", alias = "quantity")]
521 pub size: Decimal,
522}
523
524
525#[derive(Debug, Clone, Serialize, Deserialize)]
530#[serde(rename_all = "camelCase")]
531pub struct FuturesTrade {
532 #[serde(alias = "uid")]
534 pub trade_id: String,
535 pub price: Decimal,
537 #[serde(alias = "qty", alias = "quantity")]
539 pub size: Decimal,
540 pub side: BuySell,
542 #[serde(alias = "time")]
544 pub timestamp: String,
545}
546
547#[cfg(test)]
548mod tests {
549 use super::*;
550
551 #[test]
552 fn test_deserialize_position() {
553 let json = r#"{
554 "symbol": "PI_XBTUSD",
555 "side": "buy",
556 "size": "1000",
557 "price": "50000.0",
558 "unrealizedFunding": "0.001"
559 }"#;
560
561 let pos: FuturesPosition = serde_json::from_str(json).unwrap();
562 assert_eq!(pos.symbol, "PI_XBTUSD");
563 assert_eq!(pos.side, BuySell::Buy);
564 assert_eq!(pos.size, Decimal::from(1000));
565 }
566
567 #[test]
568 fn test_deserialize_order() {
569 let json = r#"{
570 "order_id": "abc123",
571 "symbol": "PI_XBTUSD",
572 "side": "sell",
573 "orderType": "lmt",
574 "status": "open",
575 "quantity": "500",
576 "filledSize": "0",
577 "unfilledSize": "500",
578 "limitPrice": "55000.0",
579 "reduceOnly": true
580 }"#;
581
582 let order: FuturesOrder = serde_json::from_str(json).unwrap();
583 assert_eq!(order.order_id, "abc123");
584 assert!(order.reduce_only);
585 assert_eq!(order.limit_price, Some(Decimal::from(55000)));
586 }
587
588 #[test]
589 fn test_deserialize_fill() {
590 let json = r#"{
591 "fill_id": "fill123",
592 "order_id": "order456",
593 "symbol": "PI_ETHUSD",
594 "side": "buy",
595 "size": "10",
596 "price": "3500.5",
597 "fillType": "taker",
598 "fillTime": "2024-01-15T10:30:00Z"
599 }"#;
600
601 let fill: FuturesFill = serde_json::from_str(json).unwrap();
602 assert_eq!(fill.fill_type, FillType::Taker);
603 }
604
605 #[test]
606 fn test_deserialize_ticker() {
607 let json = r#"{
608 "symbol": "PI_XBTUSD",
609 "last": "50000.0",
610 "bid": "49999.5",
611 "ask": "50000.5",
612 "fundingRate": "0.0001",
613 "openInterest": "1000000"
614 }"#;
615
616 let ticker: FuturesTicker = serde_json::from_str(json).unwrap();
617 assert_eq!(ticker.symbol, "PI_XBTUSD");
618 assert!(ticker.funding_rate.is_some());
619 }
620
621 #[test]
622 fn test_contract_type_serde() {
623 assert_eq!(
624 serde_json::from_str::<ContractType>(r#""perpetual""#).unwrap(),
625 ContractType::Perpetual
626 );
627 }
628
629 #[test]
630 fn test_order_type_serde() {
631 assert_eq!(
633 serde_json::from_str::<FuturesOrderType>(r#""lmt""#).unwrap(),
634 FuturesOrderType::Limit
635 );
636 assert_eq!(
638 serde_json::from_str::<FuturesOrderType>(r#""take_profit""#).unwrap(),
639 FuturesOrderType::TakeProfit
640 );
641 }
642}