/*
 * Binance Spot REST API
 *
 * OpenAPI Specifications for the Binance Spot REST API
 *
 * API documents:
 * - [Github rest-api documentation file](https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md)
 * - [General API information for rest-api on website](https://developers.binance.com/docs/binance-spot-api-docs/rest-api/general-api-information)
 *
 *
 * The version of the OpenAPI document: 1.0.0
 *
 *
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

#![allow(unused_imports)]
use async_trait::async_trait;
use derive_builder::Builder;
use reqwest;
use rust_decimal::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use std::collections::BTreeMap;

use crate::common::{
    config::ConfigurationRestApi,
    models::{ParamBuildError, RestApiResponse},
    utils::send_request,
};
use crate::spot::rest_api::models;

const HAS_TIME_UNIT: bool = true;

#[async_trait]
pub trait AccountApi: Send + Sync {
    async fn account_commission(
        &self,
        params: AccountCommissionParams,
    ) -> anyhow::Result<RestApiResponse<models::AccountCommissionResponse>>;
    async fn all_order_list(
        &self,
        params: AllOrderListParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::AllOrderListResponseInner>>>;
    async fn all_orders(
        &self,
        params: AllOrdersParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::AllOrdersResponseInner>>>;
    async fn get_account(
        &self,
        params: GetAccountParams,
    ) -> anyhow::Result<RestApiResponse<models::GetAccountResponse>>;
    async fn get_open_orders(
        &self,
        params: GetOpenOrdersParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::AllOrdersResponseInner>>>;
    async fn get_order(
        &self,
        params: GetOrderParams,
    ) -> anyhow::Result<RestApiResponse<models::GetOrderResponse>>;
    async fn get_order_list(
        &self,
        params: GetOrderListParams,
    ) -> anyhow::Result<RestApiResponse<models::GetOrderListResponse>>;
    async fn my_allocations(
        &self,
        params: MyAllocationsParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::MyAllocationsResponseInner>>>;
    async fn my_filters(
        &self,
        params: MyFiltersParams,
    ) -> anyhow::Result<RestApiResponse<models::MyFiltersResponse>>;
    async fn my_prevented_matches(
        &self,
        params: MyPreventedMatchesParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::MyPreventedMatchesResponseInner>>>;
    async fn my_trades(
        &self,
        params: MyTradesParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::MyTradesResponseInner>>>;
    async fn open_order_list(
        &self,
        params: OpenOrderListParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::OpenOrderListResponseInner>>>;
    async fn order_amendments(
        &self,
        params: OrderAmendmentsParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::OrderAmendmentsResponseInner>>>;
    async fn rate_limit_order(
        &self,
        params: RateLimitOrderParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::RateLimitOrderResponseInner>>>;
}

#[derive(Debug, Clone)]
pub struct AccountApiClient {
    configuration: ConfigurationRestApi,
}

impl AccountApiClient {
    pub fn new(configuration: ConfigurationRestApi) -> Self {
        Self { configuration }
    }
}

/// Request parameters for the [`account_commission`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`account_commission`](#method.account_commission).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct AccountCommissionParams {
    ///
    /// The `symbol` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
}

impl AccountCommissionParams {
    /// Create a builder for [`account_commission`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — String
    ///
    #[must_use]
    pub fn builder(symbol: String) -> AccountCommissionParamsBuilder {
        AccountCommissionParamsBuilder::default().symbol(symbol)
    }
}
/// Request parameters for the [`all_order_list`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`all_order_list`](#method.all_order_list).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct AllOrderListParams {
    /// ID to get aggregate trades from INCLUSIVE.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub from_id: Option<i64>,
    /// Timestamp in ms to get aggregate trades from INCLUSIVE.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    /// Timestamp in ms to get aggregate trades until INCLUSIVE.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    /// Default: 500; Maximum: 1000.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i32>,
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl AllOrderListParams {
    /// Create a builder for [`all_order_list`].
    ///
    #[must_use]
    pub fn builder() -> AllOrderListParamsBuilder {
        AllOrderListParamsBuilder::default()
    }
}
/// Request parameters for the [`all_orders`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`all_orders`](#method.all_orders).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct AllOrdersParams {
    ///
    /// The `symbol` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    ///
    /// The `order_id` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub order_id: Option<i64>,
    /// Timestamp in ms to get aggregate trades from INCLUSIVE.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    /// Timestamp in ms to get aggregate trades until INCLUSIVE.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    /// Default: 500; Maximum: 1000.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i32>,
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl AllOrdersParams {
    /// Create a builder for [`all_orders`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — String
    ///
    #[must_use]
    pub fn builder(symbol: String) -> AllOrdersParamsBuilder {
        AllOrdersParamsBuilder::default().symbol(symbol)
    }
}
/// Request parameters for the [`get_account`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_account`](#method.get_account).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetAccountParams {
    /// When set to `true`, emits only the non-zero balances of an account. <br>Default value: `false`
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub omit_zero_balances: Option<bool>,
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl GetAccountParams {
    /// Create a builder for [`get_account`].
    ///
    #[must_use]
    pub fn builder() -> GetAccountParamsBuilder {
        GetAccountParamsBuilder::default()
    }
}
/// Request parameters for the [`get_open_orders`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_open_orders`](#method.get_open_orders).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetOpenOrdersParams {
    /// Symbol to query
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub symbol: Option<String>,
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl GetOpenOrdersParams {
    /// Create a builder for [`get_open_orders`].
    ///
    #[must_use]
    pub fn builder() -> GetOpenOrdersParamsBuilder {
        GetOpenOrdersParamsBuilder::default()
    }
}
/// Request parameters for the [`get_order`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_order`](#method.get_order).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetOrderParams {
    ///
    /// The `symbol` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    ///
    /// The `order_id` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub order_id: Option<i64>,
    ///
    /// The `orig_client_order_id` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub orig_client_order_id: Option<String>,
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl GetOrderParams {
    /// Create a builder for [`get_order`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — String
    ///
    #[must_use]
    pub fn builder(symbol: String) -> GetOrderParamsBuilder {
        GetOrderParamsBuilder::default().symbol(symbol)
    }
}
/// Request parameters for the [`get_order_list`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_order_list`](#method.get_order_list).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetOrderListParams {
    /// Either `orderListId` or `listClientOrderId` must be provided
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub order_list_id: Option<i64>,
    ///
    /// The `orig_client_order_id` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub orig_client_order_id: Option<String>,
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl GetOrderListParams {
    /// Create a builder for [`get_order_list`].
    ///
    #[must_use]
    pub fn builder() -> GetOrderListParamsBuilder {
        GetOrderListParamsBuilder::default()
    }
}
/// Request parameters for the [`my_allocations`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`my_allocations`](#method.my_allocations).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct MyAllocationsParams {
    ///
    /// The `symbol` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    /// Timestamp in ms to get aggregate trades from INCLUSIVE.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    /// Timestamp in ms to get aggregate trades until INCLUSIVE.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    ///
    /// The `from_allocation_id` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub from_allocation_id: Option<i32>,
    /// Default: 500; Maximum: 1000.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i32>,
    ///
    /// The `order_id` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub order_id: Option<i64>,
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl MyAllocationsParams {
    /// Create a builder for [`my_allocations`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — String
    ///
    #[must_use]
    pub fn builder(symbol: String) -> MyAllocationsParamsBuilder {
        MyAllocationsParamsBuilder::default().symbol(symbol)
    }
}
/// Request parameters for the [`my_filters`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`my_filters`](#method.my_filters).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct MyFiltersParams {
    ///
    /// The `symbol` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl MyFiltersParams {
    /// Create a builder for [`my_filters`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — String
    ///
    #[must_use]
    pub fn builder(symbol: String) -> MyFiltersParamsBuilder {
        MyFiltersParamsBuilder::default().symbol(symbol)
    }
}
/// Request parameters for the [`my_prevented_matches`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`my_prevented_matches`](#method.my_prevented_matches).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct MyPreventedMatchesParams {
    ///
    /// The `symbol` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    ///
    /// The `prevented_match_id` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub prevented_match_id: Option<i64>,
    ///
    /// The `order_id` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub order_id: Option<i64>,
    ///
    /// The `from_prevented_match_id` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub from_prevented_match_id: Option<i64>,
    /// Default: 500; Maximum: 1000.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i32>,
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl MyPreventedMatchesParams {
    /// Create a builder for [`my_prevented_matches`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — String
    ///
    #[must_use]
    pub fn builder(symbol: String) -> MyPreventedMatchesParamsBuilder {
        MyPreventedMatchesParamsBuilder::default().symbol(symbol)
    }
}
/// Request parameters for the [`my_trades`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`my_trades`](#method.my_trades).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct MyTradesParams {
    ///
    /// The `symbol` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    ///
    /// The `order_id` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub order_id: Option<i64>,
    /// Timestamp in ms to get aggregate trades from INCLUSIVE.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    /// Timestamp in ms to get aggregate trades until INCLUSIVE.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    /// ID to get aggregate trades from INCLUSIVE.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub from_id: Option<i64>,
    /// Default: 500; Maximum: 1000.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i32>,
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl MyTradesParams {
    /// Create a builder for [`my_trades`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — String
    ///
    #[must_use]
    pub fn builder(symbol: String) -> MyTradesParamsBuilder {
        MyTradesParamsBuilder::default().symbol(symbol)
    }
}
/// Request parameters for the [`open_order_list`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`open_order_list`](#method.open_order_list).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OpenOrderListParams {
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl OpenOrderListParams {
    /// Create a builder for [`open_order_list`].
    ///
    #[must_use]
    pub fn builder() -> OpenOrderListParamsBuilder {
        OpenOrderListParamsBuilder::default()
    }
}
/// Request parameters for the [`order_amendments`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_amendments`](#method.order_amendments).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderAmendmentsParams {
    ///
    /// The `symbol` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    ///
    /// The `order_id` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub order_id: i64,
    ///
    /// The `from_execution_id` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub from_execution_id: Option<i64>,
    /// Default:500; Maximum: 1000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i64>,
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl OrderAmendmentsParams {
    /// Create a builder for [`order_amendments`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — String
    /// * `order_id` — i64
    ///
    #[must_use]
    pub fn builder(symbol: String, order_id: i64) -> OrderAmendmentsParamsBuilder {
        OrderAmendmentsParamsBuilder::default()
            .symbol(symbol)
            .order_id(order_id)
    }
}
/// Request parameters for the [`rate_limit_order`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`rate_limit_order`](#method.rate_limit_order).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct RateLimitOrderParams {
    /// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<rust_decimal::Decimal>,
}

impl RateLimitOrderParams {
    /// Create a builder for [`rate_limit_order`].
    ///
    #[must_use]
    pub fn builder() -> RateLimitOrderParamsBuilder {
        RateLimitOrderParamsBuilder::default()
    }
}

#[async_trait]
impl AccountApi for AccountApiClient {
    async fn account_commission(
        &self,
        params: AccountCommissionParams,
    ) -> anyhow::Result<RestApiResponse<models::AccountCommissionResponse>> {
        let AccountCommissionParams { symbol } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("symbol".to_string(), json!(symbol));

        send_request::<models::AccountCommissionResponse>(
            &self.configuration,
            "/api/v3/account/commission",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn all_order_list(
        &self,
        params: AllOrderListParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::AllOrderListResponseInner>>> {
        let AllOrderListParams {
            from_id,
            start_time,
            end_time,
            limit,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = from_id {
            query_params.insert("fromId".to_string(), json!(rw));
        }

        if let Some(rw) = start_time {
            query_params.insert("startTime".to_string(), json!(rw));
        }

        if let Some(rw) = end_time {
            query_params.insert("endTime".to_string(), json!(rw));
        }

        if let Some(rw) = limit {
            query_params.insert("limit".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<Vec<models::AllOrderListResponseInner>>(
            &self.configuration,
            "/api/v3/allOrderList",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn all_orders(
        &self,
        params: AllOrdersParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::AllOrdersResponseInner>>> {
        let AllOrdersParams {
            symbol,
            order_id,
            start_time,
            end_time,
            limit,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("symbol".to_string(), json!(symbol));

        if let Some(rw) = order_id {
            query_params.insert("orderId".to_string(), json!(rw));
        }

        if let Some(rw) = start_time {
            query_params.insert("startTime".to_string(), json!(rw));
        }

        if let Some(rw) = end_time {
            query_params.insert("endTime".to_string(), json!(rw));
        }

        if let Some(rw) = limit {
            query_params.insert("limit".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<Vec<models::AllOrdersResponseInner>>(
            &self.configuration,
            "/api/v3/allOrders",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn get_account(
        &self,
        params: GetAccountParams,
    ) -> anyhow::Result<RestApiResponse<models::GetAccountResponse>> {
        let GetAccountParams {
            omit_zero_balances,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = omit_zero_balances {
            query_params.insert("omitZeroBalances".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::GetAccountResponse>(
            &self.configuration,
            "/api/v3/account",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn get_open_orders(
        &self,
        params: GetOpenOrdersParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::AllOrdersResponseInner>>> {
        let GetOpenOrdersParams {
            symbol,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = symbol {
            query_params.insert("symbol".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<Vec<models::AllOrdersResponseInner>>(
            &self.configuration,
            "/api/v3/openOrders",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn get_order(
        &self,
        params: GetOrderParams,
    ) -> anyhow::Result<RestApiResponse<models::GetOrderResponse>> {
        let GetOrderParams {
            symbol,
            order_id,
            orig_client_order_id,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("symbol".to_string(), json!(symbol));

        if let Some(rw) = order_id {
            query_params.insert("orderId".to_string(), json!(rw));
        }

        if let Some(rw) = orig_client_order_id {
            query_params.insert("origClientOrderId".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::GetOrderResponse>(
            &self.configuration,
            "/api/v3/order",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn get_order_list(
        &self,
        params: GetOrderListParams,
    ) -> anyhow::Result<RestApiResponse<models::GetOrderListResponse>> {
        let GetOrderListParams {
            order_list_id,
            orig_client_order_id,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = order_list_id {
            query_params.insert("orderListId".to_string(), json!(rw));
        }

        if let Some(rw) = orig_client_order_id {
            query_params.insert("origClientOrderId".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::GetOrderListResponse>(
            &self.configuration,
            "/api/v3/orderList",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn my_allocations(
        &self,
        params: MyAllocationsParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::MyAllocationsResponseInner>>> {
        let MyAllocationsParams {
            symbol,
            start_time,
            end_time,
            from_allocation_id,
            limit,
            order_id,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("symbol".to_string(), json!(symbol));

        if let Some(rw) = start_time {
            query_params.insert("startTime".to_string(), json!(rw));
        }

        if let Some(rw) = end_time {
            query_params.insert("endTime".to_string(), json!(rw));
        }

        if let Some(rw) = from_allocation_id {
            query_params.insert("fromAllocationId".to_string(), json!(rw));
        }

        if let Some(rw) = limit {
            query_params.insert("limit".to_string(), json!(rw));
        }

        if let Some(rw) = order_id {
            query_params.insert("orderId".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<Vec<models::MyAllocationsResponseInner>>(
            &self.configuration,
            "/api/v3/myAllocations",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn my_filters(
        &self,
        params: MyFiltersParams,
    ) -> anyhow::Result<RestApiResponse<models::MyFiltersResponse>> {
        let MyFiltersParams {
            symbol,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("symbol".to_string(), json!(symbol));

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::MyFiltersResponse>(
            &self.configuration,
            "/api/v3/myFilters",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn my_prevented_matches(
        &self,
        params: MyPreventedMatchesParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::MyPreventedMatchesResponseInner>>> {
        let MyPreventedMatchesParams {
            symbol,
            prevented_match_id,
            order_id,
            from_prevented_match_id,
            limit,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("symbol".to_string(), json!(symbol));

        if let Some(rw) = prevented_match_id {
            query_params.insert("preventedMatchId".to_string(), json!(rw));
        }

        if let Some(rw) = order_id {
            query_params.insert("orderId".to_string(), json!(rw));
        }

        if let Some(rw) = from_prevented_match_id {
            query_params.insert("fromPreventedMatchId".to_string(), json!(rw));
        }

        if let Some(rw) = limit {
            query_params.insert("limit".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<Vec<models::MyPreventedMatchesResponseInner>>(
            &self.configuration,
            "/api/v3/myPreventedMatches",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn my_trades(
        &self,
        params: MyTradesParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::MyTradesResponseInner>>> {
        let MyTradesParams {
            symbol,
            order_id,
            start_time,
            end_time,
            from_id,
            limit,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("symbol".to_string(), json!(symbol));

        if let Some(rw) = order_id {
            query_params.insert("orderId".to_string(), json!(rw));
        }

        if let Some(rw) = start_time {
            query_params.insert("startTime".to_string(), json!(rw));
        }

        if let Some(rw) = end_time {
            query_params.insert("endTime".to_string(), json!(rw));
        }

        if let Some(rw) = from_id {
            query_params.insert("fromId".to_string(), json!(rw));
        }

        if let Some(rw) = limit {
            query_params.insert("limit".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<Vec<models::MyTradesResponseInner>>(
            &self.configuration,
            "/api/v3/myTrades",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn open_order_list(
        &self,
        params: OpenOrderListParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::OpenOrderListResponseInner>>> {
        let OpenOrderListParams { recv_window } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<Vec<models::OpenOrderListResponseInner>>(
            &self.configuration,
            "/api/v3/openOrderList",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn order_amendments(
        &self,
        params: OrderAmendmentsParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::OrderAmendmentsResponseInner>>> {
        let OrderAmendmentsParams {
            symbol,
            order_id,
            from_execution_id,
            limit,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("symbol".to_string(), json!(symbol));

        query_params.insert("orderId".to_string(), json!(order_id));

        if let Some(rw) = from_execution_id {
            query_params.insert("fromExecutionId".to_string(), json!(rw));
        }

        if let Some(rw) = limit {
            query_params.insert("limit".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<Vec<models::OrderAmendmentsResponseInner>>(
            &self.configuration,
            "/api/v3/order/amendments",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn rate_limit_order(
        &self,
        params: RateLimitOrderParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::RateLimitOrderResponseInner>>> {
        let RateLimitOrderParams { recv_window } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<Vec<models::RateLimitOrderResponseInner>>(
            &self.configuration,
            "/api/v3/rateLimit/order",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }
}

#[cfg(all(test, feature = "spot"))]
mod tests {
    use super::*;
    use crate::TOKIO_SHARED_RT;
    use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
    use async_trait::async_trait;
    use std::collections::HashMap;

    struct DummyRestApiResponse<T> {
        inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
        status: u16,
        headers: HashMap<String, String>,
        rate_limits: Option<Vec<RestApiRateLimit>>,
    }

    impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
        fn from(dummy: DummyRestApiResponse<T>) -> Self {
            Self {
                data_fn: dummy.inner,
                status: dummy.status,
                headers: dummy.headers,
                rate_limits: dummy.rate_limits,
            }
        }
    }

    struct MockAccountApiClient {
        force_error: bool,
    }

    #[async_trait]
    impl AccountApi for MockAccountApiClient {
        async fn account_commission(
            &self,
            _params: AccountCommissionParams,
        ) -> anyhow::Result<RestApiResponse<models::AccountCommissionResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"symbol":"BTCUSDT","standardCommission":{"maker":"0.00000010","taker":"0.00000020","buyer":"0.00000030","seller":"0.00000040"},"specialCommission":{"maker":"0.01000000","taker":"0.02000000","buyer":"0.03000000","seller":"0.04000000"},"taxCommission":{"maker":"0.00000112","taker":"0.00000114","buyer":"0.00000118","seller":"0.00000116"},"discount":{"enabledForAccount":true,"enabledForSymbol":true,"discountAsset":"BNB","discount":"0.75000000"}}"#).unwrap();
            let dummy_response: models::AccountCommissionResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::AccountCommissionResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn all_order_list(
            &self,
            _params: AllOrderListParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::AllOrderListResponseInner>>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"orderListId":29,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"amEEAXryFzFwYF1FeRpUoZ","transactionTime":1565245913483,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"Jr1h6xirOxgeJOUuYQS7V3"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"oD7aesZqjEGlZrbtRpy5zB"}]},{"orderListId":28,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"hG7hFNxJV6cZy3Ze4AUT4d","transactionTime":1565245913407,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":2,"clientOrderId":"j6lFOfbmFMRjTYA7rRJ0LP"},{"symbol":"LTCBTC","orderId":3,"clientOrderId":"z0KCjOdditiLS5ekAFtK81"}]}]"#).unwrap();
            let dummy_response: Vec<models::AllOrderListResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::AllOrderListResponseInner>");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn all_orders(
            &self,
            _params: AllOrdersParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::AllOrdersResponseInner>>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"origQuoteOrderQty":"0.000000","workingTime":1499827319559,"selfTradePreventionMode":"NONE"}]"#).unwrap();
            let dummy_response: Vec<models::AllOrdersResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::AllOrdersResponseInner>");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn get_account(
            &self,
            _params: GetAccountParams,
        ) -> anyhow::Result<RestApiResponse<models::GetAccountResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"makerCommission":15,"takerCommission":15,"buyerCommission":0,"sellerCommission":0,"commissionRates":{"maker":"0.00150000","taker":"0.00150000","buyer":"0.00000000","seller":"0.00000000"},"canTrade":true,"canWithdraw":true,"canDeposit":true,"brokered":false,"requireSelfTradePrevention":false,"preventSor":false,"updateTime":123456789,"accountType":"SPOT","balances":[{"asset":"LTC","free":"4763368.68006011","locked":"0.00000000"},{"asset":"BTC","free":"4723846.89208129","locked":"0.00000000"}],"permissions":["SPOT"],"uid":354937868}"#).unwrap();
            let dummy_response: models::GetAccountResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::GetAccountResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn get_open_orders(
            &self,
            _params: GetOpenOrdersParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::AllOrdersResponseInner>>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"origQuoteOrderQty":"0.000000","workingTime":1499827319559,"selfTradePreventionMode":"NONE"}]"#).unwrap();
            let dummy_response: Vec<models::AllOrdersResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::AllOrdersResponseInner>");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn get_order(
            &self,
            _params: GetOrderParams,
        ) -> anyhow::Result<RestApiResponse<models::GetOrderResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"workingTime":1499827319559,"origQuoteOrderQty":"0.000000","selfTradePreventionMode":"NONE"}"#).unwrap();
            let dummy_response: models::GetOrderResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::GetOrderResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn get_order_list(
            &self,
            _params: GetOrderListParams,
        ) -> anyhow::Result<RestApiResponse<models::GetOrderListResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"orderListId":27,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"h2USkA5YQpaXHPIrkd96xE","transactionTime":1565245656253,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"ARzZ9I00CPM8i3NhmU9Ega"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"qD1gy3kc3Gx0rihm9Y3xwS"}]}"#).unwrap();
            let dummy_response: models::GetOrderListResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::GetOrderListResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn my_allocations(
            &self,
            _params: MyAllocationsParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::MyAllocationsResponseInner>>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","allocationId":0,"allocationType":"SOR","orderId":1,"orderListId":-1,"price":"1.00000000","qty":"5.00000000","quoteQty":"5.00000000","commission":"0.00000000","commissionAsset":"BTC","time":1687506878118,"isBuyer":true,"isMaker":false,"isAllocator":false}]"#).unwrap();
            let dummy_response: Vec<models::MyAllocationsResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::MyAllocationsResponseInner>");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn my_filters(
            &self,
            _params: MyFiltersParams,
        ) -> anyhow::Result<RestApiResponse<models::MyFiltersResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"exchangeFilters":[{"filterType":"EXCHANGE_MAX_NUM_ORDERS","maxNumOrders":1000}],"symbolFilters":[{"filterType":"MAX_NUM_ORDER_LISTS","maxNumOrderLists":20}],"assetFilters":[{"filterType":"MAX_ASSET","asset":"JPY","limit":"1000000.00000000"}],"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000},{"rateLimitType":"RAW_REQUESTS","interval":"MINUTE","intervalNum":5,"limit":61000}]}"#).unwrap();
            let dummy_response: models::MyFiltersResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::MyFiltersResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn my_prevented_matches(
            &self,
            _params: MyPreventedMatchesParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::MyPreventedMatchesResponseInner>>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","preventedMatchId":1,"takerOrderId":5,"makerSymbol":"BTCUSDT","makerOrderId":3,"tradeGroupId":1,"selfTradePreventionMode":"EXPIRE_MAKER","price":"1.100000","makerPreventedQuantity":"1.300000","transactTime":1669101687094}]"#).unwrap();
            let dummy_response: Vec<models::MyPreventedMatchesResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::MyPreventedMatchesResponseInner>");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn my_trades(
            &self,
            _params: MyTradesParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::MyTradesResponseInner>>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BNBBTC","id":28457,"orderId":100234,"orderListId":-1,"price":"4.00000100","qty":"12.00000000","quoteQty":"48.000012","commission":"10.10000000","commissionAsset":"BNB","time":1499865549590,"isBuyer":true,"isMaker":false,"isBestMatch":true}]"#).unwrap();
            let dummy_response: Vec<models::MyTradesResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::MyTradesResponseInner>");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn open_order_list(
            &self,
            _params: OpenOrderListParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::OpenOrderListResponseInner>>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"orderListId":31,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"wuB13fmulKj3YjdqWEcsnp","transactionTime":1565246080644,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"Cv1SnyPD3qhqpbjpYEHbd2"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"r3EH2N76dHfLoSZWIUw1bT"}]}]"#).unwrap();
            let dummy_response: Vec<models::OpenOrderListResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::OpenOrderListResponseInner>");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn order_amendments(
            &self,
            _params: OrderAmendmentsParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::OrderAmendmentsResponseInner>>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","orderId":9,"executionId":22,"origClientOrderId":"W0fJ9fiLKHOJutovPK3oJp","newClientOrderId":"UQ1Np3bmQ71jJzsSDW9Vpi","origQty":"5.00000000","newQty":"4.00000000","time":1741669661670},{"symbol":"BTCUDST","orderId":9,"executionId":25,"origClientOrderId":"UQ1Np3bmQ71jJzsSDW9Vpi","newClientOrderId":"5uS0r35ohuQyDlCzZuYXq2","origQty":"4.00000000","newQty":"3.00000000","time":1741672924895}]"#).unwrap();
            let dummy_response: Vec<models::OrderAmendmentsResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::OrderAmendmentsResponseInner>");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn rate_limit_order(
            &self,
            _params: RateLimitOrderParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::RateLimitOrderResponseInner>>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":50,"count":0},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000,"count":0}]"#).unwrap();
            let dummy_response: Vec<models::RateLimitOrderResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::RateLimitOrderResponseInner>");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }
    }

    #[test]
    fn account_commission_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = AccountCommissionParams::builder("BNBUSDT".to_string()).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"symbol":"BTCUSDT","standardCommission":{"maker":"0.00000010","taker":"0.00000020","buyer":"0.00000030","seller":"0.00000040"},"specialCommission":{"maker":"0.01000000","taker":"0.02000000","buyer":"0.03000000","seller":"0.04000000"},"taxCommission":{"maker":"0.00000112","taker":"0.00000114","buyer":"0.00000118","seller":"0.00000116"},"discount":{"enabledForAccount":true,"enabledForSymbol":true,"discountAsset":"BNB","discount":"0.75000000"}}"#).unwrap();
            let expected_response : models::AccountCommissionResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AccountCommissionResponse");

            let resp = client.account_commission(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn account_commission_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = AccountCommissionParams::builder("BNBUSDT".to_string()).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"symbol":"BTCUSDT","standardCommission":{"maker":"0.00000010","taker":"0.00000020","buyer":"0.00000030","seller":"0.00000040"},"specialCommission":{"maker":"0.01000000","taker":"0.02000000","buyer":"0.03000000","seller":"0.04000000"},"taxCommission":{"maker":"0.00000112","taker":"0.00000114","buyer":"0.00000118","seller":"0.00000116"},"discount":{"enabledForAccount":true,"enabledForSymbol":true,"discountAsset":"BNB","discount":"0.75000000"}}"#).unwrap();
            let expected_response : models::AccountCommissionResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AccountCommissionResponse");

            let resp = client.account_commission(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn account_commission_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = AccountCommissionParams::builder("BNBUSDT".to_string())
                .build()
                .unwrap();

            match client.account_commission(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn all_order_list_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = AllOrderListParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"orderListId":29,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"amEEAXryFzFwYF1FeRpUoZ","transactionTime":1565245913483,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"Jr1h6xirOxgeJOUuYQS7V3"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"oD7aesZqjEGlZrbtRpy5zB"}]},{"orderListId":28,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"hG7hFNxJV6cZy3Ze4AUT4d","transactionTime":1565245913407,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":2,"clientOrderId":"j6lFOfbmFMRjTYA7rRJ0LP"},{"symbol":"LTCBTC","orderId":3,"clientOrderId":"z0KCjOdditiLS5ekAFtK81"}]}]"#).unwrap();
            let expected_response : Vec<models::AllOrderListResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllOrderListResponseInner>");

            let resp = client.all_order_list(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn all_order_list_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = AllOrderListParams::builder().from_id(1).start_time(1735693200000).end_time(1735693200000).limit(500).recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"orderListId":29,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"amEEAXryFzFwYF1FeRpUoZ","transactionTime":1565245913483,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"Jr1h6xirOxgeJOUuYQS7V3"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"oD7aesZqjEGlZrbtRpy5zB"}]},{"orderListId":28,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"hG7hFNxJV6cZy3Ze4AUT4d","transactionTime":1565245913407,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":2,"clientOrderId":"j6lFOfbmFMRjTYA7rRJ0LP"},{"symbol":"LTCBTC","orderId":3,"clientOrderId":"z0KCjOdditiLS5ekAFtK81"}]}]"#).unwrap();
            let expected_response : Vec<models::AllOrderListResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllOrderListResponseInner>");

            let resp = client.all_order_list(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn all_order_list_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = AllOrderListParams::builder().build().unwrap();

            match client.all_order_list(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn all_orders_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = AllOrdersParams::builder("BNBUSDT".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"origQuoteOrderQty":"0.000000","workingTime":1499827319559,"selfTradePreventionMode":"NONE"}]"#).unwrap();
            let expected_response : Vec<models::AllOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllOrdersResponseInner>");

            let resp = client.all_orders(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn all_orders_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = AllOrdersParams::builder("BNBUSDT".to_string(),).order_id(1).start_time(1735693200000).end_time(1735693200000).limit(500).recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"origQuoteOrderQty":"0.000000","workingTime":1499827319559,"selfTradePreventionMode":"NONE"}]"#).unwrap();
            let expected_response : Vec<models::AllOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllOrdersResponseInner>");

            let resp = client.all_orders(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn all_orders_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = AllOrdersParams::builder("BNBUSDT".to_string())
                .build()
                .unwrap();

            match client.all_orders(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn get_account_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = GetAccountParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"makerCommission":15,"takerCommission":15,"buyerCommission":0,"sellerCommission":0,"commissionRates":{"maker":"0.00150000","taker":"0.00150000","buyer":"0.00000000","seller":"0.00000000"},"canTrade":true,"canWithdraw":true,"canDeposit":true,"brokered":false,"requireSelfTradePrevention":false,"preventSor":false,"updateTime":123456789,"accountType":"SPOT","balances":[{"asset":"LTC","free":"4763368.68006011","locked":"0.00000000"},{"asset":"BTC","free":"4723846.89208129","locked":"0.00000000"}],"permissions":["SPOT"],"uid":354937868}"#).unwrap();
            let expected_response : models::GetAccountResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetAccountResponse");

            let resp = client.get_account(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_account_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = GetAccountParams::builder().omit_zero_balances(false).recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"makerCommission":15,"takerCommission":15,"buyerCommission":0,"sellerCommission":0,"commissionRates":{"maker":"0.00150000","taker":"0.00150000","buyer":"0.00000000","seller":"0.00000000"},"canTrade":true,"canWithdraw":true,"canDeposit":true,"brokered":false,"requireSelfTradePrevention":false,"preventSor":false,"updateTime":123456789,"accountType":"SPOT","balances":[{"asset":"LTC","free":"4763368.68006011","locked":"0.00000000"},{"asset":"BTC","free":"4723846.89208129","locked":"0.00000000"}],"permissions":["SPOT"],"uid":354937868}"#).unwrap();
            let expected_response : models::GetAccountResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetAccountResponse");

            let resp = client.get_account(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_account_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = GetAccountParams::builder().build().unwrap();

            match client.get_account(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn get_open_orders_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = GetOpenOrdersParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"origQuoteOrderQty":"0.000000","workingTime":1499827319559,"selfTradePreventionMode":"NONE"}]"#).unwrap();
            let expected_response : Vec<models::AllOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllOrdersResponseInner>");

            let resp = client.get_open_orders(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_open_orders_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = GetOpenOrdersParams::builder().symbol("BNBUSDT".to_string()).recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"origQuoteOrderQty":"0.000000","workingTime":1499827319559,"selfTradePreventionMode":"NONE"}]"#).unwrap();
            let expected_response : Vec<models::AllOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllOrdersResponseInner>");

            let resp = client.get_open_orders(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_open_orders_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = GetOpenOrdersParams::builder().build().unwrap();

            match client.get_open_orders(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn get_order_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = GetOrderParams::builder("BNBUSDT".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"workingTime":1499827319559,"origQuoteOrderQty":"0.000000","selfTradePreventionMode":"NONE"}"#).unwrap();
            let expected_response : models::GetOrderResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetOrderResponse");

            let resp = client.get_order(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_order_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = GetOrderParams::builder("BNBUSDT".to_string(),).order_id(1).orig_client_order_id("orig_client_order_id_example".to_string()).recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"workingTime":1499827319559,"origQuoteOrderQty":"0.000000","selfTradePreventionMode":"NONE"}"#).unwrap();
            let expected_response : models::GetOrderResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetOrderResponse");

            let resp = client.get_order(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_order_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = GetOrderParams::builder("BNBUSDT".to_string())
                .build()
                .unwrap();

            match client.get_order(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn get_order_list_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = GetOrderListParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"orderListId":27,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"h2USkA5YQpaXHPIrkd96xE","transactionTime":1565245656253,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"ARzZ9I00CPM8i3NhmU9Ega"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"qD1gy3kc3Gx0rihm9Y3xwS"}]}"#).unwrap();
            let expected_response : models::GetOrderListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetOrderListResponse");

            let resp = client.get_order_list(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_order_list_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = GetOrderListParams::builder().order_list_id(1).orig_client_order_id("orig_client_order_id_example".to_string()).recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"orderListId":27,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"h2USkA5YQpaXHPIrkd96xE","transactionTime":1565245656253,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"ARzZ9I00CPM8i3NhmU9Ega"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"qD1gy3kc3Gx0rihm9Y3xwS"}]}"#).unwrap();
            let expected_response : models::GetOrderListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetOrderListResponse");

            let resp = client.get_order_list(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_order_list_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = GetOrderListParams::builder().build().unwrap();

            match client.get_order_list(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn my_allocations_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = MyAllocationsParams::builder("BNBUSDT".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","allocationId":0,"allocationType":"SOR","orderId":1,"orderListId":-1,"price":"1.00000000","qty":"5.00000000","quoteQty":"5.00000000","commission":"0.00000000","commissionAsset":"BTC","time":1687506878118,"isBuyer":true,"isMaker":false,"isAllocator":false}]"#).unwrap();
            let expected_response : Vec<models::MyAllocationsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::MyAllocationsResponseInner>");

            let resp = client.my_allocations(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn my_allocations_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = MyAllocationsParams::builder("BNBUSDT".to_string(),).start_time(1735693200000).end_time(1735693200000).from_allocation_id(1).limit(500).order_id(1).recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","allocationId":0,"allocationType":"SOR","orderId":1,"orderListId":-1,"price":"1.00000000","qty":"5.00000000","quoteQty":"5.00000000","commission":"0.00000000","commissionAsset":"BTC","time":1687506878118,"isBuyer":true,"isMaker":false,"isAllocator":false}]"#).unwrap();
            let expected_response : Vec<models::MyAllocationsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::MyAllocationsResponseInner>");

            let resp = client.my_allocations(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn my_allocations_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = MyAllocationsParams::builder("BNBUSDT".to_string())
                .build()
                .unwrap();

            match client.my_allocations(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn my_filters_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = MyFiltersParams::builder("BNBUSDT".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"exchangeFilters":[{"filterType":"EXCHANGE_MAX_NUM_ORDERS","maxNumOrders":1000}],"symbolFilters":[{"filterType":"MAX_NUM_ORDER_LISTS","maxNumOrderLists":20}],"assetFilters":[{"filterType":"MAX_ASSET","asset":"JPY","limit":"1000000.00000000"}],"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000},{"rateLimitType":"RAW_REQUESTS","interval":"MINUTE","intervalNum":5,"limit":61000}]}"#).unwrap();
            let expected_response : models::MyFiltersResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::MyFiltersResponse");

            let resp = client.my_filters(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn my_filters_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = MyFiltersParams::builder("BNBUSDT".to_string(),).recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"exchangeFilters":[{"filterType":"EXCHANGE_MAX_NUM_ORDERS","maxNumOrders":1000}],"symbolFilters":[{"filterType":"MAX_NUM_ORDER_LISTS","maxNumOrderLists":20}],"assetFilters":[{"filterType":"MAX_ASSET","asset":"JPY","limit":"1000000.00000000"}],"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000},{"rateLimitType":"RAW_REQUESTS","interval":"MINUTE","intervalNum":5,"limit":61000}]}"#).unwrap();
            let expected_response : models::MyFiltersResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::MyFiltersResponse");

            let resp = client.my_filters(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn my_filters_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = MyFiltersParams::builder("BNBUSDT".to_string())
                .build()
                .unwrap();

            match client.my_filters(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn my_prevented_matches_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = MyPreventedMatchesParams::builder("BNBUSDT".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","preventedMatchId":1,"takerOrderId":5,"makerSymbol":"BTCUSDT","makerOrderId":3,"tradeGroupId":1,"selfTradePreventionMode":"EXPIRE_MAKER","price":"1.100000","makerPreventedQuantity":"1.300000","transactTime":1669101687094}]"#).unwrap();
            let expected_response : Vec<models::MyPreventedMatchesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::MyPreventedMatchesResponseInner>");

            let resp = client.my_prevented_matches(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn my_prevented_matches_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = MyPreventedMatchesParams::builder("BNBUSDT".to_string(),).prevented_match_id(1).order_id(1).from_prevented_match_id(1).limit(500).recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","preventedMatchId":1,"takerOrderId":5,"makerSymbol":"BTCUSDT","makerOrderId":3,"tradeGroupId":1,"selfTradePreventionMode":"EXPIRE_MAKER","price":"1.100000","makerPreventedQuantity":"1.300000","transactTime":1669101687094}]"#).unwrap();
            let expected_response : Vec<models::MyPreventedMatchesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::MyPreventedMatchesResponseInner>");

            let resp = client.my_prevented_matches(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn my_prevented_matches_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = MyPreventedMatchesParams::builder("BNBUSDT".to_string())
                .build()
                .unwrap();

            match client.my_prevented_matches(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn my_trades_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = MyTradesParams::builder("BNBUSDT".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BNBBTC","id":28457,"orderId":100234,"orderListId":-1,"price":"4.00000100","qty":"12.00000000","quoteQty":"48.000012","commission":"10.10000000","commissionAsset":"BNB","time":1499865549590,"isBuyer":true,"isMaker":false,"isBestMatch":true}]"#).unwrap();
            let expected_response : Vec<models::MyTradesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::MyTradesResponseInner>");

            let resp = client.my_trades(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn my_trades_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = MyTradesParams::builder("BNBUSDT".to_string(),).order_id(1).start_time(1735693200000).end_time(1735693200000).from_id(1).limit(500).recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BNBBTC","id":28457,"orderId":100234,"orderListId":-1,"price":"4.00000100","qty":"12.00000000","quoteQty":"48.000012","commission":"10.10000000","commissionAsset":"BNB","time":1499865549590,"isBuyer":true,"isMaker":false,"isBestMatch":true}]"#).unwrap();
            let expected_response : Vec<models::MyTradesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::MyTradesResponseInner>");

            let resp = client.my_trades(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn my_trades_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = MyTradesParams::builder("BNBUSDT".to_string())
                .build()
                .unwrap();

            match client.my_trades(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn open_order_list_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = OpenOrderListParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"orderListId":31,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"wuB13fmulKj3YjdqWEcsnp","transactionTime":1565246080644,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"Cv1SnyPD3qhqpbjpYEHbd2"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"r3EH2N76dHfLoSZWIUw1bT"}]}]"#).unwrap();
            let expected_response : Vec<models::OpenOrderListResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::OpenOrderListResponseInner>");

            let resp = client.open_order_list(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn open_order_list_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = OpenOrderListParams::builder().recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"orderListId":31,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"wuB13fmulKj3YjdqWEcsnp","transactionTime":1565246080644,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"Cv1SnyPD3qhqpbjpYEHbd2"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"r3EH2N76dHfLoSZWIUw1bT"}]}]"#).unwrap();
            let expected_response : Vec<models::OpenOrderListResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::OpenOrderListResponseInner>");

            let resp = client.open_order_list(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn open_order_list_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = OpenOrderListParams::builder().build().unwrap();

            match client.open_order_list(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn order_amendments_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = OrderAmendmentsParams::builder("BNBUSDT".to_string(),1,).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","orderId":9,"executionId":22,"origClientOrderId":"W0fJ9fiLKHOJutovPK3oJp","newClientOrderId":"UQ1Np3bmQ71jJzsSDW9Vpi","origQty":"5.00000000","newQty":"4.00000000","time":1741669661670},{"symbol":"BTCUDST","orderId":9,"executionId":25,"origClientOrderId":"UQ1Np3bmQ71jJzsSDW9Vpi","newClientOrderId":"5uS0r35ohuQyDlCzZuYXq2","origQty":"4.00000000","newQty":"3.00000000","time":1741672924895}]"#).unwrap();
            let expected_response : Vec<models::OrderAmendmentsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::OrderAmendmentsResponseInner>");

            let resp = client.order_amendments(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn order_amendments_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = OrderAmendmentsParams::builder("BNBUSDT".to_string(),1,).from_execution_id(1).limit(500).recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","orderId":9,"executionId":22,"origClientOrderId":"W0fJ9fiLKHOJutovPK3oJp","newClientOrderId":"UQ1Np3bmQ71jJzsSDW9Vpi","origQty":"5.00000000","newQty":"4.00000000","time":1741669661670},{"symbol":"BTCUDST","orderId":9,"executionId":25,"origClientOrderId":"UQ1Np3bmQ71jJzsSDW9Vpi","newClientOrderId":"5uS0r35ohuQyDlCzZuYXq2","origQty":"4.00000000","newQty":"3.00000000","time":1741672924895}]"#).unwrap();
            let expected_response : Vec<models::OrderAmendmentsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::OrderAmendmentsResponseInner>");

            let resp = client.order_amendments(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn order_amendments_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = OrderAmendmentsParams::builder("BNBUSDT".to_string(), 1)
                .build()
                .unwrap();

            match client.order_amendments(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn rate_limit_order_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = RateLimitOrderParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":50,"count":0},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000,"count":0}]"#).unwrap();
            let expected_response : Vec<models::RateLimitOrderResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::RateLimitOrderResponseInner>");

            let resp = client.rate_limit_order(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn rate_limit_order_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: false };

            let params = RateLimitOrderParams::builder().recv_window(dec!(5000.0)).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":50,"count":0},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000,"count":0}]"#).unwrap();
            let expected_response : Vec<models::RateLimitOrderResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::RateLimitOrderResponseInner>");

            let resp = client.rate_limit_order(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn rate_limit_order_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockAccountApiClient { force_error: true };

            let params = RateLimitOrderParams::builder().build().unwrap();

            match client.rate_limit_order(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }
}
