use std::collections::HashMap;
use rust_decimal::{Decimal, serde::str_option::deserialize as option_decimal};
use serde::{Deserialize, Serialize};
use serde_aux::prelude::deserialize_number_from_string as number;
use crate::{
AccountType, DCPProduct, MarginMode, Second, SpotHedgingStatus, Timestamp, UnifiedMarginStatus,
UnifiedUpdateStatus,
enums::Category,
serde::{Unique, empty_string_as_none, hash_map},
ws::WalletMsg,
};
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GetWalletBalanceParams {
pub account_type: AccountType,
pub coin: Option<String>,
}
impl GetWalletBalanceParams {
pub fn new(account_type: AccountType) -> Self {
Self {
account_type,
coin: None,
}
}
pub fn with_coin(mut self, v: impl Into<String>) -> Self {
self.coin = Some(v.into());
self
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct WalletBalance {
pub account_type: AccountType,
#[serde(rename = "accountIMRate")]
pub account_im_rate: Decimal,
#[serde(rename = "accountIMRateByMp")]
pub account_im_rate_by_mp: Decimal,
#[serde(rename = "accountMMRate")]
pub account_mm_rate: Decimal,
#[serde(rename = "accountMMRateByMp")]
pub account_mm_rate_by_mp: Decimal,
pub total_equity: Decimal,
pub total_wallet_balance: Decimal,
pub total_margin_balance: Decimal,
pub total_available_balance: Decimal,
#[serde(rename = "totalPerpUPL")]
pub total_perp_upl: Decimal,
pub total_initial_margin: Decimal,
pub total_initial_margin_by_mp: Decimal,
pub total_maintenance_margin: Decimal,
pub total_maintenance_margin_by_mp: Decimal,
#[serde(deserialize_with = "hash_map")]
pub coin: HashMap<String, WalletCoin>,
}
impl WalletBalance {
pub fn update(&mut self, msg: WalletMsg) {
*self = msg.into();
}
}
impl From<WalletMsg> for WalletBalance {
fn from(msg: WalletMsg) -> Self {
Self {
account_type: msg.account_type,
account_im_rate: msg.account_im_rate,
account_im_rate_by_mp: msg.account_im_rate_by_mp,
account_mm_rate: msg.account_mm_rate,
account_mm_rate_by_mp: msg.account_mm_rate_by_mp,
total_equity: msg.total_equity,
total_wallet_balance: msg.total_wallet_balance,
total_margin_balance: msg.total_margin_balance,
total_available_balance: msg.total_available_balance,
total_perp_upl: msg.total_perp_upl,
total_initial_margin: msg.total_initial_margin,
total_initial_margin_by_mp: msg.total_initial_margin_by_mp,
total_maintenance_margin: msg.total_maintenance_margin,
total_maintenance_margin_by_mp: msg.total_maintenance_margin_by_mp,
coin: msg.coin,
}
}
}
#[derive(Debug, Deserialize, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct WalletCoin {
pub coin: String,
pub equity: Decimal,
pub usd_value: Decimal,
pub wallet_balance: Decimal,
pub locked: Decimal,
pub spot_hedging_qty: Decimal,
pub borrow_amount: Decimal,
pub accrued_interest: Decimal,
#[serde(rename = "totalOrderIM", default, deserialize_with = "option_decimal")]
pub total_order_im: Option<Decimal>,
#[serde(
rename = "totalPositionIM",
default,
deserialize_with = "option_decimal"
)]
pub total_position_im: Option<Decimal>,
#[serde(
rename = "totalPositionMM",
default,
deserialize_with = "option_decimal"
)]
pub total_position_mm: Option<Decimal>,
pub unrealised_pnl: Decimal,
pub cum_realised_pnl: Decimal,
pub bonus: Decimal,
pub collateral_switch: bool,
pub margin_collateral: bool,
#[serde(default, deserialize_with = "option_decimal")]
pub spot_borrow: Option<Decimal>,
}
impl Unique<String> for WalletCoin {
fn unique_key(&self) -> String {
self.coin.clone()
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AccountInfo {
pub unified_margin_status: UnifiedMarginStatus,
pub margin_mode: MarginMode,
pub is_master_trader: bool,
pub spot_hedging_status: SpotHedgingStatus,
#[serde(deserialize_with = "number")]
pub updated_time: Timestamp,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DCPConfiguration {
pub dcp_infos: Vec<DCPInfo>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DCPInfo {
pub product: DCPProduct,
#[serde(rename = "dcpStatus")]
pub status: String,
#[serde(deserialize_with = "number")]
pub time_window: Second,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetTransactionLogParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub account_type: Option<AccountType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<Category>,
#[serde(skip_serializing_if = "Option::is_none")]
pub currency: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub base_coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub settle_coin: Option<String>,
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub r#type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trans_sub_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
impl GetTransactionLogParams {
pub fn new() -> Self {
Self {
account_type: None,
category: None,
currency: None,
base_coin: None,
settle_coin: None,
r#type: None,
trans_sub_type: None,
start_time: None,
end_time: None,
limit: None,
cursor: None,
}
}
pub fn with_account_type(mut self, v: AccountType) -> Self {
self.account_type = Some(v);
self
}
pub fn with_category(mut self, v: Category) -> Self {
self.category = Some(v);
self
}
pub fn with_currency(mut self, v: impl Into<String>) -> Self {
self.currency = Some(v.into());
self
}
pub fn with_base_coin(mut self, v: impl Into<String>) -> Self {
self.base_coin = Some(v.into());
self
}
pub fn with_settle_coin(mut self, v: impl Into<String>) -> Self {
self.settle_coin = Some(v.into());
self
}
pub fn with_type(mut self, v: impl Into<String>) -> Self {
self.r#type = Some(v.into());
self
}
pub fn with_trans_sub_type(mut self, v: impl Into<String>) -> Self {
self.trans_sub_type = Some(v.into());
self
}
pub fn with_start_time(mut self, v: Timestamp) -> Self {
self.start_time = Some(v);
self
}
pub fn with_end_time(mut self, v: Timestamp) -> Self {
self.end_time = Some(v);
self
}
pub fn with_limit(mut self, v: u64) -> Self {
self.limit = Some(v);
self
}
pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
self.cursor = Some(v.into());
self
}
}
impl Default for GetTransactionLogParams {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct TransactionLog {
pub id: String,
pub symbol: String,
pub category: Category,
pub side: crate::Side,
#[serde(deserialize_with = "number")]
pub transaction_time: Timestamp,
#[serde(rename = "type")]
pub r#type: String,
pub trans_sub_type: String,
pub qty: Decimal,
pub size: Decimal,
pub currency: String,
pub trade_price: Decimal,
pub funding: Decimal,
pub fee: Decimal,
pub cash_flow: Decimal,
pub change: Decimal,
pub cash_balance: Decimal,
pub fee_rate: Decimal,
pub bonus_change: Decimal,
pub trade_id: String,
pub order_id: String,
#[serde(default, deserialize_with = "crate::serde::empty_string_as_none")]
pub order_link_id: Option<String>,
#[serde(default)]
pub extra_fees: Option<serde_json::Value>,
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GetFeeRateParams {
pub category: Category,
pub symbol: Option<String>,
pub base_coin: Option<String>,
}
impl GetFeeRateParams {
pub fn new(category: Category) -> Self {
Self {
category,
symbol: None,
base_coin: None,
}
}
pub fn with_symbol(mut self, v: impl Into<String>) -> Self {
self.symbol = Some(v.into());
self
}
pub fn with_base_coin(mut self, v: impl Into<String>) -> Self {
self.base_coin = Some(v.into());
self
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct FeeRateEntry {
#[serde(default, deserialize_with = "empty_string_as_none")]
pub symbol: Option<String>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub base_coin: Option<String>,
pub taker_fee_rate: Decimal,
pub maker_fee_rate: Decimal,
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct SetMarginModeRequest {
pub set_margin_mode: MarginMode,
}
impl SetMarginModeRequest {
pub fn new(set_margin_mode: MarginMode) -> Self {
Self { set_margin_mode }
}
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct SetMarginModeResponse {
pub reasons: Vec<MarginModeFailureReason>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct MarginModeFailureReason {
pub reason_code: String,
pub reason_msg: String,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct UpgradeToUtaResult {
pub unified_update_status: UnifiedUpdateStatus,
pub unified_update_msg: Option<UnifiedUpdateMsg>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct UnifiedUpdateMsg {
pub msg: Vec<String>,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetBorrowHistoryParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub currency: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
impl GetBorrowHistoryParams {
pub fn new() -> Self {
Self {
currency: None,
start_time: None,
end_time: None,
limit: None,
cursor: None,
}
}
pub fn with_currency(mut self, v: impl Into<String>) -> Self {
self.currency = Some(v.into());
self
}
pub fn with_start_time(mut self, v: Timestamp) -> Self {
self.start_time = Some(v);
self
}
pub fn with_end_time(mut self, v: Timestamp) -> Self {
self.end_time = Some(v);
self
}
pub fn with_limit(mut self, v: u64) -> Self {
self.limit = Some(v);
self
}
pub fn with_cursor(mut self, v: impl Into<String>) -> Self {
self.cursor = Some(v.into());
self
}
}
impl Default for GetBorrowHistoryParams {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct BorrowHistoryEntry {
pub currency: String,
#[serde(deserialize_with = "number")]
pub created_time: Timestamp,
pub borrow_cost: Decimal,
pub hourly_borrow_rate: Decimal,
#[serde(rename = "InterestBearingBorrowSize")]
pub interest_bearing_borrow_size: Decimal,
pub cost_exemption: Decimal,
pub borrow_amount: Decimal,
pub unrealised_loss: Decimal,
#[serde(default, deserialize_with = "option_decimal")]
pub free_borrowed_amount: Option<Decimal>,
}
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GetCollateralInfoParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub currency: Option<String>,
}
impl GetCollateralInfoParams {
pub fn new() -> Self {
Self { currency: None }
}
pub fn with_currency(mut self, v: impl Into<String>) -> Self {
self.currency = Some(v.into());
self
}
}
impl Default for GetCollateralInfoParams {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CollateralInfoEntry {
pub currency: String,
pub hourly_borrow_rate: Decimal,
pub max_borrowing_amount: Decimal,
pub free_borrowing_limit: Decimal,
pub free_borrow_amount: Decimal,
pub borrow_amount: Decimal,
pub other_borrow_amount: Decimal,
pub available_to_borrow: Decimal,
pub borrowable: bool,
pub borrow_usage_rate: Decimal,
pub margin_collateral: bool,
pub collateral_switch: bool,
#[serde(default, deserialize_with = "option_decimal")]
pub collateral_ratio: Option<Decimal>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub free_borrowing_amount: Option<String>,
}