exc_binance/http/request/trading/
mod.rs

1use self::spot::SideEffect;
2
3use super::{MarginOp, Rest, RestEndpoint, RestError};
4use serde::Serialize;
5
6/// Usd-Margin futures.
7pub mod usd_margin_futures;
8
9/// Spot.
10pub mod spot;
11
12/// European options.
13pub mod european_options;
14
15/// Place order.
16#[derive(Debug, Clone)]
17pub struct PlaceOrder {
18    pub(crate) inner: exc_core::types::PlaceOrder,
19}
20
21impl PlaceOrder {
22    fn dispatch(&self, endpoint: &RestEndpoint) -> Result<PlaceOrderKind, RestError> {
23        match endpoint {
24            RestEndpoint::UsdMarginFutures => Ok(PlaceOrderKind::UsdMarginFutures(
25                usd_margin_futures::PlaceOrder::try_from(&self.inner)?,
26            )),
27            RestEndpoint::EuropeanOptions => Ok(PlaceOrderKind::EuropeanOptions(
28                european_options::PlaceOrder::try_from(&self.inner)?,
29            )),
30            RestEndpoint::Spot(options) => {
31                let mut req = spot::PlaceOrder::try_from(&self.inner)?;
32                if let Some(margin) = options.margin.as_ref() {
33                    let margin = if self.inner.place.size.is_sign_positive() {
34                        margin.buy.as_ref()
35                    } else {
36                        margin.sell.as_ref()
37                    };
38                    match margin {
39                        Some(MarginOp::Loan) => {
40                            req.side_effect_type = Some(SideEffect::MarginBuy);
41                        }
42                        Some(MarginOp::Repay) => {
43                            req.side_effect_type = Some(SideEffect::AutoRepay);
44                        }
45                        None => {
46                            req.side_effect_type = None;
47                        }
48                    }
49                }
50                Ok(PlaceOrderKind::Spot(req))
51            }
52        }
53    }
54}
55
56/// Response type.
57#[derive(Debug, Clone, Copy, Serialize)]
58#[serde(rename_all = "UPPERCASE")]
59pub enum RespType {
60    /// Ack.
61    Ack,
62    /// Result.
63    Result,
64}
65
66/// Place order kind.
67#[derive(Debug, Clone, Serialize)]
68#[serde(untagged)]
69pub enum PlaceOrderKind {
70    /// Usd-Margin futures.
71    UsdMarginFutures(usd_margin_futures::PlaceOrder),
72    /// Spot.
73    Spot(spot::PlaceOrder),
74    /// European options.
75    EuropeanOptions(european_options::PlaceOrder),
76}
77
78impl Rest for PlaceOrder {
79    fn method(&self, _endpoint: &RestEndpoint) -> Result<http::Method, RestError> {
80        Ok(http::Method::POST)
81    }
82
83    fn to_path(&self, endpoint: &RestEndpoint) -> Result<String, RestError> {
84        match endpoint {
85            RestEndpoint::UsdMarginFutures => Ok("/fapi/v1/order".to_string()),
86            RestEndpoint::EuropeanOptions => Ok("/eapi/v1/order".to_string()),
87            RestEndpoint::Spot(options) => {
88                if options.margin.is_some() {
89                    Ok("/sapi/v1/margin/order".to_string())
90                } else {
91                    Ok("/api/v3/order".to_string())
92                }
93            }
94        }
95    }
96
97    fn need_apikey(&self) -> bool {
98        true
99    }
100
101    fn need_sign(&self) -> bool {
102        true
103    }
104
105    fn serialize(&self, endpoint: &RestEndpoint) -> Result<serde_json::Value, RestError> {
106        Ok(serde_json::to_value(self.dispatch(endpoint)?)?)
107    }
108
109    fn to_payload(&self) -> super::Payload {
110        super::Payload::new(self.clone())
111    }
112}
113
114/// Get order inner.
115#[derive(Debug, Clone, Serialize)]
116#[serde(rename_all = "camelCase")]
117pub struct GetOrderInner {
118    /// Symbol.
119    pub symbol: String,
120    /// Order Id.
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub order_id: Option<i64>,
123    /// Client Id.
124    #[serde(skip_serializing_if = "Option::is_none")]
125    pub orig_client_order_id: Option<String>,
126    /// Client Id.
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub client_order_id: Option<String>,
129}
130
131/// Cancel order.
132#[derive(Debug, Clone, Serialize)]
133#[serde(rename_all = "camelCase")]
134pub struct CancelOrder {
135    /// Inner.
136    #[serde(flatten)]
137    pub inner: GetOrderInner,
138}
139
140impl Rest for CancelOrder {
141    fn method(&self, _endpoint: &RestEndpoint) -> Result<http::Method, RestError> {
142        Ok(http::Method::DELETE)
143    }
144
145    fn to_path(&self, endpoint: &RestEndpoint) -> Result<String, RestError> {
146        match endpoint {
147            RestEndpoint::UsdMarginFutures => Ok("/fapi/v1/order".to_string()),
148            RestEndpoint::EuropeanOptions => Ok("/eapi/v1/order".to_string()),
149            RestEndpoint::Spot(options) => {
150                if options.margin.is_some() {
151                    Ok("/sapi/v1/margin/order".to_string())
152                } else {
153                    Ok("/api/v3/order".to_string())
154                }
155            }
156        }
157    }
158
159    fn need_apikey(&self) -> bool {
160        true
161    }
162
163    fn need_sign(&self) -> bool {
164        true
165    }
166
167    fn serialize(&self, endpoint: &RestEndpoint) -> Result<serde_json::Value, RestError> {
168        Ok(serde_json::to_value(self.dispatch(endpoint)?)?)
169    }
170
171    fn to_payload(&self) -> super::Payload {
172        super::Payload::new(self.clone())
173    }
174}
175
176impl CancelOrder {
177    fn dispatch(&self, endpoint: &RestEndpoint) -> Result<Self, RestError> {
178        match endpoint {
179            RestEndpoint::UsdMarginFutures => Ok(self.clone()),
180            RestEndpoint::EuropeanOptions => {
181                let mut req = self.clone();
182                req.inner.client_order_id = req.inner.orig_client_order_id.take();
183                Ok(req)
184            }
185            RestEndpoint::Spot(_) => Ok(self.clone()),
186        }
187    }
188}
189
190/// Get order.
191#[derive(Debug, Clone, Serialize)]
192#[serde(rename_all = "camelCase")]
193pub struct GetOrder {
194    /// Inner.
195    #[serde(flatten)]
196    pub inner: GetOrderInner,
197}
198
199impl GetOrder {
200    fn dispatch(&self, endpoint: &RestEndpoint) -> Result<Self, RestError> {
201        match endpoint {
202            RestEndpoint::UsdMarginFutures => Ok(self.clone()),
203            RestEndpoint::EuropeanOptions => {
204                let mut req = self.clone();
205                req.inner.client_order_id = req.inner.orig_client_order_id.take();
206                Ok(req)
207            }
208            RestEndpoint::Spot(_) => Ok(self.clone()),
209        }
210    }
211}
212
213impl Rest for GetOrder {
214    fn method(&self, _endpoint: &RestEndpoint) -> Result<http::Method, RestError> {
215        Ok(http::Method::GET)
216    }
217
218    fn to_path(&self, endpoint: &RestEndpoint) -> Result<String, RestError> {
219        match endpoint {
220            RestEndpoint::UsdMarginFutures => Ok("/fapi/v1/order".to_string()),
221            RestEndpoint::EuropeanOptions => Ok("/eapi/v1/order".to_string()),
222            RestEndpoint::Spot(options) => {
223                if options.margin.is_some() {
224                    Ok("/sapi/v1/margin/order".to_string())
225                } else {
226                    Ok("/api/v3/order".to_string())
227                }
228            }
229        }
230    }
231
232    fn need_apikey(&self) -> bool {
233        true
234    }
235
236    fn need_sign(&self) -> bool {
237        true
238    }
239
240    fn serialize(&self, endpoint: &RestEndpoint) -> Result<serde_json::Value, RestError> {
241        Ok(serde_json::to_value(self.dispatch(endpoint)?)?)
242    }
243
244    fn to_payload(&self) -> super::Payload {
245        super::Payload::new(self.clone())
246    }
247}