1use rust_decimal::Decimal;
2use serde::{Deserialize, Serialize};
3
4use crate::{
5 Timestamp,
6 margin::{
7 IsIsolated, MarginLevelStatus, OrderResponseType, OrderSide, OrderStatus, OrderType,
8 STPMode, SideEffectType, TimeInForce,
9 },
10};
11
12#[derive(Debug, PartialEq)]
13pub struct Response<T> {
14 pub result: T,
15 pub headers: Headers,
16}
17
18#[derive(Debug, PartialEq)]
19pub struct Headers {
20 pub retry_after: Option<Timestamp>,
21}
22
23#[derive(Debug, Serialize, PartialEq, Default)]
26#[serde(rename_all = "camelCase")]
27pub struct GetAllMarginAssetsParams {
28 asset: Option<String>,
29 recv_window: Option<u64>,
30}
31
32impl GetAllMarginAssetsParams {
33 pub fn new() -> Self {
34 Self::default()
35 }
36
37 pub fn asset(mut self, value: impl Into<String>) -> Self {
38 self.asset = Some(value.into());
39 self
40 }
41
42 pub fn recv_window(mut self, value: u64) -> Self {
43 self.recv_window = Some(value);
44 self
45 }
46}
47
48#[derive(Debug, Deserialize, PartialEq)]
49#[serde(rename_all = "camelCase")]
50pub struct MarginAsset {
51 pub asset_full_name: String,
52 pub asset_name: String,
53 pub is_borrowable: bool,
54 pub is_mortgageable: bool,
55 pub user_min_borrow: Decimal,
56 pub user_min_repay: Decimal,
57}
58
59#[derive(Debug, Serialize, PartialEq, Default)]
62#[serde(rename_all = "camelCase")]
63pub struct GetMarginAccountParams {
64 recv_window: Option<u64>,
65}
66
67impl GetMarginAccountParams {
68 pub fn new() -> Self {
69 Self::default()
70 }
71
72 pub fn recv_window(mut self, value: u64) -> Self {
73 self.recv_window = Some(value);
74 self
75 }
76}
77
78#[derive(Debug, Deserialize, PartialEq)]
79#[serde(rename_all = "camelCase")]
80pub struct MarginAccount {
81 pub created: bool,
82 pub borrow_enabled: bool,
83 pub margin_level: Decimal,
84 pub collateral_margin_level: Decimal,
85 pub total_asset_of_btc: Decimal,
86 pub total_liability_of_btc: Decimal,
87 pub total_net_asset_of_btc: Decimal,
88 pub total_collateral_value_in_usdt: Decimal,
89 pub trade_enabled: bool,
90 pub transfer_in_enabled: bool,
91 pub transfer_out_enabled: bool,
92 pub account_type: String,
93 pub margin_level_status: MarginLevelStatus,
94 pub user_assets: Vec<MarginUserAsset>,
95}
96
97#[derive(Debug, Deserialize, PartialEq)]
98#[serde(rename_all = "camelCase")]
99pub struct MarginUserAsset {
100 pub asset: String,
101 pub borrowed: Decimal,
102 pub free: Decimal,
103 pub interest: Decimal,
104 pub locked: Decimal,
105 pub net_asset: Decimal,
106}
107
108#[derive(Debug, Serialize, PartialEq)]
111#[serde(rename_all = "camelCase")]
112pub struct NewOrderRequest {
113 symbol: String,
114 is_isolated: Option<IsIsolated>,
115 side: OrderSide,
116 #[serde(rename = "type")]
117 order_type: OrderType,
118 quantity: Option<Decimal>,
119 quote_order_qty: Option<Decimal>,
120 price: Option<Decimal>,
121 stop_price: Option<Decimal>,
122 new_client_order_id: Option<String>,
124 iceberg_qty: Option<Decimal>,
126 new_order_resp_type: Option<OrderResponseType>,
128 side_effect_type: Option<SideEffectType>,
129 time_in_force: Option<TimeInForce>,
130 self_trade_prevention_mode: Option<STPMode>,
131 recv_window: Option<u64>,
133}
134
135impl NewOrderRequest {
136 pub fn new(symbol: impl Into<String>, side: OrderSide, order_type: OrderType) -> Self {
137 Self {
138 symbol: symbol.into(),
139 side,
140 order_type,
141 is_isolated: None,
142 quantity: None,
143 quote_order_qty: None,
144 price: None,
145 stop_price: None,
146 new_client_order_id: None,
147 iceberg_qty: None,
148 new_order_resp_type: None,
149 side_effect_type: None,
150 time_in_force: None,
151 self_trade_prevention_mode: None,
152 recv_window: None,
153 }
154 }
155
156 pub fn is_isolated(mut self, value: IsIsolated) -> Self {
157 self.is_isolated = Some(value);
158 self
159 }
160 pub fn quantity(mut self, value: Decimal) -> Self {
161 self.quantity = Some(value);
162 self
163 }
164 pub fn quote_order_qty(mut self, value: Decimal) -> Self {
165 self.quote_order_qty = Some(value);
166 self
167 }
168 pub fn price(mut self, value: Decimal) -> Self {
169 self.price = Some(value);
170 self
171 }
172 pub fn stop_price(mut self, value: Decimal) -> Self {
173 self.stop_price = Some(value);
174 self
175 }
176 pub fn new_client_order_id(mut self, value: impl Into<String>) -> Self {
177 self.new_client_order_id = Some(value.into());
178 self
179 }
180 pub fn iceberg_qty(mut self, value: Decimal) -> Self {
181 self.iceberg_qty = Some(value);
182 self
183 }
184 pub fn new_order_resp_type(mut self, value: OrderResponseType) -> Self {
185 self.new_order_resp_type = Some(value);
186 self
187 }
188 pub fn side_effect_type(mut self, value: SideEffectType) -> Self {
189 self.side_effect_type = Some(value);
190 self
191 }
192 pub fn time_in_force(mut self, value: TimeInForce) -> Self {
193 self.time_in_force = Some(value);
194 self
195 }
196 pub fn self_trade_prevention_mode(mut self, value: STPMode) -> Self {
197 self.self_trade_prevention_mode = Some(value);
198 self
199 }
200 pub fn recv_window(mut self, value: u64) -> Self {
201 self.recv_window = Some(value);
202 self
203 }
204}
205
206#[derive(Debug, Deserialize, PartialEq)]
207#[serde(untagged)]
208pub enum NewOrderResponse {
209 Full(NewOrderResponseFull),
210 Result(NewOrderResponseResult),
211 Ack(NewOrderResponseAck),
212}
213
214#[derive(Debug, Deserialize, PartialEq)]
215#[serde(rename_all = "camelCase")]
216pub struct NewOrderResponseAck {
217 pub symbol: String,
218 pub order_id: i64,
219 pub client_order_id: String,
220 pub transact_time: Timestamp,
221 pub is_isolated: bool,
222}
223
224#[derive(Debug, Deserialize, PartialEq)]
225#[serde(rename_all = "camelCase")]
226pub struct NewOrderResponseResult {
227 pub symbol: String,
228 pub order_id: i64,
229 pub client_order_id: String,
230 pub transact_time: Timestamp,
231 pub price: Decimal,
232 pub orig_qty: Decimal,
233 pub executed_qty: Decimal,
234 pub cummulative_quote_qty: Decimal,
235 pub status: OrderStatus,
236 pub time_in_force: TimeInForce,
237 #[serde(rename = "type")]
238 pub order_type: OrderType,
239 pub side: OrderSide,
240 pub margin_buy_borrow_amount: Option<Decimal>,
241 pub margin_buy_borrow_asset: Option<String>,
242 pub is_isolated: bool,
243 pub self_trade_prevention_mode: STPMode,
244}
245
246#[derive(Debug, Deserialize, PartialEq)]
247#[serde(rename_all = "camelCase")]
248pub struct NewOrderResponseFull {
249 pub symbol: String,
250 pub order_id: i64,
251 pub client_order_id: String,
252 pub transact_time: Timestamp,
253 pub price: Decimal,
254 pub orig_qty: Decimal,
255 pub executed_qty: Decimal,
256 pub cummulative_quote_qty: Decimal,
257 pub status: OrderStatus,
258 pub time_in_force: TimeInForce,
259 #[serde(rename = "type")]
260 pub order_type: OrderType,
261 pub side: OrderSide,
262 pub fills: Vec<OrderFill>,
263 pub margin_buy_borrow_amount: Option<Decimal>,
264 pub margin_buy_borrow_asset: Option<String>,
265 pub is_isolated: bool,
266 pub self_trade_prevention_mode: STPMode,
267}
268
269#[derive(Debug, Deserialize, PartialEq)]
270#[serde(rename_all = "camelCase")]
271pub struct OrderFill {
272 pub price: Decimal,
273 pub qty: Decimal,
274 pub commission: Decimal,
275 pub commission_asset: String,
276}
277
278#[derive(Debug, Serialize, PartialEq)]
281#[serde(rename_all = "camelCase")]
282pub struct QueryOrderParams {
283 symbol: String,
284 is_isolated: Option<IsIsolated>,
285 order_id: Option<i64>,
286 orig_client_order_id: Option<String>,
287 recv_window: Option<u64>,
288}
289
290impl QueryOrderParams {
291 pub fn new(symbol: impl Into<String>) -> Self {
292 Self {
293 symbol: symbol.into(),
294 is_isolated: None,
295 order_id: None,
296 orig_client_order_id: None,
297 recv_window: None,
298 }
299 }
300
301 pub fn is_isolated(mut self, value: IsIsolated) -> Self {
302 self.is_isolated = Some(value);
303 self
304 }
305 pub fn order_id(mut self, value: i64) -> Self {
306 self.order_id = Some(value);
307 self
308 }
309 pub fn orig_client_order_id(mut self, value: impl Into<String>) -> Self {
310 self.orig_client_order_id = Some(value.into());
311 self
312 }
313 pub fn recv_window(mut self, value: u64) -> Self {
314 self.recv_window = Some(value);
315 self
316 }
317}
318
319#[derive(Debug, Deserialize, PartialEq)]
320#[serde(rename_all = "camelCase")]
321pub struct Order {
322 pub symbol: String,
323 pub order_id: i64,
324 pub client_order_id: String,
325 pub price: Decimal,
326 pub orig_qty: Decimal,
327 pub executed_qty: Decimal,
328 pub cummulative_quote_qty: Decimal,
329 pub status: OrderStatus,
330 pub time_in_force: TimeInForce,
331 #[serde(rename = "type")]
332 pub order_type: OrderType,
333 pub side: OrderSide,
334 pub stop_price: Option<Decimal>,
335 pub iceberg_qty: Option<Decimal>,
336 pub time: Timestamp,
337 pub update_time: Timestamp,
338 pub is_working: bool,
339 pub is_isolated: bool,
340 pub self_trade_prevention_mode: STPMode,
341}
342
343#[derive(Debug, Serialize, PartialEq)]
346#[serde(rename_all = "camelCase")]
347pub struct GetMaxBorrowableParams {
348 asset: String,
349 isolated_symbol: Option<String>,
351 recv_window: Option<u64>,
352}
353
354impl GetMaxBorrowableParams {
355 pub fn new(asset: impl Into<String>) -> Self {
356 Self {
357 asset: asset.into(),
358 isolated_symbol: None,
359 recv_window: None,
360 }
361 }
362
363 pub fn isolated_symbol(mut self, value: impl Into<String>) -> Self {
364 self.isolated_symbol = Some(value.into());
365 self
366 }
367 pub fn recv_window(mut self, value: u64) -> Self {
368 self.recv_window = Some(value);
369 self
370 }
371}
372
373#[derive(Debug, Deserialize, PartialEq)]
374#[serde(rename_all = "camelCase")]
375pub struct MaxBorrowable {
376 pub amount: Decimal,
377 pub borrow_limit: Decimal,
379}
380
381#[derive(Debug, Deserialize, PartialEq)]
390#[serde(rename_all = "camelCase")]
391pub struct ListenKey {
392 pub listen_key: String,
393}
394
395#[derive(Debug, Deserialize, PartialEq, Default)]
398pub struct EmptyResponse {}
399
400#[cfg(test)]
401mod tests {
402 use super::*;
403 use crate::serde::deserialize_json;
404
405 #[test]
406 fn deserialize_listen_key() {
407 let json =
408 r#"{"listenKey":"pqia91ma19a5s61cv6a81va65sdf19v8a65a1a5s61cv6a81va65sdf19v8a65a1"}"#;
409 let parsed: ListenKey = deserialize_json(json).unwrap();
410 assert_eq!(parsed.listen_key.len(), 64);
411 }
412
413 #[test]
414 fn deserialize_empty_response() {
415 let json = r#"{}"#;
416 let parsed: EmptyResponse = deserialize_json(json).unwrap();
417 assert_eq!(parsed, EmptyResponse {});
418 }
419}