asterdex-sdk 0.1.4

AsterDex Futures SDK v3 โ€” Rust async client for REST and WebSocket APIs
Documentation
// Tech Lead mini-task (Wave 4): replaced stubs with full type definitions
// per 05_detail_design.md ยง2.3

use serde::{Deserialize, Serialize};
use crate::futures::models::de;

// --- Balance ---

/// Account balance for a single asset.
#[derive(Debug, Deserialize)]
pub struct Balance {
    #[serde(rename = "accountAlias", default)]
    pub account_alias: String,
    pub asset: String,
    /// Some testnet deployments return this field as `"balance"` instead of `"walletBalance"`.
    #[serde(rename = "walletBalance", alias = "balance")]
    pub wallet_balance: String,
    #[serde(rename = "crossWalletBalance")]
    pub cross_wallet_balance: String,
    #[serde(rename = "crossUnPnl")]
    pub cross_unpnl: String,
    #[serde(rename = "availableBalance")]
    pub available_balance: String,
    #[serde(rename = "maxWithdrawAmount")]
    pub max_withdraw_amount: String,
    #[serde(rename = "marginAvailable", default)]
    pub margin_available: bool,
    #[serde(rename = "updateTime")]
    pub update_time: u64,
}

// --- Position Side ---

/// Response for the position side dual (hedge mode) setting.
#[derive(Debug, Deserialize)]
pub struct PositionSideDualResponse {
    #[serde(rename = "dualSidePosition")]
    pub dual_side_position: bool,
}

// --- Leverage ---

/// Leverage bracket information for a symbol.
#[derive(Debug, Deserialize)]
pub struct LeverageBracket {
    pub symbol: String,
    pub brackets: Vec<Bracket>,
}

/// A single leverage bracket within a `LeverageBracket`.
///
/// `notional_cap`, `notional_floor`, `maint_margin_ratio`, and `cum` are returned
/// as JSON numbers on some deployments and as JSON strings on others โ€” the
/// `string_or_number` deserializer normalises both forms to `String`.
#[derive(Debug, Deserialize)]
pub struct Bracket {
    pub bracket: u32,
    #[serde(rename = "initialLeverage")]
    pub initial_leverage: u32,
    #[serde(rename = "notionalCap", deserialize_with = "de::string_or_number")]
    pub notional_cap: String,
    #[serde(rename = "notionalFloor", deserialize_with = "de::string_or_number")]
    pub notional_floor: String,
    #[serde(rename = "maintMarginRatio", deserialize_with = "de::string_or_number")]
    pub maint_margin_ratio: String,
    #[serde(deserialize_with = "de::string_or_number")]
    pub cum: String,
}

/// Response from setting leverage for a symbol.
#[derive(Debug, Deserialize)]
pub struct SetLeverageResponse {
    pub leverage: u32,
    #[serde(rename = "maxNotionalValue")]
    pub max_notional_value: String,
    pub symbol: String,
}

// --- Cancel All Orders ---

/// Response from cancelling all open orders for a symbol.
#[derive(Debug, Deserialize)]
pub struct CancelAllResponse {
    pub code: i64,
    pub msg: String,
}

// --- Batch Orders ---

/// Per-item result in a batch order response.
/// May be a success (has `order_id`) or an error (has `code` + `msg`).
#[derive(Debug, Deserialize)]
pub struct BatchOrderResult {
    #[serde(rename = "orderId")]
    pub order_id: Option<i64>,
    pub code: Option<i64>,
    pub msg: Option<String>,
    pub symbol: Option<String>,
    pub status: Option<String>,
}

// --- Generic Status/Message Response ---

/// Generic status/message response (code + message).
#[derive(Debug, Deserialize)]
pub struct StatusMsgResponse {
    pub code: i64,
    pub msg: String,
}

// --- MMP (used in Wave 9) ---

/// Market Maker Protection (MMP) configuration response.
///
/// Limit fields use `i64` to accept the server sentinel `-1` meaning "no limit set".
#[derive(Debug, Deserialize)]
pub struct MmpResponse {
    pub symbol: String,
    #[serde(rename = "windowTimeInMilliseconds")]
    pub window_time_ms: u64,
    #[serde(rename = "frozenTimeInMilliseconds")]
    pub frozen_time_ms: u64,
    #[serde(rename = "qtyLimit", default)]
    pub qty_limit: Option<i64>,
    #[serde(rename = "valueLimit", default)]
    pub value_limit: Option<i64>,
    #[serde(rename = "deltaLimit", default)]
    pub delta_limit: Option<i64>,
}

/// Parameters for updating MMP configuration (`POST /fapi/v3/mmp`).
#[derive(Debug)]
pub struct MmpUpdateParams {
    pub symbol: String,
    /// Time window in milliseconds for calculating limits.
    pub window_time_ms: u64,
    /// Duration in milliseconds during which MMP orders are prohibited after a limit is triggered.
    pub frozen_time_ms: u64,
    /// Maximum cumulative filled quantity within the window (optional).
    pub qty_limit: Option<u64>,
    /// Maximum cumulative notional value within the window (optional).
    pub value_limit: Option<u64>,
    /// Maximum cumulative net position change within the window (optional).
    pub delta_limit: Option<u64>,
}

// --- Wallet Transfer (used in Wave 9) ---

/// Parameters for a wallet asset transfer.
#[derive(Debug, Serialize)]
pub struct WalletTransferParams {
    pub asset: String,
    pub amount: String,
    #[serde(rename = "type")]
    pub transfer_type: u32,
}

/// Response from a wallet asset transfer.
#[derive(Debug, Deserialize)]
pub struct WalletTransferResponse {
    #[serde(rename = "tranId")]
    pub tran_id: i64,
    #[serde(default)]
    pub status: String,
}

// --- ADL Quantile (used in Wave 9) ---

/// ADL (Auto-Deleveraging) quantile information for a symbol.
#[derive(Debug, Deserialize)]
pub struct AdlQuantileResponse {
    pub symbol: String,
    #[serde(rename = "adlQuantile")]
    pub adl_quantile: serde_json::Value,
}

// --- Commission Rate (used in Wave 9) ---

/// Commission rates for a trading symbol.
#[derive(Debug, Deserialize)]
pub struct CommissionRateResponse {
    pub symbol: String,
    #[serde(rename = "makerCommissionRate")]
    pub maker_commission_rate: String,
    #[serde(rename = "takerCommissionRate")]
    pub taker_commission_rate: String,
}

// --- Multi-Assets Mode (used in Wave 9) ---

/// Multi-assets margin mode setting.
#[derive(Debug, Deserialize)]
pub struct MultiAssetsModeResponse {
    #[serde(rename = "multiAssetsMargin")]
    pub multi_assets_margin: bool,
}

// --- Full Account Info (GET /fapi/v3/accountWithJoinMargin) ---

/// Full account information response.
#[derive(Debug, Deserialize)]
pub struct AccountInfoResponse {
    #[serde(rename = "feeTier")]
    pub fee_tier: u32,
    #[serde(rename = "canTrade")]
    pub can_trade: bool,
    #[serde(rename = "canDeposit")]
    pub can_deposit: bool,
    #[serde(rename = "canWithdraw")]
    pub can_withdraw: bool,
    #[serde(rename = "updateTime")]
    pub update_time: u64,
    #[serde(rename = "totalInitialMargin")]
    pub total_initial_margin: String,
    #[serde(rename = "totalMaintMargin")]
    pub total_maint_margin: String,
    #[serde(rename = "totalWalletBalance")]
    pub total_wallet_balance: String,
    #[serde(rename = "totalUnrealizedProfit")]
    pub total_unrealized_profit: String,
    #[serde(rename = "totalMarginBalance")]
    pub total_margin_balance: String,
    #[serde(rename = "totalPositionInitialMargin")]
    pub total_position_initial_margin: String,
    #[serde(rename = "totalOpenOrderInitialMargin")]
    pub total_open_order_initial_margin: String,
    #[serde(rename = "totalCrossWalletBalance")]
    pub total_cross_wallet_balance: String,
    #[serde(rename = "totalCrossUnPnl")]
    pub total_cross_unpnl: String,
    #[serde(rename = "availableBalance")]
    pub available_balance: String,
    #[serde(rename = "maxWithdrawAmount")]
    pub max_withdraw_amount: String,
    pub assets: Vec<AccountAsset>,
    pub positions: Vec<AccountPosition>,
}

/// Per-asset details within `AccountInfoResponse`.
#[derive(Debug, Deserialize)]
pub struct AccountAsset {
    pub asset: String,
    #[serde(rename = "walletBalance")]
    pub wallet_balance: String,
    #[serde(rename = "unrealizedProfit")]
    pub unrealized_profit: String,
    #[serde(rename = "marginBalance")]
    pub margin_balance: String,
    #[serde(rename = "maintMargin")]
    pub maint_margin: String,
    #[serde(rename = "initialMargin")]
    pub initial_margin: String,
    #[serde(rename = "positionInitialMargin")]
    pub position_initial_margin: String,
    #[serde(rename = "openOrderInitialMargin")]
    pub open_order_initial_margin: String,
    #[serde(rename = "crossWalletBalance")]
    pub cross_wallet_balance: String,
    #[serde(rename = "crossUnPnl")]
    pub cross_unpnl: String,
    #[serde(rename = "availableBalance")]
    pub available_balance: String,
    #[serde(rename = "maxWithdrawAmount")]
    pub max_withdraw_amount: String,
    #[serde(rename = "marginAvailable", default)]
    pub margin_available: bool,
    #[serde(rename = "updateTime")]
    pub update_time: u64,
}

/// Per-position details within `AccountInfoResponse`.
#[derive(Debug, Deserialize)]
pub struct AccountPosition {
    pub symbol: String,
    #[serde(rename = "initialMargin")]
    pub initial_margin: String,
    #[serde(rename = "maintMargin")]
    pub maint_margin: String,
    #[serde(rename = "unrealizedProfit")]
    pub unrealized_profit: String,
    #[serde(rename = "positionInitialMargin")]
    pub position_initial_margin: String,
    #[serde(rename = "openOrderInitialMargin")]
    pub open_order_initial_margin: String,
    pub leverage: String,
    pub isolated: bool,
    #[serde(rename = "entryPrice")]
    pub entry_price: String,
    #[serde(rename = "maxNotional")]
    pub max_notional: String,
    #[serde(rename = "positionSide")]
    pub position_side: String,
    #[serde(rename = "positionAmt")]
    pub position_amt: String,
    #[serde(rename = "updateTime")]
    pub update_time: u64,
}

// --- Position Margin History (GET /fapi/v3/positionMargin/history) ---

/// A single record from position margin change history.
#[derive(Debug, Deserialize)]
pub struct PositionMarginHistoryRecord {
    pub amount: String,
    pub asset: String,
    pub symbol: String,
    pub time: u64,
    #[serde(rename = "type")]
    pub margin_type: u8,
    #[serde(rename = "positionSide")]
    pub position_side: String,
}