1use std::collections::HashMap;
19
20use chrono::{DateTime, Utc};
21use rust_decimal::Decimal;
22use serde::{Deserialize, Serialize};
23use ustr::Ustr;
24
25use crate::common::{
26 enums::{AxCandleWidth, AxInstrumentState, AxOrderSide, AxOrderStatus, AxTimeInForce},
27 parse::{deserialize_decimal_or_zero, deserialize_optional_decimal_from_str},
28};
29
30fn default_instrument_state() -> AxInstrumentState {
32 AxInstrumentState::Open
33}
34
35#[derive(Clone, Debug, Serialize, Deserialize)]
40#[serde(rename_all = "snake_case")]
41pub struct AxWhoAmI {
42 pub id: String,
44 pub username: String,
46 pub created_at: DateTime<Utc>,
48 pub enabled_2fa: bool,
50 pub is_onboarded: bool,
52 pub is_frozen: bool,
54 pub is_admin: bool,
56 pub is_close_only: bool,
58 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
60 pub maker_fee: Decimal,
61 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
63 pub taker_fee: Decimal,
64}
65
66#[derive(Clone, Debug, Serialize, Deserialize)]
71#[serde(rename_all = "snake_case")]
72pub struct AxInstrument {
73 pub symbol: Ustr,
75 #[serde(default = "default_instrument_state")]
77 pub state: AxInstrumentState,
78 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
80 pub multiplier: Decimal,
81 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
83 pub minimum_order_size: Decimal,
84 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
86 pub tick_size: Decimal,
87 pub quote_currency: Ustr,
89 #[serde(alias = "funding_settlement_currency")]
92 pub finding_settlement_currency: Ustr,
93 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
95 pub maintenance_margin_pct: Decimal,
96 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
98 pub initial_margin_pct: Decimal,
99 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
101 pub contract_mark_price: Option<Decimal>,
102 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
104 pub contract_size: Option<Decimal>,
105 #[serde(default)]
107 pub description: Option<String>,
108 #[serde(default)]
110 pub funding_calendar_schedule: Option<String>,
111 #[serde(default)]
113 pub funding_frequency: Option<String>,
114 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
116 pub funding_rate_cap_lower_pct: Option<Decimal>,
117 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
119 pub funding_rate_cap_upper_pct: Option<Decimal>,
120 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
122 pub price_band_lower_deviation_pct: Option<Decimal>,
123 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
125 pub price_band_upper_deviation_pct: Option<Decimal>,
126 #[serde(default)]
128 pub price_bands: Option<String>,
129 #[serde(default)]
131 pub price_quotation: Option<String>,
132 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
134 pub underlying_benchmark_price: Option<Decimal>,
135}
136
137#[derive(Clone, Debug, Serialize, Deserialize)]
142#[serde(rename_all = "snake_case")]
143pub struct AxInstrumentsResponse {
144 pub instruments: Vec<AxInstrument>,
146}
147
148#[derive(Clone, Debug, Serialize, Deserialize)]
153#[serde(rename_all = "snake_case")]
154pub struct AxBalance {
155 pub symbol: Ustr,
157 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
159 pub amount: Decimal,
160}
161
162#[derive(Clone, Debug, Serialize, Deserialize)]
167#[serde(rename_all = "snake_case")]
168pub struct AxBalancesResponse {
169 pub balances: Vec<AxBalance>,
171}
172
173#[derive(Clone, Debug, Serialize, Deserialize)]
178#[serde(rename_all = "snake_case")]
179pub struct AxPosition {
180 pub user_id: String,
182 pub symbol: Ustr,
184 pub open_quantity: i64,
186 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
188 pub open_notional: Decimal,
189 pub timestamp: DateTime<Utc>,
191 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
193 pub realized_pnl: Decimal,
194}
195
196#[derive(Clone, Debug, Serialize, Deserialize)]
201#[serde(rename_all = "snake_case")]
202pub struct AxPositionsResponse {
203 pub positions: Vec<AxPosition>,
205}
206
207#[derive(Clone, Debug, Serialize, Deserialize)]
212#[serde(rename_all = "snake_case")]
213pub struct AxTicker {
214 pub symbol: Ustr,
216 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
218 pub bid: Option<Decimal>,
219 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
221 pub ask: Option<Decimal>,
222 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
224 pub last: Option<Decimal>,
225 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
227 pub mark: Option<Decimal>,
228 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
230 pub index: Option<Decimal>,
231 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
233 pub volume_24h: Option<Decimal>,
234 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
236 pub high_24h: Option<Decimal>,
237 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
239 pub low_24h: Option<Decimal>,
240 #[serde(default)]
242 pub timestamp: Option<DateTime<Utc>>,
243}
244
245#[derive(Clone, Debug, Serialize, Deserialize)]
250#[serde(rename_all = "snake_case")]
251pub struct AxTickersResponse {
252 pub tickers: Vec<AxTicker>,
254}
255
256#[derive(Clone, Debug, Serialize, Deserialize)]
261#[serde(rename_all = "snake_case")]
262pub struct AxAuthenticateResponse {
263 pub token: String,
265}
266
267#[derive(Clone, Debug, Serialize, Deserialize)]
272pub struct AxPlaceOrderResponse {
273 pub oid: String,
275}
276
277#[derive(Clone, Debug, Serialize, Deserialize)]
282pub struct AxCancelOrderResponse {
283 pub cxl_rx: bool,
285}
286
287#[derive(Clone, Debug, Serialize, Deserialize)]
292pub struct AxOpenOrder {
293 pub tn: i64,
295 pub ts: i64,
297 pub d: AxOrderSide,
299 pub o: AxOrderStatus,
301 pub oid: String,
303 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
305 pub p: Decimal,
306 pub q: i64,
308 pub rq: i64,
310 pub s: Ustr,
312 pub tif: AxTimeInForce,
314 pub u: String,
316 pub xq: i64,
318 #[serde(default)]
320 pub tag: Option<String>,
321}
322
323pub type AxOpenOrdersResponse = Vec<AxOpenOrder>;
330
331#[derive(Clone, Debug, Serialize, Deserialize)]
336#[serde(rename_all = "snake_case")]
337pub struct AxFill {
338 pub execution_id: String,
340 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
342 pub fee: Decimal,
343 pub is_taker: bool,
345 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
347 pub price: Decimal,
348 pub quantity: i64,
350 pub symbol: Ustr,
352 pub timestamp: DateTime<Utc>,
354 pub user_id: String,
356}
357
358#[derive(Clone, Debug, Serialize, Deserialize)]
363#[serde(rename_all = "snake_case")]
364pub struct AxFillsResponse {
365 pub fills: Vec<AxFill>,
367}
368
369#[derive(Clone, Debug, Serialize, Deserialize)]
374#[serde(rename_all = "snake_case")]
375pub struct AxCandle {
376 pub symbol: Ustr,
378 pub tn: DateTime<Utc>,
380 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
382 pub open: Decimal,
383 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
385 pub high: Decimal,
386 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
388 pub low: Decimal,
389 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
391 pub close: Decimal,
392 pub buy_volume: i64,
394 pub sell_volume: i64,
396 pub volume: i64,
398 pub width: AxCandleWidth,
400}
401
402#[derive(Clone, Debug, Serialize, Deserialize)]
407#[serde(rename_all = "snake_case")]
408pub struct AxCandlesResponse {
409 pub candles: Vec<AxCandle>,
411}
412
413#[derive(Clone, Debug, Serialize, Deserialize)]
419#[serde(rename_all = "snake_case")]
420pub struct AxCandleResponse {
421 pub candle: AxCandle,
423}
424
425#[derive(Clone, Debug, Serialize, Deserialize)]
430#[serde(rename_all = "snake_case")]
431pub struct AxFundingRate {
432 pub symbol: Ustr,
434 pub timestamp_ns: i64,
436 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
438 pub funding_rate: Decimal,
439 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
441 pub funding_amount: Decimal,
442 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
444 pub benchmark_price: Decimal,
445 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
447 pub settlement_price: Decimal,
448}
449
450#[derive(Clone, Debug, Serialize, Deserialize)]
455#[serde(rename_all = "snake_case")]
456pub struct AxFundingRatesResponse {
457 pub funding_rates: Vec<AxFundingRate>,
459}
460
461#[derive(Clone, Debug, Serialize, Deserialize)]
466#[serde(rename_all = "snake_case")]
467pub struct AxPerSymbolRisk {
468 pub open_quantity: i64,
470 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
472 pub open_notional: Decimal,
473 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
475 pub average_price: Decimal,
476 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
478 pub liquidation_price: Option<Decimal>,
479 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
481 pub initial_margin_required: Option<Decimal>,
482 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
484 pub maintenance_margin_required: Option<Decimal>,
485 #[serde(default, deserialize_with = "deserialize_optional_decimal_from_str")]
487 pub unrealized_pnl: Option<Decimal>,
488}
489
490#[derive(Clone, Debug, Serialize, Deserialize)]
495#[serde(rename_all = "snake_case")]
496pub struct AxRiskSnapshot {
497 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
499 pub balance_usd: Decimal,
500 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
502 pub equity: Decimal,
503 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
505 pub initial_margin_available: Decimal,
506 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
508 pub initial_margin_required_for_open_orders: Decimal,
509 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
511 pub initial_margin_required_for_positions: Decimal,
512 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
514 pub initial_margin_required_total: Decimal,
515 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
517 pub maintenance_margin_available: Decimal,
518 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
520 pub maintenance_margin_required: Decimal,
521 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
523 pub unrealized_pnl: Decimal,
524 pub timestamp_ns: DateTime<Utc>,
526 pub user_id: String,
528 #[serde(default)]
530 pub per_symbol: HashMap<String, AxPerSymbolRisk>,
531}
532
533#[derive(Clone, Debug, Serialize, Deserialize)]
538#[serde(rename_all = "snake_case")]
539pub struct AxRiskSnapshotResponse {
540 pub risk_snapshot: AxRiskSnapshot,
542}
543
544#[derive(Clone, Debug, Serialize, Deserialize)]
549#[serde(rename_all = "snake_case")]
550pub struct AxTransaction {
551 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
553 pub amount: Decimal,
554 pub event_id: String,
556 pub symbol: Ustr,
558 pub timestamp: DateTime<Utc>,
560 pub transaction_type: Ustr,
562 pub user_id: String,
564 #[serde(default)]
566 pub reference_id: Option<String>,
567}
568
569#[derive(Clone, Debug, Serialize, Deserialize)]
574#[serde(rename_all = "snake_case")]
575pub struct AxTransactionsResponse {
576 pub transactions: Vec<AxTransaction>,
578}
579
580#[derive(Clone, Debug, Serialize, Deserialize)]
585#[serde(rename_all = "snake_case")]
586pub struct AuthenticateApiKeyRequest {
587 pub api_key: String,
589 pub api_secret: String,
591 pub expiration_seconds: i32,
593 #[serde(skip_serializing_if = "Option::is_none")]
595 pub totp: Option<String>,
596}
597
598impl AuthenticateApiKeyRequest {
599 #[must_use]
601 pub fn new(
602 api_key: impl Into<String>,
603 api_secret: impl Into<String>,
604 expiration_seconds: i32,
605 ) -> Self {
606 Self {
607 api_key: api_key.into(),
608 api_secret: api_secret.into(),
609 expiration_seconds,
610 totp: None,
611 }
612 }
613
614 #[must_use]
616 pub fn with_totp(mut self, totp: impl Into<String>) -> Self {
617 self.totp = Some(totp.into());
618 self
619 }
620}
621
622#[derive(Clone, Debug, Serialize, Deserialize)]
627#[serde(rename_all = "snake_case")]
628pub struct AuthenticateUserRequest {
629 pub username: String,
631 pub password: String,
633 pub expiration_seconds: i32,
635 #[serde(skip_serializing_if = "Option::is_none")]
637 pub totp: Option<String>,
638}
639
640impl AuthenticateUserRequest {
641 #[must_use]
643 pub fn new(
644 username: impl Into<String>,
645 password: impl Into<String>,
646 expiration_seconds: i32,
647 ) -> Self {
648 Self {
649 username: username.into(),
650 password: password.into(),
651 expiration_seconds,
652 totp: None,
653 }
654 }
655
656 #[must_use]
658 pub fn with_totp(mut self, totp: impl Into<String>) -> Self {
659 self.totp = Some(totp.into());
660 self
661 }
662}
663
664#[derive(Clone, Debug, Serialize, Deserialize)]
669pub struct PlaceOrderRequest {
670 pub d: AxOrderSide,
672 pub p: String,
674 pub po: bool,
676 pub q: i64,
678 pub s: String,
680 pub tif: AxTimeInForce,
682 #[serde(skip_serializing_if = "Option::is_none")]
684 pub tag: Option<String>,
685}
686
687impl PlaceOrderRequest {
688 #[must_use]
690 pub fn new(
691 side: AxOrderSide,
692 price: impl Into<String>,
693 quantity: i64,
694 symbol: impl Into<String>,
695 time_in_force: AxTimeInForce,
696 post_only: bool,
697 ) -> Self {
698 Self {
699 d: side,
700 p: price.into(),
701 po: post_only,
702 q: quantity,
703 s: symbol.into(),
704 tif: time_in_force,
705 tag: None,
706 }
707 }
708
709 #[must_use]
711 pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
712 self.tag = Some(tag.into());
713 self
714 }
715}
716
717#[derive(Clone, Debug, Serialize, Deserialize)]
722pub struct CancelOrderRequest {
723 pub oid: String,
725}
726
727impl CancelOrderRequest {
728 #[must_use]
730 pub fn new(order_id: impl Into<String>) -> Self {
731 Self {
732 oid: order_id.into(),
733 }
734 }
735}