/*
* Binance Spot REST API
*
* OpenAPI Specifications for the Binance Spot REST API
*
* API documents:
* - [Github rest-api documentation file](https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md)
* - [General API information for rest-api on website](https://developers.binance.com/docs/binance-spot-api-docs/rest-api/general-api-information)
*
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
#![allow(unused_imports)]
use async_trait::async_trait;
use derive_builder::Builder;
use reqwest;
use rust_decimal::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use std::collections::BTreeMap;
use crate::common::{
config::ConfigurationRestApi,
models::{ParamBuildError, RestApiResponse},
utils::send_request,
};
use crate::spot::rest_api::models;
const HAS_TIME_UNIT: bool = true;
#[async_trait]
pub trait AccountApi: Send + Sync {
async fn account_commission(
&self,
params: AccountCommissionParams,
) -> anyhow::Result<RestApiResponse<models::AccountCommissionResponse>>;
async fn all_order_list(
&self,
params: AllOrderListParams,
) -> anyhow::Result<RestApiResponse<Vec<models::AllOrderListResponseInner>>>;
async fn all_orders(
&self,
params: AllOrdersParams,
) -> anyhow::Result<RestApiResponse<Vec<models::AllOrdersResponseInner>>>;
async fn get_account(
&self,
params: GetAccountParams,
) -> anyhow::Result<RestApiResponse<models::GetAccountResponse>>;
async fn get_open_orders(
&self,
params: GetOpenOrdersParams,
) -> anyhow::Result<RestApiResponse<Vec<models::AllOrdersResponseInner>>>;
async fn get_order(
&self,
params: GetOrderParams,
) -> anyhow::Result<RestApiResponse<models::GetOrderResponse>>;
async fn get_order_list(
&self,
params: GetOrderListParams,
) -> anyhow::Result<RestApiResponse<models::GetOrderListResponse>>;
async fn my_allocations(
&self,
params: MyAllocationsParams,
) -> anyhow::Result<RestApiResponse<Vec<models::MyAllocationsResponseInner>>>;
async fn my_filters(
&self,
params: MyFiltersParams,
) -> anyhow::Result<RestApiResponse<models::MyFiltersResponse>>;
async fn my_prevented_matches(
&self,
params: MyPreventedMatchesParams,
) -> anyhow::Result<RestApiResponse<Vec<models::MyPreventedMatchesResponseInner>>>;
async fn my_trades(
&self,
params: MyTradesParams,
) -> anyhow::Result<RestApiResponse<Vec<models::MyTradesResponseInner>>>;
async fn open_order_list(
&self,
params: OpenOrderListParams,
) -> anyhow::Result<RestApiResponse<Vec<models::OpenOrderListResponseInner>>>;
async fn order_amendments(
&self,
params: OrderAmendmentsParams,
) -> anyhow::Result<RestApiResponse<Vec<models::OrderAmendmentsResponseInner>>>;
async fn rate_limit_order(
&self,
params: RateLimitOrderParams,
) -> anyhow::Result<RestApiResponse<Vec<models::RateLimitOrderResponseInner>>>;
}
#[derive(Debug, Clone)]
pub struct AccountApiClient {
configuration: ConfigurationRestApi,
}
impl AccountApiClient {
pub fn new(configuration: ConfigurationRestApi) -> Self {
Self { configuration }
}
}
/// Request parameters for the [`account_commission`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`account_commission`](#method.account_commission).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct AccountCommissionParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
}
impl AccountCommissionParams {
/// Create a builder for [`account_commission`].
///
/// Required parameters:
///
/// * `symbol` — String
///
#[must_use]
pub fn builder(symbol: String) -> AccountCommissionParamsBuilder {
AccountCommissionParamsBuilder::default().symbol(symbol)
}
}
/// Request parameters for the [`all_order_list`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`all_order_list`](#method.all_order_list).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct AllOrderListParams {
/// ID to get aggregate trades from INCLUSIVE.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub from_id: Option<i64>,
/// Timestamp in ms to get aggregate trades from INCLUSIVE.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub start_time: Option<i64>,
/// Timestamp in ms to get aggregate trades until INCLUSIVE.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub end_time: Option<i64>,
/// Default: 500; Maximum: 1000.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub limit: Option<i32>,
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl AllOrderListParams {
/// Create a builder for [`all_order_list`].
///
#[must_use]
pub fn builder() -> AllOrderListParamsBuilder {
AllOrderListParamsBuilder::default()
}
}
/// Request parameters for the [`all_orders`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`all_orders`](#method.all_orders).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct AllOrdersParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub order_id: Option<i64>,
/// Timestamp in ms to get aggregate trades from INCLUSIVE.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub start_time: Option<i64>,
/// Timestamp in ms to get aggregate trades until INCLUSIVE.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub end_time: Option<i64>,
/// Default: 500; Maximum: 1000.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub limit: Option<i32>,
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl AllOrdersParams {
/// Create a builder for [`all_orders`].
///
/// Required parameters:
///
/// * `symbol` — String
///
#[must_use]
pub fn builder(symbol: String) -> AllOrdersParamsBuilder {
AllOrdersParamsBuilder::default().symbol(symbol)
}
}
/// Request parameters for the [`get_account`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_account`](#method.get_account).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetAccountParams {
/// When set to `true`, emits only the non-zero balances of an account. <br>Default value: `false`
///
/// This field is **optional.
#[builder(setter(into), default)]
pub omit_zero_balances: Option<bool>,
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl GetAccountParams {
/// Create a builder for [`get_account`].
///
#[must_use]
pub fn builder() -> GetAccountParamsBuilder {
GetAccountParamsBuilder::default()
}
}
/// Request parameters for the [`get_open_orders`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_open_orders`](#method.get_open_orders).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetOpenOrdersParams {
/// Symbol to query
///
/// This field is **optional.
#[builder(setter(into), default)]
pub symbol: Option<String>,
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl GetOpenOrdersParams {
/// Create a builder for [`get_open_orders`].
///
#[must_use]
pub fn builder() -> GetOpenOrdersParamsBuilder {
GetOpenOrdersParamsBuilder::default()
}
}
/// Request parameters for the [`get_order`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_order`](#method.get_order).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetOrderParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub order_id: Option<i64>,
///
/// The `orig_client_order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub orig_client_order_id: Option<String>,
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl GetOrderParams {
/// Create a builder for [`get_order`].
///
/// Required parameters:
///
/// * `symbol` — String
///
#[must_use]
pub fn builder(symbol: String) -> GetOrderParamsBuilder {
GetOrderParamsBuilder::default().symbol(symbol)
}
}
/// Request parameters for the [`get_order_list`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_order_list`](#method.get_order_list).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetOrderListParams {
/// Either `orderListId` or `listClientOrderId` must be provided
///
/// This field is **optional.
#[builder(setter(into), default)]
pub order_list_id: Option<i64>,
///
/// The `orig_client_order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub orig_client_order_id: Option<String>,
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl GetOrderListParams {
/// Create a builder for [`get_order_list`].
///
#[must_use]
pub fn builder() -> GetOrderListParamsBuilder {
GetOrderListParamsBuilder::default()
}
}
/// Request parameters for the [`my_allocations`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`my_allocations`](#method.my_allocations).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct MyAllocationsParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
/// Timestamp in ms to get aggregate trades from INCLUSIVE.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub start_time: Option<i64>,
/// Timestamp in ms to get aggregate trades until INCLUSIVE.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub end_time: Option<i64>,
///
/// The `from_allocation_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub from_allocation_id: Option<i32>,
/// Default: 500; Maximum: 1000.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub limit: Option<i32>,
///
/// The `order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub order_id: Option<i64>,
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl MyAllocationsParams {
/// Create a builder for [`my_allocations`].
///
/// Required parameters:
///
/// * `symbol` — String
///
#[must_use]
pub fn builder(symbol: String) -> MyAllocationsParamsBuilder {
MyAllocationsParamsBuilder::default().symbol(symbol)
}
}
/// Request parameters for the [`my_filters`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`my_filters`](#method.my_filters).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct MyFiltersParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl MyFiltersParams {
/// Create a builder for [`my_filters`].
///
/// Required parameters:
///
/// * `symbol` — String
///
#[must_use]
pub fn builder(symbol: String) -> MyFiltersParamsBuilder {
MyFiltersParamsBuilder::default().symbol(symbol)
}
}
/// Request parameters for the [`my_prevented_matches`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`my_prevented_matches`](#method.my_prevented_matches).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct MyPreventedMatchesParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `prevented_match_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub prevented_match_id: Option<i64>,
///
/// The `order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub order_id: Option<i64>,
///
/// The `from_prevented_match_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub from_prevented_match_id: Option<i64>,
/// Default: 500; Maximum: 1000.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub limit: Option<i32>,
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl MyPreventedMatchesParams {
/// Create a builder for [`my_prevented_matches`].
///
/// Required parameters:
///
/// * `symbol` — String
///
#[must_use]
pub fn builder(symbol: String) -> MyPreventedMatchesParamsBuilder {
MyPreventedMatchesParamsBuilder::default().symbol(symbol)
}
}
/// Request parameters for the [`my_trades`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`my_trades`](#method.my_trades).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct MyTradesParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub order_id: Option<i64>,
/// Timestamp in ms to get aggregate trades from INCLUSIVE.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub start_time: Option<i64>,
/// Timestamp in ms to get aggregate trades until INCLUSIVE.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub end_time: Option<i64>,
/// ID to get aggregate trades from INCLUSIVE.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub from_id: Option<i64>,
/// Default: 500; Maximum: 1000.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub limit: Option<i32>,
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl MyTradesParams {
/// Create a builder for [`my_trades`].
///
/// Required parameters:
///
/// * `symbol` — String
///
#[must_use]
pub fn builder(symbol: String) -> MyTradesParamsBuilder {
MyTradesParamsBuilder::default().symbol(symbol)
}
}
/// Request parameters for the [`open_order_list`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`open_order_list`](#method.open_order_list).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OpenOrderListParams {
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl OpenOrderListParams {
/// Create a builder for [`open_order_list`].
///
#[must_use]
pub fn builder() -> OpenOrderListParamsBuilder {
OpenOrderListParamsBuilder::default()
}
}
/// Request parameters for the [`order_amendments`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_amendments`](#method.order_amendments).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderAmendmentsParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `order_id` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub order_id: i64,
///
/// The `from_execution_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub from_execution_id: Option<i64>,
/// Default:500; Maximum: 1000
///
/// This field is **optional.
#[builder(setter(into), default)]
pub limit: Option<i64>,
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl OrderAmendmentsParams {
/// Create a builder for [`order_amendments`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `order_id` — i64
///
#[must_use]
pub fn builder(symbol: String, order_id: i64) -> OrderAmendmentsParamsBuilder {
OrderAmendmentsParamsBuilder::default()
.symbol(symbol)
.order_id(order_id)
}
}
/// Request parameters for the [`rate_limit_order`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`rate_limit_order`](#method.rate_limit_order).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct RateLimitOrderParams {
/// The value cannot be greater than `60000`. <br> Supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub recv_window: Option<rust_decimal::Decimal>,
}
impl RateLimitOrderParams {
/// Create a builder for [`rate_limit_order`].
///
#[must_use]
pub fn builder() -> RateLimitOrderParamsBuilder {
RateLimitOrderParamsBuilder::default()
}
}
#[async_trait]
impl AccountApi for AccountApiClient {
async fn account_commission(
&self,
params: AccountCommissionParams,
) -> anyhow::Result<RestApiResponse<models::AccountCommissionResponse>> {
let AccountCommissionParams { symbol } = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
query_params.insert("symbol".to_string(), json!(symbol));
send_request::<models::AccountCommissionResponse>(
&self.configuration,
"/api/v3/account/commission",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn all_order_list(
&self,
params: AllOrderListParams,
) -> anyhow::Result<RestApiResponse<Vec<models::AllOrderListResponseInner>>> {
let AllOrderListParams {
from_id,
start_time,
end_time,
limit,
recv_window,
} = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
if let Some(rw) = from_id {
query_params.insert("fromId".to_string(), json!(rw));
}
if let Some(rw) = start_time {
query_params.insert("startTime".to_string(), json!(rw));
}
if let Some(rw) = end_time {
query_params.insert("endTime".to_string(), json!(rw));
}
if let Some(rw) = limit {
query_params.insert("limit".to_string(), json!(rw));
}
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<Vec<models::AllOrderListResponseInner>>(
&self.configuration,
"/api/v3/allOrderList",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn all_orders(
&self,
params: AllOrdersParams,
) -> anyhow::Result<RestApiResponse<Vec<models::AllOrdersResponseInner>>> {
let AllOrdersParams {
symbol,
order_id,
start_time,
end_time,
limit,
recv_window,
} = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
query_params.insert("symbol".to_string(), json!(symbol));
if let Some(rw) = order_id {
query_params.insert("orderId".to_string(), json!(rw));
}
if let Some(rw) = start_time {
query_params.insert("startTime".to_string(), json!(rw));
}
if let Some(rw) = end_time {
query_params.insert("endTime".to_string(), json!(rw));
}
if let Some(rw) = limit {
query_params.insert("limit".to_string(), json!(rw));
}
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<Vec<models::AllOrdersResponseInner>>(
&self.configuration,
"/api/v3/allOrders",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn get_account(
&self,
params: GetAccountParams,
) -> anyhow::Result<RestApiResponse<models::GetAccountResponse>> {
let GetAccountParams {
omit_zero_balances,
recv_window,
} = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
if let Some(rw) = omit_zero_balances {
query_params.insert("omitZeroBalances".to_string(), json!(rw));
}
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<models::GetAccountResponse>(
&self.configuration,
"/api/v3/account",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn get_open_orders(
&self,
params: GetOpenOrdersParams,
) -> anyhow::Result<RestApiResponse<Vec<models::AllOrdersResponseInner>>> {
let GetOpenOrdersParams {
symbol,
recv_window,
} = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
if let Some(rw) = symbol {
query_params.insert("symbol".to_string(), json!(rw));
}
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<Vec<models::AllOrdersResponseInner>>(
&self.configuration,
"/api/v3/openOrders",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn get_order(
&self,
params: GetOrderParams,
) -> anyhow::Result<RestApiResponse<models::GetOrderResponse>> {
let GetOrderParams {
symbol,
order_id,
orig_client_order_id,
recv_window,
} = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
query_params.insert("symbol".to_string(), json!(symbol));
if let Some(rw) = order_id {
query_params.insert("orderId".to_string(), json!(rw));
}
if let Some(rw) = orig_client_order_id {
query_params.insert("origClientOrderId".to_string(), json!(rw));
}
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<models::GetOrderResponse>(
&self.configuration,
"/api/v3/order",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn get_order_list(
&self,
params: GetOrderListParams,
) -> anyhow::Result<RestApiResponse<models::GetOrderListResponse>> {
let GetOrderListParams {
order_list_id,
orig_client_order_id,
recv_window,
} = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
if let Some(rw) = order_list_id {
query_params.insert("orderListId".to_string(), json!(rw));
}
if let Some(rw) = orig_client_order_id {
query_params.insert("origClientOrderId".to_string(), json!(rw));
}
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<models::GetOrderListResponse>(
&self.configuration,
"/api/v3/orderList",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn my_allocations(
&self,
params: MyAllocationsParams,
) -> anyhow::Result<RestApiResponse<Vec<models::MyAllocationsResponseInner>>> {
let MyAllocationsParams {
symbol,
start_time,
end_time,
from_allocation_id,
limit,
order_id,
recv_window,
} = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
query_params.insert("symbol".to_string(), json!(symbol));
if let Some(rw) = start_time {
query_params.insert("startTime".to_string(), json!(rw));
}
if let Some(rw) = end_time {
query_params.insert("endTime".to_string(), json!(rw));
}
if let Some(rw) = from_allocation_id {
query_params.insert("fromAllocationId".to_string(), json!(rw));
}
if let Some(rw) = limit {
query_params.insert("limit".to_string(), json!(rw));
}
if let Some(rw) = order_id {
query_params.insert("orderId".to_string(), json!(rw));
}
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<Vec<models::MyAllocationsResponseInner>>(
&self.configuration,
"/api/v3/myAllocations",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn my_filters(
&self,
params: MyFiltersParams,
) -> anyhow::Result<RestApiResponse<models::MyFiltersResponse>> {
let MyFiltersParams {
symbol,
recv_window,
} = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
query_params.insert("symbol".to_string(), json!(symbol));
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<models::MyFiltersResponse>(
&self.configuration,
"/api/v3/myFilters",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn my_prevented_matches(
&self,
params: MyPreventedMatchesParams,
) -> anyhow::Result<RestApiResponse<Vec<models::MyPreventedMatchesResponseInner>>> {
let MyPreventedMatchesParams {
symbol,
prevented_match_id,
order_id,
from_prevented_match_id,
limit,
recv_window,
} = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
query_params.insert("symbol".to_string(), json!(symbol));
if let Some(rw) = prevented_match_id {
query_params.insert("preventedMatchId".to_string(), json!(rw));
}
if let Some(rw) = order_id {
query_params.insert("orderId".to_string(), json!(rw));
}
if let Some(rw) = from_prevented_match_id {
query_params.insert("fromPreventedMatchId".to_string(), json!(rw));
}
if let Some(rw) = limit {
query_params.insert("limit".to_string(), json!(rw));
}
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<Vec<models::MyPreventedMatchesResponseInner>>(
&self.configuration,
"/api/v3/myPreventedMatches",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn my_trades(
&self,
params: MyTradesParams,
) -> anyhow::Result<RestApiResponse<Vec<models::MyTradesResponseInner>>> {
let MyTradesParams {
symbol,
order_id,
start_time,
end_time,
from_id,
limit,
recv_window,
} = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
query_params.insert("symbol".to_string(), json!(symbol));
if let Some(rw) = order_id {
query_params.insert("orderId".to_string(), json!(rw));
}
if let Some(rw) = start_time {
query_params.insert("startTime".to_string(), json!(rw));
}
if let Some(rw) = end_time {
query_params.insert("endTime".to_string(), json!(rw));
}
if let Some(rw) = from_id {
query_params.insert("fromId".to_string(), json!(rw));
}
if let Some(rw) = limit {
query_params.insert("limit".to_string(), json!(rw));
}
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<Vec<models::MyTradesResponseInner>>(
&self.configuration,
"/api/v3/myTrades",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn open_order_list(
&self,
params: OpenOrderListParams,
) -> anyhow::Result<RestApiResponse<Vec<models::OpenOrderListResponseInner>>> {
let OpenOrderListParams { recv_window } = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<Vec<models::OpenOrderListResponseInner>>(
&self.configuration,
"/api/v3/openOrderList",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn order_amendments(
&self,
params: OrderAmendmentsParams,
) -> anyhow::Result<RestApiResponse<Vec<models::OrderAmendmentsResponseInner>>> {
let OrderAmendmentsParams {
symbol,
order_id,
from_execution_id,
limit,
recv_window,
} = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
query_params.insert("symbol".to_string(), json!(symbol));
query_params.insert("orderId".to_string(), json!(order_id));
if let Some(rw) = from_execution_id {
query_params.insert("fromExecutionId".to_string(), json!(rw));
}
if let Some(rw) = limit {
query_params.insert("limit".to_string(), json!(rw));
}
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<Vec<models::OrderAmendmentsResponseInner>>(
&self.configuration,
"/api/v3/order/amendments",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
async fn rate_limit_order(
&self,
params: RateLimitOrderParams,
) -> anyhow::Result<RestApiResponse<Vec<models::RateLimitOrderResponseInner>>> {
let RateLimitOrderParams { recv_window } = params;
let mut query_params = BTreeMap::new();
let body_params = BTreeMap::new();
if let Some(rw) = recv_window {
query_params.insert("recvWindow".to_string(), json!(rw));
}
send_request::<Vec<models::RateLimitOrderResponseInner>>(
&self.configuration,
"/api/v3/rateLimit/order",
reqwest::Method::GET,
query_params,
body_params,
if HAS_TIME_UNIT {
self.configuration.time_unit
} else {
None
},
true,
)
.await
}
}
#[cfg(all(test, feature = "spot"))]
mod tests {
use super::*;
use crate::TOKIO_SHARED_RT;
use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
use async_trait::async_trait;
use std::collections::HashMap;
struct DummyRestApiResponse<T> {
inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
status: u16,
headers: HashMap<String, String>,
rate_limits: Option<Vec<RestApiRateLimit>>,
}
impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
fn from(dummy: DummyRestApiResponse<T>) -> Self {
Self {
data_fn: dummy.inner,
status: dummy.status,
headers: dummy.headers,
rate_limits: dummy.rate_limits,
}
}
}
struct MockAccountApiClient {
force_error: bool,
}
#[async_trait]
impl AccountApi for MockAccountApiClient {
async fn account_commission(
&self,
_params: AccountCommissionParams,
) -> anyhow::Result<RestApiResponse<models::AccountCommissionResponse>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"{"symbol":"BTCUSDT","standardCommission":{"maker":"0.00000010","taker":"0.00000020","buyer":"0.00000030","seller":"0.00000040"},"specialCommission":{"maker":"0.01000000","taker":"0.02000000","buyer":"0.03000000","seller":"0.04000000"},"taxCommission":{"maker":"0.00000112","taker":"0.00000114","buyer":"0.00000118","seller":"0.00000116"},"discount":{"enabledForAccount":true,"enabledForSymbol":true,"discountAsset":"BNB","discount":"0.75000000"}}"#).unwrap();
let dummy_response: models::AccountCommissionResponse =
serde_json::from_value(resp_json.clone())
.expect("should parse into models::AccountCommissionResponse");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn all_order_list(
&self,
_params: AllOrderListParams,
) -> anyhow::Result<RestApiResponse<Vec<models::AllOrderListResponseInner>>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"[{"orderListId":29,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"amEEAXryFzFwYF1FeRpUoZ","transactionTime":1565245913483,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"Jr1h6xirOxgeJOUuYQS7V3"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"oD7aesZqjEGlZrbtRpy5zB"}]},{"orderListId":28,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"hG7hFNxJV6cZy3Ze4AUT4d","transactionTime":1565245913407,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":2,"clientOrderId":"j6lFOfbmFMRjTYA7rRJ0LP"},{"symbol":"LTCBTC","orderId":3,"clientOrderId":"z0KCjOdditiLS5ekAFtK81"}]}]"#).unwrap();
let dummy_response: Vec<models::AllOrderListResponseInner> =
serde_json::from_value(resp_json.clone())
.expect("should parse into Vec<models::AllOrderListResponseInner>");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn all_orders(
&self,
_params: AllOrdersParams,
) -> anyhow::Result<RestApiResponse<Vec<models::AllOrdersResponseInner>>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"origQuoteOrderQty":"0.000000","workingTime":1499827319559,"selfTradePreventionMode":"NONE"}]"#).unwrap();
let dummy_response: Vec<models::AllOrdersResponseInner> =
serde_json::from_value(resp_json.clone())
.expect("should parse into Vec<models::AllOrdersResponseInner>");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn get_account(
&self,
_params: GetAccountParams,
) -> anyhow::Result<RestApiResponse<models::GetAccountResponse>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"{"makerCommission":15,"takerCommission":15,"buyerCommission":0,"sellerCommission":0,"commissionRates":{"maker":"0.00150000","taker":"0.00150000","buyer":"0.00000000","seller":"0.00000000"},"canTrade":true,"canWithdraw":true,"canDeposit":true,"brokered":false,"requireSelfTradePrevention":false,"preventSor":false,"updateTime":123456789,"accountType":"SPOT","balances":[{"asset":"LTC","free":"4763368.68006011","locked":"0.00000000"},{"asset":"BTC","free":"4723846.89208129","locked":"0.00000000"}],"permissions":["SPOT"],"uid":354937868}"#).unwrap();
let dummy_response: models::GetAccountResponse =
serde_json::from_value(resp_json.clone())
.expect("should parse into models::GetAccountResponse");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn get_open_orders(
&self,
_params: GetOpenOrdersParams,
) -> anyhow::Result<RestApiResponse<Vec<models::AllOrdersResponseInner>>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"origQuoteOrderQty":"0.000000","workingTime":1499827319559,"selfTradePreventionMode":"NONE"}]"#).unwrap();
let dummy_response: Vec<models::AllOrdersResponseInner> =
serde_json::from_value(resp_json.clone())
.expect("should parse into Vec<models::AllOrdersResponseInner>");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn get_order(
&self,
_params: GetOrderParams,
) -> anyhow::Result<RestApiResponse<models::GetOrderResponse>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"workingTime":1499827319559,"origQuoteOrderQty":"0.000000","selfTradePreventionMode":"NONE"}"#).unwrap();
let dummy_response: models::GetOrderResponse =
serde_json::from_value(resp_json.clone())
.expect("should parse into models::GetOrderResponse");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn get_order_list(
&self,
_params: GetOrderListParams,
) -> anyhow::Result<RestApiResponse<models::GetOrderListResponse>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"{"orderListId":27,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"h2USkA5YQpaXHPIrkd96xE","transactionTime":1565245656253,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"ARzZ9I00CPM8i3NhmU9Ega"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"qD1gy3kc3Gx0rihm9Y3xwS"}]}"#).unwrap();
let dummy_response: models::GetOrderListResponse =
serde_json::from_value(resp_json.clone())
.expect("should parse into models::GetOrderListResponse");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn my_allocations(
&self,
_params: MyAllocationsParams,
) -> anyhow::Result<RestApiResponse<Vec<models::MyAllocationsResponseInner>>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","allocationId":0,"allocationType":"SOR","orderId":1,"orderListId":-1,"price":"1.00000000","qty":"5.00000000","quoteQty":"5.00000000","commission":"0.00000000","commissionAsset":"BTC","time":1687506878118,"isBuyer":true,"isMaker":false,"isAllocator":false}]"#).unwrap();
let dummy_response: Vec<models::MyAllocationsResponseInner> =
serde_json::from_value(resp_json.clone())
.expect("should parse into Vec<models::MyAllocationsResponseInner>");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn my_filters(
&self,
_params: MyFiltersParams,
) -> anyhow::Result<RestApiResponse<models::MyFiltersResponse>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"{"exchangeFilters":[{"filterType":"EXCHANGE_MAX_NUM_ORDERS","maxNumOrders":1000}],"symbolFilters":[{"filterType":"MAX_NUM_ORDER_LISTS","maxNumOrderLists":20}],"assetFilters":[{"filterType":"MAX_ASSET","asset":"JPY","limit":"1000000.00000000"}],"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000},{"rateLimitType":"RAW_REQUESTS","interval":"MINUTE","intervalNum":5,"limit":61000}]}"#).unwrap();
let dummy_response: models::MyFiltersResponse =
serde_json::from_value(resp_json.clone())
.expect("should parse into models::MyFiltersResponse");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn my_prevented_matches(
&self,
_params: MyPreventedMatchesParams,
) -> anyhow::Result<RestApiResponse<Vec<models::MyPreventedMatchesResponseInner>>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","preventedMatchId":1,"takerOrderId":5,"makerSymbol":"BTCUSDT","makerOrderId":3,"tradeGroupId":1,"selfTradePreventionMode":"EXPIRE_MAKER","price":"1.100000","makerPreventedQuantity":"1.300000","transactTime":1669101687094}]"#).unwrap();
let dummy_response: Vec<models::MyPreventedMatchesResponseInner> =
serde_json::from_value(resp_json.clone())
.expect("should parse into Vec<models::MyPreventedMatchesResponseInner>");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn my_trades(
&self,
_params: MyTradesParams,
) -> anyhow::Result<RestApiResponse<Vec<models::MyTradesResponseInner>>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BNBBTC","id":28457,"orderId":100234,"orderListId":-1,"price":"4.00000100","qty":"12.00000000","quoteQty":"48.000012","commission":"10.10000000","commissionAsset":"BNB","time":1499865549590,"isBuyer":true,"isMaker":false,"isBestMatch":true}]"#).unwrap();
let dummy_response: Vec<models::MyTradesResponseInner> =
serde_json::from_value(resp_json.clone())
.expect("should parse into Vec<models::MyTradesResponseInner>");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn open_order_list(
&self,
_params: OpenOrderListParams,
) -> anyhow::Result<RestApiResponse<Vec<models::OpenOrderListResponseInner>>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"[{"orderListId":31,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"wuB13fmulKj3YjdqWEcsnp","transactionTime":1565246080644,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"Cv1SnyPD3qhqpbjpYEHbd2"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"r3EH2N76dHfLoSZWIUw1bT"}]}]"#).unwrap();
let dummy_response: Vec<models::OpenOrderListResponseInner> =
serde_json::from_value(resp_json.clone())
.expect("should parse into Vec<models::OpenOrderListResponseInner>");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn order_amendments(
&self,
_params: OrderAmendmentsParams,
) -> anyhow::Result<RestApiResponse<Vec<models::OrderAmendmentsResponseInner>>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","orderId":9,"executionId":22,"origClientOrderId":"W0fJ9fiLKHOJutovPK3oJp","newClientOrderId":"UQ1Np3bmQ71jJzsSDW9Vpi","origQty":"5.00000000","newQty":"4.00000000","time":1741669661670},{"symbol":"BTCUDST","orderId":9,"executionId":25,"origClientOrderId":"UQ1Np3bmQ71jJzsSDW9Vpi","newClientOrderId":"5uS0r35ohuQyDlCzZuYXq2","origQty":"4.00000000","newQty":"3.00000000","time":1741672924895}]"#).unwrap();
let dummy_response: Vec<models::OrderAmendmentsResponseInner> =
serde_json::from_value(resp_json.clone())
.expect("should parse into Vec<models::OrderAmendmentsResponseInner>");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
async fn rate_limit_order(
&self,
_params: RateLimitOrderParams,
) -> anyhow::Result<RestApiResponse<Vec<models::RateLimitOrderResponseInner>>> {
if self.force_error {
return Err(ConnectorError::ConnectorClientError {
msg: "ResponseError".to_string(),
code: None,
}
.into());
}
let resp_json: Value = serde_json::from_str(r#"[{"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":50,"count":0},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000,"count":0}]"#).unwrap();
let dummy_response: Vec<models::RateLimitOrderResponseInner> =
serde_json::from_value(resp_json.clone())
.expect("should parse into Vec<models::RateLimitOrderResponseInner>");
let dummy = DummyRestApiResponse {
inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
status: 200,
headers: HashMap::new(),
rate_limits: None,
};
Ok(dummy.into())
}
}
#[test]
fn account_commission_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = AccountCommissionParams::builder("BNBUSDT".to_string()).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"{"symbol":"BTCUSDT","standardCommission":{"maker":"0.00000010","taker":"0.00000020","buyer":"0.00000030","seller":"0.00000040"},"specialCommission":{"maker":"0.01000000","taker":"0.02000000","buyer":"0.03000000","seller":"0.04000000"},"taxCommission":{"maker":"0.00000112","taker":"0.00000114","buyer":"0.00000118","seller":"0.00000116"},"discount":{"enabledForAccount":true,"enabledForSymbol":true,"discountAsset":"BNB","discount":"0.75000000"}}"#).unwrap();
let expected_response : models::AccountCommissionResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AccountCommissionResponse");
let resp = client.account_commission(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn account_commission_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = AccountCommissionParams::builder("BNBUSDT".to_string()).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"{"symbol":"BTCUSDT","standardCommission":{"maker":"0.00000010","taker":"0.00000020","buyer":"0.00000030","seller":"0.00000040"},"specialCommission":{"maker":"0.01000000","taker":"0.02000000","buyer":"0.03000000","seller":"0.04000000"},"taxCommission":{"maker":"0.00000112","taker":"0.00000114","buyer":"0.00000118","seller":"0.00000116"},"discount":{"enabledForAccount":true,"enabledForSymbol":true,"discountAsset":"BNB","discount":"0.75000000"}}"#).unwrap();
let expected_response : models::AccountCommissionResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AccountCommissionResponse");
let resp = client.account_commission(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn account_commission_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = AccountCommissionParams::builder("BNBUSDT".to_string())
.build()
.unwrap();
match client.account_commission(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn all_order_list_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = AllOrderListParams::builder().build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"orderListId":29,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"amEEAXryFzFwYF1FeRpUoZ","transactionTime":1565245913483,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"Jr1h6xirOxgeJOUuYQS7V3"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"oD7aesZqjEGlZrbtRpy5zB"}]},{"orderListId":28,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"hG7hFNxJV6cZy3Ze4AUT4d","transactionTime":1565245913407,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":2,"clientOrderId":"j6lFOfbmFMRjTYA7rRJ0LP"},{"symbol":"LTCBTC","orderId":3,"clientOrderId":"z0KCjOdditiLS5ekAFtK81"}]}]"#).unwrap();
let expected_response : Vec<models::AllOrderListResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllOrderListResponseInner>");
let resp = client.all_order_list(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn all_order_list_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = AllOrderListParams::builder().from_id(1).start_time(1735693200000).end_time(1735693200000).limit(500).recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"orderListId":29,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"amEEAXryFzFwYF1FeRpUoZ","transactionTime":1565245913483,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"Jr1h6xirOxgeJOUuYQS7V3"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"oD7aesZqjEGlZrbtRpy5zB"}]},{"orderListId":28,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"hG7hFNxJV6cZy3Ze4AUT4d","transactionTime":1565245913407,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":2,"clientOrderId":"j6lFOfbmFMRjTYA7rRJ0LP"},{"symbol":"LTCBTC","orderId":3,"clientOrderId":"z0KCjOdditiLS5ekAFtK81"}]}]"#).unwrap();
let expected_response : Vec<models::AllOrderListResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllOrderListResponseInner>");
let resp = client.all_order_list(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn all_order_list_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = AllOrderListParams::builder().build().unwrap();
match client.all_order_list(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn all_orders_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = AllOrdersParams::builder("BNBUSDT".to_string(),).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"origQuoteOrderQty":"0.000000","workingTime":1499827319559,"selfTradePreventionMode":"NONE"}]"#).unwrap();
let expected_response : Vec<models::AllOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllOrdersResponseInner>");
let resp = client.all_orders(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn all_orders_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = AllOrdersParams::builder("BNBUSDT".to_string(),).order_id(1).start_time(1735693200000).end_time(1735693200000).limit(500).recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"origQuoteOrderQty":"0.000000","workingTime":1499827319559,"selfTradePreventionMode":"NONE"}]"#).unwrap();
let expected_response : Vec<models::AllOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllOrdersResponseInner>");
let resp = client.all_orders(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn all_orders_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = AllOrdersParams::builder("BNBUSDT".to_string())
.build()
.unwrap();
match client.all_orders(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn get_account_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = GetAccountParams::builder().build().unwrap();
let resp_json: Value = serde_json::from_str(r#"{"makerCommission":15,"takerCommission":15,"buyerCommission":0,"sellerCommission":0,"commissionRates":{"maker":"0.00150000","taker":"0.00150000","buyer":"0.00000000","seller":"0.00000000"},"canTrade":true,"canWithdraw":true,"canDeposit":true,"brokered":false,"requireSelfTradePrevention":false,"preventSor":false,"updateTime":123456789,"accountType":"SPOT","balances":[{"asset":"LTC","free":"4763368.68006011","locked":"0.00000000"},{"asset":"BTC","free":"4723846.89208129","locked":"0.00000000"}],"permissions":["SPOT"],"uid":354937868}"#).unwrap();
let expected_response : models::GetAccountResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetAccountResponse");
let resp = client.get_account(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn get_account_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = GetAccountParams::builder().omit_zero_balances(false).recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"{"makerCommission":15,"takerCommission":15,"buyerCommission":0,"sellerCommission":0,"commissionRates":{"maker":"0.00150000","taker":"0.00150000","buyer":"0.00000000","seller":"0.00000000"},"canTrade":true,"canWithdraw":true,"canDeposit":true,"brokered":false,"requireSelfTradePrevention":false,"preventSor":false,"updateTime":123456789,"accountType":"SPOT","balances":[{"asset":"LTC","free":"4763368.68006011","locked":"0.00000000"},{"asset":"BTC","free":"4723846.89208129","locked":"0.00000000"}],"permissions":["SPOT"],"uid":354937868}"#).unwrap();
let expected_response : models::GetAccountResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetAccountResponse");
let resp = client.get_account(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn get_account_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = GetAccountParams::builder().build().unwrap();
match client.get_account(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn get_open_orders_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = GetOpenOrdersParams::builder().build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"origQuoteOrderQty":"0.000000","workingTime":1499827319559,"selfTradePreventionMode":"NONE"}]"#).unwrap();
let expected_response : Vec<models::AllOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllOrdersResponseInner>");
let resp = client.get_open_orders(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn get_open_orders_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = GetOpenOrdersParams::builder().symbol("BNBUSDT".to_string()).recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"origQuoteOrderQty":"0.000000","workingTime":1499827319559,"selfTradePreventionMode":"NONE"}]"#).unwrap();
let expected_response : Vec<models::AllOrdersResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AllOrdersResponseInner>");
let resp = client.get_open_orders(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn get_open_orders_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = GetOpenOrdersParams::builder().build().unwrap();
match client.get_open_orders(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn get_order_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = GetOrderParams::builder("BNBUSDT".to_string(),).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"workingTime":1499827319559,"origQuoteOrderQty":"0.000000","selfTradePreventionMode":"NONE"}"#).unwrap();
let expected_response : models::GetOrderResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetOrderResponse");
let resp = client.get_order(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn get_order_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = GetOrderParams::builder("BNBUSDT".to_string(),).order_id(1).orig_client_order_id("orig_client_order_id_example".to_string()).recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC","orderId":1,"orderListId":-1,"clientOrderId":"myOrder1","price":"0.1","origQty":"1.0","executedQty":"0.0","cummulativeQuoteQty":"0.0","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","stopPrice":"0.0","icebergQty":"0.0","time":1499827319559,"updateTime":1499827319559,"isWorking":true,"workingTime":1499827319559,"origQuoteOrderQty":"0.000000","selfTradePreventionMode":"NONE"}"#).unwrap();
let expected_response : models::GetOrderResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetOrderResponse");
let resp = client.get_order(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn get_order_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = GetOrderParams::builder("BNBUSDT".to_string())
.build()
.unwrap();
match client.get_order(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn get_order_list_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = GetOrderListParams::builder().build().unwrap();
let resp_json: Value = serde_json::from_str(r#"{"orderListId":27,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"h2USkA5YQpaXHPIrkd96xE","transactionTime":1565245656253,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"ARzZ9I00CPM8i3NhmU9Ega"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"qD1gy3kc3Gx0rihm9Y3xwS"}]}"#).unwrap();
let expected_response : models::GetOrderListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetOrderListResponse");
let resp = client.get_order_list(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn get_order_list_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = GetOrderListParams::builder().order_list_id(1).orig_client_order_id("orig_client_order_id_example".to_string()).recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"{"orderListId":27,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"h2USkA5YQpaXHPIrkd96xE","transactionTime":1565245656253,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"ARzZ9I00CPM8i3NhmU9Ega"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"qD1gy3kc3Gx0rihm9Y3xwS"}]}"#).unwrap();
let expected_response : models::GetOrderListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetOrderListResponse");
let resp = client.get_order_list(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn get_order_list_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = GetOrderListParams::builder().build().unwrap();
match client.get_order_list(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn my_allocations_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = MyAllocationsParams::builder("BNBUSDT".to_string(),).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","allocationId":0,"allocationType":"SOR","orderId":1,"orderListId":-1,"price":"1.00000000","qty":"5.00000000","quoteQty":"5.00000000","commission":"0.00000000","commissionAsset":"BTC","time":1687506878118,"isBuyer":true,"isMaker":false,"isAllocator":false}]"#).unwrap();
let expected_response : Vec<models::MyAllocationsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::MyAllocationsResponseInner>");
let resp = client.my_allocations(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn my_allocations_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = MyAllocationsParams::builder("BNBUSDT".to_string(),).start_time(1735693200000).end_time(1735693200000).from_allocation_id(1).limit(500).order_id(1).recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","allocationId":0,"allocationType":"SOR","orderId":1,"orderListId":-1,"price":"1.00000000","qty":"5.00000000","quoteQty":"5.00000000","commission":"0.00000000","commissionAsset":"BTC","time":1687506878118,"isBuyer":true,"isMaker":false,"isAllocator":false}]"#).unwrap();
let expected_response : Vec<models::MyAllocationsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::MyAllocationsResponseInner>");
let resp = client.my_allocations(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn my_allocations_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = MyAllocationsParams::builder("BNBUSDT".to_string())
.build()
.unwrap();
match client.my_allocations(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn my_filters_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = MyFiltersParams::builder("BNBUSDT".to_string(),).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"{"exchangeFilters":[{"filterType":"EXCHANGE_MAX_NUM_ORDERS","maxNumOrders":1000}],"symbolFilters":[{"filterType":"MAX_NUM_ORDER_LISTS","maxNumOrderLists":20}],"assetFilters":[{"filterType":"MAX_ASSET","asset":"JPY","limit":"1000000.00000000"}],"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000},{"rateLimitType":"RAW_REQUESTS","interval":"MINUTE","intervalNum":5,"limit":61000}]}"#).unwrap();
let expected_response : models::MyFiltersResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::MyFiltersResponse");
let resp = client.my_filters(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn my_filters_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = MyFiltersParams::builder("BNBUSDT".to_string(),).recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"{"exchangeFilters":[{"filterType":"EXCHANGE_MAX_NUM_ORDERS","maxNumOrders":1000}],"symbolFilters":[{"filterType":"MAX_NUM_ORDER_LISTS","maxNumOrderLists":20}],"assetFilters":[{"filterType":"MAX_ASSET","asset":"JPY","limit":"1000000.00000000"}],"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000},{"rateLimitType":"RAW_REQUESTS","interval":"MINUTE","intervalNum":5,"limit":61000}]}"#).unwrap();
let expected_response : models::MyFiltersResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::MyFiltersResponse");
let resp = client.my_filters(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn my_filters_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = MyFiltersParams::builder("BNBUSDT".to_string())
.build()
.unwrap();
match client.my_filters(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn my_prevented_matches_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = MyPreventedMatchesParams::builder("BNBUSDT".to_string(),).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","preventedMatchId":1,"takerOrderId":5,"makerSymbol":"BTCUSDT","makerOrderId":3,"tradeGroupId":1,"selfTradePreventionMode":"EXPIRE_MAKER","price":"1.100000","makerPreventedQuantity":"1.300000","transactTime":1669101687094}]"#).unwrap();
let expected_response : Vec<models::MyPreventedMatchesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::MyPreventedMatchesResponseInner>");
let resp = client.my_prevented_matches(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn my_prevented_matches_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = MyPreventedMatchesParams::builder("BNBUSDT".to_string(),).prevented_match_id(1).order_id(1).from_prevented_match_id(1).limit(500).recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","preventedMatchId":1,"takerOrderId":5,"makerSymbol":"BTCUSDT","makerOrderId":3,"tradeGroupId":1,"selfTradePreventionMode":"EXPIRE_MAKER","price":"1.100000","makerPreventedQuantity":"1.300000","transactTime":1669101687094}]"#).unwrap();
let expected_response : Vec<models::MyPreventedMatchesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::MyPreventedMatchesResponseInner>");
let resp = client.my_prevented_matches(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn my_prevented_matches_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = MyPreventedMatchesParams::builder("BNBUSDT".to_string())
.build()
.unwrap();
match client.my_prevented_matches(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn my_trades_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = MyTradesParams::builder("BNBUSDT".to_string(),).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BNBBTC","id":28457,"orderId":100234,"orderListId":-1,"price":"4.00000100","qty":"12.00000000","quoteQty":"48.000012","commission":"10.10000000","commissionAsset":"BNB","time":1499865549590,"isBuyer":true,"isMaker":false,"isBestMatch":true}]"#).unwrap();
let expected_response : Vec<models::MyTradesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::MyTradesResponseInner>");
let resp = client.my_trades(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn my_trades_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = MyTradesParams::builder("BNBUSDT".to_string(),).order_id(1).start_time(1735693200000).end_time(1735693200000).from_id(1).limit(500).recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BNBBTC","id":28457,"orderId":100234,"orderListId":-1,"price":"4.00000100","qty":"12.00000000","quoteQty":"48.000012","commission":"10.10000000","commissionAsset":"BNB","time":1499865549590,"isBuyer":true,"isMaker":false,"isBestMatch":true}]"#).unwrap();
let expected_response : Vec<models::MyTradesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::MyTradesResponseInner>");
let resp = client.my_trades(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn my_trades_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = MyTradesParams::builder("BNBUSDT".to_string())
.build()
.unwrap();
match client.my_trades(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn open_order_list_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = OpenOrderListParams::builder().build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"orderListId":31,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"wuB13fmulKj3YjdqWEcsnp","transactionTime":1565246080644,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"Cv1SnyPD3qhqpbjpYEHbd2"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"r3EH2N76dHfLoSZWIUw1bT"}]}]"#).unwrap();
let expected_response : Vec<models::OpenOrderListResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::OpenOrderListResponseInner>");
let resp = client.open_order_list(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn open_order_list_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = OpenOrderListParams::builder().recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"orderListId":31,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"wuB13fmulKj3YjdqWEcsnp","transactionTime":1565246080644,"symbol":"LTCBTC","orders":[{"symbol":"LTCBTC","orderId":5,"clientOrderId":"Cv1SnyPD3qhqpbjpYEHbd2"},{"symbol":"LTCBTC","orderId":4,"clientOrderId":"r3EH2N76dHfLoSZWIUw1bT"}]}]"#).unwrap();
let expected_response : Vec<models::OpenOrderListResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::OpenOrderListResponseInner>");
let resp = client.open_order_list(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn open_order_list_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = OpenOrderListParams::builder().build().unwrap();
match client.open_order_list(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn order_amendments_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = OrderAmendmentsParams::builder("BNBUSDT".to_string(),1,).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","orderId":9,"executionId":22,"origClientOrderId":"W0fJ9fiLKHOJutovPK3oJp","newClientOrderId":"UQ1Np3bmQ71jJzsSDW9Vpi","origQty":"5.00000000","newQty":"4.00000000","time":1741669661670},{"symbol":"BTCUDST","orderId":9,"executionId":25,"origClientOrderId":"UQ1Np3bmQ71jJzsSDW9Vpi","newClientOrderId":"5uS0r35ohuQyDlCzZuYXq2","origQty":"4.00000000","newQty":"3.00000000","time":1741672924895}]"#).unwrap();
let expected_response : Vec<models::OrderAmendmentsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::OrderAmendmentsResponseInner>");
let resp = client.order_amendments(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn order_amendments_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = OrderAmendmentsParams::builder("BNBUSDT".to_string(),1,).from_execution_id(1).limit(500).recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"symbol":"BTCUSDT","orderId":9,"executionId":22,"origClientOrderId":"W0fJ9fiLKHOJutovPK3oJp","newClientOrderId":"UQ1Np3bmQ71jJzsSDW9Vpi","origQty":"5.00000000","newQty":"4.00000000","time":1741669661670},{"symbol":"BTCUDST","orderId":9,"executionId":25,"origClientOrderId":"UQ1Np3bmQ71jJzsSDW9Vpi","newClientOrderId":"5uS0r35ohuQyDlCzZuYXq2","origQty":"4.00000000","newQty":"3.00000000","time":1741672924895}]"#).unwrap();
let expected_response : Vec<models::OrderAmendmentsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::OrderAmendmentsResponseInner>");
let resp = client.order_amendments(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn order_amendments_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = OrderAmendmentsParams::builder("BNBUSDT".to_string(), 1)
.build()
.unwrap();
match client.order_amendments(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
#[test]
fn rate_limit_order_required_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = RateLimitOrderParams::builder().build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":50,"count":0},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000,"count":0}]"#).unwrap();
let expected_response : Vec<models::RateLimitOrderResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::RateLimitOrderResponseInner>");
let resp = client.rate_limit_order(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn rate_limit_order_optional_params_success() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: false };
let params = RateLimitOrderParams::builder().recv_window(dec!(5000.0)).build().unwrap();
let resp_json: Value = serde_json::from_str(r#"[{"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":50,"count":0},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000,"count":0}]"#).unwrap();
let expected_response : Vec<models::RateLimitOrderResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::RateLimitOrderResponseInner>");
let resp = client.rate_limit_order(params).await.expect("Expected a response");
let data_future = resp.data();
let actual_response = data_future.await.unwrap();
assert_eq!(actual_response, expected_response);
});
}
#[test]
fn rate_limit_order_response_error() {
TOKIO_SHARED_RT.block_on(async {
let client = MockAccountApiClient { force_error: true };
let params = RateLimitOrderParams::builder().build().unwrap();
match client.rate_limit_order(params).await {
Ok(_) => panic!("Expected an error"),
Err(err) => {
assert_eq!(err.to_string(), "Connector client error: ResponseError");
}
}
});
}
}