exc_binance/http/request/trading/
mod.rs1use self::spot::SideEffect;
2
3use super::{MarginOp, Rest, RestEndpoint, RestError};
4use serde::Serialize;
5
6pub mod usd_margin_futures;
8
9pub mod spot;
11
12pub mod european_options;
14
15#[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#[derive(Debug, Clone, Copy, Serialize)]
58#[serde(rename_all = "UPPERCASE")]
59pub enum RespType {
60 Ack,
62 Result,
64}
65
66#[derive(Debug, Clone, Serialize)]
68#[serde(untagged)]
69pub enum PlaceOrderKind {
70 UsdMarginFutures(usd_margin_futures::PlaceOrder),
72 Spot(spot::PlaceOrder),
74 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#[derive(Debug, Clone, Serialize)]
116#[serde(rename_all = "camelCase")]
117pub struct GetOrderInner {
118 pub symbol: String,
120 #[serde(skip_serializing_if = "Option::is_none")]
122 pub order_id: Option<i64>,
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub orig_client_order_id: Option<String>,
126 #[serde(skip_serializing_if = "Option::is_none")]
128 pub client_order_id: Option<String>,
129}
130
131#[derive(Debug, Clone, Serialize)]
133#[serde(rename_all = "camelCase")]
134pub struct CancelOrder {
135 #[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#[derive(Debug, Clone, Serialize)]
192#[serde(rename_all = "camelCase")]
193pub struct GetOrder {
194 #[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}