1use std::collections::HashMap;
2
3use rust_decimal::{Decimal, serde::str_option::deserialize as option_decimal};
4use serde::{Deserialize, Serialize};
5use serde_aux::prelude::deserialize_number_from_string as number;
6
7use crate::{
8 AccountType, DCPProduct, MarginMode, Second, SpotHedgingStatus, Timestamp, UnifiedMarginStatus,
9 enums::Category,
10 serde::{Unique, empty_string_as_none, hash_map},
11 ws::WalletMsg,
12};
13
14#[derive(Debug, Serialize, Clone)]
15#[serde(rename_all = "camelCase")]
16pub struct GetWalletBalanceParams {
17 pub account_type: AccountType,
23 pub coin: Option<String>,
27}
28
29#[derive(Debug, Deserialize, PartialEq)]
30#[serde(rename_all = "camelCase")]
31pub struct WalletBalance {
32 pub account_type: AccountType,
34 #[serde(rename = "accountIMRate")]
41 pub account_im_rate: Decimal,
42 #[serde(rename = "accountIMRateByMp")]
44 pub account_im_rate_by_mp: Decimal,
45 #[serde(rename = "accountMMRate")]
47 pub account_mm_rate: Decimal,
48 #[serde(rename = "accountMMRateByMp")]
50 pub account_mm_rate_by_mp: Decimal,
51 pub total_equity: Decimal,
53 pub total_wallet_balance: Decimal,
55 pub total_margin_balance: Decimal,
57 pub total_available_balance: Decimal,
59 #[serde(rename = "totalPerpUPL")]
61 pub total_perp_upl: Decimal,
62 pub total_initial_margin: Decimal,
64 pub total_initial_margin_by_mp: Decimal,
66 pub total_maintenance_margin: Decimal,
68 pub total_maintenance_margin_by_mp: Decimal,
70 #[serde(deserialize_with = "hash_map")]
71 pub coin: HashMap<String, WalletCoin>,
72}
73
74impl WalletBalance {
75 pub fn update(&mut self, msg: WalletMsg) {
76 self.account_type = msg.account_type;
77 self.account_im_rate = msg.account_im_rate;
78 self.account_mm_rate = msg.account_mm_rate;
79 self.total_equity = msg.total_equity;
80 self.total_wallet_balance = msg.total_wallet_balance;
81 self.total_margin_balance = msg.total_margin_balance;
82 self.total_available_balance = msg.total_available_balance;
83 self.total_perp_upl = msg.total_perp_upl;
84 self.total_initial_margin = msg.total_initial_margin;
85 self.total_maintenance_margin = msg.total_maintenance_margin;
86 self.coin = msg.coin;
87 }
88}
89
90#[derive(Debug, Deserialize, PartialEq, Clone)]
91#[serde(rename_all = "camelCase")]
92pub struct WalletCoin {
93 pub coin: String,
95 pub equity: Decimal,
97 pub usd_value: Decimal,
99 pub wallet_balance: Decimal,
101 pub locked: Decimal,
103 pub spot_hedging_qty: Decimal,
105 pub borrow_amount: Decimal,
107 pub accrued_interest: Decimal,
109 #[serde(rename = "totalOrderIM", default, deserialize_with = "option_decimal")]
111 pub total_order_im: Option<Decimal>,
112 #[serde(
114 rename = "totalPositionIM",
115 default,
116 deserialize_with = "option_decimal"
117 )]
118 pub total_position_im: Option<Decimal>,
119 #[serde(
121 rename = "totalPositionMM",
122 default,
123 deserialize_with = "option_decimal"
124 )]
125 pub total_position_mm: Option<Decimal>,
126 pub unrealised_pnl: Decimal,
128 pub cum_realised_pnl: Decimal,
130 pub bonus: Decimal,
132 pub collateral_switch: bool,
135 pub margin_collateral: bool,
138 #[serde(default, deserialize_with = "option_decimal")]
140 pub spot_borrow: Option<Decimal>,
141}
142
143impl Unique<String> for WalletCoin {
144 fn unique_key(&self) -> String {
145 self.coin.clone()
146 }
147}
148
149#[derive(Debug, Deserialize, PartialEq)]
150#[serde(rename_all = "camelCase")]
151pub struct AccountInfo {
152 pub unified_margin_status: UnifiedMarginStatus,
154 pub margin_mode: MarginMode,
156 pub is_master_trader: bool,
158 pub spot_hedging_status: SpotHedgingStatus,
160 #[serde(deserialize_with = "number")]
162 pub updated_time: Timestamp,
163}
164
165#[derive(Debug, Deserialize, PartialEq)]
166#[serde(rename_all = "camelCase")]
167pub struct DCPConfiguration {
168 pub dcp_infos: Vec<DCPInfo>,
170}
171
172#[derive(Debug, Deserialize, PartialEq)]
173#[serde(rename_all = "camelCase")]
174pub struct DCPInfo {
175 pub product: DCPProduct,
177 #[serde(rename = "dcpStatus")]
179 pub status: String,
180 #[serde(deserialize_with = "number")]
182 pub time_window: Second,
183}
184
185#[derive(Clone, Debug, Serialize)]
186#[serde(rename_all = "camelCase")]
187pub struct GetTransactionLogParams {
188 #[serde(skip_serializing_if = "Option::is_none")]
190 pub account_type: Option<AccountType>,
191 #[serde(skip_serializing_if = "Option::is_none")]
193 pub category: Option<Category>,
194 #[serde(skip_serializing_if = "Option::is_none")]
196 pub currency: Option<String>,
197 #[serde(skip_serializing_if = "Option::is_none")]
199 pub base_coin: Option<String>,
200 #[serde(skip_serializing_if = "Option::is_none")]
204 pub settle_coin: Option<String>,
205 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
207 pub log_type: Option<String>,
208 #[serde(skip_serializing_if = "Option::is_none")]
210 pub trans_sub_type: Option<String>,
211 #[serde(skip_serializing_if = "Option::is_none")]
217 pub start_time: Option<Timestamp>,
218 #[serde(skip_serializing_if = "Option::is_none")]
220 pub end_time: Option<Timestamp>,
221 #[serde(skip_serializing_if = "Option::is_none")]
223 pub limit: Option<u64>,
224 #[serde(skip_serializing_if = "Option::is_none")]
226 pub cursor: Option<String>,
227}
228
229impl GetTransactionLogParams {
230 pub fn new() -> Self {
231 Self {
232 account_type: None,
233 category: None,
234 currency: None,
235 base_coin: None,
236 settle_coin: None,
237 log_type: None,
238 trans_sub_type: None,
239 start_time: None,
240 end_time: None,
241 limit: None,
242 cursor: None,
243 }
244 }
245
246 pub fn with_account_type(mut self, v: AccountType) -> Self {
247 self.account_type = Some(v);
248 self
249 }
250 pub fn with_category(mut self, v: Category) -> Self {
251 self.category = Some(v);
252 self
253 }
254 pub fn with_currency(mut self, v: String) -> Self {
255 self.currency = Some(v);
256 self
257 }
258 pub fn with_base_coin(mut self, v: String) -> Self {
259 self.base_coin = Some(v);
260 self
261 }
262 pub fn with_settle_coin(mut self, v: String) -> Self {
263 self.settle_coin = Some(v);
264 self
265 }
266 pub fn with_log_type(mut self, v: String) -> Self {
267 self.log_type = Some(v);
268 self
269 }
270 pub fn with_trans_sub_type(mut self, v: String) -> Self {
271 self.trans_sub_type = Some(v);
272 self
273 }
274 pub fn with_start_time(mut self, v: Timestamp) -> Self {
275 self.start_time = Some(v);
276 self
277 }
278 pub fn with_end_time(mut self, v: Timestamp) -> Self {
279 self.end_time = Some(v);
280 self
281 }
282 pub fn with_limit(mut self, v: u64) -> Self {
283 self.limit = Some(v);
284 self
285 }
286 pub fn with_cursor(mut self, v: String) -> Self {
287 self.cursor = Some(v);
288 self
289 }
290}
291
292impl Default for GetTransactionLogParams {
293 fn default() -> Self {
294 Self::new()
295 }
296}
297
298#[derive(Debug, Deserialize, PartialEq)]
299#[serde(rename_all = "camelCase")]
300pub struct TransactionLog {
301 pub id: String,
303 pub symbol: String,
305 pub category: Category,
307 pub side: crate::Side,
309 #[serde(deserialize_with = "number")]
311 pub transaction_time: Timestamp,
312 #[serde(rename = "type")]
314 pub log_type: String,
315 pub trans_sub_type: String,
317 pub qty: Decimal,
321 pub size: Decimal,
323 pub currency: String,
325 pub trade_price: Decimal,
327 pub funding: Decimal,
331 pub fee: Decimal,
335 pub cash_flow: Decimal,
337 pub change: Decimal,
339 pub cash_balance: Decimal,
341 pub fee_rate: Decimal,
345 pub bonus_change: Decimal,
347 pub trade_id: String,
349 pub order_id: String,
351 #[serde(default, deserialize_with = "crate::serde::empty_string_as_none")]
353 pub order_link_id: Option<String>,
354 #[serde(default)]
356 pub extra_fees: Option<serde_json::Value>,
357}
358
359#[derive(Debug, Serialize, Clone)]
363#[serde(rename_all = "camelCase")]
364pub struct GetFeeRateParams {
365 pub category: Category,
366 pub symbol: Option<String>,
367 pub base_coin: Option<String>,
369}
370
371#[derive(Debug, Deserialize, PartialEq)]
372#[serde(rename_all = "camelCase")]
373pub struct FeeRateEntry {
374 #[serde(default, deserialize_with = "empty_string_as_none")]
376 pub symbol: Option<String>,
377 #[serde(default, deserialize_with = "empty_string_as_none")]
379 pub base_coin: Option<String>,
380 pub taker_fee_rate: Decimal,
381 pub maker_fee_rate: Decimal,
382}
383
384#[derive(Debug, Serialize, Clone)]
388#[serde(rename_all = "camelCase")]
389pub struct SetMarginModeRequest {
390 pub set_margin_mode: MarginMode,
391}
392
393#[derive(Debug, Deserialize, PartialEq)]
398pub struct SetMarginModeResponse {
399 pub reasons: Vec<MarginModeFailureReason>,
400}
401
402#[derive(Debug, Deserialize, PartialEq)]
403#[serde(rename_all = "camelCase")]
404pub struct MarginModeFailureReason {
405 pub reason_code: String,
406 pub reason_msg: String,
407}