use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum OrderSide {
Buy,
Sell,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum OrderStatus {
Pending,
Open,
Filled,
Cancelled,
Expired,
Failed,
#[serde(other)]
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum StopDirection {
StopDirectionStopUp,
StopDirectionStopDown,
}
#[derive(Debug, Clone, Serialize)]
pub struct MarketIoc {
#[serde(skip_serializing_if = "Option::is_none")]
pub quote_size: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub base_size: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct LimitGtc {
pub base_size: String,
pub limit_price: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub post_only: Option<bool>,
}
#[derive(Debug, Clone, Serialize)]
pub struct LimitGtd {
pub base_size: String,
pub limit_price: String,
pub end_time: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub post_only: Option<bool>,
}
#[derive(Debug, Clone, Serialize)]
pub struct LimitFok {
pub base_size: String,
pub limit_price: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct StopLimitGtc {
pub base_size: String,
pub limit_price: String,
pub stop_price: String,
pub stop_direction: StopDirection,
}
#[derive(Debug, Clone, Serialize)]
pub struct StopLimitGtd {
pub base_size: String,
pub limit_price: String,
pub stop_price: String,
pub end_time: String,
pub stop_direction: StopDirection,
}
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum OrderConfiguration {
MarketIoc {
market_market_ioc: MarketIoc,
},
LimitGtc {
limit_limit_gtc: LimitGtc,
},
LimitGtd {
limit_limit_gtd: LimitGtd,
},
LimitFok {
limit_limit_fok: LimitFok,
},
StopLimitGtc {
stop_limit_stop_limit_gtc: StopLimitGtc,
},
StopLimitGtd {
stop_limit_stop_limit_gtd: StopLimitGtd,
},
}
impl OrderConfiguration {
pub fn market_buy_quote(quote_size: impl Into<String>) -> Self {
Self::MarketIoc {
market_market_ioc: MarketIoc {
quote_size: Some(quote_size.into()),
base_size: None,
},
}
}
pub fn market_buy_base(base_size: impl Into<String>) -> Self {
Self::MarketIoc {
market_market_ioc: MarketIoc {
quote_size: None,
base_size: Some(base_size.into()),
},
}
}
pub fn market_sell(base_size: impl Into<String>) -> Self {
Self::MarketIoc {
market_market_ioc: MarketIoc {
quote_size: None,
base_size: Some(base_size.into()),
},
}
}
pub fn limit_gtc(
base_size: impl Into<String>,
limit_price: impl Into<String>,
post_only: bool,
) -> Self {
Self::LimitGtc {
limit_limit_gtc: LimitGtc {
base_size: base_size.into(),
limit_price: limit_price.into(),
post_only: Some(post_only),
},
}
}
pub fn limit_gtd(
base_size: impl Into<String>,
limit_price: impl Into<String>,
end_time: impl Into<String>,
post_only: bool,
) -> Self {
Self::LimitGtd {
limit_limit_gtd: LimitGtd {
base_size: base_size.into(),
limit_price: limit_price.into(),
end_time: end_time.into(),
post_only: Some(post_only),
},
}
}
pub fn limit_fok(base_size: impl Into<String>, limit_price: impl Into<String>) -> Self {
Self::LimitFok {
limit_limit_fok: LimitFok {
base_size: base_size.into(),
limit_price: limit_price.into(),
},
}
}
pub fn stop_limit_gtc(
base_size: impl Into<String>,
limit_price: impl Into<String>,
stop_price: impl Into<String>,
stop_direction: StopDirection,
) -> Self {
Self::StopLimitGtc {
stop_limit_stop_limit_gtc: StopLimitGtc {
base_size: base_size.into(),
limit_price: limit_price.into(),
stop_price: stop_price.into(),
stop_direction,
},
}
}
pub fn stop_limit_gtd(
base_size: impl Into<String>,
limit_price: impl Into<String>,
stop_price: impl Into<String>,
end_time: impl Into<String>,
stop_direction: StopDirection,
) -> Self {
Self::StopLimitGtd {
stop_limit_stop_limit_gtd: StopLimitGtd {
base_size: base_size.into(),
limit_price: limit_price.into(),
stop_price: stop_price.into(),
end_time: end_time.into(),
stop_direction,
},
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateOrderRequest {
pub client_order_id: String,
pub product_id: String,
pub side: OrderSide,
pub order_configuration: OrderConfiguration,
#[serde(skip_serializing_if = "Option::is_none")]
pub self_trade_prevention_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub leverage: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub margin_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub retail_portfolio_id: Option<String>,
}
impl CreateOrderRequest {
pub fn new(
client_order_id: impl Into<String>,
product_id: impl Into<String>,
side: OrderSide,
order_configuration: OrderConfiguration,
) -> Self {
Self {
client_order_id: client_order_id.into(),
product_id: product_id.into(),
side,
order_configuration,
self_trade_prevention_id: None,
leverage: None,
margin_type: None,
retail_portfolio_id: None,
}
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct OrderSuccessResponse {
pub order_id: String,
pub product_id: Option<String>,
pub side: Option<String>,
pub client_order_id: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreateOrderResponse {
pub success: bool,
pub failure_reason: Option<String>,
pub order_id: Option<String>,
pub success_response: Option<OrderSuccessResponse>,
pub error_response: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CancelOrdersRequest {
pub order_ids: Vec<String>,
}
impl CancelOrdersRequest {
pub fn new(order_ids: Vec<String>) -> Self {
Self { order_ids }
}
pub fn single(order_id: impl Into<String>) -> Self {
Self {
order_ids: vec![order_id.into()],
}
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct CancelOrderResult {
pub success: bool,
pub failure_reason: Option<String>,
pub order_id: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CancelOrdersResponse {
pub results: Vec<CancelOrderResult>,
}
#[derive(Debug, Clone, Serialize)]
pub struct EditOrderRequest {
pub order_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<String>,
}
impl EditOrderRequest {
pub fn new(order_id: impl Into<String>) -> Self {
Self {
order_id: order_id.into(),
price: None,
size: None,
}
}
pub fn price(mut self, price: impl Into<String>) -> Self {
self.price = Some(price.into());
self
}
pub fn size(mut self, size: impl Into<String>) -> Self {
self.size = Some(size.into());
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct EditOrderResponse {
pub success: bool,
pub errors: Option<Vec<serde_json::Value>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Order {
pub order_id: String,
pub product_id: String,
pub user_id: Option<String>,
pub order_configuration: Option<serde_json::Value>,
pub side: String,
pub client_order_id: String,
pub status: String,
pub time_in_force: Option<String>,
pub created_time: Option<String>,
pub completion_percentage: Option<String>,
pub filled_size: Option<String>,
pub average_filled_price: Option<String>,
pub fee: Option<String>,
pub number_of_fills: Option<String>,
pub filled_value: Option<String>,
pub pending_cancel: Option<bool>,
pub size_in_quote: Option<bool>,
pub total_fees: Option<String>,
pub size_inclusive_of_fees: Option<bool>,
pub total_value_after_fees: Option<String>,
pub trigger_status: Option<String>,
pub order_type: Option<String>,
pub reject_reason: Option<String>,
pub settled: Option<bool>,
pub product_type: Option<String>,
pub reject_message: Option<String>,
pub cancel_message: Option<String>,
pub order_placement_source: Option<String>,
pub outstanding_hold_amount: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct ListOrdersParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub product_ids: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_date: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_date: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_side: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub product_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub retail_portfolio_id: Option<String>,
}
impl ListOrdersParams {
pub fn new() -> Self {
Self::default()
}
pub fn product_id(mut self, product_id: impl Into<String>) -> Self {
self.product_ids = Some(product_id.into());
self
}
pub fn status(mut self, status: impl Into<String>) -> Self {
self.order_status = Some(status.into());
self
}
pub fn limit(mut self, limit: u32) -> Self {
self.limit = Some(limit);
self
}
pub fn cursor(mut self, cursor: impl Into<String>) -> Self {
self.cursor = Some(cursor.into());
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct ListOrdersResponse {
pub orders: Vec<Order>,
pub sequence: Option<String>,
pub has_next: bool,
pub cursor: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Fill {
pub entry_id: String,
pub trade_id: String,
pub order_id: String,
pub trade_time: String,
pub trade_type: String,
pub price: String,
pub size: String,
pub commission: String,
pub product_id: String,
pub sequence_timestamp: Option<String>,
pub liquidity_indicator: Option<String>,
pub size_in_quote: Option<bool>,
pub user_id: Option<String>,
pub side: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct ListFillsParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub order_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub product_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_sequence_timestamp: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_sequence_timestamp: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
impl ListFillsParams {
pub fn new() -> Self {
Self::default()
}
pub fn order_id(mut self, order_id: impl Into<String>) -> Self {
self.order_id = Some(order_id.into());
self
}
pub fn product_id(mut self, product_id: impl Into<String>) -> Self {
self.product_id = Some(product_id.into());
self
}
pub fn limit(mut self, limit: u32) -> Self {
self.limit = Some(limit);
self
}
pub fn cursor(mut self, cursor: impl Into<String>) -> Self {
self.cursor = Some(cursor.into());
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct ListFillsResponse {
pub fills: Vec<Fill>,
pub cursor: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct ClosePositionRequest {
pub client_order_id: String,
pub product_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<String>,
}
impl ClosePositionRequest {
pub fn new(client_order_id: impl Into<String>, product_id: impl Into<String>) -> Self {
Self {
client_order_id: client_order_id.into(),
product_id: product_id.into(),
size: None,
}
}
pub fn size(mut self, size: impl Into<String>) -> Self {
self.size = Some(size.into());
self
}
}