Skip to main content

binance_api_client/models/
margin.rs

1//! Margin Trading API response models.
2//!
3//! Models for the Binance Margin SAPI endpoints.
4
5use serde::{Deserialize, Serialize};
6
7use super::string_or_float;
8use crate::types::{OrderSide, OrderStatus, OrderType, TimeInForce};
9
10/// Margin transfer type.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12pub enum MarginTransferType {
13    /// Transfer from main account to margin account
14    #[serde(rename = "1")]
15    MainToMargin,
16    /// Transfer from margin account to main account
17    #[serde(rename = "2")]
18    MarginToMain,
19}
20
21/// Isolated margin transfer type.
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
23#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
24pub enum IsolatedMarginTransferType {
25    /// Spot account
26    Spot,
27    /// Isolated margin account
28    IsolatedMargin,
29}
30
31/// Side effect type for margin orders.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
33#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
34pub enum SideEffectType {
35    /// No side effect
36    #[default]
37    NoSideEffect,
38    /// Margin buy
39    MarginBuy,
40    /// Auto repay
41    AutoRepay,
42}
43
44/// Transaction ID response.
45#[derive(Debug, Clone, Serialize, Deserialize)]
46#[serde(rename_all = "camelCase")]
47pub struct TransactionId {
48    /// Transaction ID
49    pub tran_id: u64,
50}
51
52/// Margin account details.
53#[derive(Debug, Clone, Serialize, Deserialize)]
54#[serde(rename_all = "camelCase")]
55pub struct MarginAccountDetails {
56    /// Whether borrow is enabled.
57    pub borrow_enabled: bool,
58    /// Margin level.
59    #[serde(with = "string_or_float")]
60    pub margin_level: f64,
61    /// Total asset in BTC.
62    #[serde(with = "string_or_float")]
63    pub total_asset_of_btc: f64,
64    /// Total liability in BTC.
65    #[serde(with = "string_or_float")]
66    pub total_liability_of_btc: f64,
67    /// Total net asset in BTC.
68    #[serde(with = "string_or_float")]
69    pub total_net_asset_of_btc: f64,
70    /// Whether trading is enabled.
71    pub trade_enabled: bool,
72    /// Whether transfer is enabled.
73    pub transfer_enabled: bool,
74    /// User assets.
75    pub user_assets: Vec<MarginAsset>,
76}
77
78/// Margin asset balance.
79#[derive(Debug, Clone, Serialize, Deserialize)]
80#[serde(rename_all = "camelCase")]
81pub struct MarginAsset {
82    /// Asset symbol.
83    pub asset: String,
84    /// Borrowed amount.
85    #[serde(with = "string_or_float")]
86    pub borrowed: f64,
87    /// Free amount.
88    #[serde(with = "string_or_float")]
89    pub free: f64,
90    /// Interest amount.
91    #[serde(with = "string_or_float")]
92    pub interest: f64,
93    /// Locked amount.
94    #[serde(with = "string_or_float")]
95    pub locked: f64,
96    /// Net asset amount.
97    #[serde(with = "string_or_float")]
98    pub net_asset: f64,
99}
100
101/// Isolated margin account details.
102#[derive(Debug, Clone, Serialize, Deserialize)]
103#[serde(rename_all = "camelCase")]
104pub struct IsolatedMarginAccountDetails {
105    /// Assets.
106    #[serde(default)]
107    pub assets: Vec<IsolatedMarginAccountAsset>,
108    /// Total asset in BTC (optional).
109    #[serde(default, with = "string_or_float_option")]
110    pub total_asset_of_btc: Option<f64>,
111    /// Total liability in BTC (optional).
112    #[serde(default, with = "string_or_float_option")]
113    pub total_liability_of_btc: Option<f64>,
114    /// Total net asset in BTC (optional).
115    #[serde(default, with = "string_or_float_option")]
116    pub total_net_asset_of_btc: Option<f64>,
117}
118
119/// Isolated margin account asset.
120#[derive(Debug, Clone, Serialize, Deserialize)]
121#[serde(rename_all = "camelCase")]
122pub struct IsolatedMarginAccountAsset {
123    /// Base asset.
124    pub base_asset: IsolatedAssetDetails,
125    /// Quote asset.
126    pub quote_asset: IsolatedAssetDetails,
127    /// Symbol.
128    pub symbol: String,
129    /// Whether isolated trading is created.
130    pub isolated_created: bool,
131    /// Whether margin trading is enabled.
132    pub enabled: bool,
133    /// Margin level.
134    #[serde(with = "string_or_float")]
135    pub margin_level: f64,
136    /// Margin ratio.
137    #[serde(with = "string_or_float")]
138    pub margin_ratio: f64,
139    /// Index price.
140    #[serde(with = "string_or_float")]
141    pub index_price: f64,
142    /// Liquidate price.
143    #[serde(with = "string_or_float")]
144    pub liquidate_price: f64,
145    /// Liquidate rate.
146    #[serde(with = "string_or_float")]
147    pub liquidate_rate: f64,
148    /// Whether trading is enabled.
149    pub trade_enabled: bool,
150}
151
152/// Isolated asset details.
153#[derive(Debug, Clone, Serialize, Deserialize)]
154#[serde(rename_all = "camelCase")]
155pub struct IsolatedAssetDetails {
156    /// Asset symbol.
157    pub asset: String,
158    /// Whether borrow is enabled.
159    pub borrow_enabled: bool,
160    /// Borrowed amount.
161    #[serde(with = "string_or_float")]
162    pub borrowed: f64,
163    /// Free amount.
164    #[serde(with = "string_or_float")]
165    pub free: f64,
166    /// Interest amount.
167    #[serde(with = "string_or_float")]
168    pub interest: f64,
169    /// Locked amount.
170    #[serde(with = "string_or_float")]
171    pub locked: f64,
172    /// Net asset amount.
173    #[serde(with = "string_or_float")]
174    pub net_asset: f64,
175    /// Net asset in BTC.
176    #[serde(with = "string_or_float")]
177    pub net_asset_of_btc: f64,
178    /// Whether repay is enabled.
179    pub repay_enabled: bool,
180    /// Total asset amount.
181    #[serde(with = "string_or_float")]
182    pub total_asset: f64,
183}
184
185/// Max borrowable amount.
186#[derive(Debug, Clone, Serialize, Deserialize)]
187#[serde(rename_all = "camelCase")]
188pub struct MaxBorrowableAmount {
189    /// Amount.
190    #[serde(with = "string_or_float")]
191    pub amount: f64,
192    /// Borrow limit.
193    #[serde(default, with = "string_or_float_option")]
194    pub borrow_limit: Option<f64>,
195}
196
197/// Max transferable amount.
198#[derive(Debug, Clone, Serialize, Deserialize)]
199#[serde(rename_all = "camelCase")]
200pub struct MaxTransferableAmount {
201    /// Amount.
202    #[serde(with = "string_or_float")]
203    pub amount: f64,
204}
205
206/// Margin order result.
207#[derive(Debug, Clone, Serialize, Deserialize)]
208#[serde(rename_all = "camelCase")]
209pub struct MarginOrderResult {
210    /// Symbol.
211    pub symbol: String,
212    /// Order ID.
213    pub order_id: u64,
214    /// Client order ID.
215    pub client_order_id: String,
216    /// Transaction time.
217    pub transact_time: u64,
218    /// Price.
219    #[serde(with = "string_or_float")]
220    pub price: f64,
221    /// Original quantity.
222    #[serde(with = "string_or_float")]
223    pub orig_qty: f64,
224    /// Executed quantity.
225    #[serde(with = "string_or_float")]
226    pub executed_qty: f64,
227    /// Cumulative quote quantity.
228    #[serde(with = "string_or_float")]
229    pub cummulative_quote_qty: f64,
230    /// Order status.
231    pub status: OrderStatus,
232    /// Time in force.
233    pub time_in_force: TimeInForce,
234    /// Order type.
235    #[serde(rename = "type")]
236    pub order_type: OrderType,
237    /// Order side.
238    pub side: OrderSide,
239    /// Whether this is isolated margin.
240    #[serde(default)]
241    pub is_isolated: Option<bool>,
242}
243
244/// Margin order state (for query).
245#[derive(Debug, Clone, Serialize, Deserialize)]
246#[serde(rename_all = "camelCase")]
247pub struct MarginOrderState {
248    /// Client order ID.
249    pub client_order_id: String,
250    /// Cumulative quote quantity.
251    #[serde(with = "string_or_float")]
252    pub cummulative_quote_qty: f64,
253    /// Executed quantity.
254    #[serde(with = "string_or_float")]
255    pub executed_qty: f64,
256    /// Iceberg quantity.
257    #[serde(default, with = "string_or_float_option")]
258    pub iceberg_qty: Option<f64>,
259    /// Whether working.
260    pub is_working: bool,
261    /// Order ID.
262    pub order_id: u64,
263    /// Original quantity.
264    #[serde(with = "string_or_float")]
265    pub orig_qty: f64,
266    /// Price.
267    #[serde(with = "string_or_float")]
268    pub price: f64,
269    /// Order side.
270    pub side: OrderSide,
271    /// Order status.
272    pub status: OrderStatus,
273    /// Stop price.
274    #[serde(default, with = "string_or_float_option")]
275    pub stop_price: Option<f64>,
276    /// Symbol.
277    pub symbol: String,
278    /// Whether this is isolated margin.
279    #[serde(default)]
280    pub is_isolated: Option<bool>,
281    /// Time.
282    pub time: u64,
283    /// Time in force.
284    pub time_in_force: TimeInForce,
285    /// Order type.
286    #[serde(rename = "type")]
287    pub order_type: OrderType,
288    /// Update time.
289    pub update_time: u64,
290}
291
292/// Margin order cancellation result.
293#[derive(Debug, Clone, Serialize, Deserialize)]
294#[serde(rename_all = "camelCase")]
295pub struct MarginOrderCancellation {
296    /// Symbol.
297    pub symbol: String,
298    /// Order ID.
299    #[serde(default)]
300    pub order_id: Option<u64>,
301    /// Original client order ID.
302    pub orig_client_order_id: String,
303    /// Client order ID.
304    pub client_order_id: String,
305    /// Price.
306    #[serde(with = "string_or_float")]
307    pub price: f64,
308    /// Original quantity.
309    #[serde(with = "string_or_float")]
310    pub orig_qty: f64,
311    /// Executed quantity.
312    #[serde(with = "string_or_float")]
313    pub executed_qty: f64,
314    /// Cumulative quote quantity.
315    #[serde(with = "string_or_float")]
316    pub cummulative_quote_qty: f64,
317    /// Order status.
318    pub status: OrderStatus,
319    /// Time in force.
320    pub time_in_force: TimeInForce,
321    /// Order type.
322    #[serde(rename = "type")]
323    pub order_type: OrderType,
324    /// Order side.
325    pub side: OrderSide,
326}
327
328/// Margin trade record.
329#[derive(Debug, Clone, Serialize, Deserialize)]
330#[serde(rename_all = "camelCase")]
331pub struct MarginTrade {
332    /// Commission.
333    #[serde(with = "string_or_float")]
334    pub commission: f64,
335    /// Commission asset.
336    pub commission_asset: String,
337    /// Trade ID.
338    pub id: u64,
339    /// Whether buyer.
340    pub is_buyer: bool,
341    /// Whether isolated margin.
342    #[serde(default)]
343    pub is_isolated: Option<bool>,
344    /// Whether maker.
345    pub is_maker: bool,
346    /// Order ID.
347    pub order_id: u64,
348    /// Price.
349    #[serde(with = "string_or_float")]
350    pub price: f64,
351    /// Quantity.
352    #[serde(with = "string_or_float")]
353    pub qty: f64,
354    /// Symbol.
355    pub symbol: String,
356    /// Time.
357    pub time: u64,
358}
359
360/// Interest history record.
361#[derive(Debug, Clone, Serialize, Deserialize)]
362#[serde(rename_all = "camelCase")]
363pub struct InterestHistoryRecord {
364    /// Asset.
365    pub asset: String,
366    /// Interest.
367    #[serde(with = "string_or_float")]
368    pub interest: f64,
369    /// Interest accrue time.
370    pub interest_accured_time: u64,
371    /// Interest rate.
372    #[serde(with = "string_or_float")]
373    pub interest_rate: f64,
374    /// Principal.
375    #[serde(with = "string_or_float")]
376    pub principal: f64,
377    /// Interest type.
378    #[serde(rename = "type")]
379    pub interest_type: String,
380    /// Isolated symbol (for isolated margin).
381    #[serde(default)]
382    pub isolated_symbol: Option<String>,
383}
384
385/// Interest rate history record.
386#[derive(Debug, Clone, Serialize, Deserialize)]
387#[serde(rename_all = "camelCase")]
388pub struct InterestRateRecord {
389    /// Asset.
390    pub asset: String,
391    /// Daily interest rate.
392    #[serde(with = "string_or_float")]
393    pub daily_interest_rate: f64,
394    /// Timestamp.
395    pub timestamp: u64,
396    /// VIP level.
397    #[serde(default)]
398    pub vip_level: Option<u32>,
399}
400
401/// Loan record.
402#[derive(Debug, Clone, Serialize, Deserialize)]
403#[serde(rename_all = "camelCase")]
404pub struct LoanRecord {
405    /// Asset.
406    pub asset: String,
407    /// Principal.
408    #[serde(with = "string_or_float")]
409    pub principal: f64,
410    /// Timestamp.
411    pub timestamp: u64,
412    /// Status (PENDING, CONFIRMED, FAILED).
413    pub status: String,
414    /// Isolated symbol (for isolated margin).
415    #[serde(default)]
416    pub isolated_symbol: Option<String>,
417    /// Transaction ID.
418    pub tx_id: u64,
419}
420
421/// Repay record.
422#[derive(Debug, Clone, Serialize, Deserialize)]
423#[serde(rename_all = "camelCase")]
424pub struct RepayRecord {
425    /// Asset.
426    pub asset: String,
427    /// Amount.
428    #[serde(with = "string_or_float")]
429    pub amount: f64,
430    /// Interest.
431    #[serde(with = "string_or_float")]
432    pub interest: f64,
433    /// Principal.
434    #[serde(with = "string_or_float")]
435    pub principal: f64,
436    /// Timestamp.
437    pub timestamp: u64,
438    /// Status (PENDING, CONFIRMED, FAILED).
439    pub status: String,
440    /// Isolated symbol (for isolated margin).
441    #[serde(default)]
442    pub isolated_symbol: Option<String>,
443    /// Transaction ID.
444    pub tx_id: u64,
445}
446
447/// Records query result (paginated).
448#[derive(Debug, Clone, Serialize, Deserialize)]
449pub struct RecordsQueryResult<T> {
450    /// Total records.
451    pub total: u64,
452    /// Records.
453    pub rows: Vec<T>,
454}
455
456/// Cross margin pair details.
457#[derive(Debug, Clone, Serialize, Deserialize)]
458#[serde(rename_all = "camelCase")]
459pub struct MarginPairDetails {
460    /// Symbol ID.
461    pub id: u64,
462    /// Symbol.
463    pub symbol: String,
464    /// Base asset.
465    pub base: String,
466    /// Quote asset.
467    pub quote: String,
468    /// Whether margin trading is enabled.
469    pub is_margin_trade: bool,
470    /// Whether buy is allowed.
471    pub is_buy_allowed: bool,
472    /// Whether sell is allowed.
473    pub is_sell_allowed: bool,
474}
475
476/// Margin asset info.
477#[derive(Debug, Clone, Serialize, Deserialize)]
478#[serde(rename_all = "camelCase")]
479pub struct MarginAssetInfo {
480    /// Asset name.
481    pub asset_name: String,
482    /// Asset full name.
483    pub asset_full_name: String,
484    /// Whether borrowing is enabled.
485    pub is_borrowable: bool,
486    /// Whether mortgage is enabled.
487    pub is_mortgageable: bool,
488    /// User min borrow.
489    #[serde(with = "string_or_float")]
490    pub user_min_borrow: f64,
491    /// User min repay.
492    #[serde(with = "string_or_float")]
493    pub user_min_repay: f64,
494}
495
496/// Margin price index.
497#[derive(Debug, Clone, Serialize, Deserialize)]
498#[serde(rename_all = "camelCase")]
499pub struct MarginPriceIndex {
500    /// Calculation time.
501    pub calc_time: u64,
502    /// Price.
503    #[serde(with = "string_or_float")]
504    pub price: f64,
505    /// Symbol.
506    pub symbol: String,
507}
508
509/// Isolated margin account limit.
510#[derive(Debug, Clone, Serialize, Deserialize)]
511#[serde(rename_all = "camelCase")]
512pub struct IsolatedAccountLimit {
513    /// Enabled account count.
514    pub enabled_account: u32,
515    /// Max account count.
516    pub max_account: u32,
517}
518
519/// BNB burn status.
520#[derive(Debug, Clone, Serialize, Deserialize)]
521#[serde(rename_all = "camelCase")]
522pub struct BnbBurnStatus {
523    /// Whether spot BNB burn is enabled.
524    pub spot_bnb_burn: bool,
525    /// Whether interest BNB burn is enabled.
526    pub interest_bnb_burn: bool,
527}
528
529/// Helper for optional f64 fields that may be strings.
530mod string_or_float_option {
531    use serde::{self, Deserialize, Deserializer, Serializer};
532
533    pub fn serialize<S>(value: &Option<f64>, serializer: S) -> Result<S::Ok, S::Error>
534    where
535        S: Serializer,
536    {
537        match value {
538            Some(v) => serializer.serialize_str(&v.to_string()),
539            None => serializer.serialize_none(),
540        }
541    }
542
543    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
544    where
545        D: Deserializer<'de>,
546    {
547        #[derive(Deserialize)]
548        #[serde(untagged)]
549        enum StringOrFloat {
550            String(String),
551            Float(f64),
552        }
553
554        let opt: Option<StringOrFloat> = Option::deserialize(deserializer)?;
555        match opt {
556            Some(StringOrFloat::Float(f)) => Ok(Some(f)),
557            Some(StringOrFloat::String(s)) => {
558                s.parse::<f64>().map(Some).map_err(serde::de::Error::custom)
559            }
560            None => Ok(None),
561        }
562    }
563}