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 UnifiedUpdateStatus,
10 enums::Category,
11 serde::{Unique, empty_string_as_none, hash_map},
12 ws::WalletMsg,
13};
14
15#[derive(Debug, Serialize, Clone)]
16#[serde(rename_all = "camelCase")]
17pub struct GetWalletBalanceParams {
18 pub account_type: AccountType,
24 pub coin: Option<String>,
28}
29
30#[derive(Debug, Deserialize, PartialEq)]
31#[serde(rename_all = "camelCase")]
32pub struct WalletBalance {
33 pub account_type: AccountType,
35 #[serde(rename = "accountIMRate")]
42 pub account_im_rate: Decimal,
43 #[serde(rename = "accountIMRateByMp")]
45 pub account_im_rate_by_mp: Decimal,
46 #[serde(rename = "accountMMRate")]
48 pub account_mm_rate: Decimal,
49 #[serde(rename = "accountMMRateByMp")]
51 pub account_mm_rate_by_mp: Decimal,
52 pub total_equity: Decimal,
54 pub total_wallet_balance: Decimal,
56 pub total_margin_balance: Decimal,
58 pub total_available_balance: Decimal,
60 #[serde(rename = "totalPerpUPL")]
62 pub total_perp_upl: Decimal,
63 pub total_initial_margin: Decimal,
65 pub total_initial_margin_by_mp: Decimal,
67 pub total_maintenance_margin: Decimal,
69 pub total_maintenance_margin_by_mp: Decimal,
71 #[serde(deserialize_with = "hash_map")]
72 pub coin: HashMap<String, WalletCoin>,
73}
74
75impl WalletBalance {
76 pub fn update(&mut self, msg: WalletMsg) {
79 *self = msg.into();
80 }
81}
82
83impl From<WalletMsg> for WalletBalance {
84 fn from(msg: WalletMsg) -> Self {
85 Self {
86 account_type: msg.account_type,
87 account_im_rate: msg.account_im_rate,
88 account_im_rate_by_mp: msg.account_im_rate_by_mp,
89 account_mm_rate: msg.account_mm_rate,
90 account_mm_rate_by_mp: msg.account_mm_rate_by_mp,
91 total_equity: msg.total_equity,
92 total_wallet_balance: msg.total_wallet_balance,
93 total_margin_balance: msg.total_margin_balance,
94 total_available_balance: msg.total_available_balance,
95 total_perp_upl: msg.total_perp_upl,
96 total_initial_margin: msg.total_initial_margin,
97 total_initial_margin_by_mp: msg.total_initial_margin_by_mp,
98 total_maintenance_margin: msg.total_maintenance_margin,
99 total_maintenance_margin_by_mp: msg.total_maintenance_margin_by_mp,
100 coin: msg.coin,
101 }
102 }
103}
104
105#[derive(Debug, Deserialize, PartialEq, Clone)]
106#[serde(rename_all = "camelCase")]
107pub struct WalletCoin {
108 pub coin: String,
110 pub equity: Decimal,
112 pub usd_value: Decimal,
114 pub wallet_balance: Decimal,
116 pub locked: Decimal,
118 pub spot_hedging_qty: Decimal,
120 pub borrow_amount: Decimal,
122 pub accrued_interest: Decimal,
124 #[serde(rename = "totalOrderIM", default, deserialize_with = "option_decimal")]
126 pub total_order_im: Option<Decimal>,
127 #[serde(
129 rename = "totalPositionIM",
130 default,
131 deserialize_with = "option_decimal"
132 )]
133 pub total_position_im: Option<Decimal>,
134 #[serde(
136 rename = "totalPositionMM",
137 default,
138 deserialize_with = "option_decimal"
139 )]
140 pub total_position_mm: Option<Decimal>,
141 pub unrealised_pnl: Decimal,
143 pub cum_realised_pnl: Decimal,
145 pub bonus: Decimal,
147 pub collateral_switch: bool,
150 pub margin_collateral: bool,
153 #[serde(default, deserialize_with = "option_decimal")]
155 pub spot_borrow: Option<Decimal>,
156}
157
158impl Unique<String> for WalletCoin {
159 fn unique_key(&self) -> String {
160 self.coin.clone()
161 }
162}
163
164#[derive(Debug, Deserialize, PartialEq)]
165#[serde(rename_all = "camelCase")]
166pub struct AccountInfo {
167 pub unified_margin_status: UnifiedMarginStatus,
169 pub margin_mode: MarginMode,
171 pub is_master_trader: bool,
173 pub spot_hedging_status: SpotHedgingStatus,
175 #[serde(deserialize_with = "number")]
177 pub updated_time: Timestamp,
178}
179
180#[derive(Debug, Deserialize, PartialEq)]
181#[serde(rename_all = "camelCase")]
182pub struct DCPConfiguration {
183 pub dcp_infos: Vec<DCPInfo>,
185}
186
187#[derive(Debug, Deserialize, PartialEq)]
188#[serde(rename_all = "camelCase")]
189pub struct DCPInfo {
190 pub product: DCPProduct,
192 #[serde(rename = "dcpStatus")]
194 pub status: String,
195 #[serde(deserialize_with = "number")]
197 pub time_window: Second,
198}
199
200#[derive(Clone, Debug, Serialize)]
201#[serde(rename_all = "camelCase")]
202pub struct GetTransactionLogParams {
203 #[serde(skip_serializing_if = "Option::is_none")]
205 pub account_type: Option<AccountType>,
206 #[serde(skip_serializing_if = "Option::is_none")]
208 pub category: Option<Category>,
209 #[serde(skip_serializing_if = "Option::is_none")]
211 pub currency: Option<String>,
212 #[serde(skip_serializing_if = "Option::is_none")]
214 pub base_coin: Option<String>,
215 #[serde(skip_serializing_if = "Option::is_none")]
219 pub settle_coin: Option<String>,
220 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
222 pub r#type: Option<String>,
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub trans_sub_type: Option<String>,
226 #[serde(skip_serializing_if = "Option::is_none")]
232 pub start_time: Option<Timestamp>,
233 #[serde(skip_serializing_if = "Option::is_none")]
235 pub end_time: Option<Timestamp>,
236 #[serde(skip_serializing_if = "Option::is_none")]
238 pub limit: Option<u64>,
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub cursor: Option<String>,
242}
243
244impl GetTransactionLogParams {
245 pub fn new() -> Self {
246 Self {
247 account_type: None,
248 category: None,
249 currency: None,
250 base_coin: None,
251 settle_coin: None,
252 r#type: None,
253 trans_sub_type: None,
254 start_time: None,
255 end_time: None,
256 limit: None,
257 cursor: None,
258 }
259 }
260
261 pub fn with_account_type(mut self, v: AccountType) -> Self {
262 self.account_type = Some(v);
263 self
264 }
265 pub fn with_category(mut self, v: Category) -> Self {
266 self.category = Some(v);
267 self
268 }
269 pub fn with_currency(mut self, v: String) -> Self {
270 self.currency = Some(v);
271 self
272 }
273 pub fn with_base_coin(mut self, v: String) -> Self {
274 self.base_coin = Some(v);
275 self
276 }
277 pub fn with_settle_coin(mut self, v: String) -> Self {
278 self.settle_coin = Some(v);
279 self
280 }
281 pub fn with_type(mut self, v: String) -> Self {
282 self.r#type = Some(v);
283 self
284 }
285 pub fn with_trans_sub_type(mut self, v: String) -> Self {
286 self.trans_sub_type = Some(v);
287 self
288 }
289 pub fn with_start_time(mut self, v: Timestamp) -> Self {
290 self.start_time = Some(v);
291 self
292 }
293 pub fn with_end_time(mut self, v: Timestamp) -> Self {
294 self.end_time = Some(v);
295 self
296 }
297 pub fn with_limit(mut self, v: u64) -> Self {
298 self.limit = Some(v);
299 self
300 }
301 pub fn with_cursor(mut self, v: String) -> Self {
302 self.cursor = Some(v);
303 self
304 }
305}
306
307impl Default for GetTransactionLogParams {
308 fn default() -> Self {
309 Self::new()
310 }
311}
312
313#[derive(Debug, Deserialize, PartialEq)]
314#[serde(rename_all = "camelCase")]
315pub struct TransactionLog {
316 pub id: String,
318 pub symbol: String,
320 pub category: Category,
322 pub side: crate::Side,
324 #[serde(deserialize_with = "number")]
326 pub transaction_time: Timestamp,
327 #[serde(rename = "type")]
329 pub r#type: String,
330 pub trans_sub_type: String,
332 pub qty: Decimal,
336 pub size: Decimal,
338 pub currency: String,
340 pub trade_price: Decimal,
342 pub funding: Decimal,
346 pub fee: Decimal,
350 pub cash_flow: Decimal,
352 pub change: Decimal,
354 pub cash_balance: Decimal,
356 pub fee_rate: Decimal,
360 pub bonus_change: Decimal,
362 pub trade_id: String,
364 pub order_id: String,
366 #[serde(default, deserialize_with = "crate::serde::empty_string_as_none")]
368 pub order_link_id: Option<String>,
369 #[serde(default)]
371 pub extra_fees: Option<serde_json::Value>,
372}
373
374#[derive(Debug, Serialize, Clone)]
378#[serde(rename_all = "camelCase")]
379pub struct GetFeeRateParams {
380 pub category: Category,
381 pub symbol: Option<String>,
382 pub base_coin: Option<String>,
384}
385
386#[derive(Debug, Deserialize, PartialEq)]
387#[serde(rename_all = "camelCase")]
388pub struct FeeRateEntry {
389 #[serde(default, deserialize_with = "empty_string_as_none")]
391 pub symbol: Option<String>,
392 #[serde(default, deserialize_with = "empty_string_as_none")]
394 pub base_coin: Option<String>,
395 pub taker_fee_rate: Decimal,
396 pub maker_fee_rate: Decimal,
397}
398
399#[derive(Debug, Serialize, Clone)]
403#[serde(rename_all = "camelCase")]
404pub struct SetMarginModeRequest {
405 pub set_margin_mode: MarginMode,
406}
407
408#[derive(Debug, Deserialize, PartialEq)]
413pub struct SetMarginModeResponse {
414 pub reasons: Vec<MarginModeFailureReason>,
415}
416
417#[derive(Debug, Deserialize, PartialEq)]
418#[serde(rename_all = "camelCase")]
419pub struct MarginModeFailureReason {
420 pub reason_code: String,
421 pub reason_msg: String,
422}
423
424#[derive(Debug, Deserialize, PartialEq)]
428#[serde(rename_all = "camelCase")]
429pub struct UpgradeToUtaResult {
430 pub unified_update_status: UnifiedUpdateStatus,
431 pub unified_update_msg: Option<UnifiedUpdateMsg>,
433}
434
435#[derive(Debug, Deserialize, PartialEq)]
436#[serde(rename_all = "camelCase")]
437pub struct UnifiedUpdateMsg {
438 pub msg: Vec<String>,
439}
440
441#[derive(Clone, Debug, Serialize)]
445#[serde(rename_all = "camelCase")]
446pub struct GetBorrowHistoryParams {
447 #[serde(skip_serializing_if = "Option::is_none")]
449 pub currency: Option<String>,
450 #[serde(skip_serializing_if = "Option::is_none")]
452 pub start_time: Option<Timestamp>,
453 #[serde(skip_serializing_if = "Option::is_none")]
455 pub end_time: Option<Timestamp>,
456 #[serde(skip_serializing_if = "Option::is_none")]
458 pub limit: Option<u64>,
459 #[serde(skip_serializing_if = "Option::is_none")]
461 pub cursor: Option<String>,
462}
463
464impl GetBorrowHistoryParams {
465 pub fn new() -> Self {
466 Self {
467 currency: None,
468 start_time: None,
469 end_time: None,
470 limit: None,
471 cursor: None,
472 }
473 }
474
475 pub fn with_currency(mut self, v: String) -> Self {
476 self.currency = Some(v);
477 self
478 }
479 pub fn with_start_time(mut self, v: Timestamp) -> Self {
480 self.start_time = Some(v);
481 self
482 }
483 pub fn with_end_time(mut self, v: Timestamp) -> Self {
484 self.end_time = Some(v);
485 self
486 }
487 pub fn with_limit(mut self, v: u64) -> Self {
488 self.limit = Some(v);
489 self
490 }
491 pub fn with_cursor(mut self, v: String) -> Self {
492 self.cursor = Some(v);
493 self
494 }
495}
496
497impl Default for GetBorrowHistoryParams {
498 fn default() -> Self {
499 Self::new()
500 }
501}
502
503#[derive(Debug, Deserialize, PartialEq)]
504#[serde(rename_all = "camelCase")]
505pub struct BorrowHistoryEntry {
506 pub currency: String,
508 #[serde(deserialize_with = "number")]
510 pub created_time: Timestamp,
511 pub borrow_cost: Decimal,
513 pub hourly_borrow_rate: Decimal,
515 #[serde(rename = "InterestBearingBorrowSize")]
517 pub interest_bearing_borrow_size: Decimal,
518 pub cost_exemption: Decimal,
520 pub borrow_amount: Decimal,
522 pub unrealised_loss: Decimal,
524 #[serde(default, deserialize_with = "option_decimal")]
526 pub free_borrowed_amount: Option<Decimal>,
527}
528
529#[derive(Debug, Serialize, Clone)]
533#[serde(rename_all = "camelCase")]
534pub struct GetCollateralInfoParams {
535 #[serde(skip_serializing_if = "Option::is_none")]
537 pub currency: Option<String>,
538}
539
540impl GetCollateralInfoParams {
541 pub fn new() -> Self {
542 Self { currency: None }
543 }
544
545 pub fn with_currency(mut self, v: String) -> Self {
546 self.currency = Some(v);
547 self
548 }
549}
550
551impl Default for GetCollateralInfoParams {
552 fn default() -> Self {
553 Self::new()
554 }
555}
556
557#[derive(Debug, Deserialize, PartialEq)]
558#[serde(rename_all = "camelCase")]
559pub struct CollateralInfoEntry {
560 pub currency: String,
562 pub hourly_borrow_rate: Decimal,
564 pub max_borrowing_amount: Decimal,
566 pub free_borrowing_limit: Decimal,
568 pub free_borrow_amount: Decimal,
570 pub borrow_amount: Decimal,
572 pub other_borrow_amount: Decimal,
574 pub available_to_borrow: Decimal,
576 pub borrowable: bool,
578 pub borrow_usage_rate: Decimal,
580 pub margin_collateral: bool,
582 pub collateral_switch: bool,
584 #[serde(default, deserialize_with = "option_decimal")]
586 pub collateral_ratio: Option<Decimal>,
587 #[serde(default, deserialize_with = "empty_string_as_none")]
589 pub free_borrowing_amount: Option<String>,
590}