1use serde::{Deserialize, Serialize};
4
5use crate::types::{AccountType, Category};
6
7
8#[derive(Debug, Clone, Serialize)]
10#[serde(rename_all = "camelCase")]
11pub struct GetWalletBalanceParams {
12 pub account_type: AccountType,
14 #[serde(skip_serializing_if = "Option::is_none")]
16 pub coin: Option<String>,
17}
18
19impl GetWalletBalanceParams {
20 pub fn new(account_type: AccountType) -> Self {
22 Self {
23 account_type,
24 coin: None,
25 }
26 }
27
28 pub fn coin(mut self, coin: impl Into<String>) -> Self {
30 self.coin = Some(coin.into());
31 self
32 }
33}
34
35#[derive(Debug, Clone, Serialize)]
37#[serde(rename_all = "camelCase")]
38pub struct GetFeeRatesParams {
39 pub category: Category,
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub symbol: Option<String>,
44 #[serde(skip_serializing_if = "Option::is_none")]
46 pub base_coin: Option<String>,
47}
48
49impl GetFeeRatesParams {
50 pub fn new(category: Category) -> Self {
52 Self {
53 category,
54 symbol: None,
55 base_coin: None,
56 }
57 }
58
59 pub fn symbol(mut self, symbol: impl Into<String>) -> Self {
61 self.symbol = Some(symbol.into());
62 self
63 }
64
65 pub fn base_coin(mut self, coin: impl Into<String>) -> Self {
67 self.base_coin = Some(coin.into());
68 self
69 }
70}
71
72#[derive(Debug, Clone, Serialize)]
74#[serde(rename_all = "camelCase")]
75pub struct GetBorrowHistoryParams {
76 #[serde(skip_serializing_if = "Option::is_none")]
78 pub currency: Option<String>,
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub start_time: Option<u64>,
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub end_time: Option<u64>,
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub limit: Option<u32>,
88 #[serde(skip_serializing_if = "Option::is_none")]
90 pub cursor: Option<String>,
91}
92
93impl GetBorrowHistoryParams {
94 pub fn new() -> Self {
96 Self {
97 currency: None,
98 start_time: None,
99 end_time: None,
100 limit: None,
101 cursor: None,
102 }
103 }
104
105 pub fn currency(mut self, currency: impl Into<String>) -> Self {
107 self.currency = Some(currency.into());
108 self
109 }
110
111 pub fn start_time(mut self, start: u64) -> Self {
113 self.start_time = Some(start);
114 self
115 }
116
117 pub fn end_time(mut self, end: u64) -> Self {
119 self.end_time = Some(end);
120 self
121 }
122
123 pub fn limit(mut self, limit: u32) -> Self {
125 self.limit = Some(limit);
126 self
127 }
128
129 pub fn cursor(mut self, cursor: impl Into<String>) -> Self {
131 self.cursor = Some(cursor.into());
132 self
133 }
134}
135
136impl Default for GetBorrowHistoryParams {
137 fn default() -> Self {
138 Self::new()
139 }
140}
141
142#[derive(Debug, Clone, Serialize)]
144#[serde(rename_all = "camelCase")]
145pub struct GetCollateralInfoParams {
146 #[serde(skip_serializing_if = "Option::is_none")]
148 pub currency: Option<String>,
149}
150
151impl GetCollateralInfoParams {
152 pub fn new() -> Self {
154 Self { currency: None }
155 }
156
157 pub fn currency(mut self, currency: impl Into<String>) -> Self {
159 self.currency = Some(currency.into());
160 self
161 }
162}
163
164impl Default for GetCollateralInfoParams {
165 fn default() -> Self {
166 Self::new()
167 }
168}
169
170#[derive(Debug, Clone, Serialize)]
172#[serde(rename_all = "camelCase")]
173pub struct SetCollateralCoinParams {
174 pub coin: String,
176 pub collateral_switch: String,
178}
179
180impl SetCollateralCoinParams {
181 pub fn enable(coin: impl Into<String>) -> Self {
183 Self {
184 coin: coin.into(),
185 collateral_switch: "ON".to_string(),
186 }
187 }
188
189 pub fn disable(coin: impl Into<String>) -> Self {
191 Self {
192 coin: coin.into(),
193 collateral_switch: "OFF".to_string(),
194 }
195 }
196}
197
198#[derive(Debug, Clone, Serialize)]
200#[serde(rename_all = "camelCase")]
201pub struct GetCoinGreeksParams {
202 #[serde(skip_serializing_if = "Option::is_none")]
204 pub base_coin: Option<String>,
205}
206
207impl GetCoinGreeksParams {
208 pub fn new() -> Self {
210 Self { base_coin: None }
211 }
212
213 pub fn base_coin(mut self, coin: impl Into<String>) -> Self {
215 self.base_coin = Some(coin.into());
216 self
217 }
218}
219
220impl Default for GetCoinGreeksParams {
221 fn default() -> Self {
222 Self::new()
223 }
224}
225
226#[derive(Debug, Clone, Serialize)]
228#[serde(rename_all = "camelCase")]
229pub struct GetTransactionLogParams {
230 #[serde(skip_serializing_if = "Option::is_none")]
232 pub account_type: Option<AccountType>,
233 #[serde(skip_serializing_if = "Option::is_none")]
235 pub category: Option<Category>,
236 #[serde(skip_serializing_if = "Option::is_none")]
238 pub currency: Option<String>,
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub base_coin: Option<String>,
242 #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
244 pub transaction_type: Option<String>,
245 #[serde(skip_serializing_if = "Option::is_none")]
247 pub start_time: Option<u64>,
248 #[serde(skip_serializing_if = "Option::is_none")]
250 pub end_time: Option<u64>,
251 #[serde(skip_serializing_if = "Option::is_none")]
253 pub limit: Option<u32>,
254 #[serde(skip_serializing_if = "Option::is_none")]
256 pub cursor: Option<String>,
257}
258
259impl GetTransactionLogParams {
260 pub fn new() -> Self {
262 Self {
263 account_type: None,
264 category: None,
265 currency: None,
266 base_coin: None,
267 transaction_type: None,
268 start_time: None,
269 end_time: None,
270 limit: None,
271 cursor: None,
272 }
273 }
274
275 pub fn account_type(mut self, account_type: AccountType) -> Self {
277 self.account_type = Some(account_type);
278 self
279 }
280
281 pub fn category(mut self, category: Category) -> Self {
283 self.category = Some(category);
284 self
285 }
286
287 pub fn currency(mut self, currency: impl Into<String>) -> Self {
289 self.currency = Some(currency.into());
290 self
291 }
292
293 pub fn transaction_type(mut self, t: impl Into<String>) -> Self {
295 self.transaction_type = Some(t.into());
296 self
297 }
298
299 pub fn start_time(mut self, start: u64) -> Self {
301 self.start_time = Some(start);
302 self
303 }
304
305 pub fn end_time(mut self, end: u64) -> Self {
307 self.end_time = Some(end);
308 self
309 }
310
311 pub fn limit(mut self, limit: u32) -> Self {
313 self.limit = Some(limit);
314 self
315 }
316
317 pub fn cursor(mut self, cursor: impl Into<String>) -> Self {
319 self.cursor = Some(cursor.into());
320 self
321 }
322}
323
324impl Default for GetTransactionLogParams {
325 fn default() -> Self {
326 Self::new()
327 }
328}
329
330#[derive(Debug, Clone, Serialize)]
332#[serde(rename_all = "camelCase")]
333pub struct SetMarginModeParams {
334 pub set_margin_mode: String,
336}
337
338impl SetMarginModeParams {
339 pub fn regular_margin() -> Self {
341 Self {
342 set_margin_mode: "REGULAR_MARGIN".to_string(),
343 }
344 }
345
346 pub fn portfolio_margin() -> Self {
348 Self {
349 set_margin_mode: "PORTFOLIO_MARGIN".to_string(),
350 }
351 }
352}
353
354
355#[derive(Debug, Clone, Deserialize)]
357#[serde(rename_all = "camelCase")]
358pub struct CoinBalance {
359 pub coin: String,
361 pub equity: String,
363 pub usd_value: String,
365 pub wallet_balance: String,
367 #[serde(default)]
369 pub free: Option<String>,
370 #[serde(default)]
372 pub locked: Option<String>,
373 #[serde(default)]
375 pub borrow_amount: Option<String>,
376 #[serde(default)]
378 pub available_to_borrow: Option<String>,
379 #[serde(default)]
381 pub available_to_withdraw: Option<String>,
382 #[serde(default)]
384 pub accrued_interest: Option<String>,
385 #[serde(default)]
387 pub total_order_i_m: Option<String>,
388 #[serde(default)]
390 pub total_position_i_m: Option<String>,
391 #[serde(default)]
393 pub total_position_m_m: Option<String>,
394 #[serde(default)]
396 pub unrealised_pnl: Option<String>,
397 #[serde(default)]
399 pub cum_realised_pnl: Option<String>,
400 #[serde(default)]
402 pub bonus: Option<String>,
403 #[serde(default)]
405 pub margin_collateral: Option<bool>,
406 #[serde(default)]
408 pub collateral_switch: Option<bool>,
409 #[serde(default)]
411 pub spot_borrow: Option<String>,
412}
413
414#[derive(Debug, Clone, Deserialize)]
416#[serde(rename_all = "camelCase")]
417pub struct WalletBalance {
418 pub account_type: String,
420 #[serde(default)]
422 pub account_l_t_v: Option<String>,
423 #[serde(default)]
425 pub account_i_m_rate: Option<String>,
426 #[serde(default)]
428 pub account_m_m_rate: Option<String>,
429 pub total_equity: String,
431 pub total_wallet_balance: String,
433 #[serde(default)]
435 pub total_margin_balance: Option<String>,
436 pub total_available_balance: String,
438 #[serde(default)]
440 pub total_perp_u_p_l: Option<String>,
441 #[serde(default)]
443 pub total_initial_margin: Option<String>,
444 #[serde(default)]
446 pub total_maintenance_margin: Option<String>,
447 pub coin: Vec<CoinBalance>,
449}
450
451#[derive(Debug, Clone, Deserialize)]
453#[serde(rename_all = "camelCase")]
454pub struct WalletBalanceResult {
455 pub list: Vec<WalletBalance>,
457}
458
459#[derive(Debug, Clone, Deserialize)]
461#[serde(rename_all = "camelCase")]
462pub struct AccountInfo {
463 #[serde(default)]
465 pub unified_margin_status: Option<i32>,
466 pub margin_mode: String,
468 #[serde(default)]
470 pub is_master_trader: Option<bool>,
471 #[serde(default)]
473 pub spot_hedging_status: Option<String>,
474 pub updated_time: String,
476}
477
478#[derive(Debug, Clone, Deserialize)]
480#[serde(rename_all = "camelCase")]
481pub struct FeeRate {
482 pub symbol: String,
484 #[serde(default)]
486 pub base_coin: Option<String>,
487 pub taker_fee_rate: String,
489 pub maker_fee_rate: String,
491}
492
493#[derive(Debug, Clone, Deserialize)]
495#[serde(rename_all = "camelCase")]
496pub struct FeeRateResult {
497 #[serde(default)]
499 pub category: Option<Category>,
500 pub list: Vec<FeeRate>,
502}
503
504#[derive(Debug, Clone, Deserialize)]
506#[serde(rename_all = "camelCase")]
507pub struct BorrowHistoryRecord {
508 pub currency: String,
510 pub created_time: u64,
512 pub borrow_cost: String,
514 pub hourly_borrow_rate: String,
516 #[serde(rename = "InterestBearingBorrowSize")]
518 #[serde(default)]
519 pub interest_bearing_borrow_size: Option<String>,
520 #[serde(default)]
522 pub cost_exemption: Option<String>,
523 #[serde(default)]
525 pub borrow_amount: Option<String>,
526 #[serde(default)]
528 pub unrealised_loss: Option<String>,
529 #[serde(default)]
531 pub free_borrowed_amount: Option<String>,
532}
533
534#[derive(Debug, Clone, Deserialize)]
536#[serde(rename_all = "camelCase")]
537pub struct BorrowHistoryResult {
538 pub list: Vec<BorrowHistoryRecord>,
540 #[serde(default)]
542 pub next_page_cursor: Option<String>,
543}
544
545#[derive(Debug, Clone, Deserialize)]
547#[serde(rename_all = "camelCase")]
548pub struct CollateralInfo {
549 pub currency: String,
551 pub hourly_borrow_rate: String,
553 pub max_borrowing_amount: String,
555 #[serde(default)]
557 pub free_borrow_amount: Option<String>,
558 #[serde(default)]
560 pub free_borrowing_limit: Option<String>,
561 #[serde(default)]
563 pub borrow_amount: Option<String>,
564 #[serde(default)]
566 pub available_to_borrow: Option<String>,
567 pub borrowable: bool,
569 #[serde(default)]
571 pub borrow_usage_rate: Option<String>,
572 #[serde(default)]
574 pub margin_collateral: Option<bool>,
575 #[serde(default)]
577 pub collateral_switch: Option<bool>,
578 #[serde(default)]
580 pub collateral_ratio: Option<String>,
581}
582
583#[derive(Debug, Clone, Deserialize)]
585#[serde(rename_all = "camelCase")]
586pub struct CollateralInfoResult {
587 pub list: Vec<CollateralInfo>,
589}
590
591#[derive(Debug, Clone, Deserialize)]
593#[serde(rename_all = "camelCase")]
594pub struct CoinGreeks {
595 pub base_coin: String,
597 pub total_delta: String,
599 pub total_gamma: String,
601 pub total_vega: String,
603 pub total_theta: String,
605}
606
607#[derive(Debug, Clone, Deserialize)]
609#[serde(rename_all = "camelCase")]
610pub struct CoinGreeksResult {
611 pub list: Vec<CoinGreeks>,
613}
614
615#[derive(Debug, Clone, Deserialize)]
617#[serde(rename_all = "camelCase")]
618pub struct TransactionLog {
619 #[serde(default)]
621 pub symbol: Option<String>,
622 #[serde(default)]
624 pub category: Option<String>,
625 #[serde(default)]
627 pub side: Option<String>,
628 pub transaction_time: String,
630 #[serde(rename = "type")]
632 pub transaction_type: String,
633 #[serde(default)]
635 pub qty: Option<String>,
636 #[serde(default)]
638 pub size: Option<String>,
639 pub currency: String,
641 #[serde(default)]
643 pub trade_price: Option<String>,
644 #[serde(default)]
646 pub funding: Option<String>,
647 #[serde(default)]
649 pub fee: Option<String>,
650 pub cash_flow: String,
652 pub change: String,
654 pub cash_balance: String,
656 #[serde(default)]
658 pub fee_rate: Option<String>,
659 #[serde(default)]
661 pub bonus_change: Option<String>,
662 #[serde(default)]
664 pub trade_id: Option<String>,
665 #[serde(default)]
667 pub order_id: Option<String>,
668 #[serde(default)]
670 pub order_link_id: Option<String>,
671}
672
673#[derive(Debug, Clone, Deserialize)]
675#[serde(rename_all = "camelCase")]
676pub struct TransactionLogResult {
677 pub list: Vec<TransactionLog>,
679 #[serde(default)]
681 pub next_page_cursor: Option<String>,
682}
683
684#[derive(Debug, Clone, Deserialize)]
686#[serde(rename_all = "camelCase")]
687pub struct MarginModeResult {
688 #[serde(default)]
690 pub reasons: Option<Vec<MarginModeReason>>,
691}
692
693#[derive(Debug, Clone, Deserialize)]
695#[serde(rename_all = "camelCase")]
696pub struct MarginModeReason {
697 pub reason_code: String,
699 pub reason_msg: String,
701}
702
703#[cfg(test)]
704mod tests {
705 use super::*;
706
707 #[test]
708 fn test_get_wallet_balance_params() {
709 let params = GetWalletBalanceParams::new(AccountType::Unified)
710 .coin("BTC");
711
712 assert_eq!(params.coin, Some("BTC".to_string()));
713 }
714
715 #[test]
716 fn test_get_fee_rates_params() {
717 let params = GetFeeRatesParams::new(Category::Linear)
718 .symbol("BTCUSDT");
719
720 assert_eq!(params.symbol, Some("BTCUSDT".to_string()));
721 }
722
723 #[test]
724 fn test_set_collateral_coin_params() {
725 let enable = SetCollateralCoinParams::enable("BTC");
726 assert_eq!(enable.collateral_switch, "ON");
727
728 let disable = SetCollateralCoinParams::disable("ETH");
729 assert_eq!(disable.collateral_switch, "OFF");
730 }
731
732 #[test]
733 fn test_set_margin_mode_params() {
734 let regular = SetMarginModeParams::regular_margin();
735 assert_eq!(regular.set_margin_mode, "REGULAR_MARGIN");
736
737 let portfolio = SetMarginModeParams::portfolio_margin();
738 assert_eq!(portfolio.set_margin_mode, "PORTFOLIO_MARGIN");
739 }
740}