use crate::api::API_MIX_ORDER_PATH;
use crate::client::BitgetClient;
use crate::error::Error;
use reqwest::Method;
use serde::Serialize;
use serde_json::Value;
#[derive(Clone)]
pub struct BitgetTrade {
client: BitgetClient,
}
impl BitgetTrade {
pub fn new(client: BitgetClient) -> Self {
Self { client }
}
pub fn from_env() -> Result<Self, Error> {
Ok(Self::new(BitgetClient::from_env()?))
}
pub async fn place_order(&self, request: NewOrderRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/place-order");
self.client
.send_signed_json_request(Method::POST, &path, &[], &request)
.await
}
pub async fn place_multiple_orders<T: Serialize>(&self, request: &T) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/batch-place-order");
self.client
.send_signed_json_request(Method::POST, &path, &[], request)
.await
}
pub async fn cancel_order(&self, request: CancelOrderRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/cancel-order");
self.client
.send_signed_json_request(Method::POST, &path, &[], &request)
.await
}
pub async fn cancel_multiple_orders<T: Serialize>(&self, request: &T) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/cancel-batch-orders");
self.client
.send_signed_json_request(Method::POST, &path, &[], request)
.await
}
pub async fn cancel_all_orders(&self, request: CancelAllOrdersRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/cancel-all-orders");
self.client
.send_signed_json_request(Method::POST, &path, &[], &request)
.await
}
pub async fn modify_order(&self, request: ModifyOrderRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/modify-order");
self.client
.send_signed_json_request(Method::POST, &path, &[], &request)
.await
}
pub async fn place_plan_order(&self, request: PlanOrderRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/place-plan-order");
self.client
.send_signed_json_request(Method::POST, &path, &[], &request)
.await
}
pub async fn place_tpsl_order(&self, request: TpslOrderRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/place-tpsl-order");
self.client
.send_signed_json_request(Method::POST, &path, &[], &request)
.await
}
pub async fn place_position_tpsl(&self, request: PositionTpslRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/place-pos-tpsl");
self.client
.send_signed_json_request(Method::POST, &path, &[], &request)
.await
}
pub async fn modify_plan_order(&self, request: ModifyPlanOrderRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/modify-plan-order");
self.client
.send_signed_json_request(Method::POST, &path, &[], &request)
.await
}
pub async fn modify_tpsl_order(&self, request: ModifyTpslOrderRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/modify-tpsl-order");
self.client
.send_signed_json_request(Method::POST, &path, &[], &request)
.await
}
pub async fn cancel_plan_order(&self, request: CancelPlanOrderRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/cancel-plan-order");
self.client
.send_signed_json_request(Method::POST, &path, &[], &request)
.await
}
pub async fn close_positions(&self, request: ClosePositionsRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/close-positions");
self.client
.send_signed_json_request(Method::POST, &path, &[], &request)
.await
}
pub async fn get_order_detail(
&self,
symbol: &str,
product_type: &str,
order_id: Option<&str>,
client_oid: Option<&str>,
) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/detail");
let mut params = vec![
("productType", product_type.to_string()),
("symbol", symbol.to_string()),
];
push_opt(&mut params, "orderId", order_id);
push_opt(&mut params, "clientOid", client_oid);
self.client
.send_signed_request(Method::GET, &path, ¶ms)
.await
}
pub async fn get_pending_orders(
&self,
product_type: &str,
symbol: Option<&str>,
) -> Result<Value, Error> {
self.get_pending_orders_with(
OrderQueryRequest::new(product_type).with_optional_symbol(symbol),
)
.await
}
pub async fn get_pending_orders_with(
&self,
request: OrderQueryRequest,
) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/orders-pending");
self.client
.send_signed_request(Method::GET, &path, &request.to_params())
.await
}
pub async fn get_order_history(
&self,
product_type: &str,
symbol: Option<&str>,
) -> Result<Value, Error> {
self.get_order_history_with(
OrderQueryRequest::new(product_type).with_optional_symbol(symbol),
)
.await
}
pub async fn get_order_history_with(&self, request: OrderQueryRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/orders-history");
self.client
.send_signed_request(Method::GET, &path, &request.to_params())
.await
}
pub async fn get_fills(
&self,
product_type: &str,
symbol: Option<&str>,
) -> Result<Value, Error> {
self.get_fills_with(OrderQueryRequest::new(product_type).with_optional_symbol(symbol))
.await
}
pub async fn get_fills_with(&self, request: OrderQueryRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/fills");
self.client
.send_signed_request(Method::GET, &path, &request.to_params())
.await
}
pub async fn get_pending_plan_orders(
&self,
request: PlanOrderQueryRequest,
) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/orders-plan-pending");
self.client
.send_signed_request(Method::GET, &path, &request.to_params())
.await
}
pub async fn get_plan_order_history(
&self,
request: PlanOrderQueryRequest,
) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/orders-plan-history");
self.client
.send_signed_request(Method::GET, &path, &request.to_params())
.await
}
pub async fn get_plan_sub_orders(&self, request: PlanSubOrderRequest) -> Result<Value, Error> {
let path = format!("{API_MIX_ORDER_PATH}/plan-sub-order");
self.client
.send_signed_request(Method::GET, &path, &request.to_params())
.await
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OrderQueryRequest {
pub product_type: String,
pub symbol: Option<String>,
pub order_id: Option<String>,
pub client_oid: Option<String>,
pub status: Option<String>,
pub id_less_than: Option<String>,
pub start_time: Option<u64>,
pub end_time: Option<u64>,
pub limit: Option<u32>,
}
impl OrderQueryRequest {
pub fn new(product_type: impl Into<String>) -> Self {
Self {
product_type: product_type.into(),
symbol: None,
order_id: None,
client_oid: None,
status: None,
id_less_than: None,
start_time: None,
end_time: None,
limit: None,
}
}
pub fn with_symbol(mut self, value: impl Into<String>) -> Self {
self.symbol = Some(value.into());
self
}
pub fn with_order_id(mut self, value: impl Into<String>) -> Self {
self.order_id = Some(value.into());
self
}
pub fn with_client_oid(mut self, value: impl Into<String>) -> Self {
self.client_oid = Some(value.into());
self
}
pub fn with_status(mut self, value: impl Into<String>) -> Self {
self.status = Some(value.into());
self
}
pub fn with_id_less_than(mut self, value: impl Into<String>) -> Self {
self.id_less_than = Some(value.into());
self
}
pub fn with_start_time(mut self, value: u64) -> Self {
self.start_time = Some(value);
self
}
pub fn with_end_time(mut self, value: u64) -> Self {
self.end_time = Some(value);
self
}
pub fn with_limit(mut self, value: u32) -> Self {
self.limit = Some(value);
self
}
fn with_optional_symbol(mut self, value: Option<&str>) -> Self {
self.symbol = value.map(ToOwned::to_owned);
self
}
fn to_params(&self) -> Vec<(&'static str, String)> {
let mut params = vec![("productType", self.product_type.clone())];
push_opt_string(&mut params, "symbol", self.symbol.clone());
push_opt_string(&mut params, "orderId", self.order_id.clone());
push_opt_string(&mut params, "clientOid", self.client_oid.clone());
push_opt_string(&mut params, "status", self.status.clone());
push_opt_string(&mut params, "idLessThan", self.id_less_than.clone());
push_opt_string(
&mut params,
"startTime",
self.start_time.map(|value| value.to_string()),
);
push_opt_string(
&mut params,
"endTime",
self.end_time.map(|value| value.to_string()),
);
push_opt_string(
&mut params,
"limit",
self.limit.map(|value| value.to_string()),
);
params
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct NewOrderRequest {
pub symbol: String,
pub product_type: String,
pub margin_mode: String,
pub margin_coin: String,
pub size: String,
pub side: String,
pub order_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trade_side: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub force: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_oid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reduce_only: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub preset_stop_surplus_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub preset_stop_loss_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stp_mode: Option<String>,
}
impl NewOrderRequest {
pub fn limit(
symbol: impl Into<String>,
product_type: impl Into<String>,
margin_mode: impl Into<String>,
margin_coin: impl Into<String>,
size: impl Into<String>,
side: impl Into<String>,
price: impl Into<String>,
) -> Self {
Self {
symbol: symbol.into(),
product_type: product_type.into(),
margin_mode: margin_mode.into(),
margin_coin: margin_coin.into(),
size: size.into(),
side: side.into(),
order_type: "limit".to_string(),
price: Some(price.into()),
trade_side: None,
force: None,
client_oid: None,
reduce_only: None,
preset_stop_surplus_price: None,
preset_stop_loss_price: None,
stp_mode: None,
}
}
pub fn market(
symbol: impl Into<String>,
product_type: impl Into<String>,
margin_mode: impl Into<String>,
margin_coin: impl Into<String>,
size: impl Into<String>,
side: impl Into<String>,
) -> Self {
Self {
symbol: symbol.into(),
product_type: product_type.into(),
margin_mode: margin_mode.into(),
margin_coin: margin_coin.into(),
size: size.into(),
side: side.into(),
order_type: "market".to_string(),
price: None,
trade_side: None,
force: None,
client_oid: None,
reduce_only: None,
preset_stop_surplus_price: None,
preset_stop_loss_price: None,
stp_mode: None,
}
}
pub fn with_trade_side(mut self, value: impl Into<String>) -> Self {
self.trade_side = Some(value.into());
self
}
pub fn with_force(mut self, value: impl Into<String>) -> Self {
self.force = Some(value.into());
self
}
pub fn with_client_oid(mut self, value: impl Into<String>) -> Self {
self.client_oid = Some(value.into());
self
}
pub fn with_reduce_only(mut self, value: impl Into<String>) -> Self {
self.reduce_only = Some(value.into());
self
}
pub fn with_preset_stop_surplus_price(mut self, value: impl Into<String>) -> Self {
self.preset_stop_surplus_price = Some(value.into());
self
}
pub fn with_preset_stop_loss_price(mut self, value: impl Into<String>) -> Self {
self.preset_stop_loss_price = Some(value.into());
self
}
pub fn with_stp_mode(mut self, value: impl Into<String>) -> Self {
self.stp_mode = Some(value.into());
self
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct CancelOrderRequest {
pub symbol: String,
pub product_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub margin_coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_oid: Option<String>,
}
impl CancelOrderRequest {
pub fn new(symbol: impl Into<String>, product_type: impl Into<String>) -> Self {
Self {
symbol: symbol.into(),
product_type: product_type.into(),
margin_coin: None,
order_id: None,
client_oid: None,
}
}
pub fn with_margin_coin(mut self, value: impl Into<String>) -> Self {
self.margin_coin = Some(value.into());
self
}
pub fn with_order_id(mut self, value: impl Into<String>) -> Self {
self.order_id = Some(value.into());
self
}
pub fn with_client_oid(mut self, value: impl Into<String>) -> Self {
self.client_oid = Some(value.into());
self
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct CancelAllOrdersRequest {
pub product_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub margin_coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub request_time: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub receive_window: Option<String>,
}
impl CancelAllOrdersRequest {
pub fn new(product_type: impl Into<String>) -> Self {
Self {
product_type: product_type.into(),
margin_coin: None,
request_time: None,
receive_window: None,
}
}
pub fn with_margin_coin(mut self, value: impl Into<String>) -> Self {
self.margin_coin = Some(value.into());
self
}
pub fn with_request_time(mut self, value: impl Into<String>) -> Self {
self.request_time = Some(value.into());
self
}
pub fn with_receive_window(mut self, value: impl Into<String>) -> Self {
self.receive_window = Some(value.into());
self
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ModifyOrderRequest {
pub symbol: String,
pub product_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub margin_coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_oid: Option<String>,
pub new_client_oid: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_size: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_preset_stop_surplus_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_preset_stop_loss_price: Option<String>,
}
impl ModifyOrderRequest {
pub fn new(
symbol: impl Into<String>,
product_type: impl Into<String>,
new_client_oid: impl Into<String>,
) -> Self {
Self {
symbol: symbol.into(),
product_type: product_type.into(),
margin_coin: None,
order_id: None,
client_oid: None,
new_client_oid: new_client_oid.into(),
new_size: None,
new_price: None,
new_preset_stop_surplus_price: None,
new_preset_stop_loss_price: None,
}
}
pub fn with_margin_coin(mut self, value: impl Into<String>) -> Self {
self.margin_coin = Some(value.into());
self
}
pub fn with_order_id(mut self, value: impl Into<String>) -> Self {
self.order_id = Some(value.into());
self
}
pub fn with_client_oid(mut self, value: impl Into<String>) -> Self {
self.client_oid = Some(value.into());
self
}
pub fn with_new_size(mut self, value: impl Into<String>) -> Self {
self.new_size = Some(value.into());
self
}
pub fn with_new_price(mut self, value: impl Into<String>) -> Self {
self.new_price = Some(value.into());
self
}
pub fn with_new_preset_stop_surplus_price(mut self, value: impl Into<String>) -> Self {
self.new_preset_stop_surplus_price = Some(value.into());
self
}
pub fn with_new_preset_stop_loss_price(mut self, value: impl Into<String>) -> Self {
self.new_preset_stop_loss_price = Some(value.into());
self
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PlanOrderRequest {
pub plan_type: String,
pub symbol: String,
pub product_type: String,
pub margin_mode: String,
pub margin_coin: String,
pub size: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub callback_ratio: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trigger_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trigger_type: Option<String>,
pub side: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub trade_side: Option<String>,
pub order_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_oid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reduce_only: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_surplus_trigger_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_surplus_execute_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_surplus_trigger_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_loss_trigger_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_loss_execute_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_loss_trigger_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stp_mode: Option<String>,
}
impl PlanOrderRequest {
pub fn new(
plan_type: impl Into<String>,
symbol: impl Into<String>,
product_type: impl Into<String>,
margin_mode: impl Into<String>,
margin_coin: impl Into<String>,
size: impl Into<String>,
side: impl Into<String>,
) -> Self {
Self {
plan_type: plan_type.into(),
symbol: symbol.into(),
product_type: product_type.into(),
margin_mode: margin_mode.into(),
margin_coin: margin_coin.into(),
size: size.into(),
price: None,
callback_ratio: None,
trigger_price: None,
trigger_type: None,
side: side.into(),
trade_side: None,
order_type: "market".to_string(),
client_oid: None,
reduce_only: None,
stop_surplus_trigger_price: None,
stop_surplus_execute_price: None,
stop_surplus_trigger_type: None,
stop_loss_trigger_price: None,
stop_loss_execute_price: None,
stop_loss_trigger_type: None,
stp_mode: None,
}
}
pub fn with_limit_price(mut self, value: impl Into<String>) -> Self {
self.order_type = "limit".to_string();
self.price = Some(value.into());
self
}
pub fn with_market_order(mut self) -> Self {
self.order_type = "market".to_string();
self.price = None;
self
}
pub fn with_trigger(
mut self,
trigger_price: impl Into<String>,
trigger_type: impl Into<String>,
) -> Self {
self.trigger_price = Some(trigger_price.into());
self.trigger_type = Some(trigger_type.into());
self
}
pub fn with_callback_ratio(mut self, value: impl Into<String>) -> Self {
self.callback_ratio = Some(value.into());
self
}
pub fn with_trade_side(mut self, value: impl Into<String>) -> Self {
self.trade_side = Some(value.into());
self
}
pub fn with_client_oid(mut self, value: impl Into<String>) -> Self {
self.client_oid = Some(value.into());
self
}
pub fn with_reduce_only(mut self, value: impl Into<String>) -> Self {
self.reduce_only = Some(value.into());
self
}
pub fn with_stop_surplus_trigger_price(mut self, value: impl Into<String>) -> Self {
self.stop_surplus_trigger_price = Some(value.into());
self
}
pub fn with_stop_surplus_execute_price(mut self, value: impl Into<String>) -> Self {
self.stop_surplus_execute_price = Some(value.into());
self
}
pub fn with_stop_surplus_trigger_type(mut self, value: impl Into<String>) -> Self {
self.stop_surplus_trigger_type = Some(value.into());
self
}
pub fn with_stop_loss_trigger_price(mut self, value: impl Into<String>) -> Self {
self.stop_loss_trigger_price = Some(value.into());
self
}
pub fn with_stop_loss_execute_price(mut self, value: impl Into<String>) -> Self {
self.stop_loss_execute_price = Some(value.into());
self
}
pub fn with_stop_loss_trigger_type(mut self, value: impl Into<String>) -> Self {
self.stop_loss_trigger_type = Some(value.into());
self
}
pub fn with_stp_mode(mut self, value: impl Into<String>) -> Self {
self.stp_mode = Some(value.into());
self
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct TpslOrderRequest {
pub margin_coin: String,
pub product_type: String,
pub symbol: String,
pub plan_type: String,
pub trigger_price: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub trigger_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub execute_price: Option<String>,
pub hold_side: String,
pub size: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub range_rate: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_oid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stp_mode: Option<String>,
}
impl TpslOrderRequest {
pub fn new(
margin_coin: impl Into<String>,
product_type: impl Into<String>,
symbol: impl Into<String>,
plan_type: impl Into<String>,
trigger_price: impl Into<String>,
hold_side: impl Into<String>,
size: impl Into<String>,
) -> Self {
Self {
margin_coin: margin_coin.into(),
product_type: product_type.into(),
symbol: symbol.into(),
plan_type: plan_type.into(),
trigger_price: trigger_price.into(),
trigger_type: None,
execute_price: None,
hold_side: hold_side.into(),
size: size.into(),
range_rate: None,
client_oid: None,
stp_mode: None,
}
}
pub fn with_trigger_type(mut self, value: impl Into<String>) -> Self {
self.trigger_type = Some(value.into());
self
}
pub fn with_execute_price(mut self, value: impl Into<String>) -> Self {
self.execute_price = Some(value.into());
self
}
pub fn with_range_rate(mut self, value: impl Into<String>) -> Self {
self.range_rate = Some(value.into());
self
}
pub fn with_client_oid(mut self, value: impl Into<String>) -> Self {
self.client_oid = Some(value.into());
self
}
pub fn with_stp_mode(mut self, value: impl Into<String>) -> Self {
self.stp_mode = Some(value.into());
self
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PositionTpslRequest {
pub margin_coin: String,
pub product_type: String,
pub symbol: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_surplus_trigger_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_surplus_size: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_surplus_trigger_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_surplus_execute_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_loss_trigger_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_loss_size: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_loss_trigger_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_loss_execute_price: Option<String>,
pub hold_side: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub stp_mode: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_surplus_client_oid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_loss_client_oid: Option<String>,
}
impl PositionTpslRequest {
pub fn new(
margin_coin: impl Into<String>,
product_type: impl Into<String>,
symbol: impl Into<String>,
hold_side: impl Into<String>,
) -> Self {
Self {
margin_coin: margin_coin.into(),
product_type: product_type.into(),
symbol: symbol.into(),
stop_surplus_trigger_price: None,
stop_surplus_size: None,
stop_surplus_trigger_type: None,
stop_surplus_execute_price: None,
stop_loss_trigger_price: None,
stop_loss_size: None,
stop_loss_trigger_type: None,
stop_loss_execute_price: None,
hold_side: hold_side.into(),
stp_mode: None,
stop_surplus_client_oid: None,
stop_loss_client_oid: None,
}
}
pub fn with_stop_surplus(
mut self,
trigger_price: impl Into<String>,
trigger_type: impl Into<String>,
execute_price: impl Into<String>,
) -> Self {
self.stop_surplus_trigger_price = Some(trigger_price.into());
self.stop_surplus_trigger_type = Some(trigger_type.into());
self.stop_surplus_execute_price = Some(execute_price.into());
self
}
pub fn with_stop_surplus_size(mut self, value: impl Into<String>) -> Self {
self.stop_surplus_size = Some(value.into());
self
}
pub fn with_stop_loss(
mut self,
trigger_price: impl Into<String>,
trigger_type: impl Into<String>,
execute_price: impl Into<String>,
) -> Self {
self.stop_loss_trigger_price = Some(trigger_price.into());
self.stop_loss_trigger_type = Some(trigger_type.into());
self.stop_loss_execute_price = Some(execute_price.into());
self
}
pub fn with_stop_loss_size(mut self, value: impl Into<String>) -> Self {
self.stop_loss_size = Some(value.into());
self
}
pub fn with_stp_mode(mut self, value: impl Into<String>) -> Self {
self.stp_mode = Some(value.into());
self
}
pub fn with_stop_surplus_client_oid(mut self, value: impl Into<String>) -> Self {
self.stop_surplus_client_oid = Some(value.into());
self
}
pub fn with_stop_loss_client_oid(mut self, value: impl Into<String>) -> Self {
self.stop_loss_client_oid = Some(value.into());
self
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ModifyPlanOrderRequest {
pub plan_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_oid: Option<String>,
pub symbol: String,
pub product_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_size: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_callback_ratio: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_trigger_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_trigger_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_stop_surplus_execute_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_stop_surplus_trigger_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_stop_surplus_trigger_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_stop_loss_execute_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_stop_loss_trigger_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_stop_loss_trigger_type: Option<String>,
}
impl ModifyPlanOrderRequest {
pub fn new(
plan_type: impl Into<String>,
symbol: impl Into<String>,
product_type: impl Into<String>,
) -> Self {
Self {
plan_type: plan_type.into(),
order_id: None,
client_oid: None,
symbol: symbol.into(),
product_type: product_type.into(),
new_size: None,
new_price: None,
new_callback_ratio: None,
new_trigger_price: None,
new_trigger_type: None,
new_stop_surplus_execute_price: None,
new_stop_surplus_trigger_price: None,
new_stop_surplus_trigger_type: None,
new_stop_loss_execute_price: None,
new_stop_loss_trigger_price: None,
new_stop_loss_trigger_type: None,
}
}
pub fn with_order_id(mut self, value: impl Into<String>) -> Self {
self.order_id = Some(value.into());
self
}
pub fn with_client_oid(mut self, value: impl Into<String>) -> Self {
self.client_oid = Some(value.into());
self
}
pub fn with_new_size(mut self, value: impl Into<String>) -> Self {
self.new_size = Some(value.into());
self
}
pub fn with_new_price(mut self, value: impl Into<String>) -> Self {
self.new_price = Some(value.into());
self
}
pub fn with_new_callback_ratio(mut self, value: impl Into<String>) -> Self {
self.new_callback_ratio = Some(value.into());
self
}
pub fn with_new_trigger_price(mut self, value: impl Into<String>) -> Self {
self.new_trigger_price = Some(value.into());
self
}
pub fn with_new_trigger_type(mut self, value: impl Into<String>) -> Self {
self.new_trigger_type = Some(value.into());
self
}
pub fn with_new_stop_surplus_execute_price(mut self, value: impl Into<String>) -> Self {
self.new_stop_surplus_execute_price = Some(value.into());
self
}
pub fn with_new_stop_surplus_trigger_price(mut self, value: impl Into<String>) -> Self {
self.new_stop_surplus_trigger_price = Some(value.into());
self
}
pub fn with_new_stop_surplus_trigger_type(mut self, value: impl Into<String>) -> Self {
self.new_stop_surplus_trigger_type = Some(value.into());
self
}
pub fn with_new_stop_loss_execute_price(mut self, value: impl Into<String>) -> Self {
self.new_stop_loss_execute_price = Some(value.into());
self
}
pub fn with_new_stop_loss_trigger_price(mut self, value: impl Into<String>) -> Self {
self.new_stop_loss_trigger_price = Some(value.into());
self
}
pub fn with_new_stop_loss_trigger_type(mut self, value: impl Into<String>) -> Self {
self.new_stop_loss_trigger_type = Some(value.into());
self
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ModifyTpslOrderRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub order_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_oid: Option<String>,
pub margin_coin: String,
pub product_type: String,
pub symbol: String,
pub trigger_price: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub trigger_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub execute_price: Option<String>,
pub size: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub range_rate: Option<String>,
}
impl ModifyTpslOrderRequest {
pub fn new(
margin_coin: impl Into<String>,
product_type: impl Into<String>,
symbol: impl Into<String>,
trigger_price: impl Into<String>,
execute_price: impl Into<String>,
size: impl Into<String>,
) -> Self {
Self {
order_id: None,
client_oid: None,
margin_coin: margin_coin.into(),
product_type: product_type.into(),
symbol: symbol.into(),
trigger_price: trigger_price.into(),
trigger_type: None,
execute_price: Some(execute_price.into()),
size: size.into(),
range_rate: None,
}
}
pub fn with_order_id(mut self, value: impl Into<String>) -> Self {
self.order_id = Some(value.into());
self
}
pub fn with_client_oid(mut self, value: impl Into<String>) -> Self {
self.client_oid = Some(value.into());
self
}
pub fn with_trigger_type(mut self, value: impl Into<String>) -> Self {
self.trigger_type = Some(value.into());
self
}
pub fn with_range_rate(mut self, value: impl Into<String>) -> Self {
self.range_rate = Some(value.into());
self
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct CancelPlanOrderRequest {
#[serde(skip_serializing_if = "Vec::is_empty")]
pub order_id_list: Vec<PlanOrderId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
pub product_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub margin_coin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub plan_type: Option<String>,
}
impl CancelPlanOrderRequest {
pub fn new(product_type: impl Into<String>) -> Self {
Self {
order_id_list: Vec::new(),
symbol: None,
product_type: product_type.into(),
margin_coin: None,
plan_type: None,
}
}
pub fn with_order_id(mut self, value: impl Into<String>) -> Self {
self.order_id_list.push(PlanOrderId::order_id(value));
self
}
pub fn with_client_oid(mut self, value: impl Into<String>) -> Self {
self.order_id_list.push(PlanOrderId::client_oid(value));
self
}
pub fn with_symbol(mut self, value: impl Into<String>) -> Self {
self.symbol = Some(value.into());
self
}
pub fn with_margin_coin(mut self, value: impl Into<String>) -> Self {
self.margin_coin = Some(value.into());
self
}
pub fn with_plan_type(mut self, value: impl Into<String>) -> Self {
self.plan_type = Some(value.into());
self
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PlanOrderId {
#[serde(skip_serializing_if = "Option::is_none")]
pub order_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_oid: Option<String>,
}
impl PlanOrderId {
pub fn order_id(value: impl Into<String>) -> Self {
Self {
order_id: Some(value.into()),
client_oid: None,
}
}
pub fn client_oid(value: impl Into<String>) -> Self {
Self {
order_id: None,
client_oid: Some(value.into()),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PlanOrderQueryRequest {
pub product_type: String,
pub plan_type: String,
pub symbol: Option<String>,
pub order_id: Option<String>,
pub client_oid: Option<String>,
pub plan_status: Option<String>,
pub id_less_than: Option<String>,
pub start_time: Option<u64>,
pub end_time: Option<u64>,
pub limit: Option<u32>,
}
impl PlanOrderQueryRequest {
pub fn new(product_type: impl Into<String>, plan_type: impl Into<String>) -> Self {
Self {
product_type: product_type.into(),
plan_type: plan_type.into(),
symbol: None,
order_id: None,
client_oid: None,
plan_status: None,
id_less_than: None,
start_time: None,
end_time: None,
limit: None,
}
}
pub fn with_symbol(mut self, value: impl Into<String>) -> Self {
self.symbol = Some(value.into());
self
}
pub fn with_order_id(mut self, value: impl Into<String>) -> Self {
self.order_id = Some(value.into());
self
}
pub fn with_client_oid(mut self, value: impl Into<String>) -> Self {
self.client_oid = Some(value.into());
self
}
pub fn with_plan_status(mut self, value: impl Into<String>) -> Self {
self.plan_status = Some(value.into());
self
}
pub fn with_id_less_than(mut self, value: impl Into<String>) -> Self {
self.id_less_than = Some(value.into());
self
}
pub fn with_start_time(mut self, value: u64) -> Self {
self.start_time = Some(value);
self
}
pub fn with_end_time(mut self, value: u64) -> Self {
self.end_time = Some(value);
self
}
pub fn with_limit(mut self, value: u32) -> Self {
self.limit = Some(value);
self
}
fn to_params(&self) -> Vec<(&'static str, String)> {
let mut params = vec![
("productType", self.product_type.clone()),
("planType", self.plan_type.clone()),
];
push_opt_string(&mut params, "symbol", self.symbol.clone());
push_opt_string(&mut params, "orderId", self.order_id.clone());
push_opt_string(&mut params, "clientOid", self.client_oid.clone());
push_opt_string(&mut params, "planStatus", self.plan_status.clone());
push_opt_string(&mut params, "idLessThan", self.id_less_than.clone());
push_opt_string(
&mut params,
"startTime",
self.start_time.map(|value| value.to_string()),
);
push_opt_string(
&mut params,
"endTime",
self.end_time.map(|value| value.to_string()),
);
push_opt_string(
&mut params,
"limit",
self.limit.map(|value| value.to_string()),
);
params
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PlanSubOrderRequest {
pub product_type: String,
pub plan_type: String,
pub plan_order_id: String,
}
impl PlanSubOrderRequest {
pub fn new(
product_type: impl Into<String>,
plan_type: impl Into<String>,
plan_order_id: impl Into<String>,
) -> Self {
Self {
product_type: product_type.into(),
plan_type: plan_type.into(),
plan_order_id: plan_order_id.into(),
}
}
fn to_params(&self) -> Vec<(&'static str, String)> {
vec![
("productType", self.product_type.clone()),
("planType", self.plan_type.clone()),
("planOrderId", self.plan_order_id.clone()),
]
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ClosePositionsRequest {
pub product_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hold_side: Option<String>,
}
impl ClosePositionsRequest {
pub fn new(product_type: impl Into<String>) -> Self {
Self {
product_type: product_type.into(),
symbol: None,
hold_side: None,
}
}
pub fn with_symbol(mut self, value: impl Into<String>) -> Self {
self.symbol = Some(value.into());
self
}
pub fn with_hold_side(mut self, value: impl Into<String>) -> Self {
self.hold_side = Some(value.into());
self
}
}
fn push_opt(params: &mut Vec<(&'static str, String)>, key: &'static str, value: Option<&str>) {
if let Some(value) = value {
params.push((key, value.to_string()));
}
}
fn push_opt_string(
params: &mut Vec<(&'static str, String)>,
key: &'static str,
value: Option<String>,
) {
if let Some(value) = value {
params.push((key, value));
}
}