/*
 * Binance Derivatives Trading Options REST API
 *
 * OpenAPI Specification for the Binance Derivatives Trading Options REST API
 *
 * 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::derivatives_trading_options::rest_api::models;

const HAS_TIME_UNIT: bool = false;

#[async_trait]
pub trait TradeApi: Send + Sync {
    async fn account_trade_list(
        &self,
        params: AccountTradeListParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::AccountTradeListResponseInner>>>;
    async fn cancel_all_option_orders_by_underlying(
        &self,
        params: CancelAllOptionOrdersByUnderlyingParams,
    ) -> anyhow::Result<RestApiResponse<models::CancelAllOptionOrdersByUnderlyingResponse>>;
    async fn cancel_all_option_orders_on_specific_symbol(
        &self,
        params: CancelAllOptionOrdersOnSpecificSymbolParams,
    ) -> anyhow::Result<RestApiResponse<models::CancelAllOptionOrdersOnSpecificSymbolResponse>>;
    async fn cancel_multiple_option_orders(
        &self,
        params: CancelMultipleOptionOrdersParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::CancelMultipleOptionOrdersResponseInner>>>;
    async fn cancel_option_order(
        &self,
        params: CancelOptionOrderParams,
    ) -> anyhow::Result<RestApiResponse<models::CancelOptionOrderResponse>>;
    async fn new_order(
        &self,
        params: NewOrderParams,
    ) -> anyhow::Result<RestApiResponse<models::NewOrderResponse>>;
    async fn option_position_information(
        &self,
        params: OptionPositionInformationParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::OptionPositionInformationResponseInner>>>;
    async fn place_multiple_orders(
        &self,
        params: PlaceMultipleOrdersParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::PlaceMultipleOrdersResponseInner>>>;
    async fn query_current_open_option_orders(
        &self,
        params: QueryCurrentOpenOptionOrdersParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::QueryCurrentOpenOptionOrdersResponseInner>>>;
    async fn query_option_order_history(
        &self,
        params: QueryOptionOrderHistoryParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::QueryOptionOrderHistoryResponseInner>>>;
    async fn query_single_order(
        &self,
        params: QuerySingleOrderParams,
    ) -> anyhow::Result<RestApiResponse<models::QuerySingleOrderResponse>>;
    async fn user_commission(
        &self,
        params: UserCommissionParams,
    ) -> anyhow::Result<RestApiResponse<models::UserCommissionResponse>>;
    async fn user_exercise_record(
        &self,
        params: UserExerciseRecordParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::UserExerciseRecordResponseInner>>>;
}

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

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

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NewOrderSideEnum {
    #[serde(rename = "BUY")]
    Buy,
    #[serde(rename = "SELL")]
    Sell,
}

impl NewOrderSideEnum {
    #[must_use]
    pub fn as_str(&self) -> &'static str {
        match self {
            Self::Buy => "BUY",
            Self::Sell => "SELL",
        }
    }
}

impl std::str::FromStr for NewOrderSideEnum {
    type Err = Box<dyn std::error::Error + Send + Sync>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "BUY" => Ok(Self::Buy),
            "SELL" => Ok(Self::Sell),
            other => Err(format!("invalid NewOrderSideEnum: {}", other).into()),
        }
    }
}

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NewOrderTypeEnum {
    #[serde(rename = "LIMIT")]
    Limit,
}

impl NewOrderTypeEnum {
    #[must_use]
    pub fn as_str(&self) -> &'static str {
        match self {
            Self::Limit => "LIMIT",
        }
    }
}

impl std::str::FromStr for NewOrderTypeEnum {
    type Err = Box<dyn std::error::Error + Send + Sync>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "LIMIT" => Ok(Self::Limit),
            other => Err(format!("invalid NewOrderTypeEnum: {}", other).into()),
        }
    }
}

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NewOrderTimeInForceEnum {
    #[serde(rename = "GTC")]
    Gtc,
    #[serde(rename = "IOC")]
    Ioc,
    #[serde(rename = "FOK")]
    Fok,
    #[serde(rename = "GTX")]
    Gtx,
}

impl NewOrderTimeInForceEnum {
    #[must_use]
    pub fn as_str(&self) -> &'static str {
        match self {
            Self::Gtc => "GTC",
            Self::Ioc => "IOC",
            Self::Fok => "FOK",
            Self::Gtx => "GTX",
        }
    }
}

impl std::str::FromStr for NewOrderTimeInForceEnum {
    type Err = Box<dyn std::error::Error + Send + Sync>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "GTC" => Ok(Self::Gtc),
            "IOC" => Ok(Self::Ioc),
            "FOK" => Ok(Self::Fok),
            "GTX" => Ok(Self::Gtx),
            other => Err(format!("invalid NewOrderTimeInForceEnum: {}", other).into()),
        }
    }
}

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NewOrderNewOrderRespTypeEnum {
    #[serde(rename = "ACK")]
    Ack,
    #[serde(rename = "RESULT")]
    Result,
}

impl NewOrderNewOrderRespTypeEnum {
    #[must_use]
    pub fn as_str(&self) -> &'static str {
        match self {
            Self::Ack => "ACK",
            Self::Result => "RESULT",
        }
    }
}

impl std::str::FromStr for NewOrderNewOrderRespTypeEnum {
    type Err = Box<dyn std::error::Error + Send + Sync>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "ACK" => Ok(Self::Ack),
            "RESULT" => Ok(Self::Result),
            other => Err(format!("invalid NewOrderNewOrderRespTypeEnum: {}", other).into()),
        }
    }
}

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NewOrderSelfTradePreventionModeEnum {
    #[serde(rename = "EXPIRE_TAKER")]
    ExpireTaker,
    #[serde(rename = "EXPIRE_BOTH")]
    ExpireBoth,
    #[serde(rename = "EXPIRE_MAKER")]
    ExpireMaker,
}

impl NewOrderSelfTradePreventionModeEnum {
    #[must_use]
    pub fn as_str(&self) -> &'static str {
        match self {
            Self::ExpireTaker => "EXPIRE_TAKER",
            Self::ExpireBoth => "EXPIRE_BOTH",
            Self::ExpireMaker => "EXPIRE_MAKER",
        }
    }
}

impl std::str::FromStr for NewOrderSelfTradePreventionModeEnum {
    type Err = Box<dyn std::error::Error + Send + Sync>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "EXPIRE_TAKER" => Ok(Self::ExpireTaker),
            "EXPIRE_BOTH" => Ok(Self::ExpireBoth),
            "EXPIRE_MAKER" => Ok(Self::ExpireMaker),
            other => Err(format!("invalid NewOrderSelfTradePreventionModeEnum: {}", other).into()),
        }
    }
}

/// Request parameters for the [`account_trade_list`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`account_trade_list`](#method.account_trade_list).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct AccountTradeListParams {
    /// Option trading pair, e.g BTC-200730-9000-C
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub symbol: Option<String>,
    /// Trade id to fetch from. Default gets most recent trades, e.g 4611875134427365376
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub from_id: Option<i64>,
    /// Start Time, e.g 1593511200000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    /// End Time, e.g 1593512200000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    /// Number of result sets returned Default:100 Max:1000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i64>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl AccountTradeListParams {
    /// Create a builder for [`account_trade_list`].
    ///
    #[must_use]
    pub fn builder() -> AccountTradeListParamsBuilder {
        AccountTradeListParamsBuilder::default()
    }
}
/// Request parameters for the [`cancel_all_option_orders_by_underlying`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`cancel_all_option_orders_by_underlying`](#method.cancel_all_option_orders_by_underlying).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct CancelAllOptionOrdersByUnderlyingParams {
    /// Option underlying, e.g BTCUSDT
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub underlying: String,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl CancelAllOptionOrdersByUnderlyingParams {
    /// Create a builder for [`cancel_all_option_orders_by_underlying`].
    ///
    /// Required parameters:
    ///
    /// * `underlying` — Option underlying, e.g BTCUSDT
    ///
    #[must_use]
    pub fn builder(underlying: String) -> CancelAllOptionOrdersByUnderlyingParamsBuilder {
        CancelAllOptionOrdersByUnderlyingParamsBuilder::default().underlying(underlying)
    }
}
/// Request parameters for the [`cancel_all_option_orders_on_specific_symbol`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`cancel_all_option_orders_on_specific_symbol`](#method.cancel_all_option_orders_on_specific_symbol).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct CancelAllOptionOrdersOnSpecificSymbolParams {
    /// Option trading pair, e.g BTC-200730-9000-C
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl CancelAllOptionOrdersOnSpecificSymbolParams {
    /// Create a builder for [`cancel_all_option_orders_on_specific_symbol`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — Option trading pair, e.g BTC-200730-9000-C
    ///
    #[must_use]
    pub fn builder(symbol: String) -> CancelAllOptionOrdersOnSpecificSymbolParamsBuilder {
        CancelAllOptionOrdersOnSpecificSymbolParamsBuilder::default().symbol(symbol)
    }
}
/// Request parameters for the [`cancel_multiple_option_orders`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`cancel_multiple_option_orders`](#method.cancel_multiple_option_orders).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct CancelMultipleOptionOrdersParams {
    /// Option trading pair, e.g BTC-200730-9000-C
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    /// Order ID, e.g [4611875134427365377,4611875134427365378]
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub order_ids: Option<Vec<i64>>,
    /// User-defined order ID, e.g ["`my_id_1","my_id_2`"]
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub client_order_ids: Option<Vec<String>>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl CancelMultipleOptionOrdersParams {
    /// Create a builder for [`cancel_multiple_option_orders`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — Option trading pair, e.g BTC-200730-9000-C
    ///
    #[must_use]
    pub fn builder(symbol: String) -> CancelMultipleOptionOrdersParamsBuilder {
        CancelMultipleOptionOrdersParamsBuilder::default().symbol(symbol)
    }
}
/// Request parameters for the [`cancel_option_order`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`cancel_option_order`](#method.cancel_option_order).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct CancelOptionOrderParams {
    /// Option trading pair, e.g BTC-200730-9000-C
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    /// Order ID, e.g 4611875134427365377
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub order_id: Option<i64>,
    /// User-defined order ID, e.g 10000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub client_order_id: Option<String>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl CancelOptionOrderParams {
    /// Create a builder for [`cancel_option_order`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — Option trading pair, e.g BTC-200730-9000-C
    ///
    #[must_use]
    pub fn builder(symbol: String) -> CancelOptionOrderParamsBuilder {
        CancelOptionOrderParamsBuilder::default().symbol(symbol)
    }
}
/// Request parameters for the [`new_order`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`new_order`](#method.new_order).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct NewOrderParams {
    /// Option trading pair, e.g BTC-200730-9000-C
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    /// Buy/sell direction: SELL, BUY
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub side: NewOrderSideEnum,
    /// Order Type: LIMIT(only support limit)
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub r#type: NewOrderTypeEnum,
    /// Order Quantity
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub quantity: rust_decimal::Decimal,
    /// Order Price
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub price: Option<rust_decimal::Decimal>,
    /// Time in force method（Default GTC）
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub time_in_force: Option<NewOrderTimeInForceEnum>,
    /// Reduce Only（Default false）
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub reduce_only: Option<bool>,
    /// Post Only（Default false）
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub post_only: Option<bool>,
    /// "ACK", "RESULT", Default "ACK"
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub new_order_resp_type: Option<NewOrderNewOrderRespTypeEnum>,
    /// User-defined order ID, e.g 10000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub client_order_id: Option<String>,
    /// is market maker protection order, true/false
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub is_mmp: Option<bool>,
    /// `EXPIRE_TAKER`:expire taker order when STP triggers/ `EXPIRE_MAKER`:expire maker order when STP triggers/ `EXPIRE_BOTH`:expire both orders when STP triggers; Default `EXPIRE_MAKER`
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub self_trade_prevention_mode: Option<NewOrderSelfTradePreventionModeEnum>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl NewOrderParams {
    /// Create a builder for [`new_order`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — Option trading pair, e.g BTC-200730-9000-C
    /// * `side` — Buy/sell direction: SELL, BUY
    /// * `r#type` — Order Type: LIMIT(only support limit)
    /// * `quantity` — Order Quantity
    ///
    #[must_use]
    pub fn builder(
        symbol: String,
        side: NewOrderSideEnum,
        r#type: NewOrderTypeEnum,
        quantity: rust_decimal::Decimal,
    ) -> NewOrderParamsBuilder {
        NewOrderParamsBuilder::default()
            .symbol(symbol)
            .side(side)
            .r#type(r#type)
            .quantity(quantity)
    }
}
/// Request parameters for the [`option_position_information`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`option_position_information`](#method.option_position_information).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OptionPositionInformationParams {
    /// Option trading pair, e.g BTC-200730-9000-C
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub symbol: Option<String>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl OptionPositionInformationParams {
    /// Create a builder for [`option_position_information`].
    ///
    #[must_use]
    pub fn builder() -> OptionPositionInformationParamsBuilder {
        OptionPositionInformationParamsBuilder::default()
    }
}
/// Request parameters for the [`place_multiple_orders`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`place_multiple_orders`](#method.place_multiple_orders).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct PlaceMultipleOrdersParams {
    /// order list. Max 10 orders
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub orders: Vec<models::PlaceMultipleOrdersOrdersParameterInner>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl PlaceMultipleOrdersParams {
    /// Create a builder for [`place_multiple_orders`].
    ///
    /// Required parameters:
    ///
    /// * `orders` — order list. Max 10 orders
    ///
    #[must_use]
    pub fn builder(
        orders: Vec<models::PlaceMultipleOrdersOrdersParameterInner>,
    ) -> PlaceMultipleOrdersParamsBuilder {
        PlaceMultipleOrdersParamsBuilder::default().orders(orders)
    }
}
/// Request parameters for the [`query_current_open_option_orders`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`query_current_open_option_orders`](#method.query_current_open_option_orders).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct QueryCurrentOpenOptionOrdersParams {
    /// Option trading pair, e.g BTC-200730-9000-C
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub symbol: Option<String>,
    /// Order ID, e.g 4611875134427365377
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub order_id: Option<i64>,
    /// Start Time, e.g 1593511200000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    /// End Time, e.g 1593512200000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl QueryCurrentOpenOptionOrdersParams {
    /// Create a builder for [`query_current_open_option_orders`].
    ///
    #[must_use]
    pub fn builder() -> QueryCurrentOpenOptionOrdersParamsBuilder {
        QueryCurrentOpenOptionOrdersParamsBuilder::default()
    }
}
/// Request parameters for the [`query_option_order_history`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`query_option_order_history`](#method.query_option_order_history).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct QueryOptionOrderHistoryParams {
    /// Option trading pair, e.g BTC-200730-9000-C
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    /// Order ID, e.g 4611875134427365377
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub order_id: Option<i64>,
    /// Start Time, e.g 1593511200000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    /// End Time, e.g 1593512200000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    /// Number of result sets returned Default:100 Max:1000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i64>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl QueryOptionOrderHistoryParams {
    /// Create a builder for [`query_option_order_history`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — Option trading pair, e.g BTC-200730-9000-C
    ///
    #[must_use]
    pub fn builder(symbol: String) -> QueryOptionOrderHistoryParamsBuilder {
        QueryOptionOrderHistoryParamsBuilder::default().symbol(symbol)
    }
}
/// Request parameters for the [`query_single_order`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`query_single_order`](#method.query_single_order).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct QuerySingleOrderParams {
    /// Option trading pair, e.g BTC-200730-9000-C
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub symbol: String,
    /// Order ID, e.g 4611875134427365377
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub order_id: Option<i64>,
    /// User-defined order ID, e.g 10000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub client_order_id: Option<String>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl QuerySingleOrderParams {
    /// Create a builder for [`query_single_order`].
    ///
    /// Required parameters:
    ///
    /// * `symbol` — Option trading pair, e.g BTC-200730-9000-C
    ///
    #[must_use]
    pub fn builder(symbol: String) -> QuerySingleOrderParamsBuilder {
        QuerySingleOrderParamsBuilder::default().symbol(symbol)
    }
}
/// Request parameters for the [`user_commission`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`user_commission`](#method.user_commission).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct UserCommissionParams {
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl UserCommissionParams {
    /// Create a builder for [`user_commission`].
    ///
    #[must_use]
    pub fn builder() -> UserCommissionParamsBuilder {
        UserCommissionParamsBuilder::default()
    }
}
/// Request parameters for the [`user_exercise_record`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`user_exercise_record`](#method.user_exercise_record).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct UserExerciseRecordParams {
    /// Option trading pair, e.g BTC-200730-9000-C
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub symbol: Option<String>,
    /// Start Time, e.g 1593511200000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    /// End Time, e.g 1593512200000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    /// Number of result sets returned Default:100 Max:1000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i64>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl UserExerciseRecordParams {
    /// Create a builder for [`user_exercise_record`].
    ///
    #[must_use]
    pub fn builder() -> UserExerciseRecordParamsBuilder {
        UserExerciseRecordParamsBuilder::default()
    }
}

#[async_trait]
impl TradeApi for TradeApiClient {
    async fn account_trade_list(
        &self,
        params: AccountTradeListParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::AccountTradeListResponseInner>>> {
        let AccountTradeListParams {
            symbol,
            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) = symbol {
            query_params.insert("symbol".to_string(), json!(rw));
        }

        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::AccountTradeListResponseInner>>(
            &self.configuration,
            "/eapi/v1/userTrades",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn cancel_all_option_orders_by_underlying(
        &self,
        params: CancelAllOptionOrdersByUnderlyingParams,
    ) -> anyhow::Result<RestApiResponse<models::CancelAllOptionOrdersByUnderlyingResponse>> {
        let CancelAllOptionOrdersByUnderlyingParams {
            underlying,
            recv_window,
        } = params;

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

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

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

        send_request::<models::CancelAllOptionOrdersByUnderlyingResponse>(
            &self.configuration,
            "/eapi/v1/allOpenOrdersByUnderlying",
            reqwest::Method::DELETE,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn cancel_all_option_orders_on_specific_symbol(
        &self,
        params: CancelAllOptionOrdersOnSpecificSymbolParams,
    ) -> anyhow::Result<RestApiResponse<models::CancelAllOptionOrdersOnSpecificSymbolResponse>>
    {
        let CancelAllOptionOrdersOnSpecificSymbolParams {
            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::CancelAllOptionOrdersOnSpecificSymbolResponse>(
            &self.configuration,
            "/eapi/v1/allOpenOrders",
            reqwest::Method::DELETE,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn cancel_multiple_option_orders(
        &self,
        params: CancelMultipleOptionOrdersParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::CancelMultipleOptionOrdersResponseInner>>> {
        let CancelMultipleOptionOrdersParams {
            symbol,
            order_ids,
            client_order_ids,
            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_ids {
            query_params.insert("orderIds".to_string(), json!(rw));
        }

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

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

        send_request::<Vec<models::CancelMultipleOptionOrdersResponseInner>>(
            &self.configuration,
            "/eapi/v1/batchOrders",
            reqwest::Method::DELETE,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn cancel_option_order(
        &self,
        params: CancelOptionOrderParams,
    ) -> anyhow::Result<RestApiResponse<models::CancelOptionOrderResponse>> {
        let CancelOptionOrderParams {
            symbol,
            order_id,
            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) = client_order_id {
            query_params.insert("clientOrderId".to_string(), json!(rw));
        }

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

        send_request::<models::CancelOptionOrderResponse>(
            &self.configuration,
            "/eapi/v1/order",
            reqwest::Method::DELETE,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn new_order(
        &self,
        params: NewOrderParams,
    ) -> anyhow::Result<RestApiResponse<models::NewOrderResponse>> {
        let NewOrderParams {
            symbol,
            side,
            r#type,
            quantity,
            price,
            time_in_force,
            reduce_only,
            post_only,
            new_order_resp_type,
            client_order_id,
            is_mmp,
            self_trade_prevention_mode,
            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("side".to_string(), json!(side));

        query_params.insert("type".to_string(), json!(r#type));

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

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

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

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

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

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

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

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

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

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

        send_request::<models::NewOrderResponse>(
            &self.configuration,
            "/eapi/v1/order",
            reqwest::Method::POST,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn option_position_information(
        &self,
        params: OptionPositionInformationParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::OptionPositionInformationResponseInner>>> {
        let OptionPositionInformationParams {
            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::OptionPositionInformationResponseInner>>(
            &self.configuration,
            "/eapi/v1/position",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn place_multiple_orders(
        &self,
        params: PlaceMultipleOrdersParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::PlaceMultipleOrdersResponseInner>>> {
        let PlaceMultipleOrdersParams {
            orders,
            recv_window,
        } = params;

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

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

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

        send_request::<Vec<models::PlaceMultipleOrdersResponseInner>>(
            &self.configuration,
            "/eapi/v1/batchOrders",
            reqwest::Method::POST,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn query_current_open_option_orders(
        &self,
        params: QueryCurrentOpenOptionOrdersParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::QueryCurrentOpenOptionOrdersResponseInner>>>
    {
        let QueryCurrentOpenOptionOrdersParams {
            symbol,
            order_id,
            start_time,
            end_time,
            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) = 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) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

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

    async fn query_option_order_history(
        &self,
        params: QueryOptionOrderHistoryParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::QueryOptionOrderHistoryResponseInner>>> {
        let QueryOptionOrderHistoryParams {
            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::QueryOptionOrderHistoryResponseInner>>(
            &self.configuration,
            "/eapi/v1/historyOrders",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn query_single_order(
        &self,
        params: QuerySingleOrderParams,
    ) -> anyhow::Result<RestApiResponse<models::QuerySingleOrderResponse>> {
        let QuerySingleOrderParams {
            symbol,
            order_id,
            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) = client_order_id {
            query_params.insert("clientOrderId".to_string(), json!(rw));
        }

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

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

    async fn user_commission(
        &self,
        params: UserCommissionParams,
    ) -> anyhow::Result<RestApiResponse<models::UserCommissionResponse>> {
        let UserCommissionParams { 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::<models::UserCommissionResponse>(
            &self.configuration,
            "/eapi/v1/commission",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn user_exercise_record(
        &self,
        params: UserExerciseRecordParams,
    ) -> anyhow::Result<RestApiResponse<Vec<models::UserExerciseRecordResponseInner>>> {
        let UserExerciseRecordParams {
            symbol,
            start_time,
            end_time,
            limit,
            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) = 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::UserExerciseRecordResponseInner>>(
            &self.configuration,
            "/eapi/v1/exerciseRecord",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }
}

#[cfg(all(test, feature = "derivatives_trading_options"))]
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 MockTradeApiClient {
        force_error: bool,
    }

    #[async_trait]
    impl TradeApi for MockTradeApiClient {
        async fn account_trade_list(
            &self,
            _params: AccountTradeListParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::AccountTradeListResponseInner>>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"id":4611875134427365000,"tradeId":239,"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","fee":"0","realizedProfit":"0.00000000","side":"BUY","type":"LIMIT","liquidity":"TAKER","time":1592465880683,"priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT"}]"#).unwrap();
            let dummy_response: Vec<models::AccountTradeListResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::AccountTradeListResponseInner>");

            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 cancel_all_option_orders_by_underlying(
            &self,
            _params: CancelAllOptionOrdersByUnderlyingParams,
        ) -> anyhow::Result<RestApiResponse<models::CancelAllOptionOrdersByUnderlyingResponse>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"success"}"#).unwrap();
            let dummy_response: models::CancelAllOptionOrdersByUnderlyingResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::CancelAllOptionOrdersByUnderlyingResponse");

            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 cancel_all_option_orders_on_specific_symbol(
            &self,
            _params: CancelAllOptionOrdersOnSpecificSymbolParams,
        ) -> anyhow::Result<RestApiResponse<models::CancelAllOptionOrdersOnSpecificSymbolResponse>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"code":"0","msg":"success"}"#).unwrap();
            let dummy_response: models::CancelAllOptionOrdersOnSpecificSymbolResponse =
                serde_json::from_value(resp_json.clone()).expect(
                    "should parse into models::CancelAllOptionOrdersOnSpecificSymbolResponse",
                );

            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 cancel_multiple_option_orders(
            &self,
            _params: CancelMultipleOptionOrdersParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::CancelMultipleOptionOrdersResponseInner>>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"NEW","avgPrice":"0","source":"API","clientOrderId":"","priceScale":3,"quantityScale":4,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}]"#).unwrap();
            let dummy_response: Vec<models::CancelMultipleOptionOrdersResponseInner> =
                serde_json::from_value(resp_json.clone()).expect(
                    "should parse into Vec<models::CancelMultipleOptionOrdersResponseInner>",
                );

            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 cancel_option_order(
            &self,
            _params: CancelOptionOrderParams,
        ) -> anyhow::Result<RestApiResponse<models::CancelOptionOrderResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createDate":1592465880683,"updateTime":1566818724722,"status":"ACCEPTED","avgPrice":"0","source":"API","clientOrderId":"","priceScale":4,"quantityScale":4,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}"#).unwrap();
            let dummy_response: models::CancelOptionOrderResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::CancelOptionOrderResponse");

            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 new_order(
            &self,
            _params: NewOrderParams,
        ) -> anyhow::Result<RestApiResponse<models::NewOrderResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"NEW","avgPrice":"0","source":"API","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}"#).unwrap();
            let dummy_response: models::NewOrderResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::NewOrderResponse");

            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 option_position_information(
            &self,
            _params: OptionPositionInformationParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::OptionPositionInformationResponseInner>>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"entryPrice":"1000","symbol":"BTC-200730-9000-C","side":"SHORT","quantity":"-0.1","markValue":"105.00138","unrealizedPNL":"-5.00138","markPrice":"1050.0138","strikePrice":"9000","expiryDate":1593511200000,"priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","time":1762872654561,"bidQuantity":"0.0000","askQuantity":"0.0000"}]"#).unwrap();
            let dummy_response: Vec<models::OptionPositionInformationResponseInner> =
                serde_json::from_value(resp_json.clone()).expect(
                    "should parse into Vec<models::OptionPositionInformationResponseInner>",
                );

            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 place_multiple_orders(
            &self,
            _params: PlaceMultipleOrdersParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::PlaceMultipleOrdersResponseInner>>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"NEW","avgPrice":"0","source":"API","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}]"#).unwrap();
            let dummy_response: Vec<models::PlaceMultipleOrdersResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::PlaceMultipleOrdersResponseInner>");

            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 query_current_open_option_orders(
            &self,
            _params: QueryCurrentOpenOptionOrdersParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::QueryCurrentOpenOptionOrdersResponseInner>>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1592465880683,"status":"NEW","avgPrice":"0","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}]"#).unwrap();
            let dummy_response: Vec<models::QueryCurrentOpenOptionOrdersResponseInner> =
                serde_json::from_value(resp_json.clone()).expect(
                    "should parse into Vec<models::QueryCurrentOpenOptionOrdersResponseInner>",
                );

            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 query_option_order_history(
            &self,
            _params: QueryOptionOrderHistoryParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::QueryOptionOrderHistoryResponseInner>>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611922413427360000,"symbol":"BTC-220715-2000-C","price":"18000.00000000","quantity":"-0.50000000","executedQty":"-0.50000000","side":"SELL","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1657867694244,"updateTime":1657867888216,"status":"FILLED","avgPrice":"18000.00000000","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false}]"#).unwrap();
            let dummy_response: Vec<models::QueryOptionOrderHistoryResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::QueryOptionOrderHistoryResponseInner>");

            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 query_single_order(
            &self,
            _params: QuerySingleOrderParams,
        ) -> anyhow::Result<RestApiResponse<models::QuerySingleOrderResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"NEW","avgPrice":"0","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}"#).unwrap();
            let dummy_response: models::QuerySingleOrderResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::QuerySingleOrderResponse");

            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 user_commission(
            &self,
            _params: UserCommissionParams,
        ) -> anyhow::Result<RestApiResponse<models::UserCommissionResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"commissions":[{"underlying":"BTCUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"ETHUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"BNBUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"SOLUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"XRPUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"DOGEUSDT","makerFee":"0.000240","takerFee":"0.000240"}]}"#).unwrap();
            let dummy_response: models::UserCommissionResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::UserCommissionResponse");

            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 user_exercise_record(
            &self,
            _params: UserExerciseRecordParams,
        ) -> anyhow::Result<RestApiResponse<Vec<models::UserExerciseRecordResponseInner>>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"[{"id":"1125899906842624042","currency":"USDT","symbol":"BTC-220721-25000-C","exercisePrice":"25000.00000000","quantity":"1.00000000","amount":"0.00000000","fee":"0.00000000","createDate":1658361600000,"priceScale":2,"quantityScale":2,"optionSide":"CALL","positionSide":"LONG","quoteAsset":"USDT"}]"#).unwrap();
            let dummy_response: Vec<models::UserExerciseRecordResponseInner> =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into Vec<models::UserExerciseRecordResponseInner>");

            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_trade_list_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

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

            let resp_json: Value = serde_json::from_str(r#"[{"id":4611875134427365000,"tradeId":239,"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","fee":"0","realizedProfit":"0.00000000","side":"BUY","type":"LIMIT","liquidity":"TAKER","time":1592465880683,"priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT"}]"#).unwrap();
            let expected_response : Vec<models::AccountTradeListResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AccountTradeListResponseInner>");

            let resp = client.account_trade_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 account_trade_list_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params = AccountTradeListParams::builder().symbol("symbol_example".to_string()).from_id(1).start_time(1623319461670).end_time(1641782889000).limit(100).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"id":4611875134427365000,"tradeId":239,"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","fee":"0","realizedProfit":"0.00000000","side":"BUY","type":"LIMIT","liquidity":"TAKER","time":1592465880683,"priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT"}]"#).unwrap();
            let expected_response : Vec<models::AccountTradeListResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AccountTradeListResponseInner>");

            let resp = client.account_trade_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 account_trade_list_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

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

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

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

            let params =
                CancelAllOptionOrdersByUnderlyingParams::builder("underlying_example".to_string())
                    .build()
                    .unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"success"}"#).unwrap();
            let expected_response: models::CancelAllOptionOrdersByUnderlyingResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::CancelAllOptionOrdersByUnderlyingResponse");

            let resp = client
                .cancel_all_option_orders_by_underlying(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 cancel_all_option_orders_by_underlying_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params =
                CancelAllOptionOrdersByUnderlyingParams::builder("underlying_example".to_string())
                    .recv_window(5000)
                    .build()
                    .unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"success"}"#).unwrap();
            let expected_response: models::CancelAllOptionOrdersByUnderlyingResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::CancelAllOptionOrdersByUnderlyingResponse");

            let resp = client
                .cancel_all_option_orders_by_underlying(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 cancel_all_option_orders_by_underlying_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

            let params =
                CancelAllOptionOrdersByUnderlyingParams::builder("underlying_example".to_string())
                    .build()
                    .unwrap();

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

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

            let params =
                CancelAllOptionOrdersOnSpecificSymbolParams::builder("symbol_example".to_string())
                    .build()
                    .unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"0","msg":"success"}"#).unwrap();
            let expected_response: models::CancelAllOptionOrdersOnSpecificSymbolResponse =
                serde_json::from_value(resp_json.clone()).expect(
                    "should parse into models::CancelAllOptionOrdersOnSpecificSymbolResponse",
                );

            let resp = client
                .cancel_all_option_orders_on_specific_symbol(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 cancel_all_option_orders_on_specific_symbol_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params =
                CancelAllOptionOrdersOnSpecificSymbolParams::builder("symbol_example".to_string())
                    .recv_window(5000)
                    .build()
                    .unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"0","msg":"success"}"#).unwrap();
            let expected_response: models::CancelAllOptionOrdersOnSpecificSymbolResponse =
                serde_json::from_value(resp_json.clone()).expect(
                    "should parse into models::CancelAllOptionOrdersOnSpecificSymbolResponse",
                );

            let resp = client
                .cancel_all_option_orders_on_specific_symbol(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 cancel_all_option_orders_on_specific_symbol_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

            let params =
                CancelAllOptionOrdersOnSpecificSymbolParams::builder("symbol_example".to_string())
                    .build()
                    .unwrap();

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

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

            let params = CancelMultipleOptionOrdersParams::builder("symbol_example".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"NEW","avgPrice":"0","source":"API","clientOrderId":"","priceScale":3,"quantityScale":4,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}]"#).unwrap();
            let expected_response : Vec<models::CancelMultipleOptionOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::CancelMultipleOptionOrdersResponseInner>");

            let resp = client.cancel_multiple_option_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 cancel_multiple_option_orders_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params = CancelMultipleOptionOrdersParams::builder("symbol_example".to_string(),).order_ids([4611875134427365000,].to_vec()).client_order_ids(["my_id_1".to_string(),].to_vec()).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"NEW","avgPrice":"0","source":"API","clientOrderId":"","priceScale":3,"quantityScale":4,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}]"#).unwrap();
            let expected_response : Vec<models::CancelMultipleOptionOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::CancelMultipleOptionOrdersResponseInner>");

            let resp = client.cancel_multiple_option_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 cancel_multiple_option_orders_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

            let params = CancelMultipleOptionOrdersParams::builder("symbol_example".to_string())
                .build()
                .unwrap();

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

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

            let params = CancelOptionOrderParams::builder("symbol_example".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createDate":1592465880683,"updateTime":1566818724722,"status":"ACCEPTED","avgPrice":"0","source":"API","clientOrderId":"","priceScale":4,"quantityScale":4,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}"#).unwrap();
            let expected_response : models::CancelOptionOrderResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::CancelOptionOrderResponse");

            let resp = client.cancel_option_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 cancel_option_order_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params = CancelOptionOrderParams::builder("symbol_example".to_string(),).order_id(1).client_order_id("1".to_string()).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createDate":1592465880683,"updateTime":1566818724722,"status":"ACCEPTED","avgPrice":"0","source":"API","clientOrderId":"","priceScale":4,"quantityScale":4,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}"#).unwrap();
            let expected_response : models::CancelOptionOrderResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::CancelOptionOrderResponse");

            let resp = client.cancel_option_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 cancel_option_order_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

            let params = CancelOptionOrderParams::builder("symbol_example".to_string())
                .build()
                .unwrap();

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

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

            let params = NewOrderParams::builder("symbol_example".to_string(),NewOrderSideEnum::Buy,NewOrderTypeEnum::Limit,dec!(1.0),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"NEW","avgPrice":"0","source":"API","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}"#).unwrap();
            let expected_response : models::NewOrderResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::NewOrderResponse");

            let resp = client.new_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 new_order_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params = NewOrderParams::builder("symbol_example".to_string(),NewOrderSideEnum::Buy,NewOrderTypeEnum::Limit,dec!(1.0),).price(dec!(1.0)).time_in_force(NewOrderTimeInForceEnum::Gtc).reduce_only(false).post_only(false).new_order_resp_type(NewOrderNewOrderRespTypeEnum::Ack).client_order_id("1".to_string()).is_mmp(true).self_trade_prevention_mode(NewOrderSelfTradePreventionModeEnum::ExpireTaker).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"NEW","avgPrice":"0","source":"API","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}"#).unwrap();
            let expected_response : models::NewOrderResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::NewOrderResponse");

            let resp = client.new_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 new_order_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

            let params = NewOrderParams::builder(
                "symbol_example".to_string(),
                NewOrderSideEnum::Buy,
                NewOrderTypeEnum::Limit,
                dec!(1.0),
            )
            .build()
            .unwrap();

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

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

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

            let resp_json: Value = serde_json::from_str(r#"[{"entryPrice":"1000","symbol":"BTC-200730-9000-C","side":"SHORT","quantity":"-0.1","markValue":"105.00138","unrealizedPNL":"-5.00138","markPrice":"1050.0138","strikePrice":"9000","expiryDate":1593511200000,"priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","time":1762872654561,"bidQuantity":"0.0000","askQuantity":"0.0000"}]"#).unwrap();
            let expected_response : Vec<models::OptionPositionInformationResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::OptionPositionInformationResponseInner>");

            let resp = client.option_position_information(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 option_position_information_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params = OptionPositionInformationParams::builder().symbol("symbol_example".to_string()).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"entryPrice":"1000","symbol":"BTC-200730-9000-C","side":"SHORT","quantity":"-0.1","markValue":"105.00138","unrealizedPNL":"-5.00138","markPrice":"1050.0138","strikePrice":"9000","expiryDate":1593511200000,"priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","time":1762872654561,"bidQuantity":"0.0000","askQuantity":"0.0000"}]"#).unwrap();
            let expected_response : Vec<models::OptionPositionInformationResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::OptionPositionInformationResponseInner>");

            let resp = client.option_position_information(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 option_position_information_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

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

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

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

            let params = PlaceMultipleOrdersParams::builder(vec![],).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"NEW","avgPrice":"0","source":"API","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}]"#).unwrap();
            let expected_response : Vec<models::PlaceMultipleOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::PlaceMultipleOrdersResponseInner>");

            let resp = client.place_multiple_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 place_multiple_orders_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params = PlaceMultipleOrdersParams::builder(vec![],).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"NEW","avgPrice":"0","source":"API","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}]"#).unwrap();
            let expected_response : Vec<models::PlaceMultipleOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::PlaceMultipleOrdersResponseInner>");

            let resp = client.place_multiple_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 place_multiple_orders_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

            let params = PlaceMultipleOrdersParams::builder(vec![]).build().unwrap();

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

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

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

            let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1592465880683,"status":"NEW","avgPrice":"0","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}]"#).unwrap();
            let expected_response : Vec<models::QueryCurrentOpenOptionOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryCurrentOpenOptionOrdersResponseInner>");

            let resp = client.query_current_open_option_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 query_current_open_option_orders_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params = QueryCurrentOpenOptionOrdersParams::builder().symbol("symbol_example".to_string()).order_id(1).start_time(1623319461670).end_time(1641782889000).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1592465880683,"status":"NEW","avgPrice":"0","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}]"#).unwrap();
            let expected_response : Vec<models::QueryCurrentOpenOptionOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryCurrentOpenOptionOrdersResponseInner>");

            let resp = client.query_current_open_option_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 query_current_open_option_orders_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

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

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

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

            let params = QueryOptionOrderHistoryParams::builder("symbol_example".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611922413427360000,"symbol":"BTC-220715-2000-C","price":"18000.00000000","quantity":"-0.50000000","executedQty":"-0.50000000","side":"SELL","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1657867694244,"updateTime":1657867888216,"status":"FILLED","avgPrice":"18000.00000000","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false}]"#).unwrap();
            let expected_response : Vec<models::QueryOptionOrderHistoryResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryOptionOrderHistoryResponseInner>");

            let resp = client.query_option_order_history(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 query_option_order_history_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params = QueryOptionOrderHistoryParams::builder("symbol_example".to_string(),).order_id(1).start_time(1623319461670).end_time(1641782889000).limit(100).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611922413427360000,"symbol":"BTC-220715-2000-C","price":"18000.00000000","quantity":"-0.50000000","executedQty":"-0.50000000","side":"SELL","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1657867694244,"updateTime":1657867888216,"status":"FILLED","avgPrice":"18000.00000000","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false}]"#).unwrap();
            let expected_response : Vec<models::QueryOptionOrderHistoryResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::QueryOptionOrderHistoryResponseInner>");

            let resp = client.query_option_order_history(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 query_option_order_history_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

            let params = QueryOptionOrderHistoryParams::builder("symbol_example".to_string())
                .build()
                .unwrap();

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

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

            let params = QuerySingleOrderParams::builder("symbol_example".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"NEW","avgPrice":"0","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}"#).unwrap();
            let expected_response : models::QuerySingleOrderResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QuerySingleOrderResponse");

            let resp = client.query_single_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 query_single_order_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params = QuerySingleOrderParams::builder("symbol_example".to_string(),).order_id(1).client_order_id("1".to_string()).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"NEW","avgPrice":"0","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false,"selfTradePreventionMode":"EXPIRE_MAKER"}"#).unwrap();
            let expected_response : models::QuerySingleOrderResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QuerySingleOrderResponse");

            let resp = client.query_single_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 query_single_order_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

            let params = QuerySingleOrderParams::builder("symbol_example".to_string())
                .build()
                .unwrap();

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

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

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

            let resp_json: Value = serde_json::from_str(r#"{"commissions":[{"underlying":"BTCUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"ETHUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"BNBUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"SOLUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"XRPUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"DOGEUSDT","makerFee":"0.000240","takerFee":"0.000240"}]}"#).unwrap();
            let expected_response : models::UserCommissionResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::UserCommissionResponse");

            let resp = client.user_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 user_commission_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params = UserCommissionParams::builder().recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"commissions":[{"underlying":"BTCUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"ETHUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"BNBUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"SOLUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"XRPUSDT","makerFee":"0.000240","takerFee":"0.000240"},{"underlying":"DOGEUSDT","makerFee":"0.000240","takerFee":"0.000240"}]}"#).unwrap();
            let expected_response : models::UserCommissionResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::UserCommissionResponse");

            let resp = client.user_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 user_commission_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

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

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

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

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

            let resp_json: Value = serde_json::from_str(r#"[{"id":"1125899906842624042","currency":"USDT","symbol":"BTC-220721-25000-C","exercisePrice":"25000.00000000","quantity":"1.00000000","amount":"0.00000000","fee":"0.00000000","createDate":1658361600000,"priceScale":2,"quantityScale":2,"optionSide":"CALL","positionSide":"LONG","quoteAsset":"USDT"}]"#).unwrap();
            let expected_response : Vec<models::UserExerciseRecordResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::UserExerciseRecordResponseInner>");

            let resp = client.user_exercise_record(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 user_exercise_record_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: false };

            let params = UserExerciseRecordParams::builder().symbol("symbol_example".to_string()).start_time(1623319461670).end_time(1641782889000).limit(100).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"[{"id":"1125899906842624042","currency":"USDT","symbol":"BTC-220721-25000-C","exercisePrice":"25000.00000000","quantity":"1.00000000","amount":"0.00000000","fee":"0.00000000","createDate":1658361600000,"priceScale":2,"quantityScale":2,"optionSide":"CALL","positionSide":"LONG","quoteAsset":"USDT"}]"#).unwrap();
            let expected_response : Vec<models::UserExerciseRecordResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::UserExerciseRecordResponseInner>");

            let resp = client.user_exercise_record(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 user_exercise_record_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockTradeApiClient { force_error: true };

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

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