/*
* 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_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,
}
impl NewOrderTimeInForceEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Gtc => "GTC",
Self::Ioc => "IOC",
Self::Fok => "FOK",
}
}
}
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),
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()),
}
}
}
/// 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>,
/// The `UniqueId` ID from which to return. The latest deal record is returned by default
///
/// 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 or SELL
///
/// 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>,
///
/// 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 or SELL
/// * `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 5 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 5 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>,
/// 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 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_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();
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,
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();
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,
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();
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,
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();
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,
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();
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,
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,
recv_window,
} = params;
let mut query_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) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<models::NewOrderResponse>(
&self.configuration,
"/eapi/v1/order",
reqwest::Method::POST,
query_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();
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,
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();
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,
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,
limit,
recv_window,
} = params;
let mut query_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) = 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::QueryCurrentOpenOptionOrdersResponseInner>>(
&self.configuration,
"/eapi/v1/openOrders",
reqwest::Method::GET,
query_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();
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,
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();
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,
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();
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,
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("ResponseError".to_string()).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","volatility":"0.9","liquidity":"TAKER","quoteAsset":"USDT","time":1592465880683,"priceScale":2,"quantityScale":2,"optionSide":"CALL"}]"#).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("ResponseError".to_string()).into(),
);
}
let resp_json: Value =
serde_json::from_str(r#"{"code":0,"msg":"success","data":0}"#).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("ResponseError".to_string()).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("ResponseError".to_string()).into(),
);
}
let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","fee":0,"side":"BUY","type":"LIMIT","timeInForce":"GTC","createTime":1592465880683,"status":"ACCEPTED","avgPrice":"0","reduceOnly":false,"clientOrderId":"","updateTime":1566818724722}]"#).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("ResponseError".to_string()).into(),
);
}
let resp_json: Value = serde_json::from_str(r#"{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","fee":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"postOnly":false,"createDate":1592465880683,"updateTime":1566818724722,"status":"ACCEPTED","avgPrice":"0","source":"API","clientOrderId":"","priceScale":4,"quantityScale":4,"optionSide":"CALL","quoteAsset":"USDT","mmp":false}"#).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("ResponseError".to_string()).into(),
);
}
let resp_json: Value = serde_json::from_str(r#"{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","side":"BUY","type":"LIMIT","createDate":1592465880683,"reduceOnly":false,"postOnly":false,"mmp":false,"executedQty":"0","fee":"0","timeInForce":"GTC","createTime":1592465880683,"updateTime":1566818724722,"status":"ACCEPTED","avgPrice":"0","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT"}"#).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("ResponseError".to_string()).into(),
);
}
let resp_json: Value = serde_json::from_str(r#"[{"entryPrice":"1000","symbol":"BTC-200730-9000-C","side":"SHORT","quantity":"-0.1","reducibleQty":"0","markValue":"105.00138","ror":"-0.05","unrealizedPNL":"-5.00138","markPrice":"1050.0138","strikePrice":"9000","positionCost":"1000.0000","expiryDate":1593511200000,"priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT"}]"#).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("ResponseError".to_string()).into(),
);
}
let resp_json: Value = serde_json::from_str(r#"[{"orderId":4612288550799409000,"symbol":"ETH-220826-1800-C","price":"100","quantity":"0.01","side":"BUY","type":"LIMIT","reduceOnly":false,"postOnly":false,"clientOrderId":"1001","mmp":false}]"#).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("ResponseError".to_string()).into(),
);
}
let resp_json: Value = serde_json::from_str(r#"[{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","fee":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"postOnly":false,"createTime":1592465880683,"updateTime":1592465880683,"status":"ACCEPTED","avgPrice":"0","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false}]"#).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("ResponseError".to_string()).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","fee":"3.00000000","side":"SELL","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"postOnly":false,"createTime":1657867694244,"updateTime":1657867888216,"status":"FILLED","reason":"0","avgPrice":"18000.00000000","source":"API","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("ResponseError".to_string()).into(),
);
}
let resp_json: Value = serde_json::from_str(r#"{"orderId":4611875134427365000,"symbol":"BTC-200730-9000-C","price":"100","quantity":"1","executedQty":"0","fee":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"postOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"ACCEPTED","avgPrice":"0","source":"API","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false}"#).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_exercise_record(
&self,
_params: UserExerciseRecordParams,
) -> anyhow::Result<RestApiResponse<Vec<models::UserExerciseRecordResponseInner>>> {
if self.force_error {
return Err(
ConnectorError::ConnectorClientError("ResponseError".to_string()).into(),
);
}
let resp_json: Value = serde_json::from_str(r#"[{"id":"1125899906842624042","currency":"USDT","symbol":"BTC-220721-25000-C","exercisePrice":"25000.00000000","markPrice":"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","volatility":"0.9","liquidity":"TAKER","quoteAsset":"USDT","time":1592465880683,"priceScale":2,"quantityScale":2,"optionSide":"CALL"}]"#).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","volatility":"0.9","liquidity":"TAKER","quoteAsset":"USDT","time":1592465880683,"priceScale":2,"quantityScale":2,"optionSide":"CALL"}]"#).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","data":0}"#).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","data":0}"#).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","fee":0,"side":"BUY","type":"LIMIT","timeInForce":"GTC","createTime":1592465880683,"status":"ACCEPTED","avgPrice":"0","reduceOnly":false,"clientOrderId":"","updateTime":1566818724722}]"#).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","fee":0,"side":"BUY","type":"LIMIT","timeInForce":"GTC","createTime":1592465880683,"status":"ACCEPTED","avgPrice":"0","reduceOnly":false,"clientOrderId":"","updateTime":1566818724722}]"#).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","fee":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"postOnly":false,"createDate":1592465880683,"updateTime":1566818724722,"status":"ACCEPTED","avgPrice":"0","source":"API","clientOrderId":"","priceScale":4,"quantityScale":4,"optionSide":"CALL","quoteAsset":"USDT","mmp":false}"#).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","fee":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"postOnly":false,"createDate":1592465880683,"updateTime":1566818724722,"status":"ACCEPTED","avgPrice":"0","source":"API","clientOrderId":"","priceScale":4,"quantityScale":4,"optionSide":"CALL","quoteAsset":"USDT","mmp":false}"#).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","side":"BUY","type":"LIMIT","createDate":1592465880683,"reduceOnly":false,"postOnly":false,"mmp":false,"executedQty":"0","fee":"0","timeInForce":"GTC","createTime":1592465880683,"updateTime":1566818724722,"status":"ACCEPTED","avgPrice":"0","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT"}"#).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).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","side":"BUY","type":"LIMIT","createDate":1592465880683,"reduceOnly":false,"postOnly":false,"mmp":false,"executedQty":"0","fee":"0","timeInForce":"GTC","createTime":1592465880683,"updateTime":1566818724722,"status":"ACCEPTED","avgPrice":"0","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT"}"#).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","reducibleQty":"0","markValue":"105.00138","ror":"-0.05","unrealizedPNL":"-5.00138","markPrice":"1050.0138","strikePrice":"9000","positionCost":"1000.0000","expiryDate":1593511200000,"priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT"}]"#).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","reducibleQty":"0","markValue":"105.00138","ror":"-0.05","unrealizedPNL":"-5.00138","markPrice":"1050.0138","strikePrice":"9000","positionCost":"1000.0000","expiryDate":1593511200000,"priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT"}]"#).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":4612288550799409000,"symbol":"ETH-220826-1800-C","price":"100","quantity":"0.01","side":"BUY","type":"LIMIT","reduceOnly":false,"postOnly":false,"clientOrderId":"1001","mmp":false}]"#).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":4612288550799409000,"symbol":"ETH-220826-1800-C","price":"100","quantity":"0.01","side":"BUY","type":"LIMIT","reduceOnly":false,"postOnly":false,"clientOrderId":"1001","mmp":false}]"#).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","fee":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"postOnly":false,"createTime":1592465880683,"updateTime":1592465880683,"status":"ACCEPTED","avgPrice":"0","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false}]"#).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).limit(100).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","fee":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"postOnly":false,"createTime":1592465880683,"updateTime":1592465880683,"status":"ACCEPTED","avgPrice":"0","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false}]"#).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","fee":"3.00000000","side":"SELL","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"postOnly":false,"createTime":1657867694244,"updateTime":1657867888216,"status":"FILLED","reason":"0","avgPrice":"18000.00000000","source":"API","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","fee":"3.00000000","side":"SELL","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"postOnly":false,"createTime":1657867694244,"updateTime":1657867888216,"status":"FILLED","reason":"0","avgPrice":"18000.00000000","source":"API","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","fee":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"postOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"ACCEPTED","avgPrice":"0","source":"API","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false}"#).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","fee":"0","side":"BUY","type":"LIMIT","timeInForce":"GTC","reduceOnly":false,"postOnly":false,"createTime":1592465880683,"updateTime":1566818724722,"status":"ACCEPTED","avgPrice":"0","source":"API","clientOrderId":"","priceScale":2,"quantityScale":2,"optionSide":"CALL","quoteAsset":"USDT","mmp":false}"#).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_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","markPrice":"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","markPrice":"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");
}
}
});
}
}