Skip to main content

binance_sdk/margin_trading/rest_api/apis/
account_api.rs

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