/*
* Binance Spot WebSocket API
*
* OpenAPI Specifications for the Binance Spot WebSocket API
*
* API documents:
* - [Github web-socket-api documentation file](https://github.com/binance/binance-spot-api-docs/blob/master/web-socket-api.md)
* - [General API information for web-socket-api on website](https://developers.binance.com/docs/binance-spot-api-docs/web-socket-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 anyhow::Context;
use async_trait::async_trait;
use derive_builder::Builder;
use rust_decimal::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::{collections::BTreeMap, sync::Arc};
use crate::common::{
errors::WebsocketError,
models::{ParamBuildError, WebsocketApiResponse},
utils::remove_empty_value,
websocket::{WebsocketApi, WebsocketMessageSendOptions},
};
use crate::spot::websocket_api::models;
#[async_trait]
pub trait TradeApi: Send + Sync {
async fn open_orders_cancel_all(
&self,
params: OpenOrdersCancelAllParams,
) -> anyhow::Result<WebsocketApiResponse<Vec<models::OpenOrdersCancelAllResponseResultInner>>>;
async fn order_amend_keep_priority(
&self,
params: OrderAmendKeepPriorityParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderAmendKeepPriorityResponseResult>>>;
async fn order_cancel(
&self,
params: OrderCancelParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderCancelResponseResult>>>;
async fn order_cancel_replace(
&self,
params: OrderCancelReplaceParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderCancelReplaceResponseResult>>>;
async fn order_list_cancel(
&self,
params: OrderListCancelParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListCancelResponseResult>>>;
async fn order_list_place(
&self,
params: OrderListPlaceParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceResponseResult>>>;
async fn order_list_place_oco(
&self,
params: OrderListPlaceOcoParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOcoResponseResult>>>;
async fn order_list_place_opo(
&self,
params: OrderListPlaceOpoParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOpoResponseResult>>>;
async fn order_list_place_opoco(
&self,
params: OrderListPlaceOpocoParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOpocoResponseResult>>>;
async fn order_list_place_oto(
&self,
params: OrderListPlaceOtoParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOtoResponseResult>>>;
async fn order_list_place_otoco(
&self,
params: OrderListPlaceOtocoParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOtocoResponseResult>>>;
async fn order_place(
&self,
params: OrderPlaceParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderPlaceResponseResult>>>;
async fn order_test(
&self,
params: OrderTestParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderTestResponseResult>>>;
async fn sor_order_place(
&self,
params: SorOrderPlaceParams,
) -> anyhow::Result<WebsocketApiResponse<Vec<models::SorOrderPlaceResponseResultInner>>>;
async fn sor_order_test(
&self,
params: SorOrderTestParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::SorOrderTestResponseResult>>>;
}
#[derive(Clone)]
pub struct TradeApiClient {
websocket_api_base: Arc<WebsocketApi>,
}
impl TradeApiClient {
pub fn new(websocket_api_base: Arc<WebsocketApi>) -> Self {
Self { websocket_api_base }
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderCancelCancelRestrictionsEnum {
#[serde(rename = "ONLY_NEW")]
OnlyNew,
#[serde(rename = "NEW")]
New,
#[serde(rename = "ONLY_PARTIALLY_FILLED")]
OnlyPartiallyFilled,
#[serde(rename = "PARTIALLY_FILLED")]
PartiallyFilled,
}
impl OrderCancelCancelRestrictionsEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::OnlyNew => "ONLY_NEW",
Self::New => "NEW",
Self::OnlyPartiallyFilled => "ONLY_PARTIALLY_FILLED",
Self::PartiallyFilled => "PARTIALLY_FILLED",
}
}
}
impl std::str::FromStr for OrderCancelCancelRestrictionsEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"ONLY_NEW" => Ok(Self::OnlyNew),
"NEW" => Ok(Self::New),
"ONLY_PARTIALLY_FILLED" => Ok(Self::OnlyPartiallyFilled),
"PARTIALLY_FILLED" => Ok(Self::PartiallyFilled),
other => Err(format!("invalid OrderCancelCancelRestrictionsEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderCancelReplaceCancelReplaceModeEnum {
#[serde(rename = "STOP_ON_FAILURE")]
StopOnFailure,
#[serde(rename = "ALLOW_FAILURE")]
AllowFailure,
}
impl OrderCancelReplaceCancelReplaceModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::StopOnFailure => "STOP_ON_FAILURE",
Self::AllowFailure => "ALLOW_FAILURE",
}
}
}
impl std::str::FromStr for OrderCancelReplaceCancelReplaceModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"STOP_ON_FAILURE" => Ok(Self::StopOnFailure),
"ALLOW_FAILURE" => Ok(Self::AllowFailure),
other => {
Err(format!("invalid OrderCancelReplaceCancelReplaceModeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderCancelReplaceSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderCancelReplaceSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderCancelReplaceSideEnum {
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 OrderCancelReplaceSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderCancelReplaceTypeEnum {
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderCancelReplaceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Market => "MARKET",
Self::Limit => "LIMIT",
Self::StopLoss => "STOP_LOSS",
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
Self::LimitMaker => "LIMIT_MAKER",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderCancelReplaceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
"STOP_LOSS" => Ok(Self::StopLoss),
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderCancelReplaceTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderCancelReplaceTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderCancelReplaceTimeInForceEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Gtc => "GTC",
Self::Ioc => "IOC",
Self::Fok => "FOK",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderCancelReplaceTimeInForceEnum {
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),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderCancelReplaceTimeInForceEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderCancelReplaceNewOrderRespTypeEnum {
#[serde(rename = "ACK")]
Ack,
#[serde(rename = "RESULT")]
Result,
#[serde(rename = "FULL")]
Full,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
}
impl OrderCancelReplaceNewOrderRespTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Ack => "ACK",
Self::Result => "RESULT",
Self::Full => "FULL",
Self::Market => "MARKET",
Self::Limit => "LIMIT",
}
}
}
impl std::str::FromStr for OrderCancelReplaceNewOrderRespTypeEnum {
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),
"FULL" => Ok(Self::Full),
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
other => {
Err(format!("invalid OrderCancelReplaceNewOrderRespTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderCancelReplaceSelfTradePreventionModeEnum {
#[serde(rename = "NONE")]
None,
#[serde(rename = "EXPIRE_TAKER")]
ExpireTaker,
#[serde(rename = "EXPIRE_MAKER")]
ExpireMaker,
#[serde(rename = "EXPIRE_BOTH")]
ExpireBoth,
#[serde(rename = "DECREMENT")]
Decrement,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderCancelReplaceSelfTradePreventionModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::None => "NONE",
Self::ExpireTaker => "EXPIRE_TAKER",
Self::ExpireMaker => "EXPIRE_MAKER",
Self::ExpireBoth => "EXPIRE_BOTH",
Self::Decrement => "DECREMENT",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderCancelReplaceSelfTradePreventionModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"NONE" => Ok(Self::None),
"EXPIRE_TAKER" => Ok(Self::ExpireTaker),
"EXPIRE_MAKER" => Ok(Self::ExpireMaker),
"EXPIRE_BOTH" => Ok(Self::ExpireBoth),
"DECREMENT" => Ok(Self::Decrement),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!(
"invalid OrderCancelReplaceSelfTradePreventionModeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderCancelReplaceCancelRestrictionsEnum {
#[serde(rename = "ONLY_NEW")]
OnlyNew,
#[serde(rename = "NEW")]
New,
#[serde(rename = "ONLY_PARTIALLY_FILLED")]
OnlyPartiallyFilled,
#[serde(rename = "PARTIALLY_FILLED")]
PartiallyFilled,
}
impl OrderCancelReplaceCancelRestrictionsEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::OnlyNew => "ONLY_NEW",
Self::New => "NEW",
Self::OnlyPartiallyFilled => "ONLY_PARTIALLY_FILLED",
Self::PartiallyFilled => "PARTIALLY_FILLED",
}
}
}
impl std::str::FromStr for OrderCancelReplaceCancelRestrictionsEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"ONLY_NEW" => Ok(Self::OnlyNew),
"NEW" => Ok(Self::New),
"ONLY_PARTIALLY_FILLED" => Ok(Self::OnlyPartiallyFilled),
"PARTIALLY_FILLED" => Ok(Self::PartiallyFilled),
other => Err(format!(
"invalid OrderCancelReplaceCancelRestrictionsEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderCancelReplaceOrderRateLimitExceededModeEnum {
#[serde(rename = "DO_NOTHING")]
DoNothing,
#[serde(rename = "CANCEL_ONLY")]
CancelOnly,
}
impl OrderCancelReplaceOrderRateLimitExceededModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::DoNothing => "DO_NOTHING",
Self::CancelOnly => "CANCEL_ONLY",
}
}
}
impl std::str::FromStr for OrderCancelReplaceOrderRateLimitExceededModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"DO_NOTHING" => Ok(Self::DoNothing),
"CANCEL_ONLY" => Ok(Self::CancelOnly),
other => Err(format!(
"invalid OrderCancelReplaceOrderRateLimitExceededModeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderCancelReplacePegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderCancelReplacePegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderCancelReplacePegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderCancelReplacePegPriceTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderCancelReplacePegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderCancelReplacePegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderCancelReplacePegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderCancelReplacePegOffsetTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderListPlaceSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderListPlaceSideEnum {
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 OrderListPlaceSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceStopLimitTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceStopLimitTimeInForceEnum {
#[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 OrderListPlaceStopLimitTimeInForceEnum {
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 OrderListPlaceStopLimitTimeInForceEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceNewOrderRespTypeEnum {
#[serde(rename = "ACK")]
Ack,
#[serde(rename = "RESULT")]
Result,
#[serde(rename = "FULL")]
Full,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
}
impl OrderListPlaceNewOrderRespTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Ack => "ACK",
Self::Result => "RESULT",
Self::Full => "FULL",
Self::Market => "MARKET",
Self::Limit => "LIMIT",
}
}
}
impl std::str::FromStr for OrderListPlaceNewOrderRespTypeEnum {
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),
"FULL" => Ok(Self::Full),
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
other => Err(format!("invalid OrderListPlaceNewOrderRespTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceSelfTradePreventionModeEnum {
#[serde(rename = "NONE")]
None,
#[serde(rename = "EXPIRE_TAKER")]
ExpireTaker,
#[serde(rename = "EXPIRE_MAKER")]
ExpireMaker,
#[serde(rename = "EXPIRE_BOTH")]
ExpireBoth,
#[serde(rename = "DECREMENT")]
Decrement,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderListPlaceSelfTradePreventionModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::None => "NONE",
Self::ExpireTaker => "EXPIRE_TAKER",
Self::ExpireMaker => "EXPIRE_MAKER",
Self::ExpireBoth => "EXPIRE_BOTH",
Self::Decrement => "DECREMENT",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderListPlaceSelfTradePreventionModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"NONE" => Ok(Self::None),
"EXPIRE_TAKER" => Ok(Self::ExpireTaker),
"EXPIRE_MAKER" => Ok(Self::ExpireMaker),
"EXPIRE_BOTH" => Ok(Self::ExpireBoth),
"DECREMENT" => Ok(Self::Decrement),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!(
"invalid OrderListPlaceSelfTradePreventionModeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOcoSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderListPlaceOcoSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderListPlaceOcoSideEnum {
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 OrderListPlaceOcoSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOcoAboveTypeEnum {
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
}
impl OrderListPlaceOcoAboveTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::StopLoss => "STOP_LOSS",
Self::LimitMaker => "LIMIT_MAKER",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
}
}
}
impl std::str::FromStr for OrderListPlaceOcoAboveTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"STOP_LOSS" => Ok(Self::StopLoss),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
other => Err(format!("invalid OrderListPlaceOcoAboveTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOcoBelowTypeEnum {
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
}
impl OrderListPlaceOcoBelowTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::StopLoss => "STOP_LOSS",
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
}
}
}
impl std::str::FromStr for OrderListPlaceOcoBelowTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"STOP_LOSS" => Ok(Self::StopLoss),
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
other => Err(format!("invalid OrderListPlaceOcoBelowTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOcoAboveTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceOcoAboveTimeInForceEnum {
#[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 OrderListPlaceOcoAboveTimeInForceEnum {
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 OrderListPlaceOcoAboveTimeInForceEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOcoAbovePegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
}
impl OrderListPlaceOcoAbovePegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
}
}
}
impl std::str::FromStr for OrderListPlaceOcoAbovePegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
other => {
Err(format!("invalid OrderListPlaceOcoAbovePegPriceTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOcoAbovePegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
}
impl OrderListPlaceOcoAbovePegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
}
}
}
impl std::str::FromStr for OrderListPlaceOcoAbovePegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
other => {
Err(format!("invalid OrderListPlaceOcoAbovePegOffsetTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOcoBelowTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceOcoBelowTimeInForceEnum {
#[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 OrderListPlaceOcoBelowTimeInForceEnum {
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 OrderListPlaceOcoBelowTimeInForceEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOcoBelowPegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
}
impl OrderListPlaceOcoBelowPegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
}
}
}
impl std::str::FromStr for OrderListPlaceOcoBelowPegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
other => {
Err(format!("invalid OrderListPlaceOcoBelowPegPriceTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOcoBelowPegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
}
impl OrderListPlaceOcoBelowPegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
}
}
}
impl std::str::FromStr for OrderListPlaceOcoBelowPegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
other => {
Err(format!("invalid OrderListPlaceOcoBelowPegOffsetTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOcoNewOrderRespTypeEnum {
#[serde(rename = "ACK")]
Ack,
#[serde(rename = "RESULT")]
Result,
#[serde(rename = "FULL")]
Full,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
}
impl OrderListPlaceOcoNewOrderRespTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Ack => "ACK",
Self::Result => "RESULT",
Self::Full => "FULL",
Self::Market => "MARKET",
Self::Limit => "LIMIT",
}
}
}
impl std::str::FromStr for OrderListPlaceOcoNewOrderRespTypeEnum {
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),
"FULL" => Ok(Self::Full),
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
other => {
Err(format!("invalid OrderListPlaceOcoNewOrderRespTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOcoSelfTradePreventionModeEnum {
#[serde(rename = "NONE")]
None,
#[serde(rename = "EXPIRE_TAKER")]
ExpireTaker,
#[serde(rename = "EXPIRE_MAKER")]
ExpireMaker,
#[serde(rename = "EXPIRE_BOTH")]
ExpireBoth,
#[serde(rename = "DECREMENT")]
Decrement,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderListPlaceOcoSelfTradePreventionModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::None => "NONE",
Self::ExpireTaker => "EXPIRE_TAKER",
Self::ExpireMaker => "EXPIRE_MAKER",
Self::ExpireBoth => "EXPIRE_BOTH",
Self::Decrement => "DECREMENT",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderListPlaceOcoSelfTradePreventionModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"NONE" => Ok(Self::None),
"EXPIRE_TAKER" => Ok(Self::ExpireTaker),
"EXPIRE_MAKER" => Ok(Self::ExpireMaker),
"EXPIRE_BOTH" => Ok(Self::ExpireBoth),
"DECREMENT" => Ok(Self::Decrement),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!(
"invalid OrderListPlaceOcoSelfTradePreventionModeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpoWorkingTypeEnum {
#[serde(rename = "LIMIT")]
Limit,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
}
impl OrderListPlaceOpoWorkingTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Limit => "LIMIT",
Self::LimitMaker => "LIMIT_MAKER",
}
}
}
impl std::str::FromStr for OrderListPlaceOpoWorkingTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"LIMIT" => Ok(Self::Limit),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
other => Err(format!("invalid OrderListPlaceOpoWorkingTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpoWorkingSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderListPlaceOpoWorkingSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderListPlaceOpoWorkingSideEnum {
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 OrderListPlaceOpoWorkingSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpoPendingTypeEnum {
#[serde(rename = "LIMIT")]
Limit,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
}
impl OrderListPlaceOpoPendingTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Limit => "LIMIT",
Self::Market => "MARKET",
Self::StopLoss => "STOP_LOSS",
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
Self::LimitMaker => "LIMIT_MAKER",
}
}
}
impl std::str::FromStr for OrderListPlaceOpoPendingTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"LIMIT" => Ok(Self::Limit),
"MARKET" => Ok(Self::Market),
"STOP_LOSS" => Ok(Self::StopLoss),
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
other => Err(format!("invalid OrderListPlaceOpoPendingTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpoPendingSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderListPlaceOpoPendingSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderListPlaceOpoPendingSideEnum {
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 OrderListPlaceOpoPendingSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpoNewOrderRespTypeEnum {
#[serde(rename = "ACK")]
Ack,
#[serde(rename = "RESULT")]
Result,
#[serde(rename = "FULL")]
Full,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
}
impl OrderListPlaceOpoNewOrderRespTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Ack => "ACK",
Self::Result => "RESULT",
Self::Full => "FULL",
Self::Market => "MARKET",
Self::Limit => "LIMIT",
}
}
}
impl std::str::FromStr for OrderListPlaceOpoNewOrderRespTypeEnum {
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),
"FULL" => Ok(Self::Full),
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
other => {
Err(format!("invalid OrderListPlaceOpoNewOrderRespTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpoSelfTradePreventionModeEnum {
#[serde(rename = "NONE")]
None,
#[serde(rename = "EXPIRE_TAKER")]
ExpireTaker,
#[serde(rename = "EXPIRE_MAKER")]
ExpireMaker,
#[serde(rename = "EXPIRE_BOTH")]
ExpireBoth,
#[serde(rename = "DECREMENT")]
Decrement,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderListPlaceOpoSelfTradePreventionModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::None => "NONE",
Self::ExpireTaker => "EXPIRE_TAKER",
Self::ExpireMaker => "EXPIRE_MAKER",
Self::ExpireBoth => "EXPIRE_BOTH",
Self::Decrement => "DECREMENT",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderListPlaceOpoSelfTradePreventionModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"NONE" => Ok(Self::None),
"EXPIRE_TAKER" => Ok(Self::ExpireTaker),
"EXPIRE_MAKER" => Ok(Self::ExpireMaker),
"EXPIRE_BOTH" => Ok(Self::ExpireBoth),
"DECREMENT" => Ok(Self::Decrement),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!(
"invalid OrderListPlaceOpoSelfTradePreventionModeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpoWorkingTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceOpoWorkingTimeInForceEnum {
#[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 OrderListPlaceOpoWorkingTimeInForceEnum {
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 OrderListPlaceOpoWorkingTimeInForceEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpoWorkingPegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
}
impl OrderListPlaceOpoWorkingPegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
}
}
}
impl std::str::FromStr for OrderListPlaceOpoWorkingPegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
other => Err(format!(
"invalid OrderListPlaceOpoWorkingPegPriceTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpoWorkingPegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
}
impl OrderListPlaceOpoWorkingPegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
}
}
}
impl std::str::FromStr for OrderListPlaceOpoWorkingPegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
other => Err(format!(
"invalid OrderListPlaceOpoWorkingPegOffsetTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpoPendingTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceOpoPendingTimeInForceEnum {
#[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 OrderListPlaceOpoPendingTimeInForceEnum {
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 OrderListPlaceOpoPendingTimeInForceEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpoPendingPegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
}
impl OrderListPlaceOpoPendingPegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
}
}
}
impl std::str::FromStr for OrderListPlaceOpoPendingPegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
other => Err(format!(
"invalid OrderListPlaceOpoPendingPegPriceTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpoPendingPegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
}
impl OrderListPlaceOpoPendingPegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
}
}
}
impl std::str::FromStr for OrderListPlaceOpoPendingPegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
other => Err(format!(
"invalid OrderListPlaceOpoPendingPegOffsetTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoWorkingTypeEnum {
#[serde(rename = "LIMIT")]
Limit,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
}
impl OrderListPlaceOpocoWorkingTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Limit => "LIMIT",
Self::LimitMaker => "LIMIT_MAKER",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoWorkingTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"LIMIT" => Ok(Self::Limit),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
other => Err(format!("invalid OrderListPlaceOpocoWorkingTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoWorkingSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderListPlaceOpocoWorkingSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoWorkingSideEnum {
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 OrderListPlaceOpocoWorkingSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoPendingSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderListPlaceOpocoPendingSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoPendingSideEnum {
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 OrderListPlaceOpocoPendingSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoPendingAboveTypeEnum {
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
}
impl OrderListPlaceOpocoPendingAboveTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::StopLoss => "STOP_LOSS",
Self::LimitMaker => "LIMIT_MAKER",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoPendingAboveTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"STOP_LOSS" => Ok(Self::StopLoss),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
other => {
Err(format!("invalid OrderListPlaceOpocoPendingAboveTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoNewOrderRespTypeEnum {
#[serde(rename = "ACK")]
Ack,
#[serde(rename = "RESULT")]
Result,
#[serde(rename = "FULL")]
Full,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
}
impl OrderListPlaceOpocoNewOrderRespTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Ack => "ACK",
Self::Result => "RESULT",
Self::Full => "FULL",
Self::Market => "MARKET",
Self::Limit => "LIMIT",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoNewOrderRespTypeEnum {
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),
"FULL" => Ok(Self::Full),
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
other => {
Err(format!("invalid OrderListPlaceOpocoNewOrderRespTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoSelfTradePreventionModeEnum {
#[serde(rename = "NONE")]
None,
#[serde(rename = "EXPIRE_TAKER")]
ExpireTaker,
#[serde(rename = "EXPIRE_MAKER")]
ExpireMaker,
#[serde(rename = "EXPIRE_BOTH")]
ExpireBoth,
#[serde(rename = "DECREMENT")]
Decrement,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderListPlaceOpocoSelfTradePreventionModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::None => "NONE",
Self::ExpireTaker => "EXPIRE_TAKER",
Self::ExpireMaker => "EXPIRE_MAKER",
Self::ExpireBoth => "EXPIRE_BOTH",
Self::Decrement => "DECREMENT",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoSelfTradePreventionModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"NONE" => Ok(Self::None),
"EXPIRE_TAKER" => Ok(Self::ExpireTaker),
"EXPIRE_MAKER" => Ok(Self::ExpireMaker),
"EXPIRE_BOTH" => Ok(Self::ExpireBoth),
"DECREMENT" => Ok(Self::Decrement),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!(
"invalid OrderListPlaceOpocoSelfTradePreventionModeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoWorkingTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceOpocoWorkingTimeInForceEnum {
#[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 OrderListPlaceOpocoWorkingTimeInForceEnum {
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 OrderListPlaceOpocoWorkingTimeInForceEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoWorkingPegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
}
impl OrderListPlaceOpocoWorkingPegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoWorkingPegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
other => Err(format!(
"invalid OrderListPlaceOpocoWorkingPegPriceTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoWorkingPegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
}
impl OrderListPlaceOpocoWorkingPegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoWorkingPegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
other => Err(format!(
"invalid OrderListPlaceOpocoWorkingPegOffsetTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoPendingAboveTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceOpocoPendingAboveTimeInForceEnum {
#[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 OrderListPlaceOpocoPendingAboveTimeInForceEnum {
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 OrderListPlaceOpocoPendingAboveTimeInForceEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoPendingAbovePegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
}
impl OrderListPlaceOpocoPendingAbovePegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoPendingAbovePegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
other => Err(format!(
"invalid OrderListPlaceOpocoPendingAbovePegPriceTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoPendingAbovePegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
}
impl OrderListPlaceOpocoPendingAbovePegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoPendingAbovePegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
other => Err(format!(
"invalid OrderListPlaceOpocoPendingAbovePegOffsetTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoPendingBelowTypeEnum {
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
}
impl OrderListPlaceOpocoPendingBelowTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::StopLoss => "STOP_LOSS",
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoPendingBelowTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"STOP_LOSS" => Ok(Self::StopLoss),
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
other => {
Err(format!("invalid OrderListPlaceOpocoPendingBelowTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoPendingBelowTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceOpocoPendingBelowTimeInForceEnum {
#[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 OrderListPlaceOpocoPendingBelowTimeInForceEnum {
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 OrderListPlaceOpocoPendingBelowTimeInForceEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoPendingBelowPegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
}
impl OrderListPlaceOpocoPendingBelowPegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoPendingBelowPegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
other => Err(format!(
"invalid OrderListPlaceOpocoPendingBelowPegPriceTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOpocoPendingBelowPegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
}
impl OrderListPlaceOpocoPendingBelowPegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
}
}
}
impl std::str::FromStr for OrderListPlaceOpocoPendingBelowPegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
other => Err(format!(
"invalid OrderListPlaceOpocoPendingBelowPegOffsetTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtoWorkingTypeEnum {
#[serde(rename = "LIMIT")]
Limit,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
}
impl OrderListPlaceOtoWorkingTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Limit => "LIMIT",
Self::LimitMaker => "LIMIT_MAKER",
}
}
}
impl std::str::FromStr for OrderListPlaceOtoWorkingTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"LIMIT" => Ok(Self::Limit),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
other => Err(format!("invalid OrderListPlaceOtoWorkingTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtoWorkingSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderListPlaceOtoWorkingSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderListPlaceOtoWorkingSideEnum {
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 OrderListPlaceOtoWorkingSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtoPendingTypeEnum {
#[serde(rename = "LIMIT")]
Limit,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
}
impl OrderListPlaceOtoPendingTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Limit => "LIMIT",
Self::Market => "MARKET",
Self::StopLoss => "STOP_LOSS",
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
Self::LimitMaker => "LIMIT_MAKER",
}
}
}
impl std::str::FromStr for OrderListPlaceOtoPendingTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"LIMIT" => Ok(Self::Limit),
"MARKET" => Ok(Self::Market),
"STOP_LOSS" => Ok(Self::StopLoss),
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
other => Err(format!("invalid OrderListPlaceOtoPendingTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtoPendingSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderListPlaceOtoPendingSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderListPlaceOtoPendingSideEnum {
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 OrderListPlaceOtoPendingSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtoNewOrderRespTypeEnum {
#[serde(rename = "ACK")]
Ack,
#[serde(rename = "RESULT")]
Result,
#[serde(rename = "FULL")]
Full,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
}
impl OrderListPlaceOtoNewOrderRespTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Ack => "ACK",
Self::Result => "RESULT",
Self::Full => "FULL",
Self::Market => "MARKET",
Self::Limit => "LIMIT",
}
}
}
impl std::str::FromStr for OrderListPlaceOtoNewOrderRespTypeEnum {
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),
"FULL" => Ok(Self::Full),
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
other => {
Err(format!("invalid OrderListPlaceOtoNewOrderRespTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtoSelfTradePreventionModeEnum {
#[serde(rename = "NONE")]
None,
#[serde(rename = "EXPIRE_TAKER")]
ExpireTaker,
#[serde(rename = "EXPIRE_MAKER")]
ExpireMaker,
#[serde(rename = "EXPIRE_BOTH")]
ExpireBoth,
#[serde(rename = "DECREMENT")]
Decrement,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderListPlaceOtoSelfTradePreventionModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::None => "NONE",
Self::ExpireTaker => "EXPIRE_TAKER",
Self::ExpireMaker => "EXPIRE_MAKER",
Self::ExpireBoth => "EXPIRE_BOTH",
Self::Decrement => "DECREMENT",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderListPlaceOtoSelfTradePreventionModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"NONE" => Ok(Self::None),
"EXPIRE_TAKER" => Ok(Self::ExpireTaker),
"EXPIRE_MAKER" => Ok(Self::ExpireMaker),
"EXPIRE_BOTH" => Ok(Self::ExpireBoth),
"DECREMENT" => Ok(Self::Decrement),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!(
"invalid OrderListPlaceOtoSelfTradePreventionModeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtoWorkingTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceOtoWorkingTimeInForceEnum {
#[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 OrderListPlaceOtoWorkingTimeInForceEnum {
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 OrderListPlaceOtoWorkingTimeInForceEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtoWorkingPegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
}
impl OrderListPlaceOtoWorkingPegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
}
}
}
impl std::str::FromStr for OrderListPlaceOtoWorkingPegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
other => Err(format!(
"invalid OrderListPlaceOtoWorkingPegPriceTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtoWorkingPegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
}
impl OrderListPlaceOtoWorkingPegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
}
}
}
impl std::str::FromStr for OrderListPlaceOtoWorkingPegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
other => Err(format!(
"invalid OrderListPlaceOtoWorkingPegOffsetTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtoPendingTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceOtoPendingTimeInForceEnum {
#[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 OrderListPlaceOtoPendingTimeInForceEnum {
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 OrderListPlaceOtoPendingTimeInForceEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtoPendingPegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
}
impl OrderListPlaceOtoPendingPegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
}
}
}
impl std::str::FromStr for OrderListPlaceOtoPendingPegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
other => Err(format!(
"invalid OrderListPlaceOtoPendingPegOffsetTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtoPendingPegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
}
impl OrderListPlaceOtoPendingPegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
}
}
}
impl std::str::FromStr for OrderListPlaceOtoPendingPegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
other => Err(format!(
"invalid OrderListPlaceOtoPendingPegPriceTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoWorkingTypeEnum {
#[serde(rename = "LIMIT")]
Limit,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
}
impl OrderListPlaceOtocoWorkingTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Limit => "LIMIT",
Self::LimitMaker => "LIMIT_MAKER",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoWorkingTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"LIMIT" => Ok(Self::Limit),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
other => Err(format!("invalid OrderListPlaceOtocoWorkingTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoWorkingSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderListPlaceOtocoWorkingSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoWorkingSideEnum {
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 OrderListPlaceOtocoWorkingSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoPendingSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderListPlaceOtocoPendingSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoPendingSideEnum {
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 OrderListPlaceOtocoPendingSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoPendingAboveTypeEnum {
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
}
impl OrderListPlaceOtocoPendingAboveTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::StopLoss => "STOP_LOSS",
Self::LimitMaker => "LIMIT_MAKER",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoPendingAboveTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"STOP_LOSS" => Ok(Self::StopLoss),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
other => {
Err(format!("invalid OrderListPlaceOtocoPendingAboveTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoNewOrderRespTypeEnum {
#[serde(rename = "ACK")]
Ack,
#[serde(rename = "RESULT")]
Result,
#[serde(rename = "FULL")]
Full,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
}
impl OrderListPlaceOtocoNewOrderRespTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Ack => "ACK",
Self::Result => "RESULT",
Self::Full => "FULL",
Self::Market => "MARKET",
Self::Limit => "LIMIT",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoNewOrderRespTypeEnum {
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),
"FULL" => Ok(Self::Full),
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
other => {
Err(format!("invalid OrderListPlaceOtocoNewOrderRespTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoSelfTradePreventionModeEnum {
#[serde(rename = "NONE")]
None,
#[serde(rename = "EXPIRE_TAKER")]
ExpireTaker,
#[serde(rename = "EXPIRE_MAKER")]
ExpireMaker,
#[serde(rename = "EXPIRE_BOTH")]
ExpireBoth,
#[serde(rename = "DECREMENT")]
Decrement,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderListPlaceOtocoSelfTradePreventionModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::None => "NONE",
Self::ExpireTaker => "EXPIRE_TAKER",
Self::ExpireMaker => "EXPIRE_MAKER",
Self::ExpireBoth => "EXPIRE_BOTH",
Self::Decrement => "DECREMENT",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoSelfTradePreventionModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"NONE" => Ok(Self::None),
"EXPIRE_TAKER" => Ok(Self::ExpireTaker),
"EXPIRE_MAKER" => Ok(Self::ExpireMaker),
"EXPIRE_BOTH" => Ok(Self::ExpireBoth),
"DECREMENT" => Ok(Self::Decrement),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!(
"invalid OrderListPlaceOtocoSelfTradePreventionModeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoWorkingTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceOtocoWorkingTimeInForceEnum {
#[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 OrderListPlaceOtocoWorkingTimeInForceEnum {
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 OrderListPlaceOtocoWorkingTimeInForceEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoWorkingPegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
}
impl OrderListPlaceOtocoWorkingPegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoWorkingPegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
other => Err(format!(
"invalid OrderListPlaceOtocoWorkingPegPriceTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoWorkingPegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
}
impl OrderListPlaceOtocoWorkingPegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoWorkingPegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
other => Err(format!(
"invalid OrderListPlaceOtocoWorkingPegOffsetTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoPendingAboveTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceOtocoPendingAboveTimeInForceEnum {
#[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 OrderListPlaceOtocoPendingAboveTimeInForceEnum {
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 OrderListPlaceOtocoPendingAboveTimeInForceEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoPendingAbovePegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
}
impl OrderListPlaceOtocoPendingAbovePegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoPendingAbovePegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
other => Err(format!(
"invalid OrderListPlaceOtocoPendingAbovePegPriceTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoPendingAbovePegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
}
impl OrderListPlaceOtocoPendingAbovePegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoPendingAbovePegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
other => Err(format!(
"invalid OrderListPlaceOtocoPendingAbovePegOffsetTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoPendingBelowTypeEnum {
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
}
impl OrderListPlaceOtocoPendingBelowTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::StopLoss => "STOP_LOSS",
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoPendingBelowTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"STOP_LOSS" => Ok(Self::StopLoss),
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
other => {
Err(format!("invalid OrderListPlaceOtocoPendingBelowTypeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoPendingBelowTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
}
impl OrderListPlaceOtocoPendingBelowTimeInForceEnum {
#[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 OrderListPlaceOtocoPendingBelowTimeInForceEnum {
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 OrderListPlaceOtocoPendingBelowTimeInForceEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoPendingBelowPegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
}
impl OrderListPlaceOtocoPendingBelowPegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoPendingBelowPegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
other => Err(format!(
"invalid OrderListPlaceOtocoPendingBelowPegPriceTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderListPlaceOtocoPendingBelowPegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
}
impl OrderListPlaceOtocoPendingBelowPegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
}
}
}
impl std::str::FromStr for OrderListPlaceOtocoPendingBelowPegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
other => Err(format!(
"invalid OrderListPlaceOtocoPendingBelowPegOffsetTypeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderPlaceSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderPlaceSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderPlaceSideEnum {
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 OrderPlaceSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderPlaceTypeEnum {
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderPlaceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Market => "MARKET",
Self::Limit => "LIMIT",
Self::StopLoss => "STOP_LOSS",
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
Self::LimitMaker => "LIMIT_MAKER",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderPlaceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
"STOP_LOSS" => Ok(Self::StopLoss),
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderPlaceTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderPlaceTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderPlaceTimeInForceEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Gtc => "GTC",
Self::Ioc => "IOC",
Self::Fok => "FOK",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderPlaceTimeInForceEnum {
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),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderPlaceTimeInForceEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderPlaceNewOrderRespTypeEnum {
#[serde(rename = "ACK")]
Ack,
#[serde(rename = "RESULT")]
Result,
#[serde(rename = "FULL")]
Full,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
}
impl OrderPlaceNewOrderRespTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Ack => "ACK",
Self::Result => "RESULT",
Self::Full => "FULL",
Self::Market => "MARKET",
Self::Limit => "LIMIT",
}
}
}
impl std::str::FromStr for OrderPlaceNewOrderRespTypeEnum {
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),
"FULL" => Ok(Self::Full),
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
other => Err(format!("invalid OrderPlaceNewOrderRespTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderPlaceSelfTradePreventionModeEnum {
#[serde(rename = "NONE")]
None,
#[serde(rename = "EXPIRE_TAKER")]
ExpireTaker,
#[serde(rename = "EXPIRE_MAKER")]
ExpireMaker,
#[serde(rename = "EXPIRE_BOTH")]
ExpireBoth,
#[serde(rename = "DECREMENT")]
Decrement,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderPlaceSelfTradePreventionModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::None => "NONE",
Self::ExpireTaker => "EXPIRE_TAKER",
Self::ExpireMaker => "EXPIRE_MAKER",
Self::ExpireBoth => "EXPIRE_BOTH",
Self::Decrement => "DECREMENT",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderPlaceSelfTradePreventionModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"NONE" => Ok(Self::None),
"EXPIRE_TAKER" => Ok(Self::ExpireTaker),
"EXPIRE_MAKER" => Ok(Self::ExpireMaker),
"EXPIRE_BOTH" => Ok(Self::ExpireBoth),
"DECREMENT" => Ok(Self::Decrement),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => {
Err(format!("invalid OrderPlaceSelfTradePreventionModeEnum: {}", other).into())
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderPlacePegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderPlacePegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderPlacePegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderPlacePegPriceTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderPlacePegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderPlacePegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderPlacePegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderPlacePegOffsetTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderTestSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl OrderTestSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for OrderTestSideEnum {
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 OrderTestSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderTestTypeEnum {
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderTestTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Market => "MARKET",
Self::Limit => "LIMIT",
Self::StopLoss => "STOP_LOSS",
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
Self::LimitMaker => "LIMIT_MAKER",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderTestTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
"STOP_LOSS" => Ok(Self::StopLoss),
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderTestTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderTestTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderTestTimeInForceEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Gtc => "GTC",
Self::Ioc => "IOC",
Self::Fok => "FOK",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderTestTimeInForceEnum {
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),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderTestTimeInForceEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderTestNewOrderRespTypeEnum {
#[serde(rename = "ACK")]
Ack,
#[serde(rename = "RESULT")]
Result,
#[serde(rename = "FULL")]
Full,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
}
impl OrderTestNewOrderRespTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Ack => "ACK",
Self::Result => "RESULT",
Self::Full => "FULL",
Self::Market => "MARKET",
Self::Limit => "LIMIT",
}
}
}
impl std::str::FromStr for OrderTestNewOrderRespTypeEnum {
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),
"FULL" => Ok(Self::Full),
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
other => Err(format!("invalid OrderTestNewOrderRespTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderTestSelfTradePreventionModeEnum {
#[serde(rename = "NONE")]
None,
#[serde(rename = "EXPIRE_TAKER")]
ExpireTaker,
#[serde(rename = "EXPIRE_MAKER")]
ExpireMaker,
#[serde(rename = "EXPIRE_BOTH")]
ExpireBoth,
#[serde(rename = "DECREMENT")]
Decrement,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderTestSelfTradePreventionModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::None => "NONE",
Self::ExpireTaker => "EXPIRE_TAKER",
Self::ExpireMaker => "EXPIRE_MAKER",
Self::ExpireBoth => "EXPIRE_BOTH",
Self::Decrement => "DECREMENT",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderTestSelfTradePreventionModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"NONE" => Ok(Self::None),
"EXPIRE_TAKER" => Ok(Self::ExpireTaker),
"EXPIRE_MAKER" => Ok(Self::ExpireMaker),
"EXPIRE_BOTH" => Ok(Self::ExpireBoth),
"DECREMENT" => Ok(Self::Decrement),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderTestSelfTradePreventionModeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderTestPegPriceTypeEnum {
#[serde(rename = "PRIMARY_PEG")]
PrimaryPeg,
#[serde(rename = "MARKET_PEG")]
MarketPeg,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderTestPegPriceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PrimaryPeg => "PRIMARY_PEG",
Self::MarketPeg => "MARKET_PEG",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderTestPegPriceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRIMARY_PEG" => Ok(Self::PrimaryPeg),
"MARKET_PEG" => Ok(Self::MarketPeg),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderTestPegPriceTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OrderTestPegOffsetTypeEnum {
#[serde(rename = "PRICE_LEVEL")]
PriceLevel,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl OrderTestPegOffsetTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::PriceLevel => "PRICE_LEVEL",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for OrderTestPegOffsetTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"PRICE_LEVEL" => Ok(Self::PriceLevel),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid OrderTestPegOffsetTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SorOrderPlaceSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl SorOrderPlaceSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for SorOrderPlaceSideEnum {
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 SorOrderPlaceSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SorOrderPlaceTypeEnum {
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl SorOrderPlaceTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Market => "MARKET",
Self::Limit => "LIMIT",
Self::StopLoss => "STOP_LOSS",
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
Self::LimitMaker => "LIMIT_MAKER",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for SorOrderPlaceTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
"STOP_LOSS" => Ok(Self::StopLoss),
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid SorOrderPlaceTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SorOrderPlaceTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl SorOrderPlaceTimeInForceEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Gtc => "GTC",
Self::Ioc => "IOC",
Self::Fok => "FOK",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for SorOrderPlaceTimeInForceEnum {
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),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid SorOrderPlaceTimeInForceEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SorOrderPlaceNewOrderRespTypeEnum {
#[serde(rename = "ACK")]
Ack,
#[serde(rename = "RESULT")]
Result,
#[serde(rename = "FULL")]
Full,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
}
impl SorOrderPlaceNewOrderRespTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Ack => "ACK",
Self::Result => "RESULT",
Self::Full => "FULL",
Self::Market => "MARKET",
Self::Limit => "LIMIT",
}
}
}
impl std::str::FromStr for SorOrderPlaceNewOrderRespTypeEnum {
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),
"FULL" => Ok(Self::Full),
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
other => Err(format!("invalid SorOrderPlaceNewOrderRespTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SorOrderPlaceSelfTradePreventionModeEnum {
#[serde(rename = "NONE")]
None,
#[serde(rename = "EXPIRE_TAKER")]
ExpireTaker,
#[serde(rename = "EXPIRE_MAKER")]
ExpireMaker,
#[serde(rename = "EXPIRE_BOTH")]
ExpireBoth,
#[serde(rename = "DECREMENT")]
Decrement,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl SorOrderPlaceSelfTradePreventionModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::None => "NONE",
Self::ExpireTaker => "EXPIRE_TAKER",
Self::ExpireMaker => "EXPIRE_MAKER",
Self::ExpireBoth => "EXPIRE_BOTH",
Self::Decrement => "DECREMENT",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for SorOrderPlaceSelfTradePreventionModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"NONE" => Ok(Self::None),
"EXPIRE_TAKER" => Ok(Self::ExpireTaker),
"EXPIRE_MAKER" => Ok(Self::ExpireMaker),
"EXPIRE_BOTH" => Ok(Self::ExpireBoth),
"DECREMENT" => Ok(Self::Decrement),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!(
"invalid SorOrderPlaceSelfTradePreventionModeEnum: {}",
other
)
.into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SorOrderTestSideEnum {
#[serde(rename = "BUY")]
Buy,
#[serde(rename = "SELL")]
Sell,
}
impl SorOrderTestSideEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Buy => "BUY",
Self::Sell => "SELL",
}
}
}
impl std::str::FromStr for SorOrderTestSideEnum {
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 SorOrderTestSideEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SorOrderTestTypeEnum {
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
#[serde(rename = "STOP_LOSS")]
StopLoss,
#[serde(rename = "STOP_LOSS_LIMIT")]
StopLossLimit,
#[serde(rename = "TAKE_PROFIT")]
TakeProfit,
#[serde(rename = "TAKE_PROFIT_LIMIT")]
TakeProfitLimit,
#[serde(rename = "LIMIT_MAKER")]
LimitMaker,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl SorOrderTestTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Market => "MARKET",
Self::Limit => "LIMIT",
Self::StopLoss => "STOP_LOSS",
Self::StopLossLimit => "STOP_LOSS_LIMIT",
Self::TakeProfit => "TAKE_PROFIT",
Self::TakeProfitLimit => "TAKE_PROFIT_LIMIT",
Self::LimitMaker => "LIMIT_MAKER",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for SorOrderTestTypeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
"STOP_LOSS" => Ok(Self::StopLoss),
"STOP_LOSS_LIMIT" => Ok(Self::StopLossLimit),
"TAKE_PROFIT" => Ok(Self::TakeProfit),
"TAKE_PROFIT_LIMIT" => Ok(Self::TakeProfitLimit),
"LIMIT_MAKER" => Ok(Self::LimitMaker),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid SorOrderTestTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SorOrderTestTimeInForceEnum {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl SorOrderTestTimeInForceEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Gtc => "GTC",
Self::Ioc => "IOC",
Self::Fok => "FOK",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for SorOrderTestTimeInForceEnum {
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),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => Err(format!("invalid SorOrderTestTimeInForceEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SorOrderTestNewOrderRespTypeEnum {
#[serde(rename = "ACK")]
Ack,
#[serde(rename = "RESULT")]
Result,
#[serde(rename = "FULL")]
Full,
#[serde(rename = "MARKET")]
Market,
#[serde(rename = "LIMIT")]
Limit,
}
impl SorOrderTestNewOrderRespTypeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Ack => "ACK",
Self::Result => "RESULT",
Self::Full => "FULL",
Self::Market => "MARKET",
Self::Limit => "LIMIT",
}
}
}
impl std::str::FromStr for SorOrderTestNewOrderRespTypeEnum {
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),
"FULL" => Ok(Self::Full),
"MARKET" => Ok(Self::Market),
"LIMIT" => Ok(Self::Limit),
other => Err(format!("invalid SorOrderTestNewOrderRespTypeEnum: {}", other).into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SorOrderTestSelfTradePreventionModeEnum {
#[serde(rename = "NONE")]
None,
#[serde(rename = "EXPIRE_TAKER")]
ExpireTaker,
#[serde(rename = "EXPIRE_MAKER")]
ExpireMaker,
#[serde(rename = "EXPIRE_BOTH")]
ExpireBoth,
#[serde(rename = "DECREMENT")]
Decrement,
#[serde(rename = "NON_REPRESENTABLE")]
NonRepresentable,
}
impl SorOrderTestSelfTradePreventionModeEnum {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::None => "NONE",
Self::ExpireTaker => "EXPIRE_TAKER",
Self::ExpireMaker => "EXPIRE_MAKER",
Self::ExpireBoth => "EXPIRE_BOTH",
Self::Decrement => "DECREMENT",
Self::NonRepresentable => "NON_REPRESENTABLE",
}
}
}
impl std::str::FromStr for SorOrderTestSelfTradePreventionModeEnum {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"NONE" => Ok(Self::None),
"EXPIRE_TAKER" => Ok(Self::ExpireTaker),
"EXPIRE_MAKER" => Ok(Self::ExpireMaker),
"EXPIRE_BOTH" => Ok(Self::ExpireBoth),
"DECREMENT" => Ok(Self::Decrement),
"NON_REPRESENTABLE" => Ok(Self::NonRepresentable),
other => {
Err(format!("invalid SorOrderTestSelfTradePreventionModeEnum: {}", other).into())
}
}
}
}
/// Request parameters for the [`open_orders_cancel_all`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`open_orders_cancel_all`](#method.open_orders_cancel_all).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OpenOrdersCancelAllParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub 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 OpenOrdersCancelAllParams {
/// Create a builder for [`open_orders_cancel_all`].
///
/// Required parameters:
///
/// * `symbol` — String
///
#[must_use]
pub fn builder(symbol: String) -> OpenOrdersCancelAllParamsBuilder {
OpenOrdersCancelAllParamsBuilder::default().symbol(symbol)
}
}
/// Request parameters for the [`order_amend_keep_priority`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_amend_keep_priority`](#method.order_amend_keep_priority).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderAmendKeepPriorityParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
/// `newQty` must be greater than 0 and less than the order's quantity.
///
/// This field is **required.
#[builder(setter(into))]
pub new_qty: rust_decimal::Decimal,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
/// `orderId`or`origClientOrderId`mustbesent
///
/// This field is **optional.
#[builder(setter(into), default)]
pub order_id: Option<i64>,
/// `orderId`or`origClientOrderId`mustbesent
///
/// This field is **optional.
#[builder(setter(into), default)]
pub orig_client_order_id: Option<String>,
/// The new client order ID for the order after being amended. <br> If not sent, one will be randomly generated. <br> It is possible to reuse the current clientOrderId by sending it as the `newClientOrderId`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_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 OrderAmendKeepPriorityParams {
/// Create a builder for [`order_amend_keep_priority`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `new_qty` — `newQty` must be greater than 0 and less than the order's quantity.
///
#[must_use]
pub fn builder(
symbol: String,
new_qty: rust_decimal::Decimal,
) -> OrderAmendKeepPriorityParamsBuilder {
OrderAmendKeepPriorityParamsBuilder::default()
.symbol(symbol)
.new_qty(new_qty)
}
}
/// Request parameters for the [`order_cancel`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_cancel`](#method.order_cancel).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderCancelParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
/// `orderId`or`origClientOrderId`mustbesent
///
/// This field is **optional.
#[builder(setter(into), default)]
pub order_id: Option<i64>,
/// `orderId`or`origClientOrderId`mustbesent
///
/// This field is **optional.
#[builder(setter(into), default)]
pub orig_client_order_id: Option<String>,
/// The new client order ID for the order after being amended. <br> If not sent, one will be randomly generated. <br> It is possible to reuse the current clientOrderId by sending it as the `newClientOrderId`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_client_order_id: Option<String>,
///
/// The `cancel_restrictions` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub cancel_restrictions: Option<OrderCancelCancelRestrictionsEnum>,
/// 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 OrderCancelParams {
/// Create a builder for [`order_cancel`].
///
/// Required parameters:
///
/// * `symbol` — String
///
#[must_use]
pub fn builder(symbol: String) -> OrderCancelParamsBuilder {
OrderCancelParamsBuilder::default().symbol(symbol)
}
}
/// Request parameters for the [`order_cancel_replace`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_cancel_replace`](#method.order_cancel_replace).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderCancelReplaceParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `cancel_replace_mode` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub cancel_replace_mode: OrderCancelReplaceCancelReplaceModeEnum,
///
/// The `side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub side: OrderCancelReplaceSideEnum,
///
/// The `r#type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub r#type: OrderCancelReplaceTypeEnum,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
/// Cancel order by orderId
///
/// This field is **optional.
#[builder(setter(into), default)]
pub cancel_order_id: Option<i64>,
///
/// The `cancel_orig_client_order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub cancel_orig_client_order_id: Option<String>,
/// New ID for the canceled order. Automatically generated if not sent
///
/// This field is **optional.
#[builder(setter(into), default)]
pub cancel_new_client_order_id: Option<String>,
///
/// The `time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub time_in_force: Option<OrderCancelReplaceTimeInForceEnum>,
///
/// The `price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub price: Option<rust_decimal::Decimal>,
///
/// The `quantity` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub quantity: Option<rust_decimal::Decimal>,
///
/// The `quote_order_qty` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub quote_order_qty: Option<rust_decimal::Decimal>,
/// The new client order ID for the order after being amended. <br> If not sent, one will be randomly generated. <br> It is possible to reuse the current clientOrderId by sending it as the `newClientOrderId`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_client_order_id: Option<String>,
///
/// The `new_order_resp_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_order_resp_type: Option<OrderCancelReplaceNewOrderRespTypeEnum>,
///
/// The `stop_price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub stop_price: Option<rust_decimal::Decimal>,
/// See Trailing Stop order FAQ
///
/// This field is **optional.
#[builder(setter(into), default)]
pub trailing_delta: Option<rust_decimal::Decimal>,
///
/// The `iceberg_qty` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub iceberg_qty: Option<rust_decimal::Decimal>,
/// Arbitrary numeric value identifying the order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the order strategy.
/// Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub strategy_type: Option<i32>,
///
/// The `self_trade_prevention_mode` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub self_trade_prevention_mode: Option<OrderCancelReplaceSelfTradePreventionModeEnum>,
///
/// The `cancel_restrictions` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub cancel_restrictions: Option<OrderCancelReplaceCancelRestrictionsEnum>,
///
/// The `order_rate_limit_exceeded_mode` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub order_rate_limit_exceeded_mode: Option<OrderCancelReplaceOrderRateLimitExceededModeEnum>,
///
/// The `peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub peg_price_type: Option<OrderCancelReplacePegPriceTypeEnum>,
/// Price level to peg the price to (max: 100)
/// See Pegged Orders
///
/// This field is **optional.
#[builder(setter(into), default)]
pub peg_offset_value: Option<i32>,
///
/// The `peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub peg_offset_type: Option<OrderCancelReplacePegOffsetTypeEnum>,
/// 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 OrderCancelReplaceParams {
/// Create a builder for [`order_cancel_replace`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `cancel_replace_mode` — String
/// * `side` — String
/// * `r#type` — String
///
#[must_use]
pub fn builder(
symbol: String,
cancel_replace_mode: OrderCancelReplaceCancelReplaceModeEnum,
side: OrderCancelReplaceSideEnum,
r#type: OrderCancelReplaceTypeEnum,
) -> OrderCancelReplaceParamsBuilder {
OrderCancelReplaceParamsBuilder::default()
.symbol(symbol)
.cancel_replace_mode(cancel_replace_mode)
.side(side)
.r#type(r#type)
}
}
/// Request parameters for the [`order_list_cancel`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_list_cancel`](#method.order_list_cancel).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderListCancelParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
/// Cancel order list by orderListId
///
/// This field is **optional.
#[builder(setter(into), default)]
pub order_list_id: Option<i32>,
///
/// The `list_client_order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub list_client_order_id: Option<String>,
/// The new client order ID for the order after being amended. <br> If not sent, one will be randomly generated. <br> It is possible to reuse the current clientOrderId by sending it as the `newClientOrderId`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_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 OrderListCancelParams {
/// Create a builder for [`order_list_cancel`].
///
/// Required parameters:
///
/// * `symbol` — String
///
#[must_use]
pub fn builder(symbol: String) -> OrderListCancelParamsBuilder {
OrderListCancelParamsBuilder::default().symbol(symbol)
}
}
/// Request parameters for the [`order_list_place`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_list_place`](#method.order_list_place).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderListPlaceParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub side: OrderListPlaceSideEnum,
/// Price for the limit order
///
/// This field is **required.
#[builder(setter(into))]
pub price: rust_decimal::Decimal,
///
/// The `quantity` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub quantity: rust_decimal::Decimal,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
///
/// The `list_client_order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub list_client_order_id: Option<String>,
/// Arbitrary unique ID among open orders for the limit order. Automatically generated if not sent
///
/// This field is **optional.
#[builder(setter(into), default)]
pub limit_client_order_id: Option<String>,
///
/// The `limit_iceberg_qty` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub limit_iceberg_qty: Option<rust_decimal::Decimal>,
/// Arbitrary numeric value identifying the limit order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub limit_strategy_id: Option<i64>,
/// <p>Arbitrary numeric value identifying the limit order strategy.</p><p>Values smaller than `1000000` are reserved and cannot be used.</p>
///
/// This field is **optional.
#[builder(setter(into), default)]
pub limit_strategy_type: Option<i32>,
///
/// The `stop_price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub stop_price: Option<rust_decimal::Decimal>,
/// See [Trailing Stop order FAQ](faqs/trailing-stop-faq.md)
///
/// This field is **optional.
#[builder(setter(into), default)]
pub trailing_delta: Option<i32>,
/// Arbitrary unique ID among open orders for the stop order. Automatically generated if not sent
///
/// This field is **optional.
#[builder(setter(into), default)]
pub stop_client_order_id: Option<String>,
///
/// The `stop_limit_price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub stop_limit_price: Option<rust_decimal::Decimal>,
///
/// The `stop_limit_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub stop_limit_time_in_force: Option<OrderListPlaceStopLimitTimeInForceEnum>,
///
/// The `stop_iceberg_qty` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub stop_iceberg_qty: Option<rust_decimal::Decimal>,
/// Arbitrary numeric value identifying the stop order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub stop_strategy_id: Option<i64>,
/// <p>Arbitrary numeric value identifying the stop order strategy.</p><p>Values smaller than `1000000` are reserved and cannot be used.</p>
///
/// This field is **optional.
#[builder(setter(into), default)]
pub stop_strategy_type: Option<i32>,
///
/// The `new_order_resp_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_order_resp_type: Option<OrderListPlaceNewOrderRespTypeEnum>,
///
/// The `self_trade_prevention_mode` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub self_trade_prevention_mode: Option<OrderListPlaceSelfTradePreventionModeEnum>,
/// 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 OrderListPlaceParams {
/// Create a builder for [`order_list_place`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `side` — String
/// * `price` — Price for the limit order
/// * `quantity` — `rust_decimal::Decimal`
///
#[must_use]
pub fn builder(
symbol: String,
side: OrderListPlaceSideEnum,
price: rust_decimal::Decimal,
quantity: rust_decimal::Decimal,
) -> OrderListPlaceParamsBuilder {
OrderListPlaceParamsBuilder::default()
.symbol(symbol)
.side(side)
.price(price)
.quantity(quantity)
}
}
/// Request parameters for the [`order_list_place_oco`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_list_place_oco`](#method.order_list_place_oco).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderListPlaceOcoParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub side: OrderListPlaceOcoSideEnum,
///
/// The `quantity` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub quantity: rust_decimal::Decimal,
///
/// The `above_type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub above_type: OrderListPlaceOcoAboveTypeEnum,
///
/// The `below_type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub below_type: OrderListPlaceOcoBelowTypeEnum,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
///
/// The `list_client_order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub list_client_order_id: Option<String>,
/// Arbitrary unique ID among open orders for the above order. Automatically generated if not sent
///
/// This field is **optional.
#[builder(setter(into), default)]
pub above_client_order_id: Option<String>,
/// Note that this can only be used if `aboveTimeInForce` is `GTC`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub above_iceberg_qty: Option<i64>,
/// Can be used if `aboveType` is `STOP_LOSS_LIMIT` , `LIMIT_MAKER`, or `TAKE_PROFIT_LIMIT` to specify the limit price.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub above_price: Option<rust_decimal::Decimal>,
/// Can be used if `aboveType` is `STOP_LOSS`, `STOP_LOSS_LIMIT`, `TAKE_PROFIT`, `TAKE_PROFIT_LIMIT`. <br>Either `aboveStopPrice` or `aboveTrailingDelta` or both, must be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub above_stop_price: Option<rust_decimal::Decimal>,
/// See [Trailing Stop order FAQ](faqs/trailing-stop-faq.md).
///
/// This field is **optional.
#[builder(setter(into), default)]
pub above_trailing_delta: Option<i64>,
///
/// The `above_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub above_time_in_force: Option<OrderListPlaceOcoAboveTimeInForceEnum>,
/// Arbitrary numeric value identifying the above order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub above_strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the above order strategy. <br>Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub above_strategy_type: Option<i32>,
///
/// The `above_peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub above_peg_price_type: Option<OrderListPlaceOcoAbovePegPriceTypeEnum>,
///
/// The `above_peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub above_peg_offset_type: Option<OrderListPlaceOcoAbovePegOffsetTypeEnum>,
///
/// The `above_peg_offset_value` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub above_peg_offset_value: Option<i32>,
///
/// The `below_client_order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub below_client_order_id: Option<String>,
/// Note that this can only be used if `belowTimeInForce` is `GTC`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub below_iceberg_qty: Option<i64>,
/// Can be used if `belowType` is `STOP_LOSS_LIMIT` , `LIMIT_MAKER`, or `TAKE_PROFIT_LIMIT` to specify the limit price.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub below_price: Option<rust_decimal::Decimal>,
/// Can be used if `belowType` is `STOP_LOSS`, `STOP_LOSS_LIMIT`, `TAKE_PROFIT` or `TAKE_PROFIT_LIMIT`. <br>Either `belowStopPrice` or `belowTrailingDelta` or both, must be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub below_stop_price: Option<rust_decimal::Decimal>,
/// See [Trailing Stop order FAQ](faqs/trailing-stop-faq.md).
///
/// This field is **optional.
#[builder(setter(into), default)]
pub below_trailing_delta: Option<i64>,
///
/// The `below_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub below_time_in_force: Option<OrderListPlaceOcoBelowTimeInForceEnum>,
/// Arbitrary numeric value identifying the below order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub below_strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the below order strategy. <br>Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub below_strategy_type: Option<i32>,
///
/// The `below_peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub below_peg_price_type: Option<OrderListPlaceOcoBelowPegPriceTypeEnum>,
///
/// The `below_peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub below_peg_offset_type: Option<OrderListPlaceOcoBelowPegOffsetTypeEnum>,
///
/// The `below_peg_offset_value` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub below_peg_offset_value: Option<i32>,
///
/// The `new_order_resp_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_order_resp_type: Option<OrderListPlaceOcoNewOrderRespTypeEnum>,
///
/// The `self_trade_prevention_mode` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub self_trade_prevention_mode: Option<OrderListPlaceOcoSelfTradePreventionModeEnum>,
/// 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 OrderListPlaceOcoParams {
/// Create a builder for [`order_list_place_oco`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `side` — String
/// * `quantity` — `rust_decimal::Decimal`
/// * `above_type` — String
/// * `below_type` — String
///
#[must_use]
pub fn builder(
symbol: String,
side: OrderListPlaceOcoSideEnum,
quantity: rust_decimal::Decimal,
above_type: OrderListPlaceOcoAboveTypeEnum,
below_type: OrderListPlaceOcoBelowTypeEnum,
) -> OrderListPlaceOcoParamsBuilder {
OrderListPlaceOcoParamsBuilder::default()
.symbol(symbol)
.side(side)
.quantity(quantity)
.above_type(above_type)
.below_type(below_type)
}
}
/// Request parameters for the [`order_list_place_opo`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_list_place_opo`](#method.order_list_place_opo).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderListPlaceOpoParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `working_type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub working_type: OrderListPlaceOpoWorkingTypeEnum,
///
/// The `working_side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub working_side: OrderListPlaceOpoWorkingSideEnum,
///
/// The `working_price` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub working_price: rust_decimal::Decimal,
/// Sets the quantity for the working order.
///
/// This field is **required.
#[builder(setter(into))]
pub working_quantity: rust_decimal::Decimal,
///
/// The `pending_type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub pending_type: OrderListPlaceOpoPendingTypeEnum,
///
/// The `pending_side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub pending_side: OrderListPlaceOpoPendingSideEnum,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
///
/// The `list_client_order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub list_client_order_id: Option<String>,
///
/// The `new_order_resp_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_order_resp_type: Option<OrderListPlaceOpoNewOrderRespTypeEnum>,
///
/// The `self_trade_prevention_mode` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub self_trade_prevention_mode: Option<OrderListPlaceOpoSelfTradePreventionModeEnum>,
/// Arbitrary unique ID among open orders for the working order. Automatically generated if not sent.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_client_order_id: Option<String>,
/// This can only be used if `workingTimeInForce` is `GTC`, or if `workingType` is `LIMIT_MAKER`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_iceberg_qty: Option<rust_decimal::Decimal>,
///
/// The `working_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_time_in_force: Option<OrderListPlaceOpoWorkingTimeInForceEnum>,
/// Arbitrary numeric value identifying the working order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the working order strategy. Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_strategy_type: Option<i32>,
///
/// The `working_peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_peg_price_type: Option<OrderListPlaceOpoWorkingPegPriceTypeEnum>,
///
/// The `working_peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_peg_offset_type: Option<OrderListPlaceOpoWorkingPegOffsetTypeEnum>,
///
/// The `working_peg_offset_value` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_peg_offset_value: Option<i32>,
/// Arbitrary unique ID among open orders for the pending order. Automatically generated if not sent.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_client_order_id: Option<String>,
///
/// The `pending_price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_price: Option<rust_decimal::Decimal>,
///
/// The `pending_stop_price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_stop_price: Option<rust_decimal::Decimal>,
///
/// The `pending_trailing_delta` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_trailing_delta: Option<rust_decimal::Decimal>,
/// This can only be used if `pendingTimeInForce` is `GTC` or if `pendingType` is `LIMIT_MAKER`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_iceberg_qty: Option<rust_decimal::Decimal>,
///
/// The `pending_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_time_in_force: Option<OrderListPlaceOpoPendingTimeInForceEnum>,
/// Arbitrary numeric value identifying the pending order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the pending order strategy. Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_strategy_type: Option<i32>,
///
/// The `pending_peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_peg_price_type: Option<OrderListPlaceOpoPendingPegPriceTypeEnum>,
///
/// The `pending_peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_peg_offset_type: Option<OrderListPlaceOpoPendingPegOffsetTypeEnum>,
///
/// The `pending_peg_offset_value` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_peg_offset_value: 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 OrderListPlaceOpoParams {
/// Create a builder for [`order_list_place_opo`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `working_type` — String
/// * `working_side` — String
/// * `working_price` — `rust_decimal::Decimal`
/// * `working_quantity` — Sets the quantity for the working order.
/// * `pending_type` — String
/// * `pending_side` — String
///
#[must_use]
pub fn builder(
symbol: String,
working_type: OrderListPlaceOpoWorkingTypeEnum,
working_side: OrderListPlaceOpoWorkingSideEnum,
working_price: rust_decimal::Decimal,
working_quantity: rust_decimal::Decimal,
pending_type: OrderListPlaceOpoPendingTypeEnum,
pending_side: OrderListPlaceOpoPendingSideEnum,
) -> OrderListPlaceOpoParamsBuilder {
OrderListPlaceOpoParamsBuilder::default()
.symbol(symbol)
.working_type(working_type)
.working_side(working_side)
.working_price(working_price)
.working_quantity(working_quantity)
.pending_type(pending_type)
.pending_side(pending_side)
}
}
/// Request parameters for the [`order_list_place_opoco`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_list_place_opoco`](#method.order_list_place_opoco).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderListPlaceOpocoParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `working_type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub working_type: OrderListPlaceOpocoWorkingTypeEnum,
///
/// The `working_side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub working_side: OrderListPlaceOpocoWorkingSideEnum,
///
/// The `working_price` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub working_price: rust_decimal::Decimal,
/// Sets the quantity for the working order.
///
/// This field is **required.
#[builder(setter(into))]
pub working_quantity: rust_decimal::Decimal,
///
/// The `pending_side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub pending_side: OrderListPlaceOpocoPendingSideEnum,
///
/// The `pending_above_type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub pending_above_type: OrderListPlaceOpocoPendingAboveTypeEnum,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
///
/// The `list_client_order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub list_client_order_id: Option<String>,
///
/// The `new_order_resp_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_order_resp_type: Option<OrderListPlaceOpocoNewOrderRespTypeEnum>,
///
/// The `self_trade_prevention_mode` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub self_trade_prevention_mode: Option<OrderListPlaceOpocoSelfTradePreventionModeEnum>,
/// Arbitrary unique ID among open orders for the working order. Automatically generated if not sent.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_client_order_id: Option<String>,
/// This can only be used if `workingTimeInForce` is `GTC`, or if `workingType` is `LIMIT_MAKER`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_iceberg_qty: Option<rust_decimal::Decimal>,
///
/// The `working_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_time_in_force: Option<OrderListPlaceOpocoWorkingTimeInForceEnum>,
/// Arbitrary numeric value identifying the working order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the working order strategy. Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_strategy_type: Option<i32>,
///
/// The `working_peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_peg_price_type: Option<OrderListPlaceOpocoWorkingPegPriceTypeEnum>,
///
/// The `working_peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_peg_offset_type: Option<OrderListPlaceOpocoWorkingPegOffsetTypeEnum>,
///
/// The `working_peg_offset_value` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_peg_offset_value: Option<i32>,
/// Arbitrary unique ID among open orders for the pending above order. Automatically generated if not sent.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_client_order_id: Option<String>,
/// Can be used if `pendingAboveType` is `STOP_LOSS_LIMIT` , `LIMIT_MAKER`, or `TAKE_PROFIT_LIMIT` to specify the limit price.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_price: Option<rust_decimal::Decimal>,
/// Can be used if `pendingAboveType` is `STOP_LOSS`, `STOP_LOSS_LIMIT`, `TAKE_PROFIT`, `TAKE_PROFIT_LIMIT`
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_stop_price: Option<rust_decimal::Decimal>,
/// See [Trailing Stop FAQ](./faqs/trailing-stop-faq.md)
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_trailing_delta: Option<rust_decimal::Decimal>,
/// This can only be used if `pendingAboveTimeInForce` is `GTC` or if `pendingAboveType` is `LIMIT_MAKER`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_iceberg_qty: Option<rust_decimal::Decimal>,
///
/// The `pending_above_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_time_in_force: Option<OrderListPlaceOpocoPendingAboveTimeInForceEnum>,
/// Arbitrary numeric value identifying the pending above order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the pending above order strategy. Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_strategy_type: Option<i32>,
///
/// The `pending_above_peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_peg_price_type: Option<OrderListPlaceOpocoPendingAbovePegPriceTypeEnum>,
///
/// The `pending_above_peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_peg_offset_type: Option<OrderListPlaceOpocoPendingAbovePegOffsetTypeEnum>,
///
/// The `pending_above_peg_offset_value` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_peg_offset_value: Option<i32>,
///
/// The `pending_below_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_type: Option<OrderListPlaceOpocoPendingBelowTypeEnum>,
/// Arbitrary unique ID among open orders for the pending below order. Automatically generated if not sent.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_client_order_id: Option<String>,
/// Can be used if `pendingBelowType` is `STOP_LOSS_LIMIT` or `TAKE_PROFIT_LIMIT` to specify limit price
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_price: Option<rust_decimal::Decimal>,
/// Can be used if `pendingBelowType` is `STOP_LOSS`, `STOP_LOSS_LIMIT, TAKE_PROFIT or TAKE_PROFIT_LIMIT`. Either `pendingBelowStopPrice` or `pendingBelowTrailingDelta` or both, must be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_stop_price: Option<rust_decimal::Decimal>,
///
/// The `pending_below_trailing_delta` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_trailing_delta: Option<rust_decimal::Decimal>,
/// This can only be used if `pendingBelowTimeInForce` is `GTC`, or if `pendingBelowType` is `LIMIT_MAKER`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_iceberg_qty: Option<rust_decimal::Decimal>,
///
/// The `pending_below_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_time_in_force: Option<OrderListPlaceOpocoPendingBelowTimeInForceEnum>,
/// Arbitrary numeric value identifying the pending below order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the pending below order strategy. Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_strategy_type: Option<i32>,
///
/// The `pending_below_peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_peg_price_type: Option<OrderListPlaceOpocoPendingBelowPegPriceTypeEnum>,
///
/// The `pending_below_peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_peg_offset_type: Option<OrderListPlaceOpocoPendingBelowPegOffsetTypeEnum>,
///
/// The `pending_below_peg_offset_value` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_peg_offset_value: 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 OrderListPlaceOpocoParams {
/// Create a builder for [`order_list_place_opoco`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `working_type` — String
/// * `working_side` — String
/// * `working_price` — `rust_decimal::Decimal`
/// * `working_quantity` — Sets the quantity for the working order.
/// * `pending_side` — String
/// * `pending_above_type` — String
///
#[must_use]
pub fn builder(
symbol: String,
working_type: OrderListPlaceOpocoWorkingTypeEnum,
working_side: OrderListPlaceOpocoWorkingSideEnum,
working_price: rust_decimal::Decimal,
working_quantity: rust_decimal::Decimal,
pending_side: OrderListPlaceOpocoPendingSideEnum,
pending_above_type: OrderListPlaceOpocoPendingAboveTypeEnum,
) -> OrderListPlaceOpocoParamsBuilder {
OrderListPlaceOpocoParamsBuilder::default()
.symbol(symbol)
.working_type(working_type)
.working_side(working_side)
.working_price(working_price)
.working_quantity(working_quantity)
.pending_side(pending_side)
.pending_above_type(pending_above_type)
}
}
/// Request parameters for the [`order_list_place_oto`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_list_place_oto`](#method.order_list_place_oto).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderListPlaceOtoParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `working_type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub working_type: OrderListPlaceOtoWorkingTypeEnum,
///
/// The `working_side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub working_side: OrderListPlaceOtoWorkingSideEnum,
///
/// The `working_price` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub working_price: rust_decimal::Decimal,
/// Sets the quantity for the working order.
///
/// This field is **required.
#[builder(setter(into))]
pub working_quantity: rust_decimal::Decimal,
///
/// The `pending_type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub pending_type: OrderListPlaceOtoPendingTypeEnum,
///
/// The `pending_side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub pending_side: OrderListPlaceOtoPendingSideEnum,
/// Sets the quantity for the pending order.
///
/// This field is **required.
#[builder(setter(into))]
pub pending_quantity: rust_decimal::Decimal,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
///
/// The `list_client_order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub list_client_order_id: Option<String>,
///
/// The `new_order_resp_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_order_resp_type: Option<OrderListPlaceOtoNewOrderRespTypeEnum>,
///
/// The `self_trade_prevention_mode` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub self_trade_prevention_mode: Option<OrderListPlaceOtoSelfTradePreventionModeEnum>,
/// Arbitrary unique ID among open orders for the working order. Automatically generated if not sent.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_client_order_id: Option<String>,
/// This can only be used if `workingTimeInForce` is `GTC`, or if `workingType` is `LIMIT_MAKER`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_iceberg_qty: Option<rust_decimal::Decimal>,
///
/// The `working_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_time_in_force: Option<OrderListPlaceOtoWorkingTimeInForceEnum>,
/// Arbitrary numeric value identifying the working order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the working order strategy. Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_strategy_type: Option<i32>,
///
/// The `working_peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_peg_price_type: Option<OrderListPlaceOtoWorkingPegPriceTypeEnum>,
///
/// The `working_peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_peg_offset_type: Option<OrderListPlaceOtoWorkingPegOffsetTypeEnum>,
///
/// The `working_peg_offset_value` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_peg_offset_value: Option<i32>,
/// Arbitrary unique ID among open orders for the pending order. Automatically generated if not sent.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_client_order_id: Option<String>,
///
/// The `pending_price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_price: Option<rust_decimal::Decimal>,
///
/// The `pending_stop_price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_stop_price: Option<rust_decimal::Decimal>,
///
/// The `pending_trailing_delta` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_trailing_delta: Option<rust_decimal::Decimal>,
/// This can only be used if `pendingTimeInForce` is `GTC` or if `pendingType` is `LIMIT_MAKER`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_iceberg_qty: Option<rust_decimal::Decimal>,
///
/// The `pending_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_time_in_force: Option<OrderListPlaceOtoPendingTimeInForceEnum>,
/// Arbitrary numeric value identifying the pending order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the pending order strategy. Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_strategy_type: Option<i32>,
///
/// The `pending_peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_peg_offset_type: Option<OrderListPlaceOtoPendingPegOffsetTypeEnum>,
///
/// The `pending_peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_peg_price_type: Option<OrderListPlaceOtoPendingPegPriceTypeEnum>,
///
/// The `pending_peg_offset_value` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_peg_offset_value: 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 OrderListPlaceOtoParams {
/// Create a builder for [`order_list_place_oto`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `working_type` — String
/// * `working_side` — String
/// * `working_price` — `rust_decimal::Decimal`
/// * `working_quantity` — Sets the quantity for the working order.
/// * `pending_type` — String
/// * `pending_side` — String
/// * `pending_quantity` — Sets the quantity for the pending order.
///
#[must_use]
pub fn builder(
symbol: String,
working_type: OrderListPlaceOtoWorkingTypeEnum,
working_side: OrderListPlaceOtoWorkingSideEnum,
working_price: rust_decimal::Decimal,
working_quantity: rust_decimal::Decimal,
pending_type: OrderListPlaceOtoPendingTypeEnum,
pending_side: OrderListPlaceOtoPendingSideEnum,
pending_quantity: rust_decimal::Decimal,
) -> OrderListPlaceOtoParamsBuilder {
OrderListPlaceOtoParamsBuilder::default()
.symbol(symbol)
.working_type(working_type)
.working_side(working_side)
.working_price(working_price)
.working_quantity(working_quantity)
.pending_type(pending_type)
.pending_side(pending_side)
.pending_quantity(pending_quantity)
}
}
/// Request parameters for the [`order_list_place_otoco`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_list_place_otoco`](#method.order_list_place_otoco).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderListPlaceOtocoParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `working_type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub working_type: OrderListPlaceOtocoWorkingTypeEnum,
///
/// The `working_side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub working_side: OrderListPlaceOtocoWorkingSideEnum,
///
/// The `working_price` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub working_price: rust_decimal::Decimal,
/// Sets the quantity for the working order.
///
/// This field is **required.
#[builder(setter(into))]
pub working_quantity: rust_decimal::Decimal,
///
/// The `pending_side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub pending_side: OrderListPlaceOtocoPendingSideEnum,
/// Sets the quantity for the pending order.
///
/// This field is **required.
#[builder(setter(into))]
pub pending_quantity: rust_decimal::Decimal,
///
/// The `pending_above_type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub pending_above_type: OrderListPlaceOtocoPendingAboveTypeEnum,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
///
/// The `list_client_order_id` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub list_client_order_id: Option<String>,
///
/// The `new_order_resp_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_order_resp_type: Option<OrderListPlaceOtocoNewOrderRespTypeEnum>,
///
/// The `self_trade_prevention_mode` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub self_trade_prevention_mode: Option<OrderListPlaceOtocoSelfTradePreventionModeEnum>,
/// Arbitrary unique ID among open orders for the working order. Automatically generated if not sent.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_client_order_id: Option<String>,
/// This can only be used if `workingTimeInForce` is `GTC`, or if `workingType` is `LIMIT_MAKER`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_iceberg_qty: Option<rust_decimal::Decimal>,
///
/// The `working_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_time_in_force: Option<OrderListPlaceOtocoWorkingTimeInForceEnum>,
/// Arbitrary numeric value identifying the working order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the working order strategy. Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_strategy_type: Option<i32>,
///
/// The `working_peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_peg_price_type: Option<OrderListPlaceOtocoWorkingPegPriceTypeEnum>,
///
/// The `working_peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_peg_offset_type: Option<OrderListPlaceOtocoWorkingPegOffsetTypeEnum>,
///
/// The `working_peg_offset_value` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub working_peg_offset_value: Option<i32>,
/// Arbitrary unique ID among open orders for the pending above order. Automatically generated if not sent.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_client_order_id: Option<String>,
/// Can be used if `pendingAboveType` is `STOP_LOSS_LIMIT` , `LIMIT_MAKER`, or `TAKE_PROFIT_LIMIT` to specify the limit price.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_price: Option<rust_decimal::Decimal>,
/// Can be used if `pendingAboveType` is `STOP_LOSS`, `STOP_LOSS_LIMIT`, `TAKE_PROFIT`, `TAKE_PROFIT_LIMIT`
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_stop_price: Option<rust_decimal::Decimal>,
/// See [Trailing Stop FAQ](./faqs/trailing-stop-faq.md)
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_trailing_delta: Option<rust_decimal::Decimal>,
/// This can only be used if `pendingAboveTimeInForce` is `GTC` or if `pendingAboveType` is `LIMIT_MAKER`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_iceberg_qty: Option<rust_decimal::Decimal>,
///
/// The `pending_above_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_time_in_force: Option<OrderListPlaceOtocoPendingAboveTimeInForceEnum>,
/// Arbitrary numeric value identifying the pending above order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the pending above order strategy. Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_strategy_type: Option<i32>,
///
/// The `pending_above_peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_peg_price_type: Option<OrderListPlaceOtocoPendingAbovePegPriceTypeEnum>,
///
/// The `pending_above_peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_peg_offset_type: Option<OrderListPlaceOtocoPendingAbovePegOffsetTypeEnum>,
///
/// The `pending_above_peg_offset_value` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_above_peg_offset_value: Option<i32>,
///
/// The `pending_below_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_type: Option<OrderListPlaceOtocoPendingBelowTypeEnum>,
/// Arbitrary unique ID among open orders for the pending below order. Automatically generated if not sent.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_client_order_id: Option<String>,
/// Can be used if `pendingBelowType` is `STOP_LOSS_LIMIT` or `TAKE_PROFIT_LIMIT` to specify limit price
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_price: Option<rust_decimal::Decimal>,
/// Can be used if `pendingBelowType` is `STOP_LOSS`, `STOP_LOSS_LIMIT, TAKE_PROFIT or TAKE_PROFIT_LIMIT`. Either `pendingBelowStopPrice` or `pendingBelowTrailingDelta` or both, must be specified.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_stop_price: Option<rust_decimal::Decimal>,
///
/// The `pending_below_trailing_delta` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_trailing_delta: Option<rust_decimal::Decimal>,
/// This can only be used if `pendingBelowTimeInForce` is `GTC`, or if `pendingBelowType` is `LIMIT_MAKER`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_iceberg_qty: Option<rust_decimal::Decimal>,
///
/// The `pending_below_time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_time_in_force: Option<OrderListPlaceOtocoPendingBelowTimeInForceEnum>,
/// Arbitrary numeric value identifying the pending below order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the pending below order strategy. Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_strategy_type: Option<i32>,
///
/// The `pending_below_peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_peg_price_type: Option<OrderListPlaceOtocoPendingBelowPegPriceTypeEnum>,
///
/// The `pending_below_peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_peg_offset_type: Option<OrderListPlaceOtocoPendingBelowPegOffsetTypeEnum>,
///
/// The `pending_below_peg_offset_value` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub pending_below_peg_offset_value: 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 OrderListPlaceOtocoParams {
/// Create a builder for [`order_list_place_otoco`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `working_type` — String
/// * `working_side` — String
/// * `working_price` — `rust_decimal::Decimal`
/// * `working_quantity` — Sets the quantity for the working order.
/// * `pending_side` — String
/// * `pending_quantity` — Sets the quantity for the pending order.
/// * `pending_above_type` — String
///
#[must_use]
pub fn builder(
symbol: String,
working_type: OrderListPlaceOtocoWorkingTypeEnum,
working_side: OrderListPlaceOtocoWorkingSideEnum,
working_price: rust_decimal::Decimal,
working_quantity: rust_decimal::Decimal,
pending_side: OrderListPlaceOtocoPendingSideEnum,
pending_quantity: rust_decimal::Decimal,
pending_above_type: OrderListPlaceOtocoPendingAboveTypeEnum,
) -> OrderListPlaceOtocoParamsBuilder {
OrderListPlaceOtocoParamsBuilder::default()
.symbol(symbol)
.working_type(working_type)
.working_side(working_side)
.working_price(working_price)
.working_quantity(working_quantity)
.pending_side(pending_side)
.pending_quantity(pending_quantity)
.pending_above_type(pending_above_type)
}
}
/// Request parameters for the [`order_place`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_place`](#method.order_place).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderPlaceParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub side: OrderPlaceSideEnum,
///
/// The `r#type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub r#type: OrderPlaceTypeEnum,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
///
/// The `time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub time_in_force: Option<OrderPlaceTimeInForceEnum>,
///
/// The `price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub price: Option<rust_decimal::Decimal>,
///
/// The `quantity` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub quantity: Option<rust_decimal::Decimal>,
///
/// The `quote_order_qty` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub quote_order_qty: Option<rust_decimal::Decimal>,
/// The new client order ID for the order after being amended. <br> If not sent, one will be randomly generated. <br> It is possible to reuse the current clientOrderId by sending it as the `newClientOrderId`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_client_order_id: Option<String>,
///
/// The `new_order_resp_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_order_resp_type: Option<OrderPlaceNewOrderRespTypeEnum>,
///
/// The `stop_price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub stop_price: Option<rust_decimal::Decimal>,
/// See [Trailing Stop order FAQ](faqs/trailing-stop-faq.md)
///
/// This field is **optional.
#[builder(setter(into), default)]
pub trailing_delta: Option<i32>,
///
/// The `iceberg_qty` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub iceberg_qty: Option<rust_decimal::Decimal>,
/// Arbitrary numeric value identifying the order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the order strategy.
/// Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub strategy_type: Option<i32>,
///
/// The `self_trade_prevention_mode` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub self_trade_prevention_mode: Option<OrderPlaceSelfTradePreventionModeEnum>,
///
/// The `peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub peg_price_type: Option<OrderPlacePegPriceTypeEnum>,
/// Price level to peg the price to (max: 100)
/// See Pegged Orders
///
/// This field is **optional.
#[builder(setter(into), default)]
pub peg_offset_value: Option<i32>,
///
/// The `peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub peg_offset_type: Option<OrderPlacePegOffsetTypeEnum>,
/// 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 OrderPlaceParams {
/// Create a builder for [`order_place`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `side` — String
/// * `r#type` — String
///
#[must_use]
pub fn builder(
symbol: String,
side: OrderPlaceSideEnum,
r#type: OrderPlaceTypeEnum,
) -> OrderPlaceParamsBuilder {
OrderPlaceParamsBuilder::default()
.symbol(symbol)
.side(side)
.r#type(r#type)
}
}
/// Request parameters for the [`order_test`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`order_test`](#method.order_test).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct OrderTestParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub side: OrderTestSideEnum,
///
/// The `r#type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub r#type: OrderTestTypeEnum,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
/// Default: `false` <br> See [Commissions FAQ](faqs/commission_faq.md#test-order-diferences) to learn more.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub compute_commission_rates: Option<bool>,
///
/// The `time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub time_in_force: Option<OrderTestTimeInForceEnum>,
///
/// The `price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub price: Option<rust_decimal::Decimal>,
///
/// The `quantity` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub quantity: Option<rust_decimal::Decimal>,
///
/// The `quote_order_qty` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub quote_order_qty: Option<rust_decimal::Decimal>,
/// The new client order ID for the order after being amended. <br> If not sent, one will be randomly generated. <br> It is possible to reuse the current clientOrderId by sending it as the `newClientOrderId`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_client_order_id: Option<String>,
///
/// The `new_order_resp_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_order_resp_type: Option<OrderTestNewOrderRespTypeEnum>,
///
/// The `stop_price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub stop_price: Option<rust_decimal::Decimal>,
/// See [Trailing Stop order FAQ](faqs/trailing-stop-faq.md)
///
/// This field is **optional.
#[builder(setter(into), default)]
pub trailing_delta: Option<i32>,
///
/// The `iceberg_qty` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub iceberg_qty: Option<rust_decimal::Decimal>,
/// Arbitrary numeric value identifying the order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the order strategy.
/// Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub strategy_type: Option<i32>,
///
/// The `self_trade_prevention_mode` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub self_trade_prevention_mode: Option<OrderTestSelfTradePreventionModeEnum>,
///
/// The `peg_price_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub peg_price_type: Option<OrderTestPegPriceTypeEnum>,
/// Price level to peg the price to (max: 100)
/// See Pegged Orders
///
/// This field is **optional.
#[builder(setter(into), default)]
pub peg_offset_value: Option<i32>,
///
/// The `peg_offset_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub peg_offset_type: Option<OrderTestPegOffsetTypeEnum>,
/// 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 OrderTestParams {
/// Create a builder for [`order_test`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `side` — String
/// * `r#type` — String
///
#[must_use]
pub fn builder(
symbol: String,
side: OrderTestSideEnum,
r#type: OrderTestTypeEnum,
) -> OrderTestParamsBuilder {
OrderTestParamsBuilder::default()
.symbol(symbol)
.side(side)
.r#type(r#type)
}
}
/// Request parameters for the [`sor_order_place`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`sor_order_place`](#method.sor_order_place).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct SorOrderPlaceParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub side: SorOrderPlaceSideEnum,
///
/// The `r#type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub r#type: SorOrderPlaceTypeEnum,
///
/// The `quantity` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub quantity: rust_decimal::Decimal,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
///
/// The `time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub time_in_force: Option<SorOrderPlaceTimeInForceEnum>,
///
/// The `price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub price: Option<rust_decimal::Decimal>,
/// The new client order ID for the order after being amended. <br> If not sent, one will be randomly generated. <br> It is possible to reuse the current clientOrderId by sending it as the `newClientOrderId`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_client_order_id: Option<String>,
///
/// The `new_order_resp_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_order_resp_type: Option<SorOrderPlaceNewOrderRespTypeEnum>,
///
/// The `iceberg_qty` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub iceberg_qty: Option<rust_decimal::Decimal>,
/// Arbitrary numeric value identifying the order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the order strategy.
/// Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub strategy_type: Option<i32>,
///
/// The `self_trade_prevention_mode` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub self_trade_prevention_mode: Option<SorOrderPlaceSelfTradePreventionModeEnum>,
/// 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 SorOrderPlaceParams {
/// Create a builder for [`sor_order_place`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `side` — String
/// * `r#type` — String
/// * `quantity` — `rust_decimal::Decimal`
///
#[must_use]
pub fn builder(
symbol: String,
side: SorOrderPlaceSideEnum,
r#type: SorOrderPlaceTypeEnum,
quantity: rust_decimal::Decimal,
) -> SorOrderPlaceParamsBuilder {
SorOrderPlaceParamsBuilder::default()
.symbol(symbol)
.side(side)
.r#type(r#type)
.quantity(quantity)
}
}
/// Request parameters for the [`sor_order_test`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`sor_order_test`](#method.sor_order_test).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct SorOrderTestParams {
///
/// The `symbol` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub symbol: String,
///
/// The `side` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub side: SorOrderTestSideEnum,
///
/// The `r#type` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub r#type: SorOrderTestTypeEnum,
///
/// The `quantity` parameter.
///
/// This field is **required.
#[builder(setter(into))]
pub quantity: rust_decimal::Decimal,
/// Unique WebSocket request ID.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub id: Option<String>,
/// Default: `false` <br> See [Commissions FAQ](faqs/commission_faq.md#test-order-diferences) to learn more.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub compute_commission_rates: Option<bool>,
///
/// The `time_in_force` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub time_in_force: Option<SorOrderTestTimeInForceEnum>,
///
/// The `price` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub price: Option<rust_decimal::Decimal>,
/// The new client order ID for the order after being amended. <br> If not sent, one will be randomly generated. <br> It is possible to reuse the current clientOrderId by sending it as the `newClientOrderId`.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_client_order_id: Option<String>,
///
/// The `new_order_resp_type` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub new_order_resp_type: Option<SorOrderTestNewOrderRespTypeEnum>,
///
/// The `iceberg_qty` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub iceberg_qty: Option<rust_decimal::Decimal>,
/// Arbitrary numeric value identifying the order within an order strategy.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub strategy_id: Option<i64>,
/// Arbitrary numeric value identifying the order strategy.
/// Values smaller than 1000000 are reserved and cannot be used.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub strategy_type: Option<i32>,
///
/// The `self_trade_prevention_mode` parameter.
///
/// This field is **optional.
#[builder(setter(into), default)]
pub self_trade_prevention_mode: Option<SorOrderTestSelfTradePreventionModeEnum>,
/// 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 SorOrderTestParams {
/// Create a builder for [`sor_order_test`].
///
/// Required parameters:
///
/// * `symbol` — String
/// * `side` — String
/// * `r#type` — String
/// * `quantity` — `rust_decimal::Decimal`
///
#[must_use]
pub fn builder(
symbol: String,
side: SorOrderTestSideEnum,
r#type: SorOrderTestTypeEnum,
quantity: rust_decimal::Decimal,
) -> SorOrderTestParamsBuilder {
SorOrderTestParamsBuilder::default()
.symbol(symbol)
.side(side)
.r#type(r#type)
.quantity(quantity)
}
}
#[async_trait]
impl TradeApi for TradeApiClient {
async fn open_orders_cancel_all(
&self,
params: OpenOrdersCancelAllParams,
) -> anyhow::Result<WebsocketApiResponse<Vec<models::OpenOrdersCancelAllResponseResultInner>>>
{
let OpenOrdersCancelAllParams {
symbol,
id,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Vec<models::OpenOrdersCancelAllResponseResultInner>>(
"/openOrders.cancelAll".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn order_amend_keep_priority(
&self,
params: OrderAmendKeepPriorityParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderAmendKeepPriorityResponseResult>>>
{
let OrderAmendKeepPriorityParams {
symbol,
new_qty,
id,
order_id,
orig_client_order_id,
new_client_order_id,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
payload.insert("newQty".to_string(), serde_json::json!(new_qty));
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = order_id {
payload.insert("orderId".to_string(), serde_json::json!(value));
}
if let Some(value) = orig_client_order_id {
payload.insert("origClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = new_client_order_id {
payload.insert("newClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::OrderAmendKeepPriorityResponseResult>>(
"/order.amend.keepPriority".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn order_cancel(
&self,
params: OrderCancelParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderCancelResponseResult>>> {
let OrderCancelParams {
symbol,
id,
order_id,
orig_client_order_id,
new_client_order_id,
cancel_restrictions,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = order_id {
payload.insert("orderId".to_string(), serde_json::json!(value));
}
if let Some(value) = orig_client_order_id {
payload.insert("origClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = new_client_order_id {
payload.insert("newClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = cancel_restrictions {
payload.insert("cancelRestrictions".to_string(), serde_json::json!(value));
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::OrderCancelResponseResult>>(
"/order.cancel".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn order_cancel_replace(
&self,
params: OrderCancelReplaceParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderCancelReplaceResponseResult>>> {
let OrderCancelReplaceParams {
symbol,
cancel_replace_mode,
side,
r#type,
id,
cancel_order_id,
cancel_orig_client_order_id,
cancel_new_client_order_id,
time_in_force,
price,
quantity,
quote_order_qty,
new_client_order_id,
new_order_resp_type,
stop_price,
trailing_delta,
iceberg_qty,
strategy_id,
strategy_type,
self_trade_prevention_mode,
cancel_restrictions,
order_rate_limit_exceeded_mode,
peg_price_type,
peg_offset_value,
peg_offset_type,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
payload.insert(
"cancelReplaceMode".to_string(),
serde_json::json!(cancel_replace_mode),
);
payload.insert("side".to_string(), serde_json::json!(side));
payload.insert("type".to_string(), serde_json::json!(r#type));
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = cancel_order_id {
payload.insert("cancelOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = cancel_orig_client_order_id {
payload.insert(
"cancelOrigClientOrderId".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = cancel_new_client_order_id {
payload.insert(
"cancelNewClientOrderId".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = time_in_force {
payload.insert("timeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = price {
payload.insert("price".to_string(), serde_json::json!(value));
}
if let Some(value) = quantity {
payload.insert("quantity".to_string(), serde_json::json!(value));
}
if let Some(value) = quote_order_qty {
payload.insert("quoteOrderQty".to_string(), serde_json::json!(value));
}
if let Some(value) = new_client_order_id {
payload.insert("newClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = new_order_resp_type {
payload.insert("newOrderRespType".to_string(), serde_json::json!(value));
}
if let Some(value) = stop_price {
payload.insert("stopPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = trailing_delta {
payload.insert("trailingDelta".to_string(), serde_json::json!(value));
}
if let Some(value) = iceberg_qty {
payload.insert("icebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = strategy_id {
payload.insert("strategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = strategy_type {
payload.insert("strategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = self_trade_prevention_mode {
payload.insert(
"selfTradePreventionMode".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = cancel_restrictions {
payload.insert("cancelRestrictions".to_string(), serde_json::json!(value));
}
if let Some(value) = order_rate_limit_exceeded_mode {
payload.insert(
"orderRateLimitExceededMode".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = peg_price_type {
payload.insert("pegPriceType".to_string(), serde_json::json!(value));
}
if let Some(value) = peg_offset_value {
payload.insert("pegOffsetValue".to_string(), serde_json::json!(value));
}
if let Some(value) = peg_offset_type {
payload.insert("pegOffsetType".to_string(), serde_json::json!(value));
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::OrderCancelReplaceResponseResult>>(
"/order.cancelReplace".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn order_list_cancel(
&self,
params: OrderListCancelParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListCancelResponseResult>>> {
let OrderListCancelParams {
symbol,
id,
order_list_id,
list_client_order_id,
new_client_order_id,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = order_list_id {
payload.insert("orderListId".to_string(), serde_json::json!(value));
}
if let Some(value) = list_client_order_id {
payload.insert("listClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = new_client_order_id {
payload.insert("newClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::OrderListCancelResponseResult>>(
"/orderList.cancel".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn order_list_place(
&self,
params: OrderListPlaceParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceResponseResult>>> {
let OrderListPlaceParams {
symbol,
side,
price,
quantity,
id,
list_client_order_id,
limit_client_order_id,
limit_iceberg_qty,
limit_strategy_id,
limit_strategy_type,
stop_price,
trailing_delta,
stop_client_order_id,
stop_limit_price,
stop_limit_time_in_force,
stop_iceberg_qty,
stop_strategy_id,
stop_strategy_type,
new_order_resp_type,
self_trade_prevention_mode,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
payload.insert("side".to_string(), serde_json::json!(side));
payload.insert("price".to_string(), serde_json::json!(price));
payload.insert("quantity".to_string(), serde_json::json!(quantity));
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = list_client_order_id {
payload.insert("listClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = limit_client_order_id {
payload.insert("limitClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = limit_iceberg_qty {
payload.insert("limitIcebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = limit_strategy_id {
payload.insert("limitStrategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = limit_strategy_type {
payload.insert("limitStrategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = stop_price {
payload.insert("stopPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = trailing_delta {
payload.insert("trailingDelta".to_string(), serde_json::json!(value));
}
if let Some(value) = stop_client_order_id {
payload.insert("stopClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = stop_limit_price {
payload.insert("stopLimitPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = stop_limit_time_in_force {
payload.insert("stopLimitTimeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = stop_iceberg_qty {
payload.insert("stopIcebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = stop_strategy_id {
payload.insert("stopStrategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = stop_strategy_type {
payload.insert("stopStrategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = new_order_resp_type {
payload.insert("newOrderRespType".to_string(), serde_json::json!(value));
}
if let Some(value) = self_trade_prevention_mode {
payload.insert(
"selfTradePreventionMode".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::OrderListPlaceResponseResult>>(
"/orderList.place".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn order_list_place_oco(
&self,
params: OrderListPlaceOcoParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOcoResponseResult>>> {
let OrderListPlaceOcoParams {
symbol,
side,
quantity,
above_type,
below_type,
id,
list_client_order_id,
above_client_order_id,
above_iceberg_qty,
above_price,
above_stop_price,
above_trailing_delta,
above_time_in_force,
above_strategy_id,
above_strategy_type,
above_peg_price_type,
above_peg_offset_type,
above_peg_offset_value,
below_client_order_id,
below_iceberg_qty,
below_price,
below_stop_price,
below_trailing_delta,
below_time_in_force,
below_strategy_id,
below_strategy_type,
below_peg_price_type,
below_peg_offset_type,
below_peg_offset_value,
new_order_resp_type,
self_trade_prevention_mode,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
payload.insert("side".to_string(), serde_json::json!(side));
payload.insert("quantity".to_string(), serde_json::json!(quantity));
payload.insert("aboveType".to_string(), serde_json::json!(above_type));
payload.insert("belowType".to_string(), serde_json::json!(below_type));
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = list_client_order_id {
payload.insert("listClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = above_client_order_id {
payload.insert("aboveClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = above_iceberg_qty {
payload.insert("aboveIcebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = above_price {
payload.insert("abovePrice".to_string(), serde_json::json!(value));
}
if let Some(value) = above_stop_price {
payload.insert("aboveStopPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = above_trailing_delta {
payload.insert("aboveTrailingDelta".to_string(), serde_json::json!(value));
}
if let Some(value) = above_time_in_force {
payload.insert("aboveTimeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = above_strategy_id {
payload.insert("aboveStrategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = above_strategy_type {
payload.insert("aboveStrategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = above_peg_price_type {
payload.insert("abovePegPriceType".to_string(), serde_json::json!(value));
}
if let Some(value) = above_peg_offset_type {
payload.insert("abovePegOffsetType".to_string(), serde_json::json!(value));
}
if let Some(value) = above_peg_offset_value {
payload.insert("abovePegOffsetValue".to_string(), serde_json::json!(value));
}
if let Some(value) = below_client_order_id {
payload.insert("belowClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = below_iceberg_qty {
payload.insert("belowIcebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = below_price {
payload.insert("belowPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = below_stop_price {
payload.insert("belowStopPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = below_trailing_delta {
payload.insert("belowTrailingDelta".to_string(), serde_json::json!(value));
}
if let Some(value) = below_time_in_force {
payload.insert("belowTimeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = below_strategy_id {
payload.insert("belowStrategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = below_strategy_type {
payload.insert("belowStrategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = below_peg_price_type {
payload.insert("belowPegPriceType".to_string(), serde_json::json!(value));
}
if let Some(value) = below_peg_offset_type {
payload.insert("belowPegOffsetType".to_string(), serde_json::json!(value));
}
if let Some(value) = below_peg_offset_value {
payload.insert("belowPegOffsetValue".to_string(), serde_json::json!(value));
}
if let Some(value) = new_order_resp_type {
payload.insert("newOrderRespType".to_string(), serde_json::json!(value));
}
if let Some(value) = self_trade_prevention_mode {
payload.insert(
"selfTradePreventionMode".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::OrderListPlaceOcoResponseResult>>(
"/orderList.place.oco".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn order_list_place_opo(
&self,
params: OrderListPlaceOpoParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOpoResponseResult>>> {
let OrderListPlaceOpoParams {
symbol,
working_type,
working_side,
working_price,
working_quantity,
pending_type,
pending_side,
id,
list_client_order_id,
new_order_resp_type,
self_trade_prevention_mode,
working_client_order_id,
working_iceberg_qty,
working_time_in_force,
working_strategy_id,
working_strategy_type,
working_peg_price_type,
working_peg_offset_type,
working_peg_offset_value,
pending_client_order_id,
pending_price,
pending_stop_price,
pending_trailing_delta,
pending_iceberg_qty,
pending_time_in_force,
pending_strategy_id,
pending_strategy_type,
pending_peg_price_type,
pending_peg_offset_type,
pending_peg_offset_value,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
payload.insert("workingType".to_string(), serde_json::json!(working_type));
payload.insert("workingSide".to_string(), serde_json::json!(working_side));
payload.insert("workingPrice".to_string(), serde_json::json!(working_price));
payload.insert(
"workingQuantity".to_string(),
serde_json::json!(working_quantity),
);
payload.insert("pendingType".to_string(), serde_json::json!(pending_type));
payload.insert("pendingSide".to_string(), serde_json::json!(pending_side));
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = list_client_order_id {
payload.insert("listClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = new_order_resp_type {
payload.insert("newOrderRespType".to_string(), serde_json::json!(value));
}
if let Some(value) = self_trade_prevention_mode {
payload.insert(
"selfTradePreventionMode".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = working_client_order_id {
payload.insert("workingClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = working_iceberg_qty {
payload.insert("workingIcebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = working_time_in_force {
payload.insert("workingTimeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = working_strategy_id {
payload.insert("workingStrategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = working_strategy_type {
payload.insert("workingStrategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = working_peg_price_type {
payload.insert("workingPegPriceType".to_string(), serde_json::json!(value));
}
if let Some(value) = working_peg_offset_type {
payload.insert("workingPegOffsetType".to_string(), serde_json::json!(value));
}
if let Some(value) = working_peg_offset_value {
payload.insert(
"workingPegOffsetValue".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_client_order_id {
payload.insert("pendingClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_price {
payload.insert("pendingPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_stop_price {
payload.insert("pendingStopPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_trailing_delta {
payload.insert("pendingTrailingDelta".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_iceberg_qty {
payload.insert("pendingIcebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_time_in_force {
payload.insert("pendingTimeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_strategy_id {
payload.insert("pendingStrategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_strategy_type {
payload.insert("pendingStrategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_peg_price_type {
payload.insert("pendingPegPriceType".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_peg_offset_type {
payload.insert("pendingPegOffsetType".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_peg_offset_value {
payload.insert(
"pendingPegOffsetValue".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::OrderListPlaceOpoResponseResult>>(
"/orderList.place.opo".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn order_list_place_opoco(
&self,
params: OrderListPlaceOpocoParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOpocoResponseResult>>> {
let OrderListPlaceOpocoParams {
symbol,
working_type,
working_side,
working_price,
working_quantity,
pending_side,
pending_above_type,
id,
list_client_order_id,
new_order_resp_type,
self_trade_prevention_mode,
working_client_order_id,
working_iceberg_qty,
working_time_in_force,
working_strategy_id,
working_strategy_type,
working_peg_price_type,
working_peg_offset_type,
working_peg_offset_value,
pending_above_client_order_id,
pending_above_price,
pending_above_stop_price,
pending_above_trailing_delta,
pending_above_iceberg_qty,
pending_above_time_in_force,
pending_above_strategy_id,
pending_above_strategy_type,
pending_above_peg_price_type,
pending_above_peg_offset_type,
pending_above_peg_offset_value,
pending_below_type,
pending_below_client_order_id,
pending_below_price,
pending_below_stop_price,
pending_below_trailing_delta,
pending_below_iceberg_qty,
pending_below_time_in_force,
pending_below_strategy_id,
pending_below_strategy_type,
pending_below_peg_price_type,
pending_below_peg_offset_type,
pending_below_peg_offset_value,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
payload.insert("workingType".to_string(), serde_json::json!(working_type));
payload.insert("workingSide".to_string(), serde_json::json!(working_side));
payload.insert("workingPrice".to_string(), serde_json::json!(working_price));
payload.insert(
"workingQuantity".to_string(),
serde_json::json!(working_quantity),
);
payload.insert("pendingSide".to_string(), serde_json::json!(pending_side));
payload.insert(
"pendingAboveType".to_string(),
serde_json::json!(pending_above_type),
);
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = list_client_order_id {
payload.insert("listClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = new_order_resp_type {
payload.insert("newOrderRespType".to_string(), serde_json::json!(value));
}
if let Some(value) = self_trade_prevention_mode {
payload.insert(
"selfTradePreventionMode".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = working_client_order_id {
payload.insert("workingClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = working_iceberg_qty {
payload.insert("workingIcebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = working_time_in_force {
payload.insert("workingTimeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = working_strategy_id {
payload.insert("workingStrategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = working_strategy_type {
payload.insert("workingStrategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = working_peg_price_type {
payload.insert("workingPegPriceType".to_string(), serde_json::json!(value));
}
if let Some(value) = working_peg_offset_type {
payload.insert("workingPegOffsetType".to_string(), serde_json::json!(value));
}
if let Some(value) = working_peg_offset_value {
payload.insert(
"workingPegOffsetValue".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_client_order_id {
payload.insert(
"pendingAboveClientOrderId".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_price {
payload.insert("pendingAbovePrice".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_above_stop_price {
payload.insert(
"pendingAboveStopPrice".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_trailing_delta {
payload.insert(
"pendingAboveTrailingDelta".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_iceberg_qty {
payload.insert(
"pendingAboveIcebergQty".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_time_in_force {
payload.insert(
"pendingAboveTimeInForce".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_strategy_id {
payload.insert(
"pendingAboveStrategyId".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_strategy_type {
payload.insert(
"pendingAboveStrategyType".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_peg_price_type {
payload.insert(
"pendingAbovePegPriceType".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_peg_offset_type {
payload.insert(
"pendingAbovePegOffsetType".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_peg_offset_value {
payload.insert(
"pendingAbovePegOffsetValue".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_type {
payload.insert("pendingBelowType".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_below_client_order_id {
payload.insert(
"pendingBelowClientOrderId".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_price {
payload.insert("pendingBelowPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_below_stop_price {
payload.insert(
"pendingBelowStopPrice".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_trailing_delta {
payload.insert(
"pendingBelowTrailingDelta".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_iceberg_qty {
payload.insert(
"pendingBelowIcebergQty".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_time_in_force {
payload.insert(
"pendingBelowTimeInForce".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_strategy_id {
payload.insert(
"pendingBelowStrategyId".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_strategy_type {
payload.insert(
"pendingBelowStrategyType".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_peg_price_type {
payload.insert(
"pendingBelowPegPriceType".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_peg_offset_type {
payload.insert(
"pendingBelowPegOffsetType".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_peg_offset_value {
payload.insert(
"pendingBelowPegOffsetValue".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::OrderListPlaceOpocoResponseResult>>(
"/orderList.place.opoco".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn order_list_place_oto(
&self,
params: OrderListPlaceOtoParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOtoResponseResult>>> {
let OrderListPlaceOtoParams {
symbol,
working_type,
working_side,
working_price,
working_quantity,
pending_type,
pending_side,
pending_quantity,
id,
list_client_order_id,
new_order_resp_type,
self_trade_prevention_mode,
working_client_order_id,
working_iceberg_qty,
working_time_in_force,
working_strategy_id,
working_strategy_type,
working_peg_price_type,
working_peg_offset_type,
working_peg_offset_value,
pending_client_order_id,
pending_price,
pending_stop_price,
pending_trailing_delta,
pending_iceberg_qty,
pending_time_in_force,
pending_strategy_id,
pending_strategy_type,
pending_peg_offset_type,
pending_peg_price_type,
pending_peg_offset_value,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
payload.insert("workingType".to_string(), serde_json::json!(working_type));
payload.insert("workingSide".to_string(), serde_json::json!(working_side));
payload.insert("workingPrice".to_string(), serde_json::json!(working_price));
payload.insert(
"workingQuantity".to_string(),
serde_json::json!(working_quantity),
);
payload.insert("pendingType".to_string(), serde_json::json!(pending_type));
payload.insert("pendingSide".to_string(), serde_json::json!(pending_side));
payload.insert(
"pendingQuantity".to_string(),
serde_json::json!(pending_quantity),
);
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = list_client_order_id {
payload.insert("listClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = new_order_resp_type {
payload.insert("newOrderRespType".to_string(), serde_json::json!(value));
}
if let Some(value) = self_trade_prevention_mode {
payload.insert(
"selfTradePreventionMode".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = working_client_order_id {
payload.insert("workingClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = working_iceberg_qty {
payload.insert("workingIcebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = working_time_in_force {
payload.insert("workingTimeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = working_strategy_id {
payload.insert("workingStrategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = working_strategy_type {
payload.insert("workingStrategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = working_peg_price_type {
payload.insert("workingPegPriceType".to_string(), serde_json::json!(value));
}
if let Some(value) = working_peg_offset_type {
payload.insert("workingPegOffsetType".to_string(), serde_json::json!(value));
}
if let Some(value) = working_peg_offset_value {
payload.insert(
"workingPegOffsetValue".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_client_order_id {
payload.insert("pendingClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_price {
payload.insert("pendingPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_stop_price {
payload.insert("pendingStopPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_trailing_delta {
payload.insert("pendingTrailingDelta".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_iceberg_qty {
payload.insert("pendingIcebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_time_in_force {
payload.insert("pendingTimeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_strategy_id {
payload.insert("pendingStrategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_strategy_type {
payload.insert("pendingStrategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_peg_offset_type {
payload.insert("pendingPegOffsetType".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_peg_price_type {
payload.insert("pendingPegPriceType".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_peg_offset_value {
payload.insert(
"pendingPegOffsetValue".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::OrderListPlaceOtoResponseResult>>(
"/orderList.place.oto".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn order_list_place_otoco(
&self,
params: OrderListPlaceOtocoParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOtocoResponseResult>>> {
let OrderListPlaceOtocoParams {
symbol,
working_type,
working_side,
working_price,
working_quantity,
pending_side,
pending_quantity,
pending_above_type,
id,
list_client_order_id,
new_order_resp_type,
self_trade_prevention_mode,
working_client_order_id,
working_iceberg_qty,
working_time_in_force,
working_strategy_id,
working_strategy_type,
working_peg_price_type,
working_peg_offset_type,
working_peg_offset_value,
pending_above_client_order_id,
pending_above_price,
pending_above_stop_price,
pending_above_trailing_delta,
pending_above_iceberg_qty,
pending_above_time_in_force,
pending_above_strategy_id,
pending_above_strategy_type,
pending_above_peg_price_type,
pending_above_peg_offset_type,
pending_above_peg_offset_value,
pending_below_type,
pending_below_client_order_id,
pending_below_price,
pending_below_stop_price,
pending_below_trailing_delta,
pending_below_iceberg_qty,
pending_below_time_in_force,
pending_below_strategy_id,
pending_below_strategy_type,
pending_below_peg_price_type,
pending_below_peg_offset_type,
pending_below_peg_offset_value,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
payload.insert("workingType".to_string(), serde_json::json!(working_type));
payload.insert("workingSide".to_string(), serde_json::json!(working_side));
payload.insert("workingPrice".to_string(), serde_json::json!(working_price));
payload.insert(
"workingQuantity".to_string(),
serde_json::json!(working_quantity),
);
payload.insert("pendingSide".to_string(), serde_json::json!(pending_side));
payload.insert(
"pendingQuantity".to_string(),
serde_json::json!(pending_quantity),
);
payload.insert(
"pendingAboveType".to_string(),
serde_json::json!(pending_above_type),
);
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = list_client_order_id {
payload.insert("listClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = new_order_resp_type {
payload.insert("newOrderRespType".to_string(), serde_json::json!(value));
}
if let Some(value) = self_trade_prevention_mode {
payload.insert(
"selfTradePreventionMode".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = working_client_order_id {
payload.insert("workingClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = working_iceberg_qty {
payload.insert("workingIcebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = working_time_in_force {
payload.insert("workingTimeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = working_strategy_id {
payload.insert("workingStrategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = working_strategy_type {
payload.insert("workingStrategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = working_peg_price_type {
payload.insert("workingPegPriceType".to_string(), serde_json::json!(value));
}
if let Some(value) = working_peg_offset_type {
payload.insert("workingPegOffsetType".to_string(), serde_json::json!(value));
}
if let Some(value) = working_peg_offset_value {
payload.insert(
"workingPegOffsetValue".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_client_order_id {
payload.insert(
"pendingAboveClientOrderId".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_price {
payload.insert("pendingAbovePrice".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_above_stop_price {
payload.insert(
"pendingAboveStopPrice".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_trailing_delta {
payload.insert(
"pendingAboveTrailingDelta".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_iceberg_qty {
payload.insert(
"pendingAboveIcebergQty".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_time_in_force {
payload.insert(
"pendingAboveTimeInForce".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_strategy_id {
payload.insert(
"pendingAboveStrategyId".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_strategy_type {
payload.insert(
"pendingAboveStrategyType".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_peg_price_type {
payload.insert(
"pendingAbovePegPriceType".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_peg_offset_type {
payload.insert(
"pendingAbovePegOffsetType".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_above_peg_offset_value {
payload.insert(
"pendingAbovePegOffsetValue".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_type {
payload.insert("pendingBelowType".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_below_client_order_id {
payload.insert(
"pendingBelowClientOrderId".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_price {
payload.insert("pendingBelowPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = pending_below_stop_price {
payload.insert(
"pendingBelowStopPrice".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_trailing_delta {
payload.insert(
"pendingBelowTrailingDelta".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_iceberg_qty {
payload.insert(
"pendingBelowIcebergQty".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_time_in_force {
payload.insert(
"pendingBelowTimeInForce".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_strategy_id {
payload.insert(
"pendingBelowStrategyId".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_strategy_type {
payload.insert(
"pendingBelowStrategyType".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_peg_price_type {
payload.insert(
"pendingBelowPegPriceType".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_peg_offset_type {
payload.insert(
"pendingBelowPegOffsetType".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = pending_below_peg_offset_value {
payload.insert(
"pendingBelowPegOffsetValue".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::OrderListPlaceOtocoResponseResult>>(
"/orderList.place.otoco".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn order_place(
&self,
params: OrderPlaceParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderPlaceResponseResult>>> {
let OrderPlaceParams {
symbol,
side,
r#type,
id,
time_in_force,
price,
quantity,
quote_order_qty,
new_client_order_id,
new_order_resp_type,
stop_price,
trailing_delta,
iceberg_qty,
strategy_id,
strategy_type,
self_trade_prevention_mode,
peg_price_type,
peg_offset_value,
peg_offset_type,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
payload.insert("side".to_string(), serde_json::json!(side));
payload.insert("type".to_string(), serde_json::json!(r#type));
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = time_in_force {
payload.insert("timeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = price {
payload.insert("price".to_string(), serde_json::json!(value));
}
if let Some(value) = quantity {
payload.insert("quantity".to_string(), serde_json::json!(value));
}
if let Some(value) = quote_order_qty {
payload.insert("quoteOrderQty".to_string(), serde_json::json!(value));
}
if let Some(value) = new_client_order_id {
payload.insert("newClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = new_order_resp_type {
payload.insert("newOrderRespType".to_string(), serde_json::json!(value));
}
if let Some(value) = stop_price {
payload.insert("stopPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = trailing_delta {
payload.insert("trailingDelta".to_string(), serde_json::json!(value));
}
if let Some(value) = iceberg_qty {
payload.insert("icebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = strategy_id {
payload.insert("strategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = strategy_type {
payload.insert("strategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = self_trade_prevention_mode {
payload.insert(
"selfTradePreventionMode".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = peg_price_type {
payload.insert("pegPriceType".to_string(), serde_json::json!(value));
}
if let Some(value) = peg_offset_value {
payload.insert("pegOffsetValue".to_string(), serde_json::json!(value));
}
if let Some(value) = peg_offset_type {
payload.insert("pegOffsetType".to_string(), serde_json::json!(value));
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::OrderPlaceResponseResult>>(
"/order.place".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn order_test(
&self,
params: OrderTestParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderTestResponseResult>>> {
let OrderTestParams {
symbol,
side,
r#type,
id,
compute_commission_rates,
time_in_force,
price,
quantity,
quote_order_qty,
new_client_order_id,
new_order_resp_type,
stop_price,
trailing_delta,
iceberg_qty,
strategy_id,
strategy_type,
self_trade_prevention_mode,
peg_price_type,
peg_offset_value,
peg_offset_type,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
payload.insert("side".to_string(), serde_json::json!(side));
payload.insert("type".to_string(), serde_json::json!(r#type));
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = compute_commission_rates {
payload.insert(
"computeCommissionRates".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = time_in_force {
payload.insert("timeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = price {
payload.insert("price".to_string(), serde_json::json!(value));
}
if let Some(value) = quantity {
payload.insert("quantity".to_string(), serde_json::json!(value));
}
if let Some(value) = quote_order_qty {
payload.insert("quoteOrderQty".to_string(), serde_json::json!(value));
}
if let Some(value) = new_client_order_id {
payload.insert("newClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = new_order_resp_type {
payload.insert("newOrderRespType".to_string(), serde_json::json!(value));
}
if let Some(value) = stop_price {
payload.insert("stopPrice".to_string(), serde_json::json!(value));
}
if let Some(value) = trailing_delta {
payload.insert("trailingDelta".to_string(), serde_json::json!(value));
}
if let Some(value) = iceberg_qty {
payload.insert("icebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = strategy_id {
payload.insert("strategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = strategy_type {
payload.insert("strategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = self_trade_prevention_mode {
payload.insert(
"selfTradePreventionMode".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = peg_price_type {
payload.insert("pegPriceType".to_string(), serde_json::json!(value));
}
if let Some(value) = peg_offset_value {
payload.insert("pegOffsetValue".to_string(), serde_json::json!(value));
}
if let Some(value) = peg_offset_type {
payload.insert("pegOffsetType".to_string(), serde_json::json!(value));
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::OrderTestResponseResult>>(
"/order.test".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn sor_order_place(
&self,
params: SorOrderPlaceParams,
) -> anyhow::Result<WebsocketApiResponse<Vec<models::SorOrderPlaceResponseResultInner>>> {
let SorOrderPlaceParams {
symbol,
side,
r#type,
quantity,
id,
time_in_force,
price,
new_client_order_id,
new_order_resp_type,
iceberg_qty,
strategy_id,
strategy_type,
self_trade_prevention_mode,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
payload.insert("side".to_string(), serde_json::json!(side));
payload.insert("type".to_string(), serde_json::json!(r#type));
payload.insert("quantity".to_string(), serde_json::json!(quantity));
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = time_in_force {
payload.insert("timeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = price {
payload.insert("price".to_string(), serde_json::json!(value));
}
if let Some(value) = new_client_order_id {
payload.insert("newClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = new_order_resp_type {
payload.insert("newOrderRespType".to_string(), serde_json::json!(value));
}
if let Some(value) = iceberg_qty {
payload.insert("icebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = strategy_id {
payload.insert("strategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = strategy_type {
payload.insert("strategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = self_trade_prevention_mode {
payload.insert(
"selfTradePreventionMode".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Vec<models::SorOrderPlaceResponseResultInner>>(
"/sor.order.place".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
async fn sor_order_test(
&self,
params: SorOrderTestParams,
) -> anyhow::Result<WebsocketApiResponse<Box<models::SorOrderTestResponseResult>>> {
let SorOrderTestParams {
symbol,
side,
r#type,
quantity,
id,
compute_commission_rates,
time_in_force,
price,
new_client_order_id,
new_order_resp_type,
iceberg_qty,
strategy_id,
strategy_type,
self_trade_prevention_mode,
recv_window,
} = params;
let mut payload: BTreeMap<String, Value> = BTreeMap::new();
payload.insert("symbol".to_string(), serde_json::json!(symbol));
payload.insert("side".to_string(), serde_json::json!(side));
payload.insert("type".to_string(), serde_json::json!(r#type));
payload.insert("quantity".to_string(), serde_json::json!(quantity));
if let Some(value) = id {
payload.insert("id".to_string(), serde_json::json!(value));
}
if let Some(value) = compute_commission_rates {
payload.insert(
"computeCommissionRates".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = time_in_force {
payload.insert("timeInForce".to_string(), serde_json::json!(value));
}
if let Some(value) = price {
payload.insert("price".to_string(), serde_json::json!(value));
}
if let Some(value) = new_client_order_id {
payload.insert("newClientOrderId".to_string(), serde_json::json!(value));
}
if let Some(value) = new_order_resp_type {
payload.insert("newOrderRespType".to_string(), serde_json::json!(value));
}
if let Some(value) = iceberg_qty {
payload.insert("icebergQty".to_string(), serde_json::json!(value));
}
if let Some(value) = strategy_id {
payload.insert("strategyId".to_string(), serde_json::json!(value));
}
if let Some(value) = strategy_type {
payload.insert("strategyType".to_string(), serde_json::json!(value));
}
if let Some(value) = self_trade_prevention_mode {
payload.insert(
"selfTradePreventionMode".to_string(),
serde_json::json!(value),
);
}
if let Some(value) = recv_window {
payload.insert("recvWindow".to_string(), serde_json::json!(value));
}
let payload = remove_empty_value(payload);
self.websocket_api_base
.send_message::<Box<models::SorOrderTestResponseResult>>(
"/sor.order.test".trim_start_matches('/'),
payload,
WebsocketMessageSendOptions::new().signed(),
)
.await
.map_err(anyhow::Error::from)?
.into_iter()
.next()
.ok_or(WebsocketError::NoResponse)
.map_err(anyhow::Error::from)
}
}
#[cfg(all(test, feature = "spot"))]
mod tests {
use super::*;
use crate::TOKIO_SHARED_RT;
use crate::common::websocket::{WebsocketApi, WebsocketConnection, WebsocketHandler};
use crate::config::ConfigurationWebsocketApi;
use crate::errors::WebsocketError;
use crate::models::WebsocketApiRateLimit;
use serde_json::{Value, json};
use tokio::spawn;
use tokio::sync::mpsc::{UnboundedReceiver, unbounded_channel};
use tokio::time::{Duration, timeout};
use tokio_tungstenite::tungstenite::Message;
async fn setup() -> (
Arc<WebsocketApi>,
Arc<WebsocketConnection>,
UnboundedReceiver<Message>,
) {
let conn = WebsocketConnection::new("test-conn");
let (tx, rx) = unbounded_channel::<Message>();
{
let mut conn_state = conn.state.lock().await;
conn_state.ws_write_tx = Some(tx);
}
let config = ConfigurationWebsocketApi::builder()
.api_key("key")
.api_secret("secret")
.build()
.expect("Failed to build configuration");
let ws_api = WebsocketApi::new(config, vec![conn.clone()]);
conn.set_handler(ws_api.clone() as Arc<dyn WebsocketHandler>)
.await;
ws_api.clone().connect().await.unwrap();
(ws_api, conn, rx)
}
#[test]
fn open_orders_cancel_all_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OpenOrdersCancelAllParams::builder("BNBUSDT".to_string(),).build().unwrap();
client.open_orders_cancel_all(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/openOrders.cancelAll".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"778f938f-9041-4b88-9914-efbf64eeacc8","status":200,"result":[{"orderListId":19431,"contingencyType":"OCO","listStatusType":"ALL_DONE","listOrderStatus":"ALL_DONE","listClientOrderId":"iuVNVJYYrByz6C4yGOPPK0","transactionTime":1660803702431,"symbol":"BTCUSDT","orders":[{"symbol":"BTCUSDT","orderId":12569099454,"clientOrderId":"Tnu2IP0J5Y4mxw3IATBfmW"},{"symbol":"BTCUSDT","orderId":12569099453,"clientOrderId":"bX5wROblo6YeDwa9iTLeyY"}],"orderReports":[{"symbol":"BTCUSDT","origClientOrderId":"Tnu2IP0J5Y4mxw3IATBfmW","orderId":12569099454,"orderListId":19431,"clientOrderId":"OFFXQtxVFZ6Nbcg4PgE2DA","transactTime":1684804350068,"price":"23400.00000000","origQty":"0.00850000","executedQty":"0.00000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"CANCELED","timeInForce":"GTC","type":"LIMIT_MAKER","side":"BUY","selfTradePreventionMode":"NONE"},{"symbol":"BTCUSDT","origClientOrderId":"bX5wROblo6YeDwa9iTLeyY","orderId":12569099453,"orderListId":19431,"clientOrderId":"OFFXQtxVFZ6Nbcg4PgE2DA","transactTime":1684804350068,"price":"23450.50000000","origQty":"0.00850000","executedQty":"0.00000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"CANCELED","timeInForce":"GTC","type":"STOP_LOSS_LIMIT","side":"BUY","stopPrice":"23430.00000000","selfTradePreventionMode":"NONE"}]},{"symbol":"BTCUSDT","origClientOrderId":"4d96324ff9d44481926157","orderId":12569099453,"orderListId":-1,"clientOrderId":"91fe37ce9e69c90d6358c0","transactTime":1684804350068,"price":"23416.10000000","origQty":"0.00847000","executedQty":"0.00001000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.23416100","status":"CANCELED","timeInForce":"GTC","type":"LIMIT","side":"SELL","stopPrice":"0.00000000","trailingDelta":0,"trailingTime":-1,"icebergQty":"0.00000000","strategyId":37463720,"strategyType":1000000,"selfTradePreventionMode":"NONE"}],"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000,"count":1}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Vec<models::OpenOrdersCancelAllResponseResultInner> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn open_orders_cancel_all_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OpenOrdersCancelAllParams::builder("BNBUSDT".to_string(),).build().unwrap();
client.open_orders_cancel_all(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn open_orders_cancel_all_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OpenOrdersCancelAllParams::builder("BNBUSDT".to_string())
.build()
.unwrap();
client.open_orders_cancel_all(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn order_amend_keep_priority_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderAmendKeepPriorityParams::builder("BNBUSDT".to_string(),dec!(1.0),).build().unwrap();
client.order_amend_keep_priority(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/order.amend.keepPriority".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"56374b46-3061-486b-a311-89ee972eb648","status":200,"result":{"transactTime":1741924229819,"executionId":60,"amendedOrder":{"symbol":"BTUCSDT","orderId":23,"orderListId":4,"origClientOrderId":"my_pending_order","clientOrderId":"xbxXh5SSwaHS7oUEOCI88B","price":"1.00000000","qty":"5.00000000","executedQty":"0.00000000","preventedQty":"0.00000000","quoteOrderQty":"0.00000000","cumulativeQuoteQty":"0.00000000","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","workingTime":1741924204920,"selfTradePreventionMode":"NONE"},"listStatus":{"orderListId":4,"contingencyType":"OTO","listOrderStatus":"EXECUTING","listClientOrderId":"8nOGLLawudj1QoOiwbroRH","symbol":"BTCUSDT","orders":[{"symbol":"BTCUSDT","orderId":23,"clientOrderId":"xbxXh5SSwaHS7oUEOCI88B"},{"symbol":"BTCUSDT","orderId":22,"clientOrderId":"g04EWsjaackzedjC9wRkWD"},{"symbol":"BTCUSDT","orderId":23,"clientOrderId":"xbxXh5SSwaHS7oUEOCI88B"},{"symbol":"BTCUSDT","orderId":22,"clientOrderId":"g04EWsjaackzedjC9wRkWD"}]}},"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000,"count":1}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::OrderAmendKeepPriorityResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn order_amend_keep_priority_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OrderAmendKeepPriorityParams::builder("BNBUSDT".to_string(),dec!(1.0),).build().unwrap();
client.order_amend_keep_priority(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn order_amend_keep_priority_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params =
OrderAmendKeepPriorityParams::builder("BNBUSDT".to_string(), dec!(1.0))
.build()
.unwrap();
client.order_amend_keep_priority(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn order_cancel_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderCancelParams::builder("BNBUSDT".to_string(),).build().unwrap();
client.order_cancel(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/order.cancel".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"16eaf097-bbec-44b9-96ff-e97e6e875870","status":200,"result":{"symbol":"BTCUSDT","origClientOrderId":"4d96324ff9d44481926157","orderId":12569099453,"orderListId":19431,"clientOrderId":"91fe37ce9e69c90d6358c0","transactTime":1684804350068,"price":"23416.10000000","origQty":"0.00847000","executedQty":"0.00001000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.23416100","status":"CANCELED","timeInForce":"GTC","type":"LIMIT","side":"SELL","stopPrice":"0.00000000","trailingDelta":0,"icebergQty":"0.00000000","strategyId":37463720,"strategyType":1000000,"selfTradePreventionMode":"NONE","contingencyType":"OCO","listStatusType":"ALL_DONE","listOrderStatus":"ALL_DONE","listClientOrderId":"iuVNVJYYrByz6C4yGOPPK0","transactionTime":1660803702431,"orders":[{"symbol":"BTCUSDT","orderId":12569099454,"clientOrderId":"Tnu2IP0J5Y4mxw3IATBfmW"},{"symbol":"BTCUSDT","orderId":12569099453,"clientOrderId":"bX5wROblo6YeDwa9iTLeyY"},{"symbol":"BTCUSDT","orderId":12569099454,"clientOrderId":"Tnu2IP0J5Y4mxw3IATBfmW"},{"symbol":"BTCUSDT","orderId":12569099453,"clientOrderId":"bX5wROblo6YeDwa9iTLeyY"}],"orderReports":[{"symbol":"BTCUSDT","origClientOrderId":"Tnu2IP0J5Y4mxw3IATBfmW","orderId":12569099454,"orderListId":19431,"clientOrderId":"OFFXQtxVFZ6Nbcg4PgE2DA","transactTime":1684804350068,"price":"23400.00000000","origQty":"0.00850000","executedQty":"0.00000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"CANCELED","timeInForce":"GTC","type":"LIMIT_MAKER","side":"BUY","selfTradePreventionMode":"NONE"},{"symbol":"BTCUSDT","origClientOrderId":"bX5wROblo6YeDwa9iTLeyY","orderId":12569099453,"orderListId":19431,"clientOrderId":"OFFXQtxVFZ6Nbcg4PgE2DA","transactTime":1684804350068,"price":"23450.50000000","origQty":"0.00850000","executedQty":"0.00000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"CANCELED","timeInForce":"GTC","type":"STOP_LOSS_LIMIT","side":"BUY","stopPrice":"23430.00000000","selfTradePreventionMode":"NONE"},{"symbol":"BTCUSDT","origClientOrderId":"Tnu2IP0J5Y4mxw3IATBfmW","orderId":12569099454,"orderListId":19431,"clientOrderId":"OFFXQtxVFZ6Nbcg4PgE2DA","transactTime":1684804350068,"price":"23400.00000000","origQty":"0.00850000","executedQty":"0.00000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"CANCELED","timeInForce":"GTC","type":"LIMIT_MAKER","side":"BUY","selfTradePreventionMode":"NONE"},{"symbol":"BTCUSDT","origClientOrderId":"bX5wROblo6YeDwa9iTLeyY","orderId":12569099453,"orderListId":19431,"clientOrderId":"OFFXQtxVFZ6Nbcg4PgE2DA","transactTime":1684804350068,"price":"23450.50000000","origQty":"0.00850000","executedQty":"0.00000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"CANCELED","timeInForce":"GTC","type":"STOP_LOSS_LIMIT","side":"BUY","stopPrice":"23430.00000000","selfTradePreventionMode":"NONE"}]},"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000,"count":1}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::OrderCancelResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn order_cancel_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OrderCancelParams::builder("BNBUSDT".to_string(),).build().unwrap();
client.order_cancel(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn order_cancel_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderCancelParams::builder("BNBUSDT".to_string())
.build()
.unwrap();
client.order_cancel(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn order_cancel_replace_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderCancelReplaceParams::builder("BNBUSDT".to_string(),OrderCancelReplaceCancelReplaceModeEnum::StopOnFailure,OrderCancelReplaceSideEnum::Buy,OrderCancelReplaceTypeEnum::Market,).build().unwrap();
client.order_cancel_replace(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/order.cancelReplace".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"99de1036-b5e2-4e0f-9b5c-13d751c93a1a","status":200,"result":{"cancelResult":"SUCCESS","newOrderResult":"SUCCESS","cancelResponse":{"symbol":"BTCUSDT","origClientOrderId":"4d96324ff9d44481926157","orderId":125690984230,"orderListId":-1,"clientOrderId":"91fe37ce9e69c90d6358c0","transactTime":1684804350068,"price":"23450.00000000","origQty":"0.00847000","executedQty":"0.00001000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.23450000","status":"CANCELED","timeInForce":"GTC","type":"LIMIT","side":"SELL","selfTradePreventionMode":"NONE"},"newOrderResponse":{"symbol":"BTCUSDT","orderId":12569099453,"orderListId":-1,"clientOrderId":"bX5wROblo6YeDwa9iTLeyY","transactTime":1660813156959,"price":"23416.10000000","origQty":"0.00847000","executedQty":"0.00000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"SELL","selfTradePreventionMode":"NONE"}},"rateLimits":[{"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":50,"count":1},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000,"count":1},{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000,"count":1}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::OrderCancelReplaceResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn order_cancel_replace_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OrderCancelReplaceParams::builder("BNBUSDT".to_string(),OrderCancelReplaceCancelReplaceModeEnum::StopOnFailure,OrderCancelReplaceSideEnum::Buy,OrderCancelReplaceTypeEnum::Market,).build().unwrap();
client.order_cancel_replace(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn order_cancel_replace_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderCancelReplaceParams::builder(
"BNBUSDT".to_string(),
OrderCancelReplaceCancelReplaceModeEnum::StopOnFailure,
OrderCancelReplaceSideEnum::Buy,
OrderCancelReplaceTypeEnum::Market,
)
.build()
.unwrap();
client.order_cancel_replace(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn order_list_cancel_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListCancelParams::builder("BNBUSDT".to_string(),).build().unwrap();
client.order_list_cancel(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/orderList.cancel".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"c5899911-d3f4-47ae-8835-97da553d27d0","status":200,"result":{"orderListId":1274512,"contingencyType":"OCO","listStatusType":"ALL_DONE","listOrderStatus":"ALL_DONE","listClientOrderId":"6023531d7edaad348f5aff","transactionTime":1660801720215,"symbol":"BTCUSDT","orders":[{"symbol":"BTCUSDT","orderId":12569138902,"clientOrderId":"jLnZpj5enfMXTuhKB1d0us"},{"symbol":"BTCUSDT","orderId":12569138901,"clientOrderId":"BqtFCj5odMoWtSqGk2X9tU"}],"orderReports":[{"symbol":"BTCUSDT","orderId":12569138902,"orderListId":1274512,"clientOrderId":"jLnZpj5enfMXTuhKB1d0us","transactTime":1660801720215,"price":"23420.00000000","origQty":"0.00650000","executedQty":"0.00000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"CANCELED","timeInForce":"GTC","type":"LIMIT_MAKER","side":"SELL","selfTradePreventionMode":"NONE"},{"symbol":"BTCUSDT","orderId":12569138901,"orderListId":1274512,"clientOrderId":"BqtFCj5odMoWtSqGk2X9tU","transactTime":1660801720215,"price":"23410.00000000","origQty":"0.00650000","executedQty":"0.00000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"CANCELED","timeInForce":"GTC","type":"STOP_LOSS_LIMIT","side":"SELL","stopPrice":"23405.00000000","selfTradePreventionMode":"NONE"}]},"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000,"count":1}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::OrderListCancelResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn order_list_cancel_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OrderListCancelParams::builder("BNBUSDT".to_string(),).build().unwrap();
client.order_list_cancel(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn order_list_cancel_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListCancelParams::builder("BNBUSDT".to_string())
.build()
.unwrap();
client.order_list_cancel(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn order_list_place_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListPlaceParams::builder("BNBUSDT".to_string(),OrderListPlaceSideEnum::Buy,dec!(1.0),dec!(1.0),).build().unwrap();
client.order_list_place(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/orderList.place".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"57833dc0-e3f2-43fb-ba20-46480973b0aa","status":200,"result":{"orderListId":1274512,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"08985fedd9ea2cf6b28996","transactionTime":1660801713793,"symbol":"BTCUSDT","orders":[{"symbol":"BTCUSDT","orderId":12569138902,"clientOrderId":"jLnZpj5enfMXTuhKB1d0us"},{"symbol":"BTCUSDT","orderId":12569138901,"clientOrderId":"BqtFCj5odMoWtSqGk2X9tU"}],"orderReports":[{"symbol":"BTCUSDT","orderId":12569138902,"orderListId":1274512,"clientOrderId":"jLnZpj5enfMXTuhKB1d0us","transactTime":1660801713793,"price":"23420.00000000","origQty":"0.00650000","executedQty":"0.00000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"NEW","timeInForce":"GTC","type":"LIMIT_MAKER","side":"SELL","workingTime":1660801713793,"selfTradePreventionMode":"NONE"},{"symbol":"BTCUSDT","orderId":12569138901,"orderListId":1274512,"clientOrderId":"BqtFCj5odMoWtSqGk2X9tU","transactTime":1660801713793,"price":"23410.00000000","origQty":"0.00650000","executedQty":"0.00000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"NEW","timeInForce":"GTC","type":"STOP_LOSS_LIMIT","side":"SELL","stopPrice":"23405.00000000","workingTime":-1,"selfTradePreventionMode":"NONE"}]},"rateLimits":[{"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":50,"count":2},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000,"count":2},{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000,"count":1}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::OrderListPlaceResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn order_list_place_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OrderListPlaceParams::builder("BNBUSDT".to_string(),OrderListPlaceSideEnum::Buy,dec!(1.0),dec!(1.0),).build().unwrap();
client.order_list_place(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn order_list_place_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListPlaceParams::builder(
"BNBUSDT".to_string(),
OrderListPlaceSideEnum::Buy,
dec!(1.0),
dec!(1.0),
)
.build()
.unwrap();
client.order_list_place(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn order_list_place_oco_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListPlaceOcoParams::builder("BNBUSDT".to_string(),OrderListPlaceOcoSideEnum::Buy,dec!(1.0),OrderListPlaceOcoAboveTypeEnum::StopLossLimit,OrderListPlaceOcoBelowTypeEnum::StopLoss,).build().unwrap();
client.order_list_place_oco(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/orderList.place.oco".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"56374a46-3261-486b-a211-99ed972eb648","status":200,"result":{"orderListId":2,"contingencyType":"OCO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"cKPMnDCbcLQILtDYM4f4fX","transactionTime":1711062760648,"symbol":"LTCBNB","orders":[{"symbol":"LTCBNB","orderId":3,"clientOrderId":"Z2IMlR79XNY5LU0tOxrWyW"},{"symbol":"LTCBNB","orderId":2,"clientOrderId":"0m6I4wfxvTUrOBSMUl0OPU"}],"orderReports":[{"symbol":"LTCBNB","orderId":3,"orderListId":2,"clientOrderId":"Z2IMlR79XNY5LU0tOxrWyW","transactTime":1711062760648,"price":"1.49999999","origQty":"1.000000","executedQty":"0.000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"NEW","timeInForce":"GTC","type":"LIMIT_MAKER","side":"BUY","workingTime":1711062760648,"selfTradePreventionMode":"NONE"},{"symbol":"LTCBNB","orderId":2,"orderListId":2,"clientOrderId":"0m6I4wfxvTUrOBSMUl0OPU","transactTime":1711062760648,"price":"1.50000000","origQty":"1.000000","executedQty":"0.000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.00000000","status":"NEW","timeInForce":"GTC","type":"STOP_LOSS_LIMIT","side":"BUY","stopPrice":"1.50000001","workingTime":-1,"selfTradePreventionMode":"NONE"}]},"rateLimits":[{"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":50,"count":2},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000,"count":2},{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000,"count":1}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::OrderListPlaceOcoResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn order_list_place_oco_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OrderListPlaceOcoParams::builder("BNBUSDT".to_string(),OrderListPlaceOcoSideEnum::Buy,dec!(1.0),OrderListPlaceOcoAboveTypeEnum::StopLossLimit,OrderListPlaceOcoBelowTypeEnum::StopLoss,).build().unwrap();
client.order_list_place_oco(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn order_list_place_oco_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListPlaceOcoParams::builder(
"BNBUSDT".to_string(),
OrderListPlaceOcoSideEnum::Buy,
dec!(1.0),
OrderListPlaceOcoAboveTypeEnum::StopLossLimit,
OrderListPlaceOcoBelowTypeEnum::StopLoss,
)
.build()
.unwrap();
client.order_list_place_oco(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn order_list_place_opo_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListPlaceOpoParams::builder("BNBUSDT".to_string(),OrderListPlaceOpoWorkingTypeEnum::Limit,OrderListPlaceOpoWorkingSideEnum::Buy,dec!(1.0),dec!(1.0),OrderListPlaceOpoPendingTypeEnum::Limit,OrderListPlaceOpoPendingSideEnum::Buy,).build().unwrap();
client.order_list_place_opo(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/orderList.place.opo".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"1762941318128","status":200,"result":{"orderListId":2,"contingencyType":"OTO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"OiOgqvRagBefpzdM5gjYX3","transactionTime":1762941318142,"symbol":"BTCUSDT","orders":[{"symbol":"BTCUSDT","orderId":3,"clientOrderId":"x7ISSjywZxFXOdzwsThNnd"},{"symbol":"BTCUSDT","orderId":2,"clientOrderId":"pUzhKBbc0ZVdMScIRAqitH"}],"orderReports":[{"symbol":"BTCUSDT","orderId":3,"orderListId":2,"clientOrderId":"x7ISSjywZxFXOdzwsThNnd","transactTime":1762941318142,"price":"0.00000000","executedQty":"0.00000000","origQuoteOrderQty":"0.00000000","cummulativeQuoteQty":"0.00000000","status":"PENDING_NEW","timeInForce":"GTC","type":"MARKET","side":"SELL","workingTime":-1,"selfTradePreventionMode":"NONE"},{"symbol":"BTCUSDT","orderId":2,"orderListId":2,"clientOrderId":"pUzhKBbc0ZVdMScIRAqitH","transactTime":1762941318142,"price":"101496.00000000","origQty":"0.00070000","executedQty":"0.00000000","origQuoteOrderQty":"0.00000000","cummulativeQuoteQty":"0.00000000","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","workingTime":1762941318142,"selfTradePreventionMode":"NONE"}]}}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::OrderListPlaceOpoResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn order_list_place_opo_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OrderListPlaceOpoParams::builder("BNBUSDT".to_string(),OrderListPlaceOpoWorkingTypeEnum::Limit,OrderListPlaceOpoWorkingSideEnum::Buy,dec!(1.0),dec!(1.0),OrderListPlaceOpoPendingTypeEnum::Limit,OrderListPlaceOpoPendingSideEnum::Buy,).build().unwrap();
client.order_list_place_opo(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn order_list_place_opo_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListPlaceOpoParams::builder(
"BNBUSDT".to_string(),
OrderListPlaceOpoWorkingTypeEnum::Limit,
OrderListPlaceOpoWorkingSideEnum::Buy,
dec!(1.0),
dec!(1.0),
OrderListPlaceOpoPendingTypeEnum::Limit,
OrderListPlaceOpoPendingSideEnum::Buy,
)
.build()
.unwrap();
client.order_list_place_opo(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn order_list_place_opoco_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListPlaceOpocoParams::builder("BNBUSDT".to_string(),OrderListPlaceOpocoWorkingTypeEnum::Limit,OrderListPlaceOpocoWorkingSideEnum::Buy,dec!(1.0),dec!(1.0),OrderListPlaceOpocoPendingSideEnum::Buy,OrderListPlaceOpocoPendingAboveTypeEnum::StopLossLimit,).build().unwrap();
client.order_list_place_opoco(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/orderList.place.opoco".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"1763000139090","status":200,"result":{"orderListId":1,"contingencyType":"OTO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"TVbG6ymkYMXTj7tczbOsBf","transactionTime":1763000139104,"symbol":"BTCUSDT","orders":[{"symbol":"BTCUSDT","orderId":8,"clientOrderId":"i76cGJWN9J1FpADS56TtQZ"},{"symbol":"BTCUSDT","orderId":7,"clientOrderId":"kyIKnMLKQclE5FmyYgaMSo"},{"symbol":"BTCUSDT","orderId":6,"clientOrderId":"3czuJSeyjPwV9Xo28j1Dv3"}],"orderReports":[{"symbol":"BTCUSDT","orderId":8,"orderListId":1,"clientOrderId":"i76cGJWN9J1FpADS56TtQZ","transactTime":1763000139104,"price":"104261.00000000","executedQty":"0.00000000","origQuoteOrderQty":"0.00000000","cummulativeQuoteQty":"0.00000000","status":"PENDING_NEW","timeInForce":"GTC","type":"LIMIT_MAKER","side":"SELL","workingTime":-1,"selfTradePreventionMode":"NONE"},{"symbol":"BTCUSDT","orderId":7,"orderListId":1,"clientOrderId":"kyIKnMLKQclE5FmyYgaMSo","transactTime":1763000139104,"price":"101613.00000000","executedQty":"0.00000000","origQuoteOrderQty":"0.00000000","cummulativeQuoteQty":"0.00000000","status":"PENDING_NEW","timeInForce":"IOC","type":"STOP_LOSS_LIMIT","side":"SELL","stopPrice":"10100.00000000","workingTime":-1,"selfTradePreventionMode":"NONE"},{"symbol":"BTCUSDT","orderId":6,"orderListId":1,"clientOrderId":"3czuJSeyjPwV9Xo28j1Dv3","transactTime":1763000139104,"price":"102496.00000000","origQty":"0.00170000","executedQty":"0.00000000","origQuoteOrderQty":"0.00000000","cummulativeQuoteQty":"0.00000000","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","workingTime":1763000139104,"selfTradePreventionMode":"NONE"}]}}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::OrderListPlaceOpocoResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn order_list_place_opoco_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OrderListPlaceOpocoParams::builder("BNBUSDT".to_string(),OrderListPlaceOpocoWorkingTypeEnum::Limit,OrderListPlaceOpocoWorkingSideEnum::Buy,dec!(1.0),dec!(1.0),OrderListPlaceOpocoPendingSideEnum::Buy,OrderListPlaceOpocoPendingAboveTypeEnum::StopLossLimit,).build().unwrap();
client.order_list_place_opoco(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn order_list_place_opoco_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListPlaceOpocoParams::builder(
"BNBUSDT".to_string(),
OrderListPlaceOpocoWorkingTypeEnum::Limit,
OrderListPlaceOpocoWorkingSideEnum::Buy,
dec!(1.0),
dec!(1.0),
OrderListPlaceOpocoPendingSideEnum::Buy,
OrderListPlaceOpocoPendingAboveTypeEnum::StopLossLimit,
)
.build()
.unwrap();
client.order_list_place_opoco(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn order_list_place_oto_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListPlaceOtoParams::builder("BNBUSDT".to_string(),OrderListPlaceOtoWorkingTypeEnum::Limit,OrderListPlaceOtoWorkingSideEnum::Buy,dec!(1.0),dec!(1.0),OrderListPlaceOtoPendingTypeEnum::Limit,OrderListPlaceOtoPendingSideEnum::Buy,dec!(1.0),).build().unwrap();
client.order_list_place_oto(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/orderList.place.oto".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"1712544395950","status":200,"result":{"orderListId":626,"contingencyType":"OTO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"KA4EBjGnzvSwSCQsDdTrlf","transactionTime":1712544395981,"symbol":"1712544378871","orders":[{"symbol":"LTCBNB","orderId":14,"clientOrderId":"9MxJSE1TYkmyx5lbGLve7R"},{"symbol":"LTCBNB","orderId":13,"clientOrderId":"YiAUtM9yJjl1a2jXHSp9Ny"}],"orderReports":[{"symbol":"LTCBNB","orderId":14,"orderListId":626,"clientOrderId":"9MxJSE1TYkmyx5lbGLve7R","transactTime":1712544395981,"price":"0.000000","origQty":"1.000000","executedQty":"0.000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.000000","status":"PENDING_NEW","timeInForce":"GTC","type":"MARKET","side":"BUY","workingTime":-1,"selfTradePreventionMode":"NONE"},{"symbol":"LTCBNB","orderId":13,"orderListId":626,"clientOrderId":"YiAUtM9yJjl1a2jXHSp9Ny","transactTime":1712544395981,"price":"1.000000","origQty":"1.000000","executedQty":"0.000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.000000","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"SELL","workingTime":1712544395981,"selfTradePreventionMode":"NONE"}]},"rateLimits":[{"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":10000000,"count":10},{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":1000,"count":38}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::OrderListPlaceOtoResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn order_list_place_oto_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OrderListPlaceOtoParams::builder("BNBUSDT".to_string(),OrderListPlaceOtoWorkingTypeEnum::Limit,OrderListPlaceOtoWorkingSideEnum::Buy,dec!(1.0),dec!(1.0),OrderListPlaceOtoPendingTypeEnum::Limit,OrderListPlaceOtoPendingSideEnum::Buy,dec!(1.0),).build().unwrap();
client.order_list_place_oto(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn order_list_place_oto_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListPlaceOtoParams::builder(
"BNBUSDT".to_string(),
OrderListPlaceOtoWorkingTypeEnum::Limit,
OrderListPlaceOtoWorkingSideEnum::Buy,
dec!(1.0),
dec!(1.0),
OrderListPlaceOtoPendingTypeEnum::Limit,
OrderListPlaceOtoPendingSideEnum::Buy,
dec!(1.0),
)
.build()
.unwrap();
client.order_list_place_oto(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn order_list_place_otoco_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListPlaceOtocoParams::builder("BNBUSDT".to_string(),OrderListPlaceOtocoWorkingTypeEnum::Limit,OrderListPlaceOtocoWorkingSideEnum::Buy,dec!(1.0),dec!(1.0),OrderListPlaceOtocoPendingSideEnum::Buy,dec!(1.0),OrderListPlaceOtocoPendingAboveTypeEnum::StopLossLimit,).build().unwrap();
client.order_list_place_otoco(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/orderList.place.otoco".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"1712544408508","status":200,"result":{"orderListId":629,"contingencyType":"OTO","listStatusType":"EXEC_STARTED","listOrderStatus":"EXECUTING","listClientOrderId":"GaeJHjZPasPItFj4x7Mqm6","transactionTime":1712544408537,"symbol":"1712544378871","orders":[{"symbol":"LTCBNB","orderId":25,"clientOrderId":"ilpIoShcFZ1ZGgSASKxMPt"},{"symbol":"LTCBNB","orderId":24,"clientOrderId":"YcCPKCDMQIjNvLtNswt82X"},{"symbol":"LTCBNB","orderId":23,"clientOrderId":"OVQOpKwfmPCfaBTD0n7e7H"}],"orderReports":[{"symbol":"LTCBNB","orderId":25,"orderListId":629,"clientOrderId":"ilpIoShcFZ1ZGgSASKxMPt","transactTime":1712544408537,"price":"5.000000","origQty":"5.000000","executedQty":"0.000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.000000","status":"PENDING_NEW","timeInForce":"GTC","type":"LIMIT_MAKER","side":"SELL","workingTime":-1,"selfTradePreventionMode":"NONE"},{"symbol":"LTCBNB","orderId":24,"orderListId":629,"clientOrderId":"YcCPKCDMQIjNvLtNswt82X","transactTime":1712544408537,"price":"0.000000","origQty":"5.000000","executedQty":"0.000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.000000","status":"PENDING_NEW","timeInForce":"GTC","type":"STOP_LOSS","side":"SELL","stopPrice":"0.500000","workingTime":-1,"selfTradePreventionMode":"NONE"},{"symbol":"LTCBNB","orderId":23,"orderListId":629,"clientOrderId":"OVQOpKwfmPCfaBTD0n7e7H","transactTime":1712544408537,"price":"1.500000","origQty":"1.000000","executedQty":"0.000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"0.000000","status":"NEW","timeInForce":"GTC","type":"LIMIT","side":"BUY","workingTime":1712544408537,"selfTradePreventionMode":"NONE"}]},"rateLimits":[{"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":10000000,"count":18},{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":1000,"count":65}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::OrderListPlaceOtocoResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn order_list_place_otoco_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OrderListPlaceOtocoParams::builder("BNBUSDT".to_string(),OrderListPlaceOtocoWorkingTypeEnum::Limit,OrderListPlaceOtocoWorkingSideEnum::Buy,dec!(1.0),dec!(1.0),OrderListPlaceOtocoPendingSideEnum::Buy,dec!(1.0),OrderListPlaceOtocoPendingAboveTypeEnum::StopLossLimit,).build().unwrap();
client.order_list_place_otoco(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn order_list_place_otoco_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderListPlaceOtocoParams::builder(
"BNBUSDT".to_string(),
OrderListPlaceOtocoWorkingTypeEnum::Limit,
OrderListPlaceOtocoWorkingSideEnum::Buy,
dec!(1.0),
dec!(1.0),
OrderListPlaceOtocoPendingSideEnum::Buy,
dec!(1.0),
OrderListPlaceOtocoPendingAboveTypeEnum::StopLossLimit,
)
.build()
.unwrap();
client.order_list_place_otoco(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn order_place_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderPlaceParams::builder("BNBUSDT".to_string(),OrderPlaceSideEnum::Buy,OrderPlaceTypeEnum::Market,).build().unwrap();
client.order_place(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/order.place".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"56374a46-3061-486b-a311-99ee972eb648","status":200,"result":{"symbol":"BTCUSDT","orderId":12569099453,"orderListId":-1,"clientOrderId":"4d96324ff9d44481926157ec08158a40","transactTime":1660801715793,"price":"23416.10000000","origQty":"0.00847000","executedQty":"0.00847000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"198.33521500","status":"FILLED","timeInForce":"GTC","type":"LIMIT","side":"SELL","workingTime":1660801715793,"selfTradePreventionMode":"NONE","fills":[{"price":"23416.50000000","qty":"0.00212000","commission":"0.000000","commissionAsset":"BNB","tradeId":1650422482},{"price":"23416.10000000","qty":"0.00635000","commission":"0.000000","commissionAsset":"BNB","tradeId":1650422481},{"price":"23416.50000000","qty":"0.00212000","commission":"0.000000","commissionAsset":"BNB","tradeId":1650422482},{"price":"23416.10000000","qty":"0.00635000","commission":"0.000000","commissionAsset":"BNB","tradeId":1650422481}]},"rateLimits":[{"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":50,"count":1},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000,"count":1},{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000,"count":1}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::OrderPlaceResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn order_place_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OrderPlaceParams::builder("BNBUSDT".to_string(),OrderPlaceSideEnum::Buy,OrderPlaceTypeEnum::Market,).build().unwrap();
client.order_place(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn order_place_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderPlaceParams::builder(
"BNBUSDT".to_string(),
OrderPlaceSideEnum::Buy,
OrderPlaceTypeEnum::Market,
)
.build()
.unwrap();
client.order_place(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn order_test_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderTestParams::builder("BNBUSDT".to_string(),OrderTestSideEnum::Buy,OrderTestTypeEnum::Market,).build().unwrap();
client.order_test(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/order.test".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"6ffebe91-01d9-43ac-be99-57cf062e0e30","status":200,"result":{"standardCommissionForOrder":{"maker":"0.00000112","taker":"0.00000114"},"specialCommissionForOrder":{"maker":"0.05000000","taker":"0.06000000"},"taxCommissionForOrder":{"maker":"0.00000112","taker":"0.00000114"},"discount":{"enabledForAccount":true,"enabledForSymbol":true,"discountAsset":"BNB","discount":"0.25000000"}},"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000,"count":1}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::OrderTestResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn order_test_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = OrderTestParams::builder("BNBUSDT".to_string(),OrderTestSideEnum::Buy,OrderTestTypeEnum::Market,).build().unwrap();
client.order_test(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn order_test_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = OrderTestParams::builder(
"BNBUSDT".to_string(),
OrderTestSideEnum::Buy,
OrderTestTypeEnum::Market,
)
.build()
.unwrap();
client.order_test(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn sor_order_place_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = SorOrderPlaceParams::builder("BNBUSDT".to_string(),SorOrderPlaceSideEnum::Buy,SorOrderPlaceTypeEnum::Market,dec!(1.0),).build().unwrap();
client.sor_order_place(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/sor.order.place".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"3a4437e2-41a3-4c19-897c-9cadc5dce8b6","status":200,"result":[{"symbol":"BTCUSDT","orderId":2,"orderListId":-1,"clientOrderId":"sBI1KM6nNtOfj5tccZSKly","transactTime":1689149087774,"price":"31000.00000000","origQty":"0.50000000","executedQty":"0.50000000","origQuoteOrderQty":"0.000000","cummulativeQuoteQty":"14000.00000000","status":"FILLED","timeInForce":"GTC","type":"LIMIT","side":"BUY","workingTime":1689149087774,"fills":[{"matchType":"ONE_PARTY_TRADE_REPORT","price":"28000.00000000","qty":"0.50000000","commission":"0.00000000","commissionAsset":"BTC","tradeId":-1,"allocId":0}],"workingFloor":"SOR","selfTradePreventionMode":"NONE","usedSor":true}],"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000,"count":1}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Vec<models::SorOrderPlaceResponseResultInner> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn sor_order_place_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = SorOrderPlaceParams::builder("BNBUSDT".to_string(),SorOrderPlaceSideEnum::Buy,SorOrderPlaceTypeEnum::Market,dec!(1.0),).build().unwrap();
client.sor_order_place(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn sor_order_place_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = SorOrderPlaceParams::builder(
"BNBUSDT".to_string(),
SorOrderPlaceSideEnum::Buy,
SorOrderPlaceTypeEnum::Market,
dec!(1.0),
)
.build()
.unwrap();
client.sor_order_place(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
#[test]
fn sor_order_test_success() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = SorOrderTestParams::builder("BNBUSDT".to_string(),SorOrderTestSideEnum::Buy,SorOrderTestTypeEnum::Market,dec!(1.0),).build().unwrap();
client.sor_order_test(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.expect("send should occur").expect("channel closed");
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap();
assert_eq!(v["method"], "/sor.order.test".trim_start_matches('/'));
let mut resp_json: Value = serde_json::from_str(r#"{"id":"3a4437e2-41a3-4c19-897c-9cadc5dce8b6","status":200,"result":{"standardCommissionForOrder":{"maker":"0.00000112","taker":"0.00000114"},"taxCommissionForOrder":{"maker":"0.00000112","taker":"0.00000114"},"discount":{"enabledForAccount":true,"enabledForSymbol":true,"discountAsset":"BNB","discount":"0.25"}},"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000,"count":1}]}"#).unwrap();
resp_json["id"] = id.into();
let raw_data = resp_json.get("result").or_else(|| resp_json.get("response")).expect("no response in JSON");
let expected_data: Box<models::SorOrderTestResponseResult> = serde_json::from_value(raw_data.clone()).expect("should parse raw response");
let empty_array = Value::Array(vec![]);
let raw_rate_limits = resp_json.get("rateLimits").unwrap_or(&empty_array);
let expected_rate_limits: Option<Vec<WebsocketApiRateLimit>> =
match raw_rate_limits.as_array() {
Some(arr) if arr.is_empty() => None,
Some(_) => Some(serde_json::from_value(raw_rate_limits.clone()).expect("should parse rateLimits array")),
None => None,
};
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let response = timeout(Duration::from_secs(1), handle).await.expect("task done").expect("no panic").expect("no error");
let response_rate_limits = response.rate_limits.clone();
let response_data = response.data().expect("deserialize data");
assert_eq!(response_rate_limits, expected_rate_limits);
assert_eq!(response_data, expected_data);
});
}
#[test]
fn sor_order_test_error_response() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = tokio::spawn(async move {
let params = SorOrderTestParams::builder("BNBUSDT".to_string(),SorOrderTestSideEnum::Buy,SorOrderTestTypeEnum::Market,dec!(1.0),).build().unwrap();
client.sor_order_test(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv()).await.unwrap().unwrap();
let Message::Text(text) = sent else { panic!() };
let v: Value = serde_json::from_str(&text).unwrap();
let id = v["id"].as_str().unwrap().to_string();
let resp_json = json!({
"id": id,
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action.",
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
],
});
WebsocketHandler::on_message(&*ws_api, resp_json.to_string(), conn.clone()).await;
let join = timeout(Duration::from_secs(1), handle).await.unwrap();
match join {
Ok(Err(e)) => {
let msg = e.to_string();
assert!(
msg.contains("Server‐side response error (code -2010): Account has insufficient balance for requested action."),
"Expected error msg to contain server error, got: {msg}"
);
}
Ok(Ok(_)) => panic!("Expected error"),
Err(_) => panic!("Task panicked"),
}
});
}
#[test]
fn sor_order_test_request_timeout() {
TOKIO_SHARED_RT.block_on(async {
let (ws_api, _conn, mut rx) = setup().await;
let client = TradeApiClient::new(ws_api.clone());
let handle = spawn(async move {
let params = SorOrderTestParams::builder(
"BNBUSDT".to_string(),
SorOrderTestSideEnum::Buy,
SorOrderTestTypeEnum::Market,
dec!(1.0),
)
.build()
.unwrap();
client.sor_order_test(params).await
});
let sent = timeout(Duration::from_secs(1), rx.recv())
.await
.expect("send should occur")
.expect("channel closed");
let Message::Text(text) = sent else {
panic!("expected Message Text")
};
let _: Value = serde_json::from_str(&text).unwrap();
let result = handle.await.expect("task completed");
match result {
Err(e) => {
if let Some(inner) = e.downcast_ref::<WebsocketError>() {
assert!(matches!(inner, WebsocketError::Timeout));
} else {
panic!("Unexpected error type: {:?}", e);
}
}
Ok(_) => panic!("Expected timeout error"),
}
});
}
}