Skip to main content

binance_sdk/margin_trading/rest_api/apis/
account_api.rs

1/*
2 * Margin REST API
3 *
4 * Access account information, borrow and repay assets, and trade with Binance Margin.
5 *
6 * The version of the OpenAPI document: 1.0.0
7 *
8 *
9 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
10 * https://openapi-generator.tech
11 * Do not edit the class manually.
12 */
13
14#![allow(unused_imports)]
15use async_trait::async_trait;
16use derive_builder::Builder;
17use reqwest;
18use rust_decimal::prelude::*;
19use serde::{Deserialize, Serialize};
20use serde_json::{Value, json};
21use std::collections::BTreeMap;
22
23use crate::common::{
24    config::ConfigurationRestApi,
25    models::{ParamBuildError, RestApiResponse},
26    utils::send_request,
27};
28use crate::margin_trading::rest_api::models;
29
30const HAS_TIME_UNIT: bool = false;
31
32#[async_trait]
33pub trait AccountApi: Send + Sync {
34    async fn adjust_cross_margin_max_leverage(
35        &self,
36        params: AdjustCrossMarginMaxLeverageParams,
37    ) -> anyhow::Result<RestApiResponse<models::AdjustCrossMarginMaxLeverageResponse>>;
38    async fn disable_isolated_margin_account(
39        &self,
40        params: DisableIsolatedMarginAccountParams,
41    ) -> anyhow::Result<RestApiResponse<models::DisableIsolatedMarginAccountResponse>>;
42    async fn enable_isolated_margin_account(
43        &self,
44        params: EnableIsolatedMarginAccountParams,
45    ) -> anyhow::Result<RestApiResponse<models::EnableIsolatedMarginAccountResponse>>;
46    async fn get_bnb_burn_status(
47        &self,
48        params: GetBnbBurnStatusParams,
49    ) -> anyhow::Result<RestApiResponse<models::GetBnbBurnStatusResponse>>;
50    async fn get_summary_of_margin_account(
51        &self,
52        params: GetSummaryOfMarginAccountParams,
53    ) -> anyhow::Result<RestApiResponse<models::GetSummaryOfMarginAccountResponse>>;
54    async fn query_cross_isolated_margin_capital_flow(
55        &self,
56        params: QueryCrossIsolatedMarginCapitalFlowParams,
57    ) -> anyhow::Result<
58        RestApiResponse<Vec<models::QueryCrossIsolatedMarginCapitalFlowResponseInner>>,
59    >;
60    async fn query_cross_margin_account_details(
61        &self,
62        params: QueryCrossMarginAccountDetailsParams,
63    ) -> anyhow::Result<RestApiResponse<models::QueryCrossMarginAccountDetailsResponse>>;
64    async fn query_cross_margin_fee_data(
65        &self,
66        params: QueryCrossMarginFeeDataParams,
67    ) -> anyhow::Result<RestApiResponse<Vec<models::QueryCrossMarginFeeDataResponseInner>>>;
68    async fn query_enabled_isolated_margin_account_limit(
69        &self,
70        params: QueryEnabledIsolatedMarginAccountLimitParams,
71    ) -> anyhow::Result<RestApiResponse<models::QueryEnabledIsolatedMarginAccountLimitResponse>>;
72    async fn query_isolated_margin_account_info(
73        &self,
74        params: QueryIsolatedMarginAccountInfoParams,
75    ) -> anyhow::Result<RestApiResponse<models::QueryIsolatedMarginAccountInfoResponse>>;
76    async fn query_isolated_margin_fee_data(
77        &self,
78        params: QueryIsolatedMarginFeeDataParams,
79    ) -> anyhow::Result<RestApiResponse<Vec<models::QueryIsolatedMarginFeeDataResponseInner>>>;
80}
81
82#[derive(Debug, Clone)]
83pub struct AccountApiClient {
84    configuration: ConfigurationRestApi,
85}
86
87impl AccountApiClient {
88    pub fn new(configuration: ConfigurationRestApi) -> Self {
89        Self { configuration }
90    }
91}
92
93#[allow(non_camel_case_types)]
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub enum QueryCrossIsolatedMarginCapitalFlowTypeEnum {
96    #[serde(rename = "TRANSFER")]
97    Transfer,
98    #[serde(rename = "BORROW")]
99    Borrow,
100    #[serde(rename = "REPAY")]
101    Repay,
102    #[serde(rename = "BUY_INCOME")]
103    BuyIncome,
104    #[serde(rename = "BUY_EXPENSE")]
105    BuyExpense,
106    #[serde(rename = "SELL_INCOME")]
107    SellIncome,
108    #[serde(rename = "SELL_EXPENSE")]
109    SellExpense,
110    #[serde(rename = "TRADING_COMMISSION")]
111    TradingCommission,
112    #[serde(rename = "BUY_LIQUIDATION")]
113    BuyLiquidation,
114    #[serde(rename = "SELL_LIQUIDATION")]
115    SellLiquidation,
116    #[serde(rename = "REPAY_LIQUIDATION")]
117    RepayLiquidation,
118    #[serde(rename = "OTHER_LIQUIDATION")]
119    OtherLiquidation,
120    #[serde(rename = "LIQUIDATION_FEE")]
121    LiquidationFee,
122    #[serde(rename = "SMALL_BALANCE_CONVERT")]
123    SmallBalanceConvert,
124    #[serde(rename = "COMMISSION_RETURN")]
125    CommissionReturn,
126    #[serde(rename = "SMALL_CONVERT")]
127    SmallConvert,
128}
129
130impl QueryCrossIsolatedMarginCapitalFlowTypeEnum {
131    #[must_use]
132    pub fn as_str(&self) -> &'static str {
133        match self {
134            Self::Transfer => "TRANSFER",
135            Self::Borrow => "BORROW",
136            Self::Repay => "REPAY",
137            Self::BuyIncome => "BUY_INCOME",
138            Self::BuyExpense => "BUY_EXPENSE",
139            Self::SellIncome => "SELL_INCOME",
140            Self::SellExpense => "SELL_EXPENSE",
141            Self::TradingCommission => "TRADING_COMMISSION",
142            Self::BuyLiquidation => "BUY_LIQUIDATION",
143            Self::SellLiquidation => "SELL_LIQUIDATION",
144            Self::RepayLiquidation => "REPAY_LIQUIDATION",
145            Self::OtherLiquidation => "OTHER_LIQUIDATION",
146            Self::LiquidationFee => "LIQUIDATION_FEE",
147            Self::SmallBalanceConvert => "SMALL_BALANCE_CONVERT",
148            Self::CommissionReturn => "COMMISSION_RETURN",
149            Self::SmallConvert => "SMALL_CONVERT",
150        }
151    }
152}
153
154impl std::str::FromStr for QueryCrossIsolatedMarginCapitalFlowTypeEnum {
155    type Err = Box<dyn std::error::Error + Send + Sync>;
156
157    fn from_str(s: &str) -> Result<Self, Self::Err> {
158        match s {
159            "TRANSFER" => Ok(Self::Transfer),
160            "BORROW" => Ok(Self::Borrow),
161            "REPAY" => Ok(Self::Repay),
162            "BUY_INCOME" => Ok(Self::BuyIncome),
163            "BUY_EXPENSE" => Ok(Self::BuyExpense),
164            "SELL_INCOME" => Ok(Self::SellIncome),
165            "SELL_EXPENSE" => Ok(Self::SellExpense),
166            "TRADING_COMMISSION" => Ok(Self::TradingCommission),
167            "BUY_LIQUIDATION" => Ok(Self::BuyLiquidation),
168            "SELL_LIQUIDATION" => Ok(Self::SellLiquidation),
169            "REPAY_LIQUIDATION" => Ok(Self::RepayLiquidation),
170            "OTHER_LIQUIDATION" => Ok(Self::OtherLiquidation),
171            "LIQUIDATION_FEE" => Ok(Self::LiquidationFee),
172            "SMALL_BALANCE_CONVERT" => Ok(Self::SmallBalanceConvert),
173            "COMMISSION_RETURN" => Ok(Self::CommissionReturn),
174            "SMALL_CONVERT" => Ok(Self::SmallConvert),
175            other => Err(format!(
176                "invalid QueryCrossIsolatedMarginCapitalFlowTypeEnum: {}",
177                other
178            )
179            .into()),
180        }
181    }
182}
183
184/// Request parameters for the [`adjust_cross_margin_max_leverage`] operation.
185///
186/// This struct holds all of the inputs you can pass when calling
187/// [`adjust_cross_margin_max_leverage`](#method.adjust_cross_margin_max_leverage).
188#[derive(Clone, Debug, Builder, Deserialize)]
189#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
190pub struct AdjustCrossMarginMaxLeverageParams {
191    /// Can only adjust 3 , 5 or 10,Example: maxLeverage = 5 or 3 for Cross Margin Classic; maxLeverage=10 for Cross Margin Pro 10x leverage or 20x if compliance allows.
192    ///
193    /// This field is **required.
194    #[builder(setter(into))]
195    #[serde(rename = "maxLeverage")]
196    pub max_leverage: i64,
197}
198
199impl AdjustCrossMarginMaxLeverageParams {
200    /// Create a builder for [`adjust_cross_margin_max_leverage`].
201    ///
202    /// Required parameters:
203    ///
204    /// * `max_leverage` — Can only adjust 3 , 5 or 10,Example: maxLeverage = 5 or 3 for Cross Margin Classic; maxLeverage=10 for Cross Margin Pro 10x leverage or 20x if compliance allows.
205    ///
206    #[must_use]
207    pub fn builder(max_leverage: i64) -> AdjustCrossMarginMaxLeverageParamsBuilder {
208        AdjustCrossMarginMaxLeverageParamsBuilder::default().max_leverage(max_leverage)
209    }
210}
211/// Request parameters for the [`disable_isolated_margin_account`] operation.
212///
213/// This struct holds all of the inputs you can pass when calling
214/// [`disable_isolated_margin_account`](#method.disable_isolated_margin_account).
215#[derive(Clone, Debug, Builder, Deserialize)]
216#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
217pub struct DisableIsolatedMarginAccountParams {
218    ///
219    /// The `symbol` parameter.
220    ///
221    /// This field is **required.
222    #[builder(setter(into))]
223    #[serde(rename = "symbol")]
224    pub symbol: String,
225    ///
226    /// The `recv_window` parameter.
227    ///
228    /// This field is **optional.
229    #[builder(setter(into), default)]
230    #[serde(rename = "recvWindow", default)]
231    pub recv_window: Option<i64>,
232}
233
234impl DisableIsolatedMarginAccountParams {
235    /// Create a builder for [`disable_isolated_margin_account`].
236    ///
237    /// Required parameters:
238    ///
239    /// * `symbol` — String
240    ///
241    #[must_use]
242    pub fn builder(symbol: String) -> DisableIsolatedMarginAccountParamsBuilder {
243        DisableIsolatedMarginAccountParamsBuilder::default().symbol(symbol)
244    }
245}
246/// Request parameters for the [`enable_isolated_margin_account`] operation.
247///
248/// This struct holds all of the inputs you can pass when calling
249/// [`enable_isolated_margin_account`](#method.enable_isolated_margin_account).
250#[derive(Clone, Debug, Builder, Deserialize)]
251#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
252pub struct EnableIsolatedMarginAccountParams {
253    ///
254    /// The `symbol` parameter.
255    ///
256    /// This field is **required.
257    #[builder(setter(into))]
258    #[serde(rename = "symbol")]
259    pub symbol: String,
260    ///
261    /// The `recv_window` parameter.
262    ///
263    /// This field is **optional.
264    #[builder(setter(into), default)]
265    #[serde(rename = "recvWindow", default)]
266    pub recv_window: Option<i64>,
267}
268
269impl EnableIsolatedMarginAccountParams {
270    /// Create a builder for [`enable_isolated_margin_account`].
271    ///
272    /// Required parameters:
273    ///
274    /// * `symbol` — String
275    ///
276    #[must_use]
277    pub fn builder(symbol: String) -> EnableIsolatedMarginAccountParamsBuilder {
278        EnableIsolatedMarginAccountParamsBuilder::default().symbol(symbol)
279    }
280}
281/// Request parameters for the [`get_bnb_burn_status`] operation.
282///
283/// This struct holds all of the inputs you can pass when calling
284/// [`get_bnb_burn_status`](#method.get_bnb_burn_status).
285#[derive(Clone, Debug, Builder, Deserialize, Default)]
286#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
287pub struct GetBnbBurnStatusParams {
288    ///
289    /// The `recv_window` parameter.
290    ///
291    /// This field is **optional.
292    #[builder(setter(into), default)]
293    #[serde(rename = "recvWindow", default)]
294    pub recv_window: Option<i64>,
295}
296
297impl GetBnbBurnStatusParams {
298    /// Create a builder for [`get_bnb_burn_status`].
299    ///
300    #[must_use]
301    pub fn builder() -> GetBnbBurnStatusParamsBuilder {
302        GetBnbBurnStatusParamsBuilder::default()
303    }
304}
305/// Request parameters for the [`get_summary_of_margin_account`] operation.
306///
307/// This struct holds all of the inputs you can pass when calling
308/// [`get_summary_of_margin_account`](#method.get_summary_of_margin_account).
309#[derive(Clone, Debug, Builder, Deserialize, Default)]
310#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
311pub struct GetSummaryOfMarginAccountParams {
312    ///
313    /// The `recv_window` parameter.
314    ///
315    /// This field is **optional.
316    #[builder(setter(into), default)]
317    #[serde(rename = "recvWindow", default)]
318    pub recv_window: Option<i64>,
319}
320
321impl GetSummaryOfMarginAccountParams {
322    /// Create a builder for [`get_summary_of_margin_account`].
323    ///
324    #[must_use]
325    pub fn builder() -> GetSummaryOfMarginAccountParamsBuilder {
326        GetSummaryOfMarginAccountParamsBuilder::default()
327    }
328}
329/// Request parameters for the [`query_cross_isolated_margin_capital_flow`] operation.
330///
331/// This struct holds all of the inputs you can pass when calling
332/// [`query_cross_isolated_margin_capital_flow`](#method.query_cross_isolated_margin_capital_flow).
333#[derive(Clone, Debug, Builder, Deserialize, Default)]
334#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
335pub struct QueryCrossIsolatedMarginCapitalFlowParams {
336    ///
337    /// The `asset` parameter.
338    ///
339    /// This field is **optional.
340    #[builder(setter(into), default)]
341    #[serde(rename = "asset", default)]
342    pub asset: Option<String>,
343    /// Mandatory for Isolated data
344    ///
345    /// This field is **optional.
346    #[builder(setter(into), default)]
347    #[serde(rename = "symbol", default)]
348    pub symbol: Option<String>,
349    ///
350    /// The `r#type` parameter.
351    ///
352    /// This field is **optional.
353    #[builder(setter(into), default)]
354    #[serde(rename = "type", default)]
355    pub r#type: Option<QueryCrossIsolatedMarginCapitalFlowTypeEnum>,
356    ///
357    /// The `start_time` parameter.
358    ///
359    /// This field is **optional.
360    #[builder(setter(into), default)]
361    #[serde(rename = "startTime", default)]
362    pub start_time: Option<i64>,
363    ///
364    /// The `end_time` parameter.
365    ///
366    /// This field is **optional.
367    #[builder(setter(into), default)]
368    #[serde(rename = "endTime", default)]
369    pub end_time: Option<i64>,
370    ///
371    /// The `from_id` parameter.
372    ///
373    /// This field is **optional.
374    #[builder(setter(into), default)]
375    #[serde(rename = "fromId", default)]
376    pub from_id: Option<i64>,
377    ///
378    /// The `limit` parameter.
379    ///
380    /// This field is **optional.
381    #[builder(setter(into), default)]
382    #[serde(rename = "limit", default)]
383    pub limit: Option<i64>,
384    ///
385    /// The `recv_window` parameter.
386    ///
387    /// This field is **optional.
388    #[builder(setter(into), default)]
389    #[serde(rename = "recvWindow", default)]
390    pub recv_window: Option<i64>,
391}
392
393impl QueryCrossIsolatedMarginCapitalFlowParams {
394    /// Create a builder for [`query_cross_isolated_margin_capital_flow`].
395    ///
396    #[must_use]
397    pub fn builder() -> QueryCrossIsolatedMarginCapitalFlowParamsBuilder {
398        QueryCrossIsolatedMarginCapitalFlowParamsBuilder::default()
399    }
400}
401/// Request parameters for the [`query_cross_margin_account_details`] operation.
402///
403/// This struct holds all of the inputs you can pass when calling
404/// [`query_cross_margin_account_details`](#method.query_cross_margin_account_details).
405#[derive(Clone, Debug, Builder, Deserialize, Default)]
406#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
407pub struct QueryCrossMarginAccountDetailsParams {
408    ///
409    /// The `recv_window` parameter.
410    ///
411    /// This field is **optional.
412    #[builder(setter(into), default)]
413    #[serde(rename = "recvWindow", default)]
414    pub recv_window: Option<i64>,
415}
416
417impl QueryCrossMarginAccountDetailsParams {
418    /// Create a builder for [`query_cross_margin_account_details`].
419    ///
420    #[must_use]
421    pub fn builder() -> QueryCrossMarginAccountDetailsParamsBuilder {
422        QueryCrossMarginAccountDetailsParamsBuilder::default()
423    }
424}
425/// Request parameters for the [`query_cross_margin_fee_data`] operation.
426///
427/// This struct holds all of the inputs you can pass when calling
428/// [`query_cross_margin_fee_data`](#method.query_cross_margin_fee_data).
429#[derive(Clone, Debug, Builder, Deserialize, Default)]
430#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
431pub struct QueryCrossMarginFeeDataParams {
432    /// User's current specific margin data will be returned if vipLevel is omitted
433    ///
434    /// This field is **optional.
435    #[builder(setter(into), default)]
436    #[serde(rename = "vipLevel", default)]
437    pub vip_level: Option<i64>,
438    ///
439    /// The `coin` parameter.
440    ///
441    /// This field is **optional.
442    #[builder(setter(into), default)]
443    #[serde(rename = "coin", default)]
444    pub coin: Option<String>,
445    ///
446    /// The `recv_window` parameter.
447    ///
448    /// This field is **optional.
449    #[builder(setter(into), default)]
450    #[serde(rename = "recvWindow", default)]
451    pub recv_window: Option<i64>,
452}
453
454impl QueryCrossMarginFeeDataParams {
455    /// Create a builder for [`query_cross_margin_fee_data`].
456    ///
457    #[must_use]
458    pub fn builder() -> QueryCrossMarginFeeDataParamsBuilder {
459        QueryCrossMarginFeeDataParamsBuilder::default()
460    }
461}
462/// Request parameters for the [`query_enabled_isolated_margin_account_limit`] operation.
463///
464/// This struct holds all of the inputs you can pass when calling
465/// [`query_enabled_isolated_margin_account_limit`](#method.query_enabled_isolated_margin_account_limit).
466#[derive(Clone, Debug, Builder, Deserialize, Default)]
467#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
468pub struct QueryEnabledIsolatedMarginAccountLimitParams {
469    ///
470    /// The `recv_window` parameter.
471    ///
472    /// This field is **optional.
473    #[builder(setter(into), default)]
474    #[serde(rename = "recvWindow", default)]
475    pub recv_window: Option<i64>,
476}
477
478impl QueryEnabledIsolatedMarginAccountLimitParams {
479    /// Create a builder for [`query_enabled_isolated_margin_account_limit`].
480    ///
481    #[must_use]
482    pub fn builder() -> QueryEnabledIsolatedMarginAccountLimitParamsBuilder {
483        QueryEnabledIsolatedMarginAccountLimitParamsBuilder::default()
484    }
485}
486/// Request parameters for the [`query_isolated_margin_account_info`] operation.
487///
488/// This struct holds all of the inputs you can pass when calling
489/// [`query_isolated_margin_account_info`](#method.query_isolated_margin_account_info).
490#[derive(Clone, Debug, Builder, Deserialize, Default)]
491#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
492pub struct QueryIsolatedMarginAccountInfoParams {
493    ///
494    /// The `symbols` parameter.
495    ///
496    /// This field is **optional.
497    #[builder(setter(into), default)]
498    #[serde(rename = "symbols", default)]
499    pub symbols: Option<String>,
500    ///
501    /// The `recv_window` parameter.
502    ///
503    /// This field is **optional.
504    #[builder(setter(into), default)]
505    #[serde(rename = "recvWindow", default)]
506    pub recv_window: Option<i64>,
507}
508
509impl QueryIsolatedMarginAccountInfoParams {
510    /// Create a builder for [`query_isolated_margin_account_info`].
511    ///
512    #[must_use]
513    pub fn builder() -> QueryIsolatedMarginAccountInfoParamsBuilder {
514        QueryIsolatedMarginAccountInfoParamsBuilder::default()
515    }
516}
517/// Request parameters for the [`query_isolated_margin_fee_data`] operation.
518///
519/// This struct holds all of the inputs you can pass when calling
520/// [`query_isolated_margin_fee_data`](#method.query_isolated_margin_fee_data).
521#[derive(Clone, Debug, Builder, Deserialize, Default)]
522#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
523pub struct QueryIsolatedMarginFeeDataParams {
524    ///
525    /// The `vip_level` parameter.
526    ///
527    /// This field is **optional.
528    #[builder(setter(into), default)]
529    #[serde(rename = "vipLevel", default)]
530    pub vip_level: Option<i64>,
531    ///
532    /// The `symbol` parameter.
533    ///
534    /// This field is **optional.
535    #[builder(setter(into), default)]
536    #[serde(rename = "symbol", default)]
537    pub symbol: Option<String>,
538    ///
539    /// The `recv_window` parameter.
540    ///
541    /// This field is **optional.
542    #[builder(setter(into), default)]
543    #[serde(rename = "recvWindow", default)]
544    pub recv_window: Option<i64>,
545}
546
547impl QueryIsolatedMarginFeeDataParams {
548    /// Create a builder for [`query_isolated_margin_fee_data`].
549    ///
550    #[must_use]
551    pub fn builder() -> QueryIsolatedMarginFeeDataParamsBuilder {
552        QueryIsolatedMarginFeeDataParamsBuilder::default()
553    }
554}
555
556#[async_trait]
557impl AccountApi for AccountApiClient {
558    async fn adjust_cross_margin_max_leverage(
559        &self,
560        params: AdjustCrossMarginMaxLeverageParams,
561    ) -> anyhow::Result<RestApiResponse<models::AdjustCrossMarginMaxLeverageResponse>> {
562        let AdjustCrossMarginMaxLeverageParams { max_leverage } = params;
563
564        let mut query_params = BTreeMap::new();
565        let body_params = BTreeMap::new();
566
567        query_params.insert("maxLeverage".to_string(), json!(max_leverage));
568
569        send_request::<models::AdjustCrossMarginMaxLeverageResponse>(
570            &self.configuration,
571            "/sapi/v1/margin/max-leverage",
572            reqwest::Method::POST,
573            query_params,
574            body_params,
575            if HAS_TIME_UNIT {
576                self.configuration.time_unit
577            } else {
578                None
579            },
580            true,
581        )
582        .await
583    }
584
585    async fn disable_isolated_margin_account(
586        &self,
587        params: DisableIsolatedMarginAccountParams,
588    ) -> anyhow::Result<RestApiResponse<models::DisableIsolatedMarginAccountResponse>> {
589        let DisableIsolatedMarginAccountParams {
590            symbol,
591            recv_window,
592        } = params;
593
594        let mut query_params = BTreeMap::new();
595        let body_params = BTreeMap::new();
596
597        query_params.insert("symbol".to_string(), json!(symbol));
598
599        if let Some(rw) = recv_window {
600            query_params.insert("recvWindow".to_string(), json!(rw));
601        }
602
603        send_request::<models::DisableIsolatedMarginAccountResponse>(
604            &self.configuration,
605            "/sapi/v1/margin/isolated/account",
606            reqwest::Method::DELETE,
607            query_params,
608            body_params,
609            if HAS_TIME_UNIT {
610                self.configuration.time_unit
611            } else {
612                None
613            },
614            true,
615        )
616        .await
617    }
618
619    async fn enable_isolated_margin_account(
620        &self,
621        params: EnableIsolatedMarginAccountParams,
622    ) -> anyhow::Result<RestApiResponse<models::EnableIsolatedMarginAccountResponse>> {
623        let EnableIsolatedMarginAccountParams {
624            symbol,
625            recv_window,
626        } = params;
627
628        let mut query_params = BTreeMap::new();
629        let body_params = BTreeMap::new();
630
631        query_params.insert("symbol".to_string(), json!(symbol));
632
633        if let Some(rw) = recv_window {
634            query_params.insert("recvWindow".to_string(), json!(rw));
635        }
636
637        send_request::<models::EnableIsolatedMarginAccountResponse>(
638            &self.configuration,
639            "/sapi/v1/margin/isolated/account",
640            reqwest::Method::POST,
641            query_params,
642            body_params,
643            if HAS_TIME_UNIT {
644                self.configuration.time_unit
645            } else {
646                None
647            },
648            true,
649        )
650        .await
651    }
652
653    async fn get_bnb_burn_status(
654        &self,
655        params: GetBnbBurnStatusParams,
656    ) -> anyhow::Result<RestApiResponse<models::GetBnbBurnStatusResponse>> {
657        let GetBnbBurnStatusParams { recv_window } = params;
658
659        let mut query_params = BTreeMap::new();
660        let body_params = BTreeMap::new();
661
662        if let Some(rw) = recv_window {
663            query_params.insert("recvWindow".to_string(), json!(rw));
664        }
665
666        send_request::<models::GetBnbBurnStatusResponse>(
667            &self.configuration,
668            "/sapi/v1/bnbBurn",
669            reqwest::Method::GET,
670            query_params,
671            body_params,
672            if HAS_TIME_UNIT {
673                self.configuration.time_unit
674            } else {
675                None
676            },
677            true,
678        )
679        .await
680    }
681
682    async fn get_summary_of_margin_account(
683        &self,
684        params: GetSummaryOfMarginAccountParams,
685    ) -> anyhow::Result<RestApiResponse<models::GetSummaryOfMarginAccountResponse>> {
686        let GetSummaryOfMarginAccountParams { recv_window } = params;
687
688        let mut query_params = BTreeMap::new();
689        let body_params = BTreeMap::new();
690
691        if let Some(rw) = recv_window {
692            query_params.insert("recvWindow".to_string(), json!(rw));
693        }
694
695        send_request::<models::GetSummaryOfMarginAccountResponse>(
696            &self.configuration,
697            "/sapi/v1/margin/tradeCoeff",
698            reqwest::Method::GET,
699            query_params,
700            body_params,
701            if HAS_TIME_UNIT {
702                self.configuration.time_unit
703            } else {
704                None
705            },
706            true,
707        )
708        .await
709    }
710
711    async fn query_cross_isolated_margin_capital_flow(
712        &self,
713        params: QueryCrossIsolatedMarginCapitalFlowParams,
714    ) -> anyhow::Result<
715        RestApiResponse<Vec<models::QueryCrossIsolatedMarginCapitalFlowResponseInner>>,
716    > {
717        let QueryCrossIsolatedMarginCapitalFlowParams {
718            asset,
719            symbol,
720            r#type,
721            start_time,
722            end_time,
723            from_id,
724            limit,
725            recv_window,
726        } = params;
727
728        let mut query_params = BTreeMap::new();
729        let body_params = BTreeMap::new();
730
731        if let Some(rw) = asset {
732            query_params.insert("asset".to_string(), json!(rw));
733        }
734
735        if let Some(rw) = symbol {
736            query_params.insert("symbol".to_string(), json!(rw));
737        }
738
739        if let Some(rw) = r#type {
740            query_params.insert("type".to_string(), json!(rw));
741        }
742
743        if let Some(rw) = start_time {
744            query_params.insert("startTime".to_string(), json!(rw));
745        }
746
747        if let Some(rw) = end_time {
748            query_params.insert("endTime".to_string(), json!(rw));
749        }
750
751        if let Some(rw) = from_id {
752            query_params.insert("fromId".to_string(), json!(rw));
753        }
754
755        if let Some(rw) = limit {
756            query_params.insert("limit".to_string(), json!(rw));
757        }
758
759        if let Some(rw) = recv_window {
760            query_params.insert("recvWindow".to_string(), json!(rw));
761        }
762
763        send_request::<Vec<models::QueryCrossIsolatedMarginCapitalFlowResponseInner>>(
764            &self.configuration,
765            "/sapi/v1/margin/capital-flow",
766            reqwest::Method::GET,
767            query_params,
768            body_params,
769            if HAS_TIME_UNIT {
770                self.configuration.time_unit
771            } else {
772                None
773            },
774            true,
775        )
776        .await
777    }
778
779    async fn query_cross_margin_account_details(
780        &self,
781        params: QueryCrossMarginAccountDetailsParams,
782    ) -> anyhow::Result<RestApiResponse<models::QueryCrossMarginAccountDetailsResponse>> {
783        let QueryCrossMarginAccountDetailsParams { recv_window } = params;
784
785        let mut query_params = BTreeMap::new();
786        let body_params = BTreeMap::new();
787
788        if let Some(rw) = recv_window {
789            query_params.insert("recvWindow".to_string(), json!(rw));
790        }
791
792        send_request::<models::QueryCrossMarginAccountDetailsResponse>(
793            &self.configuration,
794            "/sapi/v1/margin/account",
795            reqwest::Method::GET,
796            query_params,
797            body_params,
798            if HAS_TIME_UNIT {
799                self.configuration.time_unit
800            } else {
801                None
802            },
803            true,
804        )
805        .await
806    }
807
808    async fn query_cross_margin_fee_data(
809        &self,
810        params: QueryCrossMarginFeeDataParams,
811    ) -> anyhow::Result<RestApiResponse<Vec<models::QueryCrossMarginFeeDataResponseInner>>> {
812        let QueryCrossMarginFeeDataParams {
813            vip_level,
814            coin,
815            recv_window,
816        } = params;
817
818        let mut query_params = BTreeMap::new();
819        let body_params = BTreeMap::new();
820
821        if let Some(rw) = vip_level {
822            query_params.insert("vipLevel".to_string(), json!(rw));
823        }
824
825        if let Some(rw) = coin {
826            query_params.insert("coin".to_string(), json!(rw));
827        }
828
829        if let Some(rw) = recv_window {
830            query_params.insert("recvWindow".to_string(), json!(rw));
831        }
832
833        send_request::<Vec<models::QueryCrossMarginFeeDataResponseInner>>(
834            &self.configuration,
835            "/sapi/v1/margin/crossMarginData",
836            reqwest::Method::GET,
837            query_params,
838            body_params,
839            if HAS_TIME_UNIT {
840                self.configuration.time_unit
841            } else {
842                None
843            },
844            true,
845        )
846        .await
847    }
848
849    async fn query_enabled_isolated_margin_account_limit(
850        &self,
851        params: QueryEnabledIsolatedMarginAccountLimitParams,
852    ) -> anyhow::Result<RestApiResponse<models::QueryEnabledIsolatedMarginAccountLimitResponse>>
853    {
854        let QueryEnabledIsolatedMarginAccountLimitParams { recv_window } = params;
855
856        let mut query_params = BTreeMap::new();
857        let body_params = BTreeMap::new();
858
859        if let Some(rw) = recv_window {
860            query_params.insert("recvWindow".to_string(), json!(rw));
861        }
862
863        send_request::<models::QueryEnabledIsolatedMarginAccountLimitResponse>(
864            &self.configuration,
865            "/sapi/v1/margin/isolated/accountLimit",
866            reqwest::Method::GET,
867            query_params,
868            body_params,
869            if HAS_TIME_UNIT {
870                self.configuration.time_unit
871            } else {
872                None
873            },
874            true,
875        )
876        .await
877    }
878
879    async fn query_isolated_margin_account_info(
880        &self,
881        params: QueryIsolatedMarginAccountInfoParams,
882    ) -> anyhow::Result<RestApiResponse<models::QueryIsolatedMarginAccountInfoResponse>> {
883        let QueryIsolatedMarginAccountInfoParams {
884            symbols,
885            recv_window,
886        } = params;
887
888        let mut query_params = BTreeMap::new();
889        let body_params = BTreeMap::new();
890
891        if let Some(rw) = symbols {
892            query_params.insert("symbols".to_string(), json!(rw));
893        }
894
895        if let Some(rw) = recv_window {
896            query_params.insert("recvWindow".to_string(), json!(rw));
897        }
898
899        send_request::<models::QueryIsolatedMarginAccountInfoResponse>(
900            &self.configuration,
901            "/sapi/v1/margin/isolated/account",
902            reqwest::Method::GET,
903            query_params,
904            body_params,
905            if HAS_TIME_UNIT {
906                self.configuration.time_unit
907            } else {
908                None
909            },
910            true,
911        )
912        .await
913    }
914
915    async fn query_isolated_margin_fee_data(
916        &self,
917        params: QueryIsolatedMarginFeeDataParams,
918    ) -> anyhow::Result<RestApiResponse<Vec<models::QueryIsolatedMarginFeeDataResponseInner>>> {
919        let QueryIsolatedMarginFeeDataParams {
920            vip_level,
921            symbol,
922            recv_window,
923        } = params;
924
925        let mut query_params = BTreeMap::new();
926        let body_params = BTreeMap::new();
927
928        if let Some(rw) = vip_level {
929            query_params.insert("vipLevel".to_string(), json!(rw));
930        }
931
932        if let Some(rw) = symbol {
933            query_params.insert("symbol".to_string(), json!(rw));
934        }
935
936        if let Some(rw) = recv_window {
937            query_params.insert("recvWindow".to_string(), json!(rw));
938        }
939
940        send_request::<Vec<models::QueryIsolatedMarginFeeDataResponseInner>>(
941            &self.configuration,
942            "/sapi/v1/margin/isolatedMarginData",
943            reqwest::Method::GET,
944            query_params,
945            body_params,
946            if HAS_TIME_UNIT {
947                self.configuration.time_unit
948            } else {
949                None
950            },
951            true,
952        )
953        .await
954    }
955}
956
957#[cfg(all(test, feature = "margin_trading"))]
958mod tests {
959    use super::*;
960    use crate::TOKIO_SHARED_RT;
961    use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
962    use async_trait::async_trait;
963    use std::collections::HashMap;
964
965    struct DummyRestApiResponse<T> {
966        inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
967        status: u16,
968        headers: HashMap<String, String>,
969        rate_limits: Option<Vec<RestApiRateLimit>>,
970    }
971
972    impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
973        fn from(dummy: DummyRestApiResponse<T>) -> Self {
974            Self {
975                data_fn: dummy.inner,
976                status: dummy.status,
977                headers: dummy.headers,
978                rate_limits: dummy.rate_limits,
979            }
980        }
981    }
982
983    struct MockAccountApiClient {
984        force_error: bool,
985    }
986
987    #[async_trait]
988    impl AccountApi for MockAccountApiClient {
989        async fn adjust_cross_margin_max_leverage(
990            &self,
991            _params: AdjustCrossMarginMaxLeverageParams,
992        ) -> anyhow::Result<RestApiResponse<models::AdjustCrossMarginMaxLeverageResponse>> {
993            if self.force_error {
994                return Err(ConnectorError::ConnectorClientError {
995                    msg: "ResponseError".to_string(),
996                    code: None,
997                }
998                .into());
999            }
1000
1001            let resp_json: Value = serde_json::from_str(r#"{"success":true}"#)
1002                .unwrap_or_else(|_| serde_json::json!({}));
1003            let dummy_response: models::AdjustCrossMarginMaxLeverageResponse =
1004                serde_json::from_value(resp_json.clone())
1005                    .expect("should parse into models::AdjustCrossMarginMaxLeverageResponse");
1006
1007            let dummy = DummyRestApiResponse {
1008                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1009                status: 200,
1010                headers: HashMap::new(),
1011                rate_limits: None,
1012            };
1013
1014            Ok(dummy.into())
1015        }
1016
1017        async fn disable_isolated_margin_account(
1018            &self,
1019            _params: DisableIsolatedMarginAccountParams,
1020        ) -> anyhow::Result<RestApiResponse<models::DisableIsolatedMarginAccountResponse>> {
1021            if self.force_error {
1022                return Err(ConnectorError::ConnectorClientError {
1023                    msg: "ResponseError".to_string(),
1024                    code: None,
1025                }
1026                .into());
1027            }
1028
1029            let resp_json: Value = serde_json::from_str(r#"{"success":true,"symbol":"BTCUSDT"}"#)
1030                .unwrap_or_else(|_| serde_json::json!({}));
1031            let dummy_response: models::DisableIsolatedMarginAccountResponse =
1032                serde_json::from_value(resp_json.clone())
1033                    .expect("should parse into models::DisableIsolatedMarginAccountResponse");
1034
1035            let dummy = DummyRestApiResponse {
1036                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1037                status: 200,
1038                headers: HashMap::new(),
1039                rate_limits: None,
1040            };
1041
1042            Ok(dummy.into())
1043        }
1044
1045        async fn enable_isolated_margin_account(
1046            &self,
1047            _params: EnableIsolatedMarginAccountParams,
1048        ) -> anyhow::Result<RestApiResponse<models::EnableIsolatedMarginAccountResponse>> {
1049            if self.force_error {
1050                return Err(ConnectorError::ConnectorClientError {
1051                    msg: "ResponseError".to_string(),
1052                    code: None,
1053                }
1054                .into());
1055            }
1056
1057            let resp_json: Value = serde_json::from_str(r#"{"success":true,"symbol":"BTCUSDT"}"#)
1058                .unwrap_or_else(|_| serde_json::json!({}));
1059            let dummy_response: models::EnableIsolatedMarginAccountResponse =
1060                serde_json::from_value(resp_json.clone())
1061                    .expect("should parse into models::EnableIsolatedMarginAccountResponse");
1062
1063            let dummy = DummyRestApiResponse {
1064                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1065                status: 200,
1066                headers: HashMap::new(),
1067                rate_limits: None,
1068            };
1069
1070            Ok(dummy.into())
1071        }
1072
1073        async fn get_bnb_burn_status(
1074            &self,
1075            _params: GetBnbBurnStatusParams,
1076        ) -> anyhow::Result<RestApiResponse<models::GetBnbBurnStatusResponse>> {
1077            if self.force_error {
1078                return Err(ConnectorError::ConnectorClientError {
1079                    msg: "ResponseError".to_string(),
1080                    code: None,
1081                }
1082                .into());
1083            }
1084
1085            let resp_json: Value =
1086                serde_json::from_str(r#"{"spotBNBBurn":true,"interestBNBBurn":false}"#)
1087                    .unwrap_or_else(|_| serde_json::json!({}));
1088            let dummy_response: models::GetBnbBurnStatusResponse =
1089                serde_json::from_value(resp_json.clone())
1090                    .expect("should parse into models::GetBnbBurnStatusResponse");
1091
1092            let dummy = DummyRestApiResponse {
1093                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1094                status: 200,
1095                headers: HashMap::new(),
1096                rate_limits: None,
1097            };
1098
1099            Ok(dummy.into())
1100        }
1101
1102        async fn get_summary_of_margin_account(
1103            &self,
1104            _params: GetSummaryOfMarginAccountParams,
1105        ) -> anyhow::Result<RestApiResponse<models::GetSummaryOfMarginAccountResponse>> {
1106            if self.force_error {
1107                return Err(ConnectorError::ConnectorClientError {
1108                    msg: "ResponseError".to_string(),
1109                    code: None,
1110                }
1111                .into());
1112            }
1113
1114            let resp_json: Value = serde_json::from_str(
1115                r#"{"normalBar":"1.5","marginCallBar":"1.3","forceLiquidationBar":"1.1"}"#,
1116            )
1117            .unwrap_or_else(|_| serde_json::json!({}));
1118            let dummy_response: models::GetSummaryOfMarginAccountResponse =
1119                serde_json::from_value(resp_json.clone())
1120                    .expect("should parse into models::GetSummaryOfMarginAccountResponse");
1121
1122            let dummy = DummyRestApiResponse {
1123                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1124                status: 200,
1125                headers: HashMap::new(),
1126                rate_limits: None,
1127            };
1128
1129            Ok(dummy.into())
1130        }
1131
1132        async fn query_cross_isolated_margin_capital_flow(
1133            &self,
1134            _params: QueryCrossIsolatedMarginCapitalFlowParams,
1135        ) -> anyhow::Result<
1136            RestApiResponse<Vec<models::QueryCrossIsolatedMarginCapitalFlowResponseInner>>,
1137        > {
1138            if self.force_error {
1139                return Err(ConnectorError::ConnectorClientError {
1140                    msg: "ResponseError".to_string(),
1141                    code: None,
1142                }
1143                .into());
1144            }
1145
1146            let resp_json: Value = serde_json::from_str(r#"[{"id":123456,"tranId":123123,"timestamp":1691116657000,"asset":"USDT","symbol":"BTCUSDT","type":"BORROW","amount":"101","note":"INSTITUTIONAL_LOAN_TRANSFER"}]"#).unwrap_or_else(|_| serde_json::json!({}));
1147            let dummy_response : Vec<models::QueryCrossIsolatedMarginCapitalFlowResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryCrossIsolatedMarginCapitalFlowResponseInner>");
1148
1149            let dummy = DummyRestApiResponse {
1150                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1151                status: 200,
1152                headers: HashMap::new(),
1153                rate_limits: None,
1154            };
1155
1156            Ok(dummy.into())
1157        }
1158
1159        async fn query_cross_margin_account_details(
1160            &self,
1161            _params: QueryCrossMarginAccountDetailsParams,
1162        ) -> anyhow::Result<RestApiResponse<models::QueryCrossMarginAccountDetailsResponse>>
1163        {
1164            if self.force_error {
1165                return Err(ConnectorError::ConnectorClientError {
1166                    msg: "ResponseError".to_string(),
1167                    code: None,
1168                }
1169                .into());
1170            }
1171
1172            let resp_json: Value = serde_json::from_str(r#"{"created":true,"borrowEnabled":true,"marginLevel":"11.64405625","collateralMarginLevel":"3.2","totalAssetOfBtc":"6.82728457","totalLiabilityOfBtc":"0.58633215","totalNetAssetOfBtc":"6.24095242","TotalCollateralValueInUSDT":"5.82728457","totalOpenOrderLossInUSDT":"582.728457","tradeEnabled":true,"transferInEnabled":true,"transferOutEnabled":true,"accountType":"MARGIN_1","userAssets":[{"asset":"BTC","borrowed":"0.00000000","free":"0.00499500","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00499500"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1173            let dummy_response: models::QueryCrossMarginAccountDetailsResponse =
1174                serde_json::from_value(resp_json.clone())
1175                    .expect("should parse into models::QueryCrossMarginAccountDetailsResponse");
1176
1177            let dummy = DummyRestApiResponse {
1178                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1179                status: 200,
1180                headers: HashMap::new(),
1181                rate_limits: None,
1182            };
1183
1184            Ok(dummy.into())
1185        }
1186
1187        async fn query_cross_margin_fee_data(
1188            &self,
1189            _params: QueryCrossMarginFeeDataParams,
1190        ) -> anyhow::Result<RestApiResponse<Vec<models::QueryCrossMarginFeeDataResponseInner>>>
1191        {
1192            if self.force_error {
1193                return Err(ConnectorError::ConnectorClientError {
1194                    msg: "ResponseError".to_string(),
1195                    code: None,
1196                }
1197                .into());
1198            }
1199
1200            let resp_json: Value = serde_json::from_str(r#"[{"vipLevel":0,"coin":"BTC","transferIn":true,"borrowable":true,"dailyInterest":"0.00026125","yearlyInterest":"0.0953","borrowLimit":"180","marginablePairs":["BNBBTC"]}]"#).unwrap_or_else(|_| serde_json::json!({}));
1201            let dummy_response: Vec<models::QueryCrossMarginFeeDataResponseInner> =
1202                serde_json::from_value(resp_json.clone())
1203                    .expect("should parse into Vec<models::QueryCrossMarginFeeDataResponseInner>");
1204
1205            let dummy = DummyRestApiResponse {
1206                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1207                status: 200,
1208                headers: HashMap::new(),
1209                rate_limits: None,
1210            };
1211
1212            Ok(dummy.into())
1213        }
1214
1215        async fn query_enabled_isolated_margin_account_limit(
1216            &self,
1217            _params: QueryEnabledIsolatedMarginAccountLimitParams,
1218        ) -> anyhow::Result<RestApiResponse<models::QueryEnabledIsolatedMarginAccountLimitResponse>>
1219        {
1220            if self.force_error {
1221                return Err(ConnectorError::ConnectorClientError {
1222                    msg: "ResponseError".to_string(),
1223                    code: None,
1224                }
1225                .into());
1226            }
1227
1228            let resp_json: Value = serde_json::from_str(r#"{"enabledAccount":5,"maxAccount":20}"#)
1229                .unwrap_or_else(|_| serde_json::json!({}));
1230            let dummy_response: models::QueryEnabledIsolatedMarginAccountLimitResponse =
1231                serde_json::from_value(resp_json.clone()).expect(
1232                    "should parse into models::QueryEnabledIsolatedMarginAccountLimitResponse",
1233                );
1234
1235            let dummy = DummyRestApiResponse {
1236                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1237                status: 200,
1238                headers: HashMap::new(),
1239                rate_limits: None,
1240            };
1241
1242            Ok(dummy.into())
1243        }
1244
1245        async fn query_isolated_margin_account_info(
1246            &self,
1247            _params: QueryIsolatedMarginAccountInfoParams,
1248        ) -> anyhow::Result<RestApiResponse<models::QueryIsolatedMarginAccountInfoResponse>>
1249        {
1250            if self.force_error {
1251                return Err(ConnectorError::ConnectorClientError {
1252                    msg: "ResponseError".to_string(),
1253                    code: None,
1254                }
1255                .into());
1256            }
1257
1258            let resp_json: Value = serde_json::from_str(r#"{"assets":[{"baseAsset":{"asset":"BTC","borrowEnabled":true,"borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000","netAssetOfBtc":"0.00000000","repayEnabled":true,"totalAsset":"0.00000000"},"quoteAsset":{"asset":"USDT","borrowEnabled":true,"borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000","netAssetOfBtc":"0.00000000","repayEnabled":true,"totalAsset":"0.00000000"},"symbol":"BTCUSDT","isolatedCreated":true,"enabled":true,"marginLevel":"0.00000000","marginLevelStatus":"EXCESSIVE","marginRatio":"0.00000000","indexPrice":"10000.00000000","liquidatePrice":"1000.00000000","liquidateRate":"1.00000000","tradeEnabled":true}],"totalAssetOfBtc":"0.00000000","totalLiabilityOfBtc":"0.00000000","totalNetAssetOfBtc":"0.00000000"}"#).unwrap_or_else(|_| serde_json::json!({}));
1259            let dummy_response: models::QueryIsolatedMarginAccountInfoResponse =
1260                serde_json::from_value(resp_json.clone())
1261                    .expect("should parse into models::QueryIsolatedMarginAccountInfoResponse");
1262
1263            let dummy = DummyRestApiResponse {
1264                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1265                status: 200,
1266                headers: HashMap::new(),
1267                rate_limits: None,
1268            };
1269
1270            Ok(dummy.into())
1271        }
1272
1273        async fn query_isolated_margin_fee_data(
1274            &self,
1275            _params: QueryIsolatedMarginFeeDataParams,
1276        ) -> anyhow::Result<RestApiResponse<Vec<models::QueryIsolatedMarginFeeDataResponseInner>>>
1277        {
1278            if self.force_error {
1279                return Err(ConnectorError::ConnectorClientError {
1280                    msg: "ResponseError".to_string(),
1281                    code: None,
1282                }
1283                .into());
1284            }
1285
1286            let resp_json: Value = serde_json::from_str(r#"[{"vipLevel":0,"symbol":"BTCUSDT","leverage":"10","data":[{"coin":"BTC","dailyInterest":"0.00026125","borrowLimit":"270"}]}]"#).unwrap_or_else(|_| serde_json::json!({}));
1287            let dummy_response: Vec<models::QueryIsolatedMarginFeeDataResponseInner> =
1288                serde_json::from_value(resp_json.clone()).expect(
1289                    "should parse into Vec<models::QueryIsolatedMarginFeeDataResponseInner>",
1290                );
1291
1292            let dummy = DummyRestApiResponse {
1293                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1294                status: 200,
1295                headers: HashMap::new(),
1296                rate_limits: None,
1297            };
1298
1299            Ok(dummy.into())
1300        }
1301    }
1302
1303    #[test]
1304    fn adjust_cross_margin_max_leverage_required_params_success() {
1305        TOKIO_SHARED_RT.block_on(async {
1306            let client = MockAccountApiClient { force_error: false };
1307
1308            let params = AdjustCrossMarginMaxLeverageParams::builder(3)
1309                .build()
1310                .unwrap();
1311
1312            let resp_json: Value = serde_json::from_str(r#"{"success":true}"#)
1313                .unwrap_or_else(|_| serde_json::json!({}));
1314            let expected_response: models::AdjustCrossMarginMaxLeverageResponse =
1315                serde_json::from_value(resp_json.clone())
1316                    .expect("should parse into models::AdjustCrossMarginMaxLeverageResponse");
1317
1318            let resp = client
1319                .adjust_cross_margin_max_leverage(params)
1320                .await
1321                .expect("Expected a response");
1322            let data_future = resp.data();
1323            let actual_response = data_future.await.unwrap();
1324            assert_eq!(actual_response, expected_response);
1325        });
1326    }
1327
1328    #[test]
1329    fn adjust_cross_margin_max_leverage_optional_params_success() {
1330        TOKIO_SHARED_RT.block_on(async {
1331            let client = MockAccountApiClient { force_error: false };
1332
1333            let params = AdjustCrossMarginMaxLeverageParams::builder(3)
1334                .build()
1335                .unwrap();
1336
1337            let resp_json: Value = serde_json::from_str(r#"{"success":true}"#)
1338                .unwrap_or_else(|_| serde_json::json!({}));
1339            let expected_response: models::AdjustCrossMarginMaxLeverageResponse =
1340                serde_json::from_value(resp_json.clone())
1341                    .expect("should parse into models::AdjustCrossMarginMaxLeverageResponse");
1342
1343            let resp = client
1344                .adjust_cross_margin_max_leverage(params)
1345                .await
1346                .expect("Expected a response");
1347            let data_future = resp.data();
1348            let actual_response = data_future.await.unwrap();
1349            assert_eq!(actual_response, expected_response);
1350        });
1351    }
1352
1353    #[test]
1354    fn adjust_cross_margin_max_leverage_response_error() {
1355        TOKIO_SHARED_RT.block_on(async {
1356            let client = MockAccountApiClient { force_error: true };
1357
1358            let params = AdjustCrossMarginMaxLeverageParams::builder(3)
1359                .build()
1360                .unwrap();
1361
1362            match client.adjust_cross_margin_max_leverage(params).await {
1363                Ok(_) => panic!("Expected an error"),
1364                Err(err) => {
1365                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1366                }
1367            }
1368        });
1369    }
1370
1371    #[test]
1372    fn disable_isolated_margin_account_required_params_success() {
1373        TOKIO_SHARED_RT.block_on(async {
1374            let client = MockAccountApiClient { force_error: false };
1375
1376            let params = DisableIsolatedMarginAccountParams::builder("BTCUSDT".to_string())
1377                .build()
1378                .unwrap();
1379
1380            let resp_json: Value = serde_json::from_str(r#"{"success":true,"symbol":"BTCUSDT"}"#)
1381                .unwrap_or_else(|_| serde_json::json!({}));
1382            let expected_response: models::DisableIsolatedMarginAccountResponse =
1383                serde_json::from_value(resp_json.clone())
1384                    .expect("should parse into models::DisableIsolatedMarginAccountResponse");
1385
1386            let resp = client
1387                .disable_isolated_margin_account(params)
1388                .await
1389                .expect("Expected a response");
1390            let data_future = resp.data();
1391            let actual_response = data_future.await.unwrap();
1392            assert_eq!(actual_response, expected_response);
1393        });
1394    }
1395
1396    #[test]
1397    fn disable_isolated_margin_account_optional_params_success() {
1398        TOKIO_SHARED_RT.block_on(async {
1399            let client = MockAccountApiClient { force_error: false };
1400
1401            let params = DisableIsolatedMarginAccountParams::builder("BTCUSDT".to_string())
1402                .recv_window(5000)
1403                .build()
1404                .unwrap();
1405
1406            let resp_json: Value = serde_json::from_str(r#"{"success":true,"symbol":"BTCUSDT"}"#)
1407                .unwrap_or_else(|_| serde_json::json!({}));
1408            let expected_response: models::DisableIsolatedMarginAccountResponse =
1409                serde_json::from_value(resp_json.clone())
1410                    .expect("should parse into models::DisableIsolatedMarginAccountResponse");
1411
1412            let resp = client
1413                .disable_isolated_margin_account(params)
1414                .await
1415                .expect("Expected a response");
1416            let data_future = resp.data();
1417            let actual_response = data_future.await.unwrap();
1418            assert_eq!(actual_response, expected_response);
1419        });
1420    }
1421
1422    #[test]
1423    fn disable_isolated_margin_account_response_error() {
1424        TOKIO_SHARED_RT.block_on(async {
1425            let client = MockAccountApiClient { force_error: true };
1426
1427            let params = DisableIsolatedMarginAccountParams::builder("BTCUSDT".to_string())
1428                .build()
1429                .unwrap();
1430
1431            match client.disable_isolated_margin_account(params).await {
1432                Ok(_) => panic!("Expected an error"),
1433                Err(err) => {
1434                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1435                }
1436            }
1437        });
1438    }
1439
1440    #[test]
1441    fn enable_isolated_margin_account_required_params_success() {
1442        TOKIO_SHARED_RT.block_on(async {
1443            let client = MockAccountApiClient { force_error: false };
1444
1445            let params = EnableIsolatedMarginAccountParams::builder("BTCUSDT".to_string())
1446                .build()
1447                .unwrap();
1448
1449            let resp_json: Value = serde_json::from_str(r#"{"success":true,"symbol":"BTCUSDT"}"#)
1450                .unwrap_or_else(|_| serde_json::json!({}));
1451            let expected_response: models::EnableIsolatedMarginAccountResponse =
1452                serde_json::from_value(resp_json.clone())
1453                    .expect("should parse into models::EnableIsolatedMarginAccountResponse");
1454
1455            let resp = client
1456                .enable_isolated_margin_account(params)
1457                .await
1458                .expect("Expected a response");
1459            let data_future = resp.data();
1460            let actual_response = data_future.await.unwrap();
1461            assert_eq!(actual_response, expected_response);
1462        });
1463    }
1464
1465    #[test]
1466    fn enable_isolated_margin_account_optional_params_success() {
1467        TOKIO_SHARED_RT.block_on(async {
1468            let client = MockAccountApiClient { force_error: false };
1469
1470            let params = EnableIsolatedMarginAccountParams::builder("BTCUSDT".to_string())
1471                .recv_window(5000)
1472                .build()
1473                .unwrap();
1474
1475            let resp_json: Value = serde_json::from_str(r#"{"success":true,"symbol":"BTCUSDT"}"#)
1476                .unwrap_or_else(|_| serde_json::json!({}));
1477            let expected_response: models::EnableIsolatedMarginAccountResponse =
1478                serde_json::from_value(resp_json.clone())
1479                    .expect("should parse into models::EnableIsolatedMarginAccountResponse");
1480
1481            let resp = client
1482                .enable_isolated_margin_account(params)
1483                .await
1484                .expect("Expected a response");
1485            let data_future = resp.data();
1486            let actual_response = data_future.await.unwrap();
1487            assert_eq!(actual_response, expected_response);
1488        });
1489    }
1490
1491    #[test]
1492    fn enable_isolated_margin_account_response_error() {
1493        TOKIO_SHARED_RT.block_on(async {
1494            let client = MockAccountApiClient { force_error: true };
1495
1496            let params = EnableIsolatedMarginAccountParams::builder("BTCUSDT".to_string())
1497                .build()
1498                .unwrap();
1499
1500            match client.enable_isolated_margin_account(params).await {
1501                Ok(_) => panic!("Expected an error"),
1502                Err(err) => {
1503                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1504                }
1505            }
1506        });
1507    }
1508
1509    #[test]
1510    fn get_bnb_burn_status_required_params_success() {
1511        TOKIO_SHARED_RT.block_on(async {
1512            let client = MockAccountApiClient { force_error: false };
1513
1514            let params = GetBnbBurnStatusParams::builder().build().unwrap();
1515
1516            let resp_json: Value =
1517                serde_json::from_str(r#"{"spotBNBBurn":true,"interestBNBBurn":false}"#)
1518                    .unwrap_or_else(|_| serde_json::json!({}));
1519            let expected_response: models::GetBnbBurnStatusResponse =
1520                serde_json::from_value(resp_json.clone())
1521                    .expect("should parse into models::GetBnbBurnStatusResponse");
1522
1523            let resp = client
1524                .get_bnb_burn_status(params)
1525                .await
1526                .expect("Expected a response");
1527            let data_future = resp.data();
1528            let actual_response = data_future.await.unwrap();
1529            assert_eq!(actual_response, expected_response);
1530        });
1531    }
1532
1533    #[test]
1534    fn get_bnb_burn_status_optional_params_success() {
1535        TOKIO_SHARED_RT.block_on(async {
1536            let client = MockAccountApiClient { force_error: false };
1537
1538            let params = GetBnbBurnStatusParams::builder()
1539                .recv_window(5000)
1540                .build()
1541                .unwrap();
1542
1543            let resp_json: Value =
1544                serde_json::from_str(r#"{"spotBNBBurn":true,"interestBNBBurn":false}"#)
1545                    .unwrap_or_else(|_| serde_json::json!({}));
1546            let expected_response: models::GetBnbBurnStatusResponse =
1547                serde_json::from_value(resp_json.clone())
1548                    .expect("should parse into models::GetBnbBurnStatusResponse");
1549
1550            let resp = client
1551                .get_bnb_burn_status(params)
1552                .await
1553                .expect("Expected a response");
1554            let data_future = resp.data();
1555            let actual_response = data_future.await.unwrap();
1556            assert_eq!(actual_response, expected_response);
1557        });
1558    }
1559
1560    #[test]
1561    fn get_bnb_burn_status_response_error() {
1562        TOKIO_SHARED_RT.block_on(async {
1563            let client = MockAccountApiClient { force_error: true };
1564
1565            let params = GetBnbBurnStatusParams::builder().build().unwrap();
1566
1567            match client.get_bnb_burn_status(params).await {
1568                Ok(_) => panic!("Expected an error"),
1569                Err(err) => {
1570                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1571                }
1572            }
1573        });
1574    }
1575
1576    #[test]
1577    fn get_summary_of_margin_account_required_params_success() {
1578        TOKIO_SHARED_RT.block_on(async {
1579            let client = MockAccountApiClient { force_error: false };
1580
1581            let params = GetSummaryOfMarginAccountParams::builder().build().unwrap();
1582
1583            let resp_json: Value = serde_json::from_str(
1584                r#"{"normalBar":"1.5","marginCallBar":"1.3","forceLiquidationBar":"1.1"}"#,
1585            )
1586            .unwrap_or_else(|_| serde_json::json!({}));
1587            let expected_response: models::GetSummaryOfMarginAccountResponse =
1588                serde_json::from_value(resp_json.clone())
1589                    .expect("should parse into models::GetSummaryOfMarginAccountResponse");
1590
1591            let resp = client
1592                .get_summary_of_margin_account(params)
1593                .await
1594                .expect("Expected a response");
1595            let data_future = resp.data();
1596            let actual_response = data_future.await.unwrap();
1597            assert_eq!(actual_response, expected_response);
1598        });
1599    }
1600
1601    #[test]
1602    fn get_summary_of_margin_account_optional_params_success() {
1603        TOKIO_SHARED_RT.block_on(async {
1604            let client = MockAccountApiClient { force_error: false };
1605
1606            let params = GetSummaryOfMarginAccountParams::builder()
1607                .recv_window(5000)
1608                .build()
1609                .unwrap();
1610
1611            let resp_json: Value = serde_json::from_str(
1612                r#"{"normalBar":"1.5","marginCallBar":"1.3","forceLiquidationBar":"1.1"}"#,
1613            )
1614            .unwrap_or_else(|_| serde_json::json!({}));
1615            let expected_response: models::GetSummaryOfMarginAccountResponse =
1616                serde_json::from_value(resp_json.clone())
1617                    .expect("should parse into models::GetSummaryOfMarginAccountResponse");
1618
1619            let resp = client
1620                .get_summary_of_margin_account(params)
1621                .await
1622                .expect("Expected a response");
1623            let data_future = resp.data();
1624            let actual_response = data_future.await.unwrap();
1625            assert_eq!(actual_response, expected_response);
1626        });
1627    }
1628
1629    #[test]
1630    fn get_summary_of_margin_account_response_error() {
1631        TOKIO_SHARED_RT.block_on(async {
1632            let client = MockAccountApiClient { force_error: true };
1633
1634            let params = GetSummaryOfMarginAccountParams::builder().build().unwrap();
1635
1636            match client.get_summary_of_margin_account(params).await {
1637                Ok(_) => panic!("Expected an error"),
1638                Err(err) => {
1639                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1640                }
1641            }
1642        });
1643    }
1644
1645    #[test]
1646    fn query_cross_isolated_margin_capital_flow_required_params_success() {
1647        TOKIO_SHARED_RT.block_on(async {
1648            let client = MockAccountApiClient { force_error: false };
1649
1650            let params = QueryCrossIsolatedMarginCapitalFlowParams::builder().build().unwrap();
1651
1652            let resp_json: Value = serde_json::from_str(r#"[{"id":123456,"tranId":123123,"timestamp":1691116657000,"asset":"USDT","symbol":"BTCUSDT","type":"BORROW","amount":"101","note":"INSTITUTIONAL_LOAN_TRANSFER"}]"#).unwrap_or_else(|_| serde_json::json!({}));
1653            let expected_response : Vec<models::QueryCrossIsolatedMarginCapitalFlowResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryCrossIsolatedMarginCapitalFlowResponseInner>");
1654
1655            let resp = client.query_cross_isolated_margin_capital_flow(params).await.expect("Expected a response");
1656            let data_future = resp.data();
1657            let actual_response = data_future.await.unwrap();
1658            assert_eq!(actual_response, expected_response);
1659        });
1660    }
1661
1662    #[test]
1663    fn query_cross_isolated_margin_capital_flow_optional_params_success() {
1664        TOKIO_SHARED_RT.block_on(async {
1665            let client = MockAccountApiClient { force_error: false };
1666
1667            let params = QueryCrossIsolatedMarginCapitalFlowParams::builder().asset("USDT".to_string()).symbol("BTCUSDT".to_string()).r#type(QueryCrossIsolatedMarginCapitalFlowTypeEnum::Transfer).start_time(1623319461670).end_time(1641782889000).from_id(1).limit(500).recv_window(5000).build().unwrap();
1668
1669            let resp_json: Value = serde_json::from_str(r#"[{"id":123456,"tranId":123123,"timestamp":1691116657000,"asset":"USDT","symbol":"BTCUSDT","type":"BORROW","amount":"101","note":"INSTITUTIONAL_LOAN_TRANSFER"}]"#).unwrap_or_else(|_| serde_json::json!({}));
1670            let expected_response : Vec<models::QueryCrossIsolatedMarginCapitalFlowResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryCrossIsolatedMarginCapitalFlowResponseInner>");
1671
1672            let resp = client.query_cross_isolated_margin_capital_flow(params).await.expect("Expected a response");
1673            let data_future = resp.data();
1674            let actual_response = data_future.await.unwrap();
1675            assert_eq!(actual_response, expected_response);
1676        });
1677    }
1678
1679    #[test]
1680    fn query_cross_isolated_margin_capital_flow_response_error() {
1681        TOKIO_SHARED_RT.block_on(async {
1682            let client = MockAccountApiClient { force_error: true };
1683
1684            let params = QueryCrossIsolatedMarginCapitalFlowParams::builder()
1685                .build()
1686                .unwrap();
1687
1688            match client
1689                .query_cross_isolated_margin_capital_flow(params)
1690                .await
1691            {
1692                Ok(_) => panic!("Expected an error"),
1693                Err(err) => {
1694                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1695                }
1696            }
1697        });
1698    }
1699
1700    #[test]
1701    fn query_cross_margin_account_details_required_params_success() {
1702        TOKIO_SHARED_RT.block_on(async {
1703            let client = MockAccountApiClient { force_error: false };
1704
1705            let params = QueryCrossMarginAccountDetailsParams::builder().build().unwrap();
1706
1707            let resp_json: Value = serde_json::from_str(r#"{"created":true,"borrowEnabled":true,"marginLevel":"11.64405625","collateralMarginLevel":"3.2","totalAssetOfBtc":"6.82728457","totalLiabilityOfBtc":"0.58633215","totalNetAssetOfBtc":"6.24095242","TotalCollateralValueInUSDT":"5.82728457","totalOpenOrderLossInUSDT":"582.728457","tradeEnabled":true,"transferInEnabled":true,"transferOutEnabled":true,"accountType":"MARGIN_1","userAssets":[{"asset":"BTC","borrowed":"0.00000000","free":"0.00499500","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00499500"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1708            let expected_response : models::QueryCrossMarginAccountDetailsResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QueryCrossMarginAccountDetailsResponse");
1709
1710            let resp = client.query_cross_margin_account_details(params).await.expect("Expected a response");
1711            let data_future = resp.data();
1712            let actual_response = data_future.await.unwrap();
1713            assert_eq!(actual_response, expected_response);
1714        });
1715    }
1716
1717    #[test]
1718    fn query_cross_margin_account_details_optional_params_success() {
1719        TOKIO_SHARED_RT.block_on(async {
1720            let client = MockAccountApiClient { force_error: false };
1721
1722            let params = QueryCrossMarginAccountDetailsParams::builder().recv_window(5000).build().unwrap();
1723
1724            let resp_json: Value = serde_json::from_str(r#"{"created":true,"borrowEnabled":true,"marginLevel":"11.64405625","collateralMarginLevel":"3.2","totalAssetOfBtc":"6.82728457","totalLiabilityOfBtc":"0.58633215","totalNetAssetOfBtc":"6.24095242","TotalCollateralValueInUSDT":"5.82728457","totalOpenOrderLossInUSDT":"582.728457","tradeEnabled":true,"transferInEnabled":true,"transferOutEnabled":true,"accountType":"MARGIN_1","userAssets":[{"asset":"BTC","borrowed":"0.00000000","free":"0.00499500","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00499500"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1725            let expected_response : models::QueryCrossMarginAccountDetailsResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QueryCrossMarginAccountDetailsResponse");
1726
1727            let resp = client.query_cross_margin_account_details(params).await.expect("Expected a response");
1728            let data_future = resp.data();
1729            let actual_response = data_future.await.unwrap();
1730            assert_eq!(actual_response, expected_response);
1731        });
1732    }
1733
1734    #[test]
1735    fn query_cross_margin_account_details_response_error() {
1736        TOKIO_SHARED_RT.block_on(async {
1737            let client = MockAccountApiClient { force_error: true };
1738
1739            let params = QueryCrossMarginAccountDetailsParams::builder()
1740                .build()
1741                .unwrap();
1742
1743            match client.query_cross_margin_account_details(params).await {
1744                Ok(_) => panic!("Expected an error"),
1745                Err(err) => {
1746                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1747                }
1748            }
1749        });
1750    }
1751
1752    #[test]
1753    fn query_cross_margin_fee_data_required_params_success() {
1754        TOKIO_SHARED_RT.block_on(async {
1755            let client = MockAccountApiClient { force_error: false };
1756
1757            let params = QueryCrossMarginFeeDataParams::builder().build().unwrap();
1758
1759            let resp_json: Value = serde_json::from_str(r#"[{"vipLevel":0,"coin":"BTC","transferIn":true,"borrowable":true,"dailyInterest":"0.00026125","yearlyInterest":"0.0953","borrowLimit":"180","marginablePairs":["BNBBTC"]}]"#).unwrap_or_else(|_| serde_json::json!({}));
1760            let expected_response : Vec<models::QueryCrossMarginFeeDataResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryCrossMarginFeeDataResponseInner>");
1761
1762            let resp = client.query_cross_margin_fee_data(params).await.expect("Expected a response");
1763            let data_future = resp.data();
1764            let actual_response = data_future.await.unwrap();
1765            assert_eq!(actual_response, expected_response);
1766        });
1767    }
1768
1769    #[test]
1770    fn query_cross_margin_fee_data_optional_params_success() {
1771        TOKIO_SHARED_RT.block_on(async {
1772            let client = MockAccountApiClient { force_error: false };
1773
1774            let params = QueryCrossMarginFeeDataParams::builder().vip_level(1).coin("BTC".to_string()).recv_window(5000).build().unwrap();
1775
1776            let resp_json: Value = serde_json::from_str(r#"[{"vipLevel":0,"coin":"BTC","transferIn":true,"borrowable":true,"dailyInterest":"0.00026125","yearlyInterest":"0.0953","borrowLimit":"180","marginablePairs":["BNBBTC"]}]"#).unwrap_or_else(|_| serde_json::json!({}));
1777            let expected_response : Vec<models::QueryCrossMarginFeeDataResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryCrossMarginFeeDataResponseInner>");
1778
1779            let resp = client.query_cross_margin_fee_data(params).await.expect("Expected a response");
1780            let data_future = resp.data();
1781            let actual_response = data_future.await.unwrap();
1782            assert_eq!(actual_response, expected_response);
1783        });
1784    }
1785
1786    #[test]
1787    fn query_cross_margin_fee_data_response_error() {
1788        TOKIO_SHARED_RT.block_on(async {
1789            let client = MockAccountApiClient { force_error: true };
1790
1791            let params = QueryCrossMarginFeeDataParams::builder().build().unwrap();
1792
1793            match client.query_cross_margin_fee_data(params).await {
1794                Ok(_) => panic!("Expected an error"),
1795                Err(err) => {
1796                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1797                }
1798            }
1799        });
1800    }
1801
1802    #[test]
1803    fn query_enabled_isolated_margin_account_limit_required_params_success() {
1804        TOKIO_SHARED_RT.block_on(async {
1805            let client = MockAccountApiClient { force_error: false };
1806
1807            let params = QueryEnabledIsolatedMarginAccountLimitParams::builder()
1808                .build()
1809                .unwrap();
1810
1811            let resp_json: Value = serde_json::from_str(r#"{"enabledAccount":5,"maxAccount":20}"#)
1812                .unwrap_or_else(|_| serde_json::json!({}));
1813            let expected_response: models::QueryEnabledIsolatedMarginAccountLimitResponse =
1814                serde_json::from_value(resp_json.clone()).expect(
1815                    "should parse into models::QueryEnabledIsolatedMarginAccountLimitResponse",
1816                );
1817
1818            let resp = client
1819                .query_enabled_isolated_margin_account_limit(params)
1820                .await
1821                .expect("Expected a response");
1822            let data_future = resp.data();
1823            let actual_response = data_future.await.unwrap();
1824            assert_eq!(actual_response, expected_response);
1825        });
1826    }
1827
1828    #[test]
1829    fn query_enabled_isolated_margin_account_limit_optional_params_success() {
1830        TOKIO_SHARED_RT.block_on(async {
1831            let client = MockAccountApiClient { force_error: false };
1832
1833            let params = QueryEnabledIsolatedMarginAccountLimitParams::builder()
1834                .recv_window(5000)
1835                .build()
1836                .unwrap();
1837
1838            let resp_json: Value = serde_json::from_str(r#"{"enabledAccount":5,"maxAccount":20}"#)
1839                .unwrap_or_else(|_| serde_json::json!({}));
1840            let expected_response: models::QueryEnabledIsolatedMarginAccountLimitResponse =
1841                serde_json::from_value(resp_json.clone()).expect(
1842                    "should parse into models::QueryEnabledIsolatedMarginAccountLimitResponse",
1843                );
1844
1845            let resp = client
1846                .query_enabled_isolated_margin_account_limit(params)
1847                .await
1848                .expect("Expected a response");
1849            let data_future = resp.data();
1850            let actual_response = data_future.await.unwrap();
1851            assert_eq!(actual_response, expected_response);
1852        });
1853    }
1854
1855    #[test]
1856    fn query_enabled_isolated_margin_account_limit_response_error() {
1857        TOKIO_SHARED_RT.block_on(async {
1858            let client = MockAccountApiClient { force_error: true };
1859
1860            let params = QueryEnabledIsolatedMarginAccountLimitParams::builder()
1861                .build()
1862                .unwrap();
1863
1864            match client
1865                .query_enabled_isolated_margin_account_limit(params)
1866                .await
1867            {
1868                Ok(_) => panic!("Expected an error"),
1869                Err(err) => {
1870                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1871                }
1872            }
1873        });
1874    }
1875
1876    #[test]
1877    fn query_isolated_margin_account_info_required_params_success() {
1878        TOKIO_SHARED_RT.block_on(async {
1879            let client = MockAccountApiClient { force_error: false };
1880
1881            let params = QueryIsolatedMarginAccountInfoParams::builder().build().unwrap();
1882
1883            let resp_json: Value = serde_json::from_str(r#"{"assets":[{"baseAsset":{"asset":"BTC","borrowEnabled":true,"borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000","netAssetOfBtc":"0.00000000","repayEnabled":true,"totalAsset":"0.00000000"},"quoteAsset":{"asset":"USDT","borrowEnabled":true,"borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000","netAssetOfBtc":"0.00000000","repayEnabled":true,"totalAsset":"0.00000000"},"symbol":"BTCUSDT","isolatedCreated":true,"enabled":true,"marginLevel":"0.00000000","marginLevelStatus":"EXCESSIVE","marginRatio":"0.00000000","indexPrice":"10000.00000000","liquidatePrice":"1000.00000000","liquidateRate":"1.00000000","tradeEnabled":true}],"totalAssetOfBtc":"0.00000000","totalLiabilityOfBtc":"0.00000000","totalNetAssetOfBtc":"0.00000000"}"#).unwrap_or_else(|_| serde_json::json!({}));
1884            let expected_response : models::QueryIsolatedMarginAccountInfoResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QueryIsolatedMarginAccountInfoResponse");
1885
1886            let resp = client.query_isolated_margin_account_info(params).await.expect("Expected a response");
1887            let data_future = resp.data();
1888            let actual_response = data_future.await.unwrap();
1889            assert_eq!(actual_response, expected_response);
1890        });
1891    }
1892
1893    #[test]
1894    fn query_isolated_margin_account_info_optional_params_success() {
1895        TOKIO_SHARED_RT.block_on(async {
1896            let client = MockAccountApiClient { force_error: false };
1897
1898            let params = QueryIsolatedMarginAccountInfoParams::builder().symbols("BTCUSDT,BNBUSDT,ADAUSDT".to_string()).recv_window(5000).build().unwrap();
1899
1900            let resp_json: Value = serde_json::from_str(r#"{"assets":[{"baseAsset":{"asset":"BTC","borrowEnabled":true,"borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000","netAssetOfBtc":"0.00000000","repayEnabled":true,"totalAsset":"0.00000000"},"quoteAsset":{"asset":"USDT","borrowEnabled":true,"borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000","netAssetOfBtc":"0.00000000","repayEnabled":true,"totalAsset":"0.00000000"},"symbol":"BTCUSDT","isolatedCreated":true,"enabled":true,"marginLevel":"0.00000000","marginLevelStatus":"EXCESSIVE","marginRatio":"0.00000000","indexPrice":"10000.00000000","liquidatePrice":"1000.00000000","liquidateRate":"1.00000000","tradeEnabled":true}],"totalAssetOfBtc":"0.00000000","totalLiabilityOfBtc":"0.00000000","totalNetAssetOfBtc":"0.00000000"}"#).unwrap_or_else(|_| serde_json::json!({}));
1901            let expected_response : models::QueryIsolatedMarginAccountInfoResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QueryIsolatedMarginAccountInfoResponse");
1902
1903            let resp = client.query_isolated_margin_account_info(params).await.expect("Expected a response");
1904            let data_future = resp.data();
1905            let actual_response = data_future.await.unwrap();
1906            assert_eq!(actual_response, expected_response);
1907        });
1908    }
1909
1910    #[test]
1911    fn query_isolated_margin_account_info_response_error() {
1912        TOKIO_SHARED_RT.block_on(async {
1913            let client = MockAccountApiClient { force_error: true };
1914
1915            let params = QueryIsolatedMarginAccountInfoParams::builder()
1916                .build()
1917                .unwrap();
1918
1919            match client.query_isolated_margin_account_info(params).await {
1920                Ok(_) => panic!("Expected an error"),
1921                Err(err) => {
1922                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1923                }
1924            }
1925        });
1926    }
1927
1928    #[test]
1929    fn query_isolated_margin_fee_data_required_params_success() {
1930        TOKIO_SHARED_RT.block_on(async {
1931            let client = MockAccountApiClient { force_error: false };
1932
1933            let params = QueryIsolatedMarginFeeDataParams::builder().build().unwrap();
1934
1935            let resp_json: Value = serde_json::from_str(r#"[{"vipLevel":0,"symbol":"BTCUSDT","leverage":"10","data":[{"coin":"BTC","dailyInterest":"0.00026125","borrowLimit":"270"}]}]"#).unwrap_or_else(|_| serde_json::json!({}));
1936            let expected_response : Vec<models::QueryIsolatedMarginFeeDataResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryIsolatedMarginFeeDataResponseInner>");
1937
1938            let resp = client.query_isolated_margin_fee_data(params).await.expect("Expected a response");
1939            let data_future = resp.data();
1940            let actual_response = data_future.await.unwrap();
1941            assert_eq!(actual_response, expected_response);
1942        });
1943    }
1944
1945    #[test]
1946    fn query_isolated_margin_fee_data_optional_params_success() {
1947        TOKIO_SHARED_RT.block_on(async {
1948            let client = MockAccountApiClient { force_error: false };
1949
1950            let params = QueryIsolatedMarginFeeDataParams::builder().vip_level(1).symbol("BTCUSDT".to_string()).recv_window(5000).build().unwrap();
1951
1952            let resp_json: Value = serde_json::from_str(r#"[{"vipLevel":0,"symbol":"BTCUSDT","leverage":"10","data":[{"coin":"BTC","dailyInterest":"0.00026125","borrowLimit":"270"}]}]"#).unwrap_or_else(|_| serde_json::json!({}));
1953            let expected_response : Vec<models::QueryIsolatedMarginFeeDataResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryIsolatedMarginFeeDataResponseInner>");
1954
1955            let resp = client.query_isolated_margin_fee_data(params).await.expect("Expected a response");
1956            let data_future = resp.data();
1957            let actual_response = data_future.await.unwrap();
1958            assert_eq!(actual_response, expected_response);
1959        });
1960    }
1961
1962    #[test]
1963    fn query_isolated_margin_fee_data_response_error() {
1964        TOKIO_SHARED_RT.block_on(async {
1965            let client = MockAccountApiClient { force_error: true };
1966
1967            let params = QueryIsolatedMarginFeeDataParams::builder().build().unwrap();
1968
1969            match client.query_isolated_margin_fee_data(params).await {
1970                Ok(_) => panic!("Expected an error"),
1971                Err(err) => {
1972                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1973                }
1974            }
1975        });
1976    }
1977}