1#![allow(unused_imports)]
2use crate::errors::BybitError;
3use serde::{Deserialize, Serialize};
4use serde_json::{from_value, Value};
5use std::{borrow::Cow, collections::BTreeMap};
6use thiserror::Error;
7
8#[derive(Serialize, Default, Deserialize, Clone, Debug)]
9pub struct Empty {}
10
11#[derive(Serialize, Deserialize, Clone, Debug)]
16#[serde(rename_all = "camelCase")]
17pub struct ServerTimeResponse {
18 #[serde(rename = "retCode")]
19 pub ret_code: i16,
20 #[serde(rename = "retMsg")]
21 pub ret_msg: String,
22 pub result: ServerTime,
23 #[serde(rename = "retExtInfo")]
24 pub ret_ext_info: Empty,
25 pub time: u64,
26}
27
28#[derive(Serialize, Deserialize, Clone, Debug)]
29#[serde(rename_all = "camelCase")]
30pub struct ServerTime {
31 #[serde(with = "string_to_u64")]
32 pub time_second: u64,
33 #[serde(with = "string_to_u64")]
34 pub time_nano: u64,
35}
36
37#[derive(Clone, Default)]
38pub struct KlineRequest<'a> {
39 pub category: Option<Category>,
40 pub symbol: Cow<'a, str>,
41 pub interval: Cow<'a, str>,
42 pub start: Option<Cow<'a, str>>,
43 pub end: Option<Cow<'a, str>>,
44 pub limit: Option<u64>,
45}
46
47impl<'a> KlineRequest<'a> {
48 pub fn default() -> KlineRequest<'a> {
49 KlineRequest::new(None, "BTCUSDT", "", None, None, None)
50 }
51 pub fn new(
52 category: Option<Category>,
53 symbol: &'a str,
54 interval: &'a str,
55 start: Option<&'a str>,
56 end: Option<&'a str>,
57 limit: Option<u64>,
58 ) -> KlineRequest<'a> {
59 KlineRequest {
60 category: category,
61 symbol: Cow::Borrowed(symbol),
62 interval: Cow::Borrowed(interval),
63 start: start.map(|s| Cow::Borrowed(s)),
64 end: end.map(|s| Cow::Borrowed(s)),
65 limit,
66 }
67 }
68}
69#[derive(Serialize, Deserialize, Clone, Debug)]
70#[serde(rename_all = "camelCase")]
71pub struct KlineResponse {
72 #[serde(rename = "retCode")]
73 pub ret_code: i16,
74 #[serde(rename = "retMsg")]
75 pub ret_msg: String,
76 pub result: KlineSummary,
77 #[serde(rename = "retExtInfo")]
78 pub ret_ext_info: Empty,
79 pub time: u64,
80}
81
82#[derive(Serialize, Deserialize, Clone, Debug)]
83#[serde(rename_all = "camelCase")]
84pub struct KlineSummary {
85 pub symbol: String,
86 pub category: String,
87 pub list: Vec<Kline>,
88}
89
90#[derive(Serialize, Deserialize, Clone, Debug)]
91#[serde(rename_all = "camelCase")]
92pub struct Kline {
93 #[serde(with = "string_to_u64")]
94 pub start_time: u64,
95 pub open_price: String,
96 pub high_price: String,
97 pub low_price: String,
98 pub close_price: String,
99 pub volume: String,
100 pub quote_asset_volume: String,
101}
102
103#[derive(Serialize, Deserialize, Clone, Debug)]
104#[serde(rename_all = "camelCase")]
105pub struct MarkPriceKlineResponse {
106 #[serde(rename = "retCode")]
107 pub ret_code: i16,
108 #[serde(rename = "retMsg")]
109 pub ret_msg: String,
110 pub result: MarkPriceKlineSummary,
111 #[serde(rename = "retExtInfo")]
112 pub ret_ext_info: Empty,
113 pub time: u64,
114}
115
116#[derive(Serialize, Deserialize, Clone, Debug)]
117#[serde(rename_all = "camelCase")]
118pub struct MarkPriceKlineSummary {
119 pub symbol: String,
120 pub category: String,
121 pub list: Vec<MarkPriceKline>,
122}
123
124#[derive(Serialize, Deserialize, Clone, Debug)]
125#[serde(rename_all = "camelCase")]
126pub struct MarkPriceKline {
127 #[serde(with = "string_to_u64")]
128 pub start_time: u64,
129 pub open_price: String,
130 pub high_price: String,
131 pub low_price: String,
132 pub close_price: String,
133}
134
135#[derive(Serialize, Deserialize, Clone, Debug)]
136#[serde(rename_all = "camelCase")]
137pub struct IndexPriceKlineResponse {
138 #[serde(rename = "retCode")]
139 pub ret_code: i16,
140 #[serde(rename = "retMsg")]
141 pub ret_msg: String,
142 pub result: IndexPriceKlineSummary,
143 #[serde(rename = "retExtInfo")]
144 pub ret_ext_info: Empty,
145 pub time: u64,
146}
147
148#[derive(Serialize, Deserialize, Clone, Debug)]
149#[serde(rename_all = "camelCase")]
150pub struct IndexPriceKlineSummary {
151 pub symbol: String,
152 pub category: String,
153 pub list: Vec<IndexPriceKline>,
154}
155
156#[derive(Serialize, Deserialize, Clone, Debug)]
157#[serde(rename_all = "camelCase")]
158pub struct IndexPriceKline {
159 #[serde(with = "string_to_u64")]
160 pub start_time: u64,
161 pub open_price: String,
162 pub high_price: String,
163 pub low_price: String,
164 pub close_price: String,
165}
166
167#[derive(Serialize, Deserialize, Clone, Debug)]
168#[serde(rename_all = "camelCase")]
169pub struct PremiumIndexPriceKlineResponse {
170 #[serde(rename = "retCode")]
171 pub ret_code: i16,
172 #[serde(rename = "retMsg")]
173 pub ret_msg: String,
174 pub result: PremiumIndexPriceKlineSummary,
175 #[serde(rename = "retExtInfo")]
176 pub ret_ext_info: Empty,
177 pub time: u64,
178}
179
180#[derive(Serialize, Deserialize, Clone, Debug)]
181#[serde(rename_all = "camelCase")]
182pub struct PremiumIndexPriceKlineSummary {
183 pub symbol: String,
184 pub category: String,
185 pub list: Vec<PremiumIndexPriceKline>,
186}
187
188#[derive(Serialize, Deserialize, Clone, Debug)]
189#[serde(rename_all = "camelCase")]
190pub struct PremiumIndexPriceKline {
191 #[serde(with = "string_to_u64")]
192 pub start_time: u64,
193 pub open_price: String,
194 pub high_price: String,
195 pub low_price: String,
196 pub close_price: String,
197}
198
199#[derive(Clone, Default)]
200pub struct InstrumentRequest<'a> {
201 pub category: Category,
202 pub symbol: Option<Cow<'a, str>>,
203 pub status: Option<bool>,
204 pub base_coin: Option<Cow<'a, str>>,
205 pub limit: Option<u64>,
206}
207impl<'a> InstrumentRequest<'a> {
208 pub fn default() -> InstrumentRequest<'a> {
209 InstrumentRequest::new(Category::Linear, Some("BTCUSDT"), None, None, None)
210 }
211 pub fn new(
212 category: Category,
213 symbol: Option<&'a str>,
214 status: Option<bool>,
215 base_coin: Option<&'a str>,
216 limit: Option<u64>,
217 ) -> InstrumentRequest<'a> {
218 InstrumentRequest {
219 category: category,
220 symbol: symbol.map(|s| Cow::Borrowed(s)),
221 status: status,
222 base_coin: base_coin.map(|s| Cow::Borrowed(s)),
223 limit,
224 }
225 }
226}
227
228#[derive(Serialize, Deserialize, Clone, Debug)]
229#[serde(rename_all = "camelCase")]
230pub struct FuturesInstrumentsInfoResponse {
231 #[serde(rename = "retCode")]
232 pub ret_code: i16,
233 #[serde(rename = "retMsg")]
234 pub ret_msg: String,
235 pub result: FuturesInstrumentsInfo,
236 #[serde(rename = "retExtInfo")]
237 pub ret_ext_info: Empty,
238 pub time: u64,
239}
240
241#[derive(Serialize, Deserialize, Clone, Debug)]
242#[serde(rename_all = "camelCase")]
243pub struct FuturesInstrumentsInfo {
244 pub category: String,
245 pub list: Vec<FuturesInstrument>,
246 #[serde(rename = "nextPageCursor", skip_serializing_if = "String::is_empty")]
247 pub next_page_cursor: String,
248}
249
250#[derive(Serialize, Deserialize, Clone, Debug)]
251#[serde(rename_all = "camelCase")]
252pub struct FuturesInstrument {
253 pub symbol: String,
254 #[serde(rename = "contractType")]
255 pub contract_type: String,
256 pub status: String,
257 #[serde(rename = "baseCoin")]
258 pub base_coin: String,
259 #[serde(rename = "quoteCoin")]
260 pub quote_coin: String,
261 #[serde(rename = "launchTime", with = "string_to_u64")]
262 pub launch_time: u64,
263 #[serde(rename = "deliveryTime", skip_serializing_if = "String::is_empty")]
264 pub delivery_time: String,
265 #[serde(rename = "deliveryFeeRate")]
266 pub delivery_fee_rate: String,
267 #[serde(rename = "priceScale")]
268 pub price_scale: String,
269 #[serde(rename = "leverageFilter")]
270 pub leverage_filter: LeverageFilter,
271 #[serde(rename = "priceFilter")]
272 pub price_filter: PriceFilter,
273 #[serde(rename = "lotSizeFilter")]
274 pub lot_size_filter: LotSizeFilter,
275 #[serde(rename = "unifiedMarginTrade")]
276 pub unified_margin_trade: bool,
277 #[serde(rename = "fundingInterval")]
278 pub funding_interval: u64,
279 #[serde(rename = "settleCoin")]
280 pub settle_coin: String,
281 #[serde(rename = "copyTrading")]
282 pub copy_trading: String,
283 #[serde(rename = "upperFundingRate")]
284 pub upper_funding_rate: String,
285 #[serde(rename = "lowerFundingRate")]
286 pub lower_funding_rate: String,
287 }
292
293#[derive(Serialize, Deserialize, Clone, Debug)]
294#[serde(rename_all = "camelCase")]
295pub struct SpotInstrumentsInfoResponse {
296 #[serde(rename = "retCode")]
297 pub ret_code: i16,
298 #[serde(rename = "retMsg")]
299 pub ret_msg: String,
300 pub result: SpotInstrumentsInfo,
301 #[serde(rename = "retExtInfo")]
302 pub ret_ext_info: Empty,
303 pub time: u64,
304}
305
306#[derive(Serialize, Deserialize, Clone, Debug)]
307#[serde(rename_all = "camelCase")]
308pub struct SpotInstrumentsInfo {
309 pub category: String,
310 pub list: Vec<SpotInstrument>,
311 #[serde(rename = "nextPageCursor", skip_serializing_if = "String::is_empty")]
312 pub next_page_cursor: String,
313}
314#[derive(Serialize, Deserialize, Clone, Debug)]
315#[serde(rename_all = "camelCase")]
316pub struct SpotInstrument {
317 pub symbol: String,
318 #[serde(rename = "baseCoin")]
319 pub base_coin: String,
320 #[serde(rename = "quoteCoin")]
321 pub quote_coin: String,
322 pub innovation: String,
323 pub status: String,
324 #[serde(rename = "marginTrading")]
325 pub margin_trading: String,
326 #[serde(rename = "lotSizeFilter")]
327 pub lot_size_filter: LotSizeFilter,
328 #[serde(rename = "priceFilter")]
329 pub price_filter: PriceFilter,
330 #[serde(rename = "riskParameters")]
331 pub risk_parameters: RiskParameters,
332}
333
334#[derive(Serialize, Deserialize, Clone, Debug)]
335#[serde(rename_all = "camelCase")]
336pub struct OptionsInstrument {
337 pub symbol: String,
338 pub status: String,
339 #[serde(rename = "baseCoin")]
340 pub base_coin: String,
341 #[serde(rename = "quoteCoin")]
342 pub quote_coin: String,
343 #[serde(rename = "settleCoin")]
344 pub settle_coin: String,
345 #[serde(rename = "optionType")]
346 pub option_type: String,
347 #[serde(rename = "launchTime", with = "string_to_u64")]
348 pub launch_time: u64,
349 #[serde(rename = "deliveryTime", with = "string_to_u64")]
350 pub delivery_time: u64,
351 #[serde(rename = "deliveryFeeRate")]
352 pub delivery_fee_rate: String,
353 #[serde(rename = "priceFilter")]
354 pub price_filter: PriceFilter,
355 #[serde(rename = "lotSizeFilter")]
356 pub lot_size_filter: LotSizeFilter,
357}
358
359#[derive(Serialize, Deserialize, Clone, Debug)]
360#[serde(rename_all = "camelCase")]
361pub struct PreListingInfo {
362 pub cur_auction_phase: String,
363 pub phases: Vec<PreListingPhase>,
364 pub auction_fee_info: AuctionFeeInfo,
365}
366
367#[derive(Serialize, Deserialize, Clone, Debug)]
368#[serde(rename_all = "camelCase")]
369pub struct PreListingPhase {
370 pub phase: String,
371 #[serde(rename = "startTime", with = "string_to_u64")]
372 pub start_time: u64,
373 #[serde(rename = "endTime", with = "string_to_u64")]
374 pub end_time: u64,
375}
376
377#[derive(Serialize, Deserialize, Clone, Debug)]
378#[serde(rename_all = "camelCase")]
379pub struct AuctionFeeInfo {
380 pub auction_fee_rate: String,
381 pub taker_fee_rate: String,
382 pub maker_fee_rate: String,
383}
384
385#[derive(Debug, Serialize, Deserialize, Clone)]
386#[serde(rename_all = "camelCase")]
387pub struct RiskParameters {
388 #[serde(rename = "limitParameter")]
389 pub limit_parameter: String,
390 #[serde(rename = "marketParameter")]
391 pub market_parameter: String,
392}
393
394#[derive(Debug, Serialize, Deserialize, Clone)]
395#[serde(rename_all = "camelCase")]
396pub struct LeverageFilter {
397 #[serde(rename = "minLeverage")]
398 pub min_leverage: String,
399 #[serde(rename = "maxLeverage")]
400 pub max_leverage: String,
401 #[serde(rename = "leverageStep")]
402 pub leverage_step: String,
403}
404
405#[derive(Debug, Serialize, Deserialize, Clone)]
406#[serde(rename_all = "camelCase")]
407pub struct PriceFilter {
408 #[serde(rename = "minPrice")]
409 pub min_price: Option<String>,
410 #[serde(rename = "maxPrice")]
411 pub max_price: Option<String>,
412 #[serde(rename = "tickSize", with = "string_to_float")]
413 pub tick_size: f64,
414}
415
416#[derive(Debug, Serialize, Deserialize, Clone)]
417#[serde(rename_all = "camelCase")]
418pub struct LotSizeFilter {
419 #[serde(
420 rename = "basePrecision",
421 skip_serializing_if = "Option::is_none",
422 default
423 )]
424 pub base_precision: Option<String>,
425 #[serde(rename = "quotePrecision", skip_serializing_if = "Option::is_none")]
426 pub quote_precision: Option<String>,
427 #[serde(rename = "maxMktOrderQty", skip_serializing_if = "Option::is_none")]
428 pub max_mkt_order_qty: Option<String>,
429 #[serde(rename = "minOrderQty", with = "string_to_float")]
430 pub min_order_qty: f64,
431 #[serde(rename = "maxOrderQty", with = "string_to_float")]
432 pub max_order_qty: f64,
433 #[serde(rename = "minOrderAmt", skip_serializing_if = "Option::is_none")]
434 pub min_order_amt: Option<String>,
435 #[serde(rename = "maxOrderAmt", skip_serializing_if = "Option::is_none")]
436 pub max_order_amt: Option<String>,
437 #[serde(rename = "qtyStep", skip_serializing_if = "Option::is_none")]
438 pub qty_step: Option<String>,
439 #[serde(
440 rename = "postOnlyMaxOrderQty",
441 skip_serializing_if = "Option::is_none"
442 )]
443 pub post_only_max_order_qty: Option<String>,
444 #[serde(rename = "minNotionalValue", skip_serializing_if = "Option::is_none")]
445 pub min_notional_value: Option<String>,
446}
447
448#[derive(Clone, Default)]
449pub struct OrderbookRequest<'a> {
450 pub symbol: Cow<'a, str>,
451 pub category: Category,
452 pub limit: Option<u64>,
453}
454
455impl<'a> OrderbookRequest<'a> {
456 pub fn default() -> OrderbookRequest<'a> {
457 OrderbookRequest::new("BTCUSDT", Category::Linear, None)
458 }
459
460 pub fn new(symbol: &'a str, category: Category, limit: Option<u64>) -> OrderbookRequest<'a> {
461 OrderbookRequest {
462 symbol: Cow::Borrowed(symbol),
463 category,
464 limit,
465 }
466 }
467}
468#[derive(Serialize, Deserialize, Clone, Debug)]
469#[serde(rename_all = "camelCase")]
470pub struct OrderBookResponse {
471 #[serde(rename = "retCode")]
472 pub ret_code: i16,
473 #[serde(rename = "retMsg")]
474 pub ret_msg: String,
475 pub result: OrderBook,
476 #[serde(rename = "retExtInfo")]
477 pub ret_ext_info: Empty,
478 pub time: u64,
479}
480
481#[derive(Serialize, Deserialize, Clone, Debug)]
482#[serde(rename_all = "camelCase")]
483pub struct OrderBook {
484 #[serde(rename = "s")]
485 pub symbol: String,
486 #[serde(rename = "a")]
487 pub asks: Vec<Ask>,
488 #[serde(rename = "b")]
489 pub bids: Vec<Bid>,
490 #[serde(rename = "ts")]
491 pub timestamp: u64,
492 #[serde(rename = "u")]
493 pub update_id: u64,
494}
495
496#[derive(Serialize, Deserialize, Clone, Debug)]
497#[serde(rename_all = "camelCase")]
498pub struct Ask {
499 #[serde(with = "string_to_float")]
500 pub price: f64,
501 #[serde(with = "string_to_float")]
502 pub qty: f64,
503}
504
505#[derive(Serialize, Deserialize, Clone, Debug)]
506#[serde(rename_all = "camelCase")]
507pub struct Bid {
508 #[serde(with = "string_to_float")]
509 pub price: f64,
510 #[serde(with = "string_to_float")]
511 pub qty: f64,
512}
513
514impl Bid {
515 pub fn new(price: f64, qty: f64) -> Bid {
516 Bid { price, qty }
517 }
518}
519impl Ask {
520 pub fn new(price: f64, qty: f64) -> Ask {
521 Ask { price, qty }
522 }
523}
524
525#[derive(Serialize, Deserialize, Clone, Debug)]
526#[serde(rename_all = "camelCase")]
527pub struct FuturesTickersResponse {
528 #[serde(rename = "retCode")]
529 pub ret_code: i16,
530 #[serde(rename = "retMsg")]
531 pub ret_msg: String,
532 pub result: FuturesTickers,
533 #[serde(rename = "retExtInfo")]
534 pub ret_ext_info: Empty,
535 pub time: u64,
536}
537#[derive(Serialize, Deserialize, Clone, Debug)]
538#[serde(rename_all = "camelCase")]
539pub struct SpotTickersResponse {
540 #[serde(rename = "retCode")]
541 pub ret_code: i16,
542 #[serde(rename = "retMsg")]
543 pub ret_msg: String,
544 pub result: SpotTickers,
545 #[serde(rename = "retExtInfo")]
546 pub ret_ext_info: Empty,
547 pub time: u64,
548}
549
550#[derive(Serialize, Deserialize, Clone, Debug)]
551#[serde(rename_all = "camelCase")]
552pub struct FuturesTickers {
553 pub category: String,
554 pub list: Vec<FuturesTicker>,
555}
556
557#[derive(Serialize, Deserialize, Clone, Debug)]
558#[serde(rename_all = "camelCase")]
559pub struct SpotTickers {
560 pub category: String,
561 pub list: Vec<SpotTicker>,
562}
563
564#[derive(Serialize, Deserialize, Clone, Debug)]
565#[serde(rename_all = "camelCase")]
566pub struct FuturesTicker {
567 pub symbol: String,
568 #[serde(with = "string_to_float")]
569 pub last_price: f64,
570 #[serde(with = "string_to_float")]
571 pub index_price: f64,
572 #[serde(with = "string_to_float")]
573 pub mark_price: f64,
574 #[serde(rename = "prevPrice24h", with = "string_to_float")]
575 pub prev_price_24h: f64,
576 #[serde(rename = "price24hPcnt", with = "string_to_float")]
577 pub daily_change_percentage: f64,
578 #[serde(rename = "highPrice24h", with = "string_to_float")]
579 pub high_24h: f64,
580 #[serde(rename = "lowPrice24h", with = "string_to_float")]
581 pub low_24h: f64,
582 #[serde(rename = "prevPrice1h", with = "string_to_float")]
583 pub prev_price_1h: f64,
584 #[serde(with = "string_to_float")]
585 pub open_interest: f64,
586 #[serde(with = "string_to_float")]
587 pub open_interest_value: f64,
588 #[serde(rename = "turnover24h")]
589 pub turnover_24h: String,
590 #[serde(rename = "volume24h")]
591 pub volume_24h: String,
592 pub funding_rate: String,
593 #[serde(rename = "nextFundingTime", with = "string_to_u64")]
594 pub next_funding_time: u64,
595 #[serde(skip_serializing_if = "String::is_empty")]
596 pub predicted_delivery_price: String,
597 #[serde(skip_serializing_if = "String::is_empty")]
598 pub basis_rate: String,
599 pub delivery_fee_rate: String,
600 #[serde(rename = "deliveryTime", with = "string_to_u64")]
601 pub delivery_time: u64,
602 #[serde(rename = "ask1Size", with = "string_to_float")]
603 pub ask_size: f64,
604 #[serde(rename = "bid1Price", with = "string_to_float")]
605 pub bid_price: f64,
606 #[serde(rename = "ask1Price", with = "string_to_float")]
607 pub ask_price: f64,
608 #[serde(rename = "bid1Size", with = "string_to_float")]
609 pub bid_size: f64,
610 #[serde(skip_serializing_if = "String::is_empty")]
611 pub basis: String,
612}
613
614#[derive(Serialize, Deserialize, Clone, Debug)]
615#[serde(rename_all = "camelCase")]
616pub struct SpotTicker {
617 pub symbol: String,
618 #[serde(rename = "bid1Price", with = "string_to_float")]
619 pub bid_price: f64,
620 #[serde(rename = "bid1Size", with = "string_to_float")]
621 pub bid_size: f64,
622 #[serde(rename = "ask1Price", with = "string_to_float")]
623 pub ask_price: f64,
624 #[serde(rename = "ask1Size", with = "string_to_float")]
625 pub ask_size: f64,
626 #[serde(with = "string_to_float")]
627 pub last_price: f64,
628 #[serde(rename = "prevPrice24h", with = "string_to_float")]
629 pub prev_price_24h: f64,
630 #[serde(rename = "price24hPcnt", with = "string_to_float")]
631 pub daily_change_percentage: f64,
632 #[serde(rename = "highPrice24h", with = "string_to_float")]
633 pub high_24h: f64,
634 #[serde(rename = "lowPrice24h", with = "string_to_float")]
635 pub low_24h: f64,
636 #[serde(rename = "turnover24h")]
637 pub turnover_24h: String,
638 #[serde(rename = "volume24h")]
639 pub volume_24h: String,
640 #[serde(rename = "usdIndexPrice")]
641 pub usd_index_price: String,
642}
643
644#[derive(Clone, Default)]
645pub struct FundingHistoryRequest<'a> {
646 pub category: Category,
647 pub symbol: Cow<'a, str>,
648 pub start_time: Option<Cow<'a, str>>,
649 pub end_time: Option<Cow<'a, str>>,
650 pub limit: Option<u64>,
651}
652impl<'a> FundingHistoryRequest<'a> {
653 pub fn default() -> FundingHistoryRequest<'a> {
654 FundingHistoryRequest::new(Category::Linear, "BTCUSDT", None, None, None)
655 }
656 pub fn new(
657 category: Category,
658 symbol: &'a str,
659 start_time: Option<&'a str>,
660 end_time: Option<&'a str>,
661 limit: Option<u64>,
662 ) -> FundingHistoryRequest<'a> {
663 FundingHistoryRequest {
664 category,
665 symbol: Cow::Borrowed(symbol),
666 start_time: start_time.map(|s| Cow::Borrowed(s)),
667 end_time: end_time.map(|s| Cow::Borrowed(s)),
668 limit,
669 }
670 }
671}
672
673#[derive(Serialize, Deserialize, Clone, Debug)]
674#[serde(rename_all = "camelCase")]
675pub struct FundingRateResponse {
676 #[serde(rename = "retCode")]
677 pub ret_code: i16,
678 #[serde(rename = "retMsg")]
679 pub ret_msg: String,
680 pub result: FundingRateSummary,
681 #[serde(rename = "retExtInfo")]
682 pub ret_ext_info: Empty,
683 pub time: u64,
684}
685
686#[derive(Serialize, Deserialize, Clone, Debug)]
687#[serde(rename_all = "camelCase")]
688pub struct FundingRateSummary {
689 pub category: String,
690 pub list: Vec<FundingRate>,
691}
692
693#[derive(Serialize, Deserialize, Clone, Debug)]
694#[serde(rename_all = "camelCase")]
695pub struct FundingRate {
696 pub symbol: String,
697 #[serde(rename = "fundingRate", with = "string_to_float")]
698 pub funding_rate: f64,
699 #[serde(rename = "fundingRateTimestamp", with = "string_to_u64")]
700 pub funding_rate_timestamp: u64,
701}
702
703#[derive(Clone, Default)]
704pub struct RecentTradesRequest<'a> {
705 pub category: Category,
706 pub symbol: Option<Cow<'a, str>>,
707 pub base_coin: Option<Cow<'a, str>>,
708 pub limit: Option<u64>,
709}
710impl<'a> RecentTradesRequest<'a> {
711 pub fn default() -> RecentTradesRequest<'a> {
712 RecentTradesRequest::new(Category::Linear, Some("BTCUSDT"), None, None)
713 }
714 pub fn new(
715 category: Category,
716 symbol: Option<&'a str>,
717 base_coin: Option<&'a str>,
718 limit: Option<u64>,
719 ) -> RecentTradesRequest<'a> {
720 RecentTradesRequest {
721 category,
722 symbol: symbol.map(|s| Cow::Borrowed(s)),
723 base_coin: base_coin.map(|s| Cow::Borrowed(s)),
724 limit,
725 }
726 }
727}
728
729#[derive(Serialize, Deserialize, Clone, Debug)]
730#[serde(rename_all = "camelCase")]
731pub struct RecentTradesResponse {
732 #[serde(rename = "retCode")]
733 pub ret_code: i16,
734 #[serde(rename = "retMsg")]
735 pub ret_msg: String,
736 pub result: RecentTrades,
737 #[serde(rename = "retExtInfo")]
738 pub ret_ext_info: Empty,
739 pub time: u64,
740}
741
742#[derive(Serialize, Deserialize, Clone, Debug)]
743#[serde(rename_all = "camelCase")]
744pub struct RecentTrades {
745 pub category: String,
746 pub list: Vec<RecentTrade>,
747}
748
749#[derive(Serialize, Deserialize, Clone, Debug)]
750#[serde(rename_all = "camelCase")]
751pub struct RecentTrade {
752 #[serde(rename = "execId")]
753 pub exec_id: String,
754 pub symbol: String,
755 #[serde(with = "string_to_float")]
756 pub price: f64,
757 #[serde(rename = "size", with = "string_to_float")]
758 pub qty: f64,
759 pub side: String,
760 #[serde(rename = "time")]
761 pub timestamp: String,
762 #[serde(rename = "isBlockTrade")]
763 pub is_block_trade: bool,
764}
765
766#[derive(Clone, Default)]
767pub struct OpenInterestRequest<'a> {
768 pub category: Category,
769 pub symbol: Cow<'a, str>,
770 pub interval: Cow<'a, str>,
771 pub start: Option<Cow<'a, str>>,
772 pub end: Option<Cow<'a, str>>,
773 pub limit: Option<u64>,
774}
775
776impl<'a> OpenInterestRequest<'a> {
777 pub fn default() -> OpenInterestRequest<'a> {
778 OpenInterestRequest::new(Category::Linear, "BTCUSDT", "4h", None, None, None)
779 }
780 pub fn new(
781 category: Category,
782 symbol: &'a str,
783 interval: &'a str,
784 start: Option<&'a str>,
785 end: Option<&'a str>,
786 limit: Option<u64>,
787 ) -> OpenInterestRequest<'a> {
788 OpenInterestRequest {
789 category,
790 symbol: Cow::Borrowed(symbol),
791 interval: Cow::Borrowed(interval),
792 start: start.map(|s| Cow::Borrowed(s)),
793 end: end.map(|s| Cow::Borrowed(s)),
794 limit,
795 }
796 }
797}
798#[derive(Serialize, Deserialize, Clone, Debug)]
799#[serde(rename_all = "camelCase")]
800pub struct OpeninterestResponse {
801 #[serde(rename = "retCode")]
802 pub ret_code: i16,
803 #[serde(rename = "retMsg")]
804 pub ret_msg: String,
805 pub result: OpenInterestSummary,
806 #[serde(rename = "retExtInfo")]
807 pub ret_ext_info: Empty,
808 pub time: u64,
809}
810
811#[derive(Serialize, Deserialize, Clone, Debug)]
812#[serde(rename_all = "camelCase")]
813pub struct OpenInterestSummary {
814 pub symbol: String,
815 pub category: String,
816 pub list: Vec<OpenInterest>,
817 #[serde(rename = "nextPageCursor", skip_serializing_if = "String::is_empty")]
818 pub next_page_cursor: String,
819}
820
821#[derive(Serialize, Deserialize, Clone, Debug)]
822#[serde(rename_all = "camelCase")]
823pub struct OpenInterest {
824 #[serde(rename = "openInterest", with = "string_to_float")]
825 pub open_interest: f64,
826 #[serde(with = "string_to_u64")]
827 pub timestamp: u64,
828}
829
830#[derive(Clone, Default)]
831pub struct HistoricalVolatilityRequest<'a> {
832 pub base_coin: Option<Cow<'a, str>>,
833 pub period: Option<Cow<'a, str>>,
834 pub start: Option<Cow<'a, str>>,
835 pub end: Option<Cow<'a, str>>,
836}
837
838impl<'a> HistoricalVolatilityRequest<'a> {
839 pub fn default() -> HistoricalVolatilityRequest<'a> {
840 HistoricalVolatilityRequest::new(Some("BTC"), None, None, None)
841 }
842 pub fn new(
843 base_coin: Option<&'a str>,
844 period: Option<&'a str>,
845 start: Option<&'a str>,
846 end: Option<&'a str>,
847 ) -> HistoricalVolatilityRequest<'a> {
848 HistoricalVolatilityRequest {
849 base_coin: base_coin.map(|s| Cow::Borrowed(s)),
850 period: period.map(|s| Cow::Borrowed(s)),
851 start: start.map(|s| Cow::Borrowed(s)),
852 end: end.map(|s| Cow::Borrowed(s)),
853 }
854 }
855}
856
857#[derive(Serialize, Deserialize, Clone, Debug)]
858#[serde(rename_all = "camelCase")]
859pub struct HistoricalVolatilityResponse {
860 #[serde(rename = "retCode")]
861 pub ret_code: i16,
862 #[serde(rename = "retMsg")]
863 pub ret_msg: String,
864 pub category: String,
865 #[serde(rename = "result")]
866 pub result: Vec<HistoricalVolatility>,
867}
868
869#[derive(Serialize, Deserialize, Clone, Debug)]
870#[serde(rename_all = "camelCase")]
871pub struct HistoricalVolatility {
872 pub period: u64,
873 #[serde(with = "string_to_float")]
874 pub value: f64,
875 #[serde(rename = "time", with = "string_to_u64")]
876 pub timestamp: u64,
877}
878
879#[derive(Serialize, Deserialize, Clone, Debug)]
880#[serde(rename_all = "camelCase")]
881pub struct InsuranceResponse {
882 #[serde(rename = "retCode")]
883 pub ret_code: i16,
884 #[serde(rename = "retMsg")]
885 pub ret_msg: String,
886 pub result: InsuranceSummary,
887 #[serde(rename = "retExtInfo")]
888 pub ret_ext_info: Empty,
889 pub time: u64,
890}
891
892#[derive(Serialize, Deserialize, Clone, Debug)]
893#[serde(rename_all = "camelCase")]
894pub struct InsuranceSummary {
895 #[serde(rename = "updatedTime", with = "string_to_u64")]
896 pub updated_time: u64,
897 pub list: Vec<Insurance>,
898}
899
900#[derive(Serialize, Deserialize, Clone, Debug)]
901#[serde(rename_all = "camelCase")]
902pub struct Insurance {
903 pub coin: String,
904 #[serde(with = "string_to_float")]
905 pub balance: f64,
906 pub value: String,
907}
908
909#[derive(Clone, Default)]
910pub struct RiskLimitRequest<'a> {
911 pub category: Category,
912 pub symbol: Option<Cow<'a, str>>,
913}
914
915impl<'a> RiskLimitRequest<'a> {
916 pub fn default() -> RiskLimitRequest<'a> {
917 RiskLimitRequest::new(Category::Linear, None)
918 }
919 pub fn new(category: Category, symbol: Option<&'a str>) -> RiskLimitRequest<'a> {
920 RiskLimitRequest {
921 category,
922 symbol: symbol.map(|s| Cow::Borrowed(s)),
923 }
924 }
925}
926
927#[derive(Serialize, Deserialize, Clone, Debug)]
928pub struct RiskLimitResponse {
929 #[serde(rename = "retCode")]
930 pub ret_code: i16,
931 #[serde(rename = "retMsg")]
932 pub ret_msg: String,
933 pub result: RiskLimitSummary,
934 #[serde(rename = "retExtInfo")]
935 pub ret_ext_info: Empty,
936 pub time: u64,
937}
938
939#[derive(Serialize, Deserialize, Clone, Debug)]
940pub struct RiskLimitSummary {
941 pub category: String,
942 pub list: Vec<RiskLimit>,
943}
944
945#[derive(Serialize, Deserialize, Clone, Debug)]
946pub struct RiskLimit {
947 pub id: u64,
948 pub symbol: String,
949 #[serde(rename = "riskLimitValue", with = "string_to_float")]
950 pub risk_limit_value: f64,
951 #[serde(rename = "maintenanceMargin", with = "string_to_float")]
952 pub maintainence_margin: f64,
953 #[serde(rename = "initialMargin", with = "string_to_float")]
954 pub initial_margin: f64,
955 #[serde(rename = "isLowestRisk")]
956 pub is_lowest_risk: u8,
957 #[serde(rename = "maxLeverage")]
958 pub max_leverage: String,
959}
960
961#[derive(Serialize, Deserialize, Clone, Debug)]
962#[serde(rename_all = "camelCase")]
963pub struct DeliveryPriceResponse {
964 pub ret_code: i16,
965 pub ret_msg: String,
966 pub result: DeliveryPriceSummary,
967 pub ret_ext_info: Empty,
968 pub time: u64,
969}
970
971#[derive(Serialize, Deserialize, Clone, Debug)]
972#[serde(rename_all = "camelCase")]
973pub struct DeliveryPriceSummary {
974 pub category: String,
975 #[serde(rename = "nextPageCursor", skip_serializing_if = "Option::is_none")]
976 pub next_page_cursor: Option<String>,
977 pub list: Vec<DeliveryPrice>,
978}
979
980#[derive(Serialize, Deserialize, Clone, Debug)]
981#[serde(rename_all = "camelCase")]
982pub struct DeliveryPrice {
983 pub symbol: String,
984 pub delivery_price: String,
985 #[serde(with = "string_to_u64")]
986 pub delivery_time: u64,
987}
988
989#[derive(Serialize, Deserialize, Clone, Debug)]
990#[serde(rename_all = "camelCase")]
991pub struct LongShortRatioResponse {
992 #[serde(rename = "retCode")]
993 pub ret_code: i16,
994 #[serde(rename = "retMsg")]
995 pub ret_msg: String,
996 pub result: LongShortRatioSummary,
997 #[serde(rename = "retExtInfo")]
998 pub ret_ext_info: Empty,
999 pub time: u64,
1000}
1001
1002#[derive(Serialize, Deserialize, Clone, Debug)]
1003#[serde(rename_all = "camelCase")]
1004pub struct LongShortRatioSummary {
1005 pub list: Vec<LongShortRatio>,
1006}
1007
1008#[derive(Serialize, Deserialize, Clone, Debug)]
1009#[serde(rename_all = "camelCase")]
1010pub struct LongShortRatio {
1011 #[serde(rename = "symbol")]
1012 pub symbol: String,
1013 #[serde(rename = "buyRatio", with = "string_to_float")]
1014 pub buy_ratio: f64,
1015 #[serde(rename = "sellRatio", with = "string_to_float")]
1016 pub sell_ratio: f64,
1017 #[serde(rename = "timestamp", with = "string_to_u64")]
1018 pub timestamp: u64,
1019}
1020
1021#[derive(Clone, Copy, Default, Serialize)]
1025pub enum Category {
1026 Spot,
1027 #[default]
1028 Linear,
1029 Inverse,
1030 Option,
1031}
1032impl Category {
1033 pub fn as_str(&self) -> &str {
1034 match self {
1035 Category::Spot => "spot",
1036 Category::Linear => "linear",
1037 Category::Inverse => "inverse",
1038 Category::Option => "option",
1039 }
1040 }
1041}
1042
1043#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1044pub enum Side {
1045 #[default]
1046 Buy,
1047 Sell,
1048}
1049
1050impl Side {
1051 pub fn as_str(&self) -> &str {
1052 match self {
1053 Side::Buy => "Buy",
1054 Side::Sell => "Sell",
1055 }
1056 }
1057}
1058
1059#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1060pub enum OrderType {
1061 Limit,
1062 #[default]
1063 Market,
1064}
1065
1066impl OrderType {
1067 pub fn as_str(&self) -> &str {
1068 match self {
1069 OrderType::Limit => "Limit",
1070 OrderType::Market => "Market",
1071 }
1072 }
1073}
1074
1075#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1076pub enum TimeInForce {
1077 #[default]
1078 GTC,
1079 IOC,
1080 FOK,
1081 PostOnly,
1082}
1083
1084impl TimeInForce {
1085 pub fn as_str(&self) -> &str {
1086 match self {
1087 TimeInForce::GTC => "GTC",
1088 TimeInForce::IOC => "IOC",
1089 TimeInForce::FOK => "FOK",
1090 TimeInForce::PostOnly => "PostOnly",
1091 }
1092 }
1093}
1094#[derive(Clone, Default, Serialize)]
1095pub struct OrderRequest<'a> {
1096 pub category: Category, pub symbol: Cow<'a, str>, pub is_leverage: Option<bool>, pub side: Side, pub order_type: OrderType, pub qty: f64, pub market_unit: Option<f64>, pub price: Option<f64>, pub trigger_direction: Option<bool>, pub order_filter: Option<Cow<'a, str>>, pub trigger_price: Option<f64>,
1107 pub trigger_by: Option<Cow<'a, str>>, pub order_iv: Option<f64>, pub time_in_force: Option<Cow<'a, str>>, pub position_idx: Option<u8>,
1111 pub order_link_id: Option<Cow<'a, str>>,
1112 pub take_profit: Option<f64>,
1113 pub stop_loss: Option<f64>,
1114 pub tp_trigger_by: Option<Cow<'a, str>>,
1115 pub sl_trigger_by: Option<Cow<'a, str>>,
1116 pub reduce_only: Option<bool>,
1117 pub close_on_trigger: Option<bool>,
1118 pub smp_type: Option<Cow<'a, str>>,
1119 pub mmp: Option<bool>,
1120 pub tpsl_mode: Option<Cow<'a, str>>,
1121 pub tp_limit_price: Option<f64>,
1122 pub sl_limit_price: Option<f64>,
1123 pub tp_order_type: Option<Cow<'a, str>>,
1124 pub sl_order_type: Option<Cow<'a, str>>,
1125}
1126
1127impl<'a> OrderRequest<'a> {
1128 pub fn default() -> Self {
1129 Self {
1130 category: Category::Linear,
1131 symbol: Cow::Borrowed("BTCUSDT"),
1132 is_leverage: None,
1133 side: Side::default(),
1134 order_type: OrderType::Market,
1135 qty: 0.00,
1136 market_unit: None,
1137 price: None,
1138 trigger_direction: None,
1139 order_filter: None,
1140 trigger_price: None,
1141 trigger_by: None,
1142 order_iv: None,
1143 time_in_force: None,
1144 position_idx: None,
1145 order_link_id: None,
1146 take_profit: None,
1147 stop_loss: None,
1148 tp_trigger_by: None,
1149 sl_trigger_by: None,
1150 reduce_only: None,
1151 close_on_trigger: None,
1152 smp_type: None,
1153 mmp: None,
1154 tpsl_mode: None,
1155 tp_limit_price: None,
1156 sl_limit_price: None,
1157 tp_order_type: None,
1158 sl_order_type: None,
1159 }
1160 }
1161 pub fn custom(
1162 category: Category,
1163 symbol: &'a str,
1164 leverage: Option<bool>,
1165 side: Side,
1166 order_type: OrderType,
1167 qty: f64,
1168 market_unit: Option<f64>,
1169 price: Option<f64>,
1170 trigger_direction: Option<bool>,
1171 order_filter: Option<&'a str>,
1172 trigger_price: Option<f64>,
1173 trigger_by: Option<&'a str>,
1174 order_iv: Option<f64>,
1175 time_in_force: Option<&'a str>,
1176 position_idx: Option<u8>,
1177 order_link_id: Option<&'a str>,
1178 take_profit: Option<f64>,
1179 stop_loss: Option<f64>,
1180 tp_trigger_by: Option<&'a str>,
1181 sl_trigger_by: Option<&'a str>,
1182 reduce_only: Option<bool>,
1183 close_on_trigger: Option<bool>,
1184 smp_type: Option<&'a str>,
1185 mmp: Option<bool>,
1186 tpsl_mode: Option<&'a str>,
1187 tp_limit_price: Option<f64>,
1188 sl_limit_price: Option<f64>,
1189 tp_order_type: Option<&'a str>,
1190 sl_order_type: Option<&'a str>,
1191 ) -> Self {
1192 Self {
1193 category,
1194 symbol: Cow::Borrowed(symbol),
1195 is_leverage: leverage,
1196 side,
1197 order_type,
1198 qty,
1199 market_unit,
1200 price,
1201 trigger_direction,
1202 order_filter: order_filter.map(Cow::Borrowed),
1203 trigger_price,
1204 trigger_by: trigger_by.map(Cow::Borrowed),
1205 order_iv,
1206 time_in_force: time_in_force.map(Cow::Borrowed),
1207 position_idx,
1208 order_link_id: order_link_id.map(Cow::Borrowed),
1209 take_profit,
1210 stop_loss,
1211 tp_trigger_by: tp_trigger_by.map(Cow::Borrowed),
1212 sl_trigger_by: sl_trigger_by.map(Cow::Borrowed),
1213 reduce_only,
1214 close_on_trigger,
1215 smp_type: smp_type.map(Cow::Borrowed),
1216 mmp,
1217 tpsl_mode: tpsl_mode.map(Cow::Borrowed),
1218 tp_limit_price,
1219 sl_limit_price,
1220 tp_order_type: tp_order_type.map(Cow::Borrowed),
1221 sl_order_type: sl_order_type.map(Cow::Borrowed),
1222 }
1223 }
1224 pub fn spot_limit_with_market_tpsl(
1225 symbol: &'a str,
1226 side: Side,
1227 qty: f64,
1228 price: f64,
1229 tp: f64,
1230 sl: f64,
1231 ) -> Self {
1232 Self {
1233 category: Category::Spot,
1234 symbol: Cow::Borrowed(symbol),
1235 side,
1236 order_type: OrderType::Limit,
1237 qty,
1238 price: Some(price),
1239 time_in_force: Some(Cow::Borrowed(TimeInForce::PostOnly.as_str())),
1240 take_profit: Some(tp),
1241 stop_loss: Some(sl),
1242 tp_order_type: Some(Cow::Borrowed("Market")),
1243 sl_order_type: Some(Cow::Borrowed("Market")),
1244 ..Self::default()
1245 }
1246 }
1247 pub fn spot_limit_with_limit_tpsl(
1248 symbol: &'a str,
1249 side: Side,
1250 qty: f64,
1251 price: f64,
1252 tp: f64,
1253 sl: f64,
1254 ) -> Self {
1255 Self {
1256 category: Category::Spot,
1257 symbol: Cow::Borrowed(symbol),
1258 side,
1259 order_type: OrderType::Limit,
1260 qty,
1261 price: Some(price),
1262 time_in_force: Some(Cow::Borrowed(TimeInForce::PostOnly.as_str())),
1263 take_profit: Some(tp),
1264 stop_loss: Some(sl),
1265 tp_limit_price: Some(tp),
1266 sl_limit_price: Some(sl),
1267 tp_order_type: Some(Cow::Borrowed("Limit")),
1268 sl_order_type: Some(Cow::Borrowed("Limit")),
1269 ..Self::default()
1270 }
1271 }
1272 pub fn spot_postonly(symbol: &'a str, side: Side, qty: f64, price: f64) -> Self {
1273 Self {
1274 category: Category::Spot,
1275 symbol: Cow::Borrowed(symbol),
1276 side,
1277 order_type: OrderType::Limit,
1278 qty,
1279 price: Some(price),
1280 time_in_force: Some(Cow::Borrowed(TimeInForce::PostOnly.as_str())),
1281 ..Self::default()
1282 }
1283 }
1284 pub fn spot_tpsl(
1285 symbol: &'a str,
1286 side: Side,
1287 price: f64,
1288 qty: f64,
1289 order_link_id: Option<&'a str>,
1290 ) -> Self {
1291 Self {
1292 category: Category::Spot,
1293 symbol: Cow::Borrowed(symbol),
1294 side,
1295 order_type: OrderType::Limit,
1296 qty,
1297 price: Some(price),
1298 time_in_force: Some(Cow::Borrowed(TimeInForce::GTC.as_str())),
1299 order_link_id: order_link_id.map(Cow::Borrowed),
1300 order_filter: Some(Cow::Borrowed("tpslOrder")),
1301 ..Self::default()
1302 }
1303 }
1304 pub fn spot_margin(symbol: &'a str, side: Side, qty: f64, price: f64) -> Self {
1305 Self {
1306 category: Category::Spot,
1307 symbol: Cow::Borrowed(symbol),
1308 side,
1309 order_type: OrderType::Market,
1310 qty,
1311 price: Some(price),
1312 time_in_force: Some(Cow::Borrowed(TimeInForce::PostOnly.as_str())),
1313 is_leverage: Some(true),
1314 ..Self::default()
1315 }
1316 }
1317
1318 pub fn spot_market(symbol: &'a str, side: Side, qty: f64) -> Self {
1319 Self {
1320 category: Category::Spot,
1321 symbol: Cow::Borrowed(symbol),
1322 side,
1323 order_type: OrderType::Market,
1324 qty,
1325 time_in_force: Some(Cow::Borrowed(TimeInForce::IOC.as_str())),
1326 ..Self::default()
1327 }
1328 }
1329
1330 pub fn futures_limit_with_market_tpsl(
1331 symbol: &'a str,
1332 side: Side,
1333 qty: f64,
1334 price: f64,
1335 tp: f64,
1336 sl: f64,
1337 ) -> Self {
1338 Self {
1339 category: Category::Linear,
1340 symbol: Cow::Borrowed(symbol),
1341 side,
1342 order_type: OrderType::Limit,
1343 qty,
1344 price: Some(price),
1345 time_in_force: Some(Cow::Borrowed(TimeInForce::PostOnly.as_str())),
1346 reduce_only: Some(false),
1347 take_profit: Some(tp),
1348 stop_loss: Some(sl),
1349 tpsl_mode: Some(Cow::Borrowed("Full")),
1350 tp_order_type: Some(Cow::Borrowed("Market")),
1351 sl_order_type: Some(Cow::Borrowed("Market")),
1352 ..Self::default()
1353 }
1354 }
1355
1356 pub fn futures_limit_with_limit_tpsl(
1357 symbol: &'a str,
1358 side: Side,
1359 qty: f64,
1360 price: f64,
1361 tp: f64,
1362 sl: f64,
1363 ) -> Self {
1364 Self {
1365 category: Category::Linear,
1366 symbol: Cow::Borrowed(symbol),
1367 side,
1368 order_type: OrderType::Limit,
1369 qty,
1370 price: Some(price),
1371 time_in_force: Some(Cow::Borrowed(TimeInForce::PostOnly.as_str())),
1372 reduce_only: Some(false),
1373 take_profit: Some(tp),
1374 stop_loss: Some(sl),
1375 tpsl_mode: Some(Cow::Borrowed("Partial")),
1376 tp_order_type: Some(Cow::Borrowed("Limit")),
1377 sl_order_type: Some(Cow::Borrowed("Limit")),
1378 tp_limit_price: Some(tp),
1379 sl_limit_price: Some(sl),
1380 ..Self::default()
1381 }
1382 }
1383
1384 pub fn futures_market(symbol: &'a str, side: Side, qty: f64) -> Self {
1385 Self {
1386 category: Category::Linear,
1387 symbol: Cow::Borrowed(symbol),
1388 side,
1389 order_type: OrderType::Market,
1390 qty,
1391 time_in_force: Some(Cow::Borrowed(TimeInForce::IOC.as_str())),
1392 reduce_only: Some(false),
1393 ..Self::default()
1394 }
1395 }
1396
1397 pub fn futures_close_limit(
1398 symbol: &'a str,
1399 side: Side,
1400 qty: f64,
1401 price: f64,
1402 order_link_id: &'a str,
1403 ) -> Self {
1404 Self {
1405 category: Category::Linear,
1406 symbol: Cow::Borrowed(symbol),
1407 side,
1408 order_type: OrderType::Limit,
1409 qty,
1410 price: Some(price),
1411 time_in_force: Some(Cow::Borrowed(TimeInForce::GTC.as_str())),
1412 order_link_id: Some(Cow::Borrowed(order_link_id)),
1413 reduce_only: Some(true),
1414 ..Self::default()
1415 }
1416 }
1417
1418 pub fn futures_market_close(symbol: &'a str, side: Side, qty: f64) -> Self {
1419 Self {
1420 category: Category::Linear,
1421 symbol: Cow::Borrowed(symbol),
1422 side,
1423 order_type: OrderType::Market,
1424 qty,
1425 time_in_force: Some(Cow::Borrowed(TimeInForce::IOC.as_str())),
1426 reduce_only: Some(true),
1427 ..Self::default()
1428 }
1429 }
1430}
1431#[derive(Serialize, Deserialize, Clone, Debug)]
1432#[serde(rename_all = "camelCase")]
1433pub struct AmendOrderResponse {
1434 pub ret_code: i16,
1435 pub ret_msg: String,
1436 pub result: OrderStatus,
1437 pub ret_ext_info: Empty,
1438 pub time: u64,
1439}
1440
1441#[derive(Clone, Default, Serialize)]
1442pub struct AmendOrderRequest<'a> {
1443 pub category: Category, pub symbol: Cow<'a, str>, pub order_id: Option<Cow<'a, str>>,
1446 pub order_link_id: Option<Cow<'a, str>>,
1447 pub order_iv: Option<f64>, pub trigger_price: Option<f64>,
1449 pub qty: f64, pub price: Option<f64>, pub tpsl_mode: Option<Cow<'a, str>>,
1452 pub take_profit: Option<f64>,
1453 pub stop_loss: Option<f64>,
1454 pub tp_trigger_by: Option<Cow<'a, str>>,
1455 pub sl_trigger_by: Option<Cow<'a, str>>,
1456 pub trigger_by: Option<Cow<'a, str>>, pub tp_limit_price: Option<f64>,
1458 pub sl_limit_price: Option<f64>,
1459}
1460
1461impl<'a> AmendOrderRequest<'a> {
1462 pub fn default() -> Self {
1463 Self {
1464 category: Category::Linear,
1465 symbol: Cow::Borrowed("BTCUSDT"),
1466 order_id: None,
1467 order_link_id: None,
1468 order_iv: None,
1469 trigger_price: None,
1470 qty: 0.00,
1471 price: None,
1472 tpsl_mode: None,
1473 take_profit: None,
1474 stop_loss: None,
1475 tp_trigger_by: None,
1476 sl_trigger_by: None,
1477 trigger_by: None,
1478 tp_limit_price: None,
1479 sl_limit_price: None,
1480 }
1481 }
1482 pub fn custom(
1483 category: Category,
1484 symbol: &'a str,
1485 order_id: Option<&'a str>,
1486 order_link_id: Option<&'a str>,
1487 order_iv: Option<f64>,
1488 trigger_price: Option<f64>,
1489 qty: f64,
1490 price: Option<f64>,
1491 tpsl_mode: Option<&'a str>,
1492 take_profit: Option<f64>,
1493 stop_loss: Option<f64>,
1494 tp_trigger_by: Option<&'a str>,
1495 sl_trigger_by: Option<&'a str>,
1496 trigger_by: Option<&'a str>,
1497 tp_limit_price: Option<f64>,
1498 sl_limit_price: Option<f64>,
1499 ) -> Self {
1500 Self {
1501 category,
1502 symbol: Cow::Borrowed(symbol),
1503 order_id: order_id.map(Cow::Borrowed),
1504 order_link_id: order_link_id.map(Cow::Borrowed),
1505 order_iv,
1506 trigger_price,
1507 qty,
1508 price,
1509 tpsl_mode: tpsl_mode.map(Cow::Borrowed),
1510 take_profit,
1511 stop_loss,
1512 tp_trigger_by: tp_trigger_by.map(Cow::Borrowed),
1513 sl_trigger_by: sl_trigger_by.map(Cow::Borrowed),
1514 trigger_by: trigger_by.map(Cow::Borrowed),
1515 tp_limit_price,
1516 sl_limit_price,
1517 }
1518 }
1519}
1520
1521#[derive(Clone, Serialize)]
1522pub struct CancelOrderRequest<'a> {
1523 pub category: Category,
1524 pub symbol: Cow<'a, str>,
1525 pub order_id: Option<Cow<'a, str>>,
1526 pub order_link_id: Option<Cow<'a, str>>,
1527 pub order_filter: Option<Cow<'a, str>>,
1528}
1529
1530#[derive(Debug, Serialize, Deserialize, Clone)]
1531#[serde(rename_all = "camelCase")]
1532pub struct CancelOrderResponse {
1533 pub ret_code: i16,
1534 pub ret_msg: String,
1535 pub result: OrderStatus,
1536 pub ret_ext_info: Empty,
1537 pub time: u64,
1538}
1539
1540#[derive(Clone, Default)]
1541pub struct OpenOrdersRequest<'a> {
1542 pub category: Category,
1543 pub symbol: Cow<'a, str>,
1544 pub base_coin: Option<Cow<'a, str>>,
1545 pub settle_coin: Option<Cow<'a, str>>,
1546 pub order_id: Option<Cow<'a, str>>,
1547 pub order_link_id: Option<Cow<'a, str>>,
1548 pub open_only: Option<usize>,
1549 pub order_filter: Option<Cow<'a, str>>,
1550 pub limit: Option<usize>,
1551}
1552
1553impl<'a> OpenOrdersRequest<'a> {
1554 pub fn default() -> Self {
1555 Self {
1556 category: Category::Linear,
1557 symbol: Cow::Borrowed("BTCUSDT"),
1558 base_coin: None,
1559 settle_coin: None,
1560 order_id: None,
1561 order_link_id: None,
1562 open_only: None,
1563 order_filter: None,
1564 limit: None,
1565 }
1566 }
1567
1568 pub fn custom(
1569 category: Category,
1570 symbol: &'a str,
1571 base_coin: Option<&'a str>,
1572 settle_coin: Option<&'a str>,
1573 order_id: Option<&'a str>,
1574 order_link_id: Option<&'a str>,
1575 open_only: usize,
1576 order_filter: Option<&'a str>,
1577 limit: Option<usize>,
1578 ) -> Self {
1579 Self {
1580 category,
1581 symbol: Cow::Borrowed(symbol),
1582 base_coin: base_coin.map(Cow::Borrowed),
1583 settle_coin: settle_coin.map(Cow::Borrowed),
1584 order_id: order_id.map(Cow::Borrowed),
1585 order_link_id: order_link_id.map(Cow::Borrowed),
1586 open_only: match open_only {
1587 0 | 1 | 2 => Some(open_only),
1588 _ => None,
1589 },
1590 order_filter: order_filter.map(Cow::Borrowed),
1591 limit,
1592 }
1593 }
1594}
1595
1596#[derive(Debug, Serialize, Deserialize, Clone)]
1597#[serde(rename_all = "camelCase")]
1598pub struct OpenOrdersResponse {
1599 pub ret_code: i16,
1600 pub ret_msg: String,
1601 pub result: OrderHistory,
1602 pub ret_ext_info: Empty,
1603 pub time: u64,
1604}
1605
1606#[derive(Serialize, Deserialize, Clone, Debug)]
1607#[serde(rename_all = "camelCase")]
1608pub struct OrderStatus {
1609 #[serde(rename = "orderId")]
1610 pub order_id: String,
1611 #[serde(rename = "orderLinkId")]
1612 pub order_link_id: String,
1613}
1614
1615#[derive(Serialize, Deserialize, Clone, Debug)]
1616#[serde(rename_all = "camelCase")]
1617pub struct OrderResponse {
1618 #[serde(rename = "retCode")]
1619 pub ret_code: i16,
1620 #[serde(rename = "retMsg")]
1621 pub ret_msg: String,
1622 pub result: OrderStatus,
1623 #[serde(rename = "retExtInfo")]
1624 pub ret_ext_info: Empty,
1625 pub time: u64,
1626}
1627
1628#[derive(Clone, Default)]
1629pub struct OrderHistoryRequest<'a> {
1630 pub category: Category,
1631 pub symbol: Option<Cow<'a, str>>,
1632 pub base_coin: Option<Cow<'a, str>>,
1633 pub settle_coin: Option<Cow<'a, str>>,
1634 pub order_id: Option<Cow<'a, str>>,
1635 pub order_link_id: Option<Cow<'a, str>>,
1636 pub order_filter: Option<Cow<'a, str>>,
1637 pub order_status: Option<Cow<'a, str>>,
1638 pub start_time: Option<Cow<'a, str>>,
1639 pub end_time: Option<Cow<'a, str>>,
1640 pub limit: Option<u64>,
1641}
1642
1643impl<'a> OrderHistoryRequest<'a> {
1644 pub fn default() -> Self {
1645 Self {
1646 category: Category::Linear,
1647 symbol: None,
1648 base_coin: None,
1649 settle_coin: None,
1650 order_id: None,
1651 order_link_id: None,
1652 order_filter: None,
1653 order_status: None,
1654 start_time: None,
1655 end_time: None,
1656 limit: None,
1657 }
1658 }
1659 pub fn new(
1660 category: Category,
1661 symbol: Option<&'a str>,
1662 base_coin: Option<&'a str>,
1663 settle_coin: Option<&'a str>,
1664 order_id: Option<&'a str>,
1665 order_link_id: Option<&'a str>,
1666 order_filter: Option<&'a str>,
1667 order_status: Option<&'a str>,
1668 start_time: Option<&'a str>,
1669 end_time: Option<&'a str>,
1670 limit: Option<u64>,
1671 ) -> Self {
1672 Self {
1673 category,
1674 symbol: symbol.map(Cow::Borrowed),
1675 base_coin: base_coin.map(Cow::Borrowed),
1676 settle_coin: settle_coin.map(Cow::Borrowed),
1677 order_id: order_id.map(Cow::Borrowed),
1678 order_link_id: order_link_id.map(Cow::Borrowed),
1679 order_filter: order_filter.map(Cow::Borrowed),
1680 order_status: order_status.map(Cow::Borrowed),
1681 start_time: start_time.map(Cow::Borrowed),
1682 end_time: end_time.map(Cow::Borrowed),
1683 limit,
1684 }
1685 }
1686}
1687
1688#[derive(Serialize, Deserialize, Clone, Debug)]
1689#[serde(rename_all = "camelCase")]
1690pub struct OrderHistoryResponse {
1691 #[serde(rename = "retCode")]
1692 pub ret_code: i16,
1693 #[serde(rename = "retMsg")]
1694 pub ret_msg: String,
1695 pub result: OrderHistory,
1696 #[serde(rename = "retExtInfo")]
1697 pub ret_ext_info: Empty,
1698 pub time: u64,
1699}
1700
1701#[derive(Serialize, Deserialize, Clone, Debug)]
1702#[serde(rename_all = "camelCase")]
1703pub struct OrderHistory {
1704 pub category: String,
1705 pub list: Vec<Orders>,
1706 #[serde(rename = "nextPageCursor", skip_serializing_if = "String::is_empty")]
1707 pub next_page_cursor: String,
1708}
1709
1710#[derive(Serialize, Deserialize, Clone, Debug)]
1711#[serde(rename_all = "camelCase")]
1712pub struct Orders {
1713 pub order_id: String,
1714 pub order_link_id: String,
1715 pub block_trade_id: String,
1716 pub symbol: String,
1717
1718 #[serde(with = "string_to_float")]
1719 pub price: f64,
1720
1721 #[serde(with = "string_to_float")]
1722 pub qty: f64,
1723
1724 pub side: Side,
1725
1726 #[serde(skip_serializing_if = "String::is_empty")]
1727 pub is_leverage: String,
1728
1729 pub position_idx: i32,
1730 pub order_status: String,
1731 pub cancel_type: String,
1732 pub reject_reason: String,
1733
1734 #[serde(with = "string_to_float_optional")]
1735 pub avg_price: Option<f64>,
1736
1737 #[serde(with = "string_to_float")]
1738 pub leaves_qty: f64,
1739
1740 #[serde(with = "string_to_float")]
1741 pub leaves_value: f64,
1742
1743 #[serde(with = "string_to_float")]
1744 pub cum_exec_qty: f64,
1745
1746 #[serde(with = "string_to_float")]
1747 pub cum_exec_value: f64,
1748
1749 #[serde(with = "string_to_float")]
1750 pub cum_exec_fee: f64,
1751
1752 pub time_in_force: String,
1753 pub order_type: OrderType,
1754 pub stop_order_type: String,
1755
1756 #[serde(skip_serializing_if = "String::is_empty")]
1757 pub order_iv: String,
1758
1759 #[serde(with = "string_to_float")]
1760 pub trigger_price: f64,
1761
1762 #[serde(with = "string_to_float_optional")]
1763 pub take_profit: Option<f64>,
1764
1765 #[serde(with = "string_to_float_optional")]
1766 pub stop_loss: Option<f64>,
1767
1768 pub tp_trigger_by: String,
1769 pub sl_trigger_by: String,
1770 pub trigger_direction: i32,
1771 pub trigger_by: String,
1772
1773 #[serde(with = "string_to_float_optional")]
1774 pub last_price_on_created: Option<f64>,
1775
1776 pub reduce_only: bool,
1777 pub close_on_trigger: bool,
1778 pub smp_type: String,
1779 pub smp_group: i32,
1780
1781 #[serde(skip_serializing_if = "String::is_empty")]
1782 pub smp_order_id: String,
1783
1784 #[serde(skip_serializing_if = "String::is_empty")]
1785 pub tpsl_mode: String,
1786
1787 #[serde(with = "string_to_float_optional")]
1788 pub tp_limit_price: Option<f64>,
1789
1790 #[serde(with = "string_to_float_optional")]
1791 pub sl_limit_price: Option<f64>,
1792
1793 #[serde(skip_serializing_if = "String::is_empty")]
1794 pub place_type: String,
1795
1796 #[serde(with = "string_to_u64")]
1797 pub created_time: u64,
1798
1799 #[serde(with = "string_to_u64")]
1800 pub updated_time: u64,
1801}
1802
1803#[cfg(test)]
1804mod tests {
1805 use super::*;
1806
1807 #[test]
1808 fn test_deserialize_orders() {
1809 let json = r#"
1810 {
1811 "orderId": "fd4300ae-7847-404e-b947-b46980a4d140",
1812 "orderLinkId": "test-000005",
1813 "blockTradeId": "",
1814 "symbol": "ETHUSDT",
1815 "price": "1600.00",
1816 "qty": "0.10",
1817 "side": "Buy",
1818 "isLeverage": "",
1819 "positionIdx": 1,
1820 "orderStatus": "New",
1821 "cancelType": "UNKNOWN",
1822 "rejectReason": "EC_NoError",
1823 "avgPrice": "0",
1824 "leavesQty": "0.10",
1825 "leavesValue": "160",
1826 "cumExecQty": "0.00",
1827 "cumExecValue": "0",
1828 "cumExecFee": "0",
1829 "timeInForce": "GTC",
1830 "orderType": "Limit",
1831 "stopOrderType": "UNKNOWN",
1832 "orderIv": "",
1833 "triggerPrice": "0.00",
1834 "takeProfit": "2500.00",
1835 "stopLoss": "1500.00",
1836 "tpTriggerBy": "LastPrice",
1837 "slTriggerBy": "LastPrice",
1838 "triggerDirection": 0,
1839 "triggerBy": "UNKNOWN",
1840 "lastPriceOnCreated": "",
1841 "reduceOnly": false,
1842 "closeOnTrigger": false,
1843 "smpType": "None",
1844 "smpGroup": 0,
1845 "smpOrderId": "",
1846 "tpslMode": "Full",
1847 "tpLimitPrice": "",
1848 "slLimitPrice": "",
1849 "placeType": "",
1850 "createdTime": "1684738540559",
1851 "updatedTime": "1684738540561"
1852 }
1853 "#;
1854 let order: Orders = serde_json::from_str(json).unwrap();
1855 assert_eq!(order.order_id, "fd4300ae-7847-404e-b947-b46980a4d140");
1856 }
1857}
1858
1859#[derive(Clone, Default)]
1860pub struct CancelallRequest<'a> {
1861 pub category: Category,
1862 pub symbol: &'a str,
1863 pub base_coin: Option<&'a str>,
1864 pub settle_coin: Option<&'a str>,
1865 pub order_filter: Option<&'a str>,
1866 pub stop_order_type: Option<&'a str>,
1867}
1868
1869impl<'a> CancelallRequest<'a> {
1870 pub fn default() -> Self {
1871 Self {
1872 category: Category::Linear,
1873 symbol: "BTCUSDT",
1874 base_coin: None,
1875 settle_coin: None,
1876 order_filter: None,
1877 stop_order_type: None,
1878 }
1879 }
1880 pub fn new(
1881 category: Category,
1882 symbol: &'a str,
1883 base_coin: Option<&'a str>,
1884 settle_coin: Option<&'a str>,
1885 order_filter: Option<&'a str>,
1886 stop_order_type: Option<&'a str>,
1887 ) -> Self {
1888 Self {
1889 category,
1890 symbol,
1891 base_coin,
1892 settle_coin,
1893 order_filter,
1894 stop_order_type,
1895 }
1896 }
1897}
1898
1899#[derive(Serialize, Deserialize, Clone, Debug)]
1900#[serde(rename_all = "camelCase")]
1901pub struct CancelallResponse {
1902 #[serde(rename = "retCode")]
1903 pub ret_code: i16,
1904 #[serde(rename = "retMsg")]
1905 pub ret_msg: String,
1906 pub result: CancelledList,
1907 #[serde(rename = "retExtInfo")]
1908 pub ret_ext_info: Empty,
1909 pub time: u64,
1910}
1911
1912#[derive(Serialize, Deserialize, Clone, Debug)]
1913#[serde(rename_all = "camelCase")]
1914pub struct CancelledList {
1915 pub list: Vec<OrderStatus>,
1916}
1917
1918#[derive(Serialize, Deserialize, Clone, Debug)]
1919#[serde(rename_all = "camelCase")]
1920pub struct TradeHistoryResponse {
1921 pub ret_code: i16,
1922 pub ret_msg: String,
1923 pub result: TradeHistorySummary,
1924 pub ret_ext_info: Empty,
1925 pub time: u64,
1926}
1927
1928#[derive(Serialize, Deserialize, Clone, Debug)]
1929#[serde(rename_all = "camelCase")]
1930pub struct TradeHistorySummary {
1931 #[serde(rename = "nextPageCursor", skip_serializing_if = "String::is_empty")]
1932 pub next_page_cursor: String,
1933 pub category: String,
1934 pub list: Vec<TradeHistory>,
1935}
1936#[derive(Serialize, Deserialize, Clone, Debug)]
1937#[serde(rename_all = "camelCase")]
1938pub struct TradeHistory {
1939 pub symbol: String,
1940 #[serde(rename = "orderType")]
1941 pub order_type: String,
1942 #[serde(
1943 rename = "underlyingPrice",
1944 default,
1945 skip_serializing_if = "String::is_empty"
1946 )]
1947 pub underlying_price: String,
1948 #[serde(
1949 rename = "orderLinkId",
1950 default,
1951 skip_serializing_if = "String::is_empty"
1952 )]
1953 pub order_link_id: String,
1954 pub side: String,
1955 #[serde(
1956 rename = "indexPrice",
1957 default,
1958 skip_serializing_if = "String::is_empty"
1959 )]
1960 pub index_price: String,
1961 #[serde(rename = "orderId")]
1962 pub order_id: String,
1963 #[serde(rename = "stopOrderType")]
1964 pub stop_order_type: String,
1965 #[serde(rename = "leavesQty")]
1966 pub leaves_qty: String,
1967 #[serde(rename = "execTime")]
1968 pub exec_time: String,
1969 #[serde(
1970 rename = "feeCurrency",
1971 default,
1972 skip_serializing_if = "String::is_empty"
1973 )]
1974 pub fee_currency: String,
1975 #[serde(rename = "isMaker")]
1976 pub is_maker: bool,
1977 #[serde(rename = "execFee")]
1978 pub exec_fee: String,
1979 #[serde(rename = "feeRate")]
1980 pub fee_rate: String,
1981 #[serde(rename = "execId")]
1982 pub exec_id: String,
1983 #[serde(rename = "tradeIv", default, skip_serializing_if = "String::is_empty")]
1984 pub trade_iv: String,
1985 #[serde(
1986 rename = "blockTradeId",
1987 default,
1988 skip_serializing_if = "String::is_empty"
1989 )]
1990 pub block_trade_id: String,
1991 #[serde(rename = "markPrice")]
1992 pub mark_price: String,
1993 #[serde(rename = "execPrice")]
1994 pub exec_price: String,
1995 #[serde(rename = "markIv", default, skip_serializing_if = "String::is_empty")]
1996 pub mark_iv: String,
1997 #[serde(rename = "orderQty")]
1998 pub order_qty: String,
1999 #[serde(rename = "orderPrice")]
2000 pub order_price: String,
2001 #[serde(rename = "execValue")]
2002 pub exec_value: String,
2003 #[serde(rename = "execType")]
2004 pub exec_type: String,
2005 #[serde(rename = "execQty")]
2006 pub exec_qty: String,
2007 #[serde(
2008 rename = "closedSize",
2009 default,
2010 skip_serializing_if = "String::is_empty"
2011 )]
2012 pub closed_size: String,
2013 pub seq: u64,
2014}
2015
2016#[derive(Clone, Default)]
2017pub struct TradeHistoryRequest<'a> {
2018 pub category: Category,
2019 pub symbol: Option<Cow<'a, str>>,
2020 pub order_id: Option<Cow<'a, str>>,
2021 pub order_link_id: Option<Cow<'a, str>>,
2022 pub base_coin: Option<Cow<'a, str>>,
2023 pub start_time: Option<Cow<'a, str>>,
2024 pub end_time: Option<Cow<'a, str>>,
2025 pub exec_type: Option<Cow<'a, str>>,
2026 pub limit: Option<u64>,
2027}
2028
2029impl<'a> TradeHistoryRequest<'a> {
2030 pub fn default() -> TradeHistoryRequest<'a> {
2031 TradeHistoryRequest::new(
2032 Category::Linear,
2033 None,
2034 None,
2035 None,
2036 None,
2037 None,
2038 None,
2039 None,
2040 None,
2041 )
2042 }
2043 pub fn new(
2044 category: Category,
2045 symbol: Option<&'a str>,
2046 order_id: Option<&'a str>,
2047 order_link_id: Option<&'a str>,
2048 base_coin: Option<&'a str>,
2049 start_time: Option<&'a str>,
2050 end_time: Option<&'a str>,
2051 exec_type: Option<&'a str>,
2052 limit: Option<u64>,
2053 ) -> TradeHistoryRequest<'a> {
2054 TradeHistoryRequest {
2055 category,
2056 symbol: symbol.map(|s| Cow::Borrowed(s)),
2057 order_id: order_id.map(|s| Cow::Borrowed(s)),
2058 order_link_id: order_link_id.map(|s| Cow::Borrowed(s)),
2059 base_coin: base_coin.map(|s| Cow::Borrowed(s)),
2060 start_time: start_time.map(|s| Cow::Borrowed(s)),
2061 end_time: end_time.map(|s| Cow::Borrowed(s)),
2062 exec_type: exec_type.map(|s| Cow::Borrowed(s)),
2063 limit,
2064 }
2065 }
2066}
2067
2068#[derive(Clone, Default)]
2069pub struct BatchPlaceRequest<'a> {
2070 pub category: Category,
2071 pub requests: Vec<OrderRequest<'a>>,
2072}
2073impl<'a> BatchPlaceRequest<'a> {
2074 pub fn new(category: Category, requests: Vec<OrderRequest<'a>>) -> BatchPlaceRequest<'a> {
2075 BatchPlaceRequest { category, requests }
2076 }
2077}
2078#[derive(Serialize, Deserialize, Clone, Debug)]
2079#[serde(rename_all = "camelCase")]
2080pub struct BatchPlaceResponse {
2081 #[serde(rename = "retCode")]
2082 pub ret_code: i16,
2083 #[serde(rename = "retMsg")]
2084 pub ret_msg: String,
2085 pub result: BatchedOrderList,
2086 #[serde(rename = "retExtInfo")]
2087 pub ret_ext_info: OrderConfirmationList,
2088 pub time: u64,
2089}
2090
2091#[derive(Serialize, Deserialize, Clone, Debug)]
2092#[serde(rename_all = "camelCase")]
2093pub struct BatchedOrderList {
2094 pub list: Vec<BatchedOrder>,
2095}
2096
2097#[derive(Serialize, Deserialize, Clone, Debug)]
2098#[serde(rename_all = "camelCase")]
2099pub struct BatchedOrder {
2100 pub category: String,
2101 pub symbol: String,
2102 #[serde(rename = "orderId")]
2103 pub order_id: String,
2104 #[serde(rename = "orderLinkId")]
2105 pub order_link_id: String,
2106 #[serde(rename = "createAt")]
2107 pub create_at: String,
2108}
2109
2110#[derive(Serialize, Deserialize, Clone, Debug)]
2111#[serde(rename_all = "camelCase")]
2112pub struct OrderConfirmationList {
2113 pub list: Vec<OrderConfirmation>,
2114}
2115
2116#[derive(Serialize, Deserialize, Clone, Debug)]
2117#[serde(rename_all = "camelCase")]
2118pub struct OrderConfirmation {
2119 pub code: i16,
2120 pub msg: String,
2121}
2122
2123#[derive(Clone, Default)]
2124pub struct BatchAmendRequest<'a> {
2125 pub category: Category,
2126 pub requests: Vec<AmendOrderRequest<'a>>,
2127}
2128
2129impl<'a> BatchAmendRequest<'a> {
2130 pub fn new(category: Category, requests: Vec<AmendOrderRequest<'a>>) -> BatchAmendRequest<'a> {
2131 BatchAmendRequest { category, requests }
2132 }
2133}
2134
2135#[derive(Serialize, Deserialize, Clone, Debug)]
2136#[serde(rename_all = "camelCase")]
2137pub struct BatchAmendResponse {
2138 #[serde(rename = "retCode")]
2139 pub ret_code: i16,
2140 #[serde(rename = "retMsg")]
2141 pub ret_msg: String,
2142 pub result: AmendedOrderList,
2143 #[serde(rename = "retExtInfo")]
2144 pub ret_ext_info: OrderConfirmationList,
2145 pub time: u64,
2146}
2147
2148#[derive(Serialize, Deserialize, Clone, Debug)]
2149#[serde(rename_all = "camelCase")]
2150pub struct AmendedOrderList {
2151 pub list: Vec<AmendedOrder>,
2152}
2153
2154#[derive(Serialize, Deserialize, Clone, Debug)]
2155#[serde(rename_all = "camelCase")]
2156pub struct AmendedOrder {
2157 pub category: String,
2158 pub symbol: String,
2159 #[serde(rename = "orderId")]
2160 pub order_id: String,
2161 #[serde(rename = "orderLinkId")]
2162 pub order_link_id: String,
2163}
2164
2165#[derive(Clone, Default)]
2166pub struct BatchCancelRequest<'a> {
2167 pub category: Category,
2168 pub requests: Vec<CancelOrderRequest<'a>>,
2169}
2170
2171impl<'a> BatchCancelRequest<'a> {
2172 pub fn new(
2173 category: Category,
2174 requests: Vec<CancelOrderRequest<'a>>,
2175 ) -> BatchCancelRequest<'a> {
2176 BatchCancelRequest { category, requests }
2177 }
2178}
2179
2180#[derive(Serialize, Deserialize, Clone, Debug)]
2181#[serde(rename_all = "camelCase")]
2182pub struct BatchCancelResponse {
2183 #[serde(rename = "retCode")]
2184 pub ret_code: i16,
2185 #[serde(rename = "retMsg")]
2186 pub ret_msg: String,
2187 pub result: CanceledOrderList,
2188 #[serde(rename = "retExtInfo")]
2189 pub ret_ext_info: OrderConfirmationList,
2190 pub time: u64,
2191}
2192
2193#[derive(Serialize, Deserialize, Clone, Debug)]
2194#[serde(rename_all = "camelCase")]
2195pub struct CanceledOrderList {
2196 pub list: Vec<CanceledOrder>,
2197}
2198
2199#[derive(Serialize, Deserialize, Clone, Debug)]
2200#[serde(rename_all = "camelCase")]
2201pub struct CanceledOrder {
2202 pub category: String,
2203 pub symbol: String,
2204 #[serde(rename = "orderId")]
2205 pub order_id: String,
2206 #[serde(rename = "orderLinkId")]
2207 pub order_link_id: String,
2208}
2209
2210#[derive(Clone)]
2211pub enum RequestType<'a> {
2212 Create(BatchPlaceRequest<'a>),
2213 Amend(BatchAmendRequest<'a>),
2214 Cancel(BatchCancelRequest<'a>),
2215}
2216
2217#[derive(Clone, Default)]
2222pub struct PositionRequest<'a> {
2223 pub category: Category,
2224 pub symbol: Option<Cow<'a, str>>,
2225 pub base_coin: Option<Cow<'a, str>>,
2226 pub settle_coin: Option<Cow<'a, str>>,
2227 pub limit: Option<usize>,
2228}
2229
2230impl<'a> PositionRequest<'a> {
2231 pub fn default() -> Self {
2232 Self::new(Category::Linear, None, None, None, None)
2233 }
2234 pub fn new(
2235 category: Category,
2236 symbol: Option<&'a str>,
2237 base_coin: Option<&'a str>,
2238 settle_coin: Option<&'a str>,
2239 limit: Option<usize>,
2240 ) -> Self {
2241 Self {
2242 category,
2243 symbol: symbol.map(Cow::Borrowed),
2244 base_coin: base_coin.map(Cow::Borrowed),
2245 settle_coin: settle_coin.map(Cow::Borrowed),
2246 limit,
2247 }
2248 }
2249}
2250
2251#[derive(Debug, Serialize, Deserialize, Clone)]
2252#[serde(rename_all = "camelCase")]
2253pub struct InfoResponse {
2254 pub ret_code: i32,
2255 pub ret_msg: String,
2256 pub result: InfoResult,
2257 pub ret_ext_info: Empty,
2258 pub time: u64,
2259}
2260
2261#[derive(Debug, Serialize, Deserialize, Clone)]
2262pub struct InfoResult {
2263 pub list: Vec<PositionInfo>,
2264 #[serde(rename = "nextPageCursor", skip_serializing_if = "Option::is_none")]
2265 pub next_page_cursor: Option<String>,
2266 pub category: String,
2267}
2268
2269mod string_to_float_default_zero {
2270 use serde::{Deserialize, Deserializer, Serializer};
2271 use std::str::FromStr;
2272
2273 pub fn serialize<S>(value: &f64, serializer: S) -> Result<S::Ok, S::Error>
2275 where
2276 S: Serializer,
2277 {
2278 serializer.serialize_str(&value.to_string())
2279 }
2280
2281 pub fn deserialize<'de, D>(deserializer: D) -> Result<f64, D::Error>
2283 where
2284 D: Deserializer<'de>,
2285 {
2286 let s = String::deserialize(deserializer)?;
2287 if s.is_empty() {
2288 Ok(0.0) } else {
2290 f64::from_str(&s).map_err(serde::de::Error::custom)
2291 }
2292 }
2293}
2294
2295mod string_to_float_optional {
2296 use serde::{Deserialize, Deserializer, Serializer};
2297 use std::str::FromStr;
2298
2299 pub fn serialize<S>(value: &Option<f64>, serializer: S) -> Result<S::Ok, S::Error>
2301 where
2302 S: Serializer,
2303 {
2304 match value {
2305 Some(v) => serializer.serialize_str(&v.to_string()),
2306 None => serializer.serialize_str(""),
2307 }
2308 }
2309
2310 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
2312 where
2313 D: Deserializer<'de>,
2314 {
2315 let s = String::deserialize(deserializer)?;
2316 if s.is_empty() {
2317 Ok(None) } else {
2319 f64::from_str(&s)
2320 .map(Some)
2321 .map_err(serde::de::Error::custom)
2322 }
2323 }
2324}
2325
2326#[derive(Debug, Serialize, Deserialize, Clone)]
2327#[serde(rename_all = "camelCase")]
2328pub struct PositionInfo {
2329 pub position_idx: i32,
2330
2331 pub risk_id: i32,
2332
2333 #[serde(with = "string_to_float")]
2334 pub risk_limit_value: f64,
2335
2336 pub symbol: String,
2337
2338 pub side: String,
2339
2340 #[serde(with = "string_to_float")]
2341 pub size: f64,
2342
2343 #[serde(with = "string_to_float_optional")]
2344 pub avg_price: Option<f64>,
2345
2346 #[serde(with = "string_to_float_optional")]
2347 pub position_value: Option<f64>,
2348
2349 pub trade_mode: i32,
2350
2351 pub position_status: String,
2352
2353 pub auto_add_margin: i32,
2354
2355 pub adl_rank_indicator: i32,
2356
2357 #[serde(with = "string_to_float_optional")]
2358 pub leverage: Option<f64>,
2359
2360 #[serde(with = "string_to_float")]
2361 pub position_balance: f64,
2362
2363 #[serde(with = "string_to_float")]
2364 pub mark_price: f64,
2365
2366 #[serde(with = "string_to_float_optional")]
2367 pub liq_price: Option<f64>,
2368
2369 pub bust_price: String,
2370
2371 #[serde(rename = "positionMM", with = "string_to_float_optional")]
2372 pub position_mm: Option<f64>,
2373
2374 #[serde(rename = "positionIM", with = "string_to_float_optional")]
2375 pub position_im: Option<f64>,
2376
2377 pub tpsl_mode: String,
2378
2379 pub take_profit: String,
2380
2381 pub stop_loss: String,
2382
2383 pub trailing_stop: String,
2384
2385 #[serde(with = "string_to_float_optional")]
2386 pub unrealised_pnl: Option<f64>,
2387
2388 #[serde(with = "string_to_float_optional")]
2389 pub cum_realised_pnl: Option<f64>,
2390
2391 pub seq: u64,
2392
2393 pub is_reduce_only: bool,
2394
2395 #[serde(with = "string_to_u64_optional")]
2396 pub mmr_sys_updated_time: Option<u64>,
2397
2398 #[serde(with = "string_to_u64_optional")]
2399 pub leverage_sys_updated_time: Option<u64>,
2400
2401 #[serde(with = "string_to_u64")]
2402 pub created_time: u64,
2403
2404 #[serde(with = "string_to_u64")]
2405 pub updated_time: u64,
2406}
2407#[cfg(test)]
2408mod test_decode_position_info {
2409 use super::*;
2410
2411 #[test]
2412 fn test_deserialize() {
2413 let json = r#"
2414 {
2415 "positionIdx": 0,
2416 "riskId": 1,
2417 "riskLimitValue": "150",
2418 "symbol": "BTCUSD",
2419 "side": "Sell",
2420 "size": "300",
2421 "avgPrice": "27464.50441675",
2422 "positionValue": "0.01092319",
2423 "tradeMode": 0,
2424 "positionStatus": "Normal",
2425 "autoAddMargin": 1,
2426 "adlRankIndicator": 2,
2427 "leverage": "10",
2428 "positionBalance": "0.00139186",
2429 "markPrice": "28224.50",
2430 "liqPrice": "",
2431 "bustPrice": "999999.00",
2432 "positionMM": "0.0000015",
2433 "positionIM": "0.00010923",
2434 "tpslMode": "Full",
2435 "takeProfit": "0.00",
2436 "stopLoss": "0.00",
2437 "trailingStop": "0.00",
2438 "unrealisedPnl": "-0.00029413",
2439 "curRealisedPnl": "0.00013123",
2440 "cumRealisedPnl": "-0.00096902",
2441 "seq": 5723621632,
2442 "isReduceOnly": false,
2443 "mmrSysUpdatedTime": "1676538056444",
2444 "leverageSysUpdatedTime": "1676538056333",
2445 "sessionAvgPrice": "",
2446 "createdTime": "1676538056258",
2447 "updatedTime": "1697673600012"
2448 }
2449 "#;
2450 let result = serde_json::from_str::<PositionInfo>(json);
2451 let result = result.unwrap();
2452 assert_eq!(result.cum_realised_pnl, Some(-0.00096902));
2453 assert_eq!(result.mmr_sys_updated_time, Some(1676538056444));
2454 assert_eq!(result.leverage_sys_updated_time, Some(1676538056333));
2455 assert_eq!(result.created_time, 1676538056258);
2456 assert_eq!(result.updated_time, 1697673600012);
2457 }
2458}
2459
2460#[derive(Clone, Default)]
2461pub struct LeverageRequest<'a> {
2462 pub category: Category,
2463 pub symbol: Cow<'a, str>,
2464 pub leverage: i8,
2465}
2466
2467impl<'a> LeverageRequest<'a> {
2468 pub fn new(category: Category, symbol: &'a str, leverage: i8) -> Self {
2469 Self {
2470 category,
2471 symbol: Cow::Borrowed(symbol),
2472 leverage,
2473 }
2474 }
2475 pub fn default() -> LeverageRequest<'a> {
2476 LeverageRequest::new(Category::Linear, "BTCUSDT", 10)
2477 }
2478}
2479
2480#[derive(Serialize, Deserialize, Clone, Debug)]
2481#[serde(rename_all = "camelCase")]
2482pub struct LeverageResponse {
2483 #[serde(rename = "retCode")]
2484 pub ret_code: i32,
2485 #[serde(rename = "retMsg")]
2486 pub ret_msg: String,
2487 pub result: Empty, #[serde(rename = "retExtInfo")]
2489 pub ret_ext_info: Empty, pub time: u64,
2491}
2492
2493#[derive(Default, Clone)]
2494pub struct ChangeMarginRequest<'a> {
2495 pub category: Category,
2496 pub symbol: Cow<'a, str>,
2497 pub trade_mode: i8,
2498 pub leverage: i8,
2499}
2500
2501impl<'a> ChangeMarginRequest<'a> {
2502 pub fn new(category: Category, symbol: &'a str, trade_mode: i8, leverage: i8) -> Self {
2503 Self {
2504 category,
2505 symbol: Cow::Borrowed(symbol),
2506 trade_mode: match trade_mode {
2507 1 => 1,
2508 0 => 0,
2509 _ => 0,
2510 },
2511 leverage,
2512 }
2513 }
2514 pub fn default() -> ChangeMarginRequest<'a> {
2515 ChangeMarginRequest::new(Category::Linear, "BTCUSDT", 0, 10)
2516 }
2517}
2518
2519#[derive(Serialize, Deserialize, Clone, Debug)]
2520#[serde(rename_all = "camelCase")]
2521pub struct ChangeMarginResponse {
2522 #[serde(rename = "retCode")]
2523 pub ret_code: i32,
2524 #[serde(rename = "retMsg")]
2525 pub ret_msg: String,
2526 pub result: Empty, #[serde(rename = "retExtInfo")]
2528 pub ret_ext_info: Empty, pub time: u64,
2530}
2531
2532#[derive(Clone, Default)]
2533pub struct MarginModeRequest<'a> {
2534 pub category: Category,
2535 pub mode: i8,
2536 pub symbol: Option<Cow<'a, str>>,
2537 pub coin: Option<Cow<'a, str>>,
2538}
2539
2540impl<'a> MarginModeRequest<'a> {
2541 pub fn new(
2542 category: Category,
2543 mode: i8,
2544 symbol: Option<&'a str>,
2545 coin: Option<&'a str>,
2546 ) -> Self {
2547 Self {
2548 category,
2549 mode,
2550 symbol: symbol.map(|s| Cow::Borrowed(s)),
2551 coin: coin.map(|s| Cow::Borrowed(s)),
2552 }
2553 }
2554 pub fn default() -> MarginModeRequest<'a> {
2555 MarginModeRequest::new(Category::Linear, 1, None, None)
2556 }
2557}
2558
2559#[derive(Serialize, Deserialize, Clone, Debug)]
2560#[serde(rename_all = "camelCase")]
2561pub struct MarginModeResponse {
2562 #[serde(rename = "retCode")]
2563 pub ret_code: i32,
2564 #[serde(rename = "retMsg")]
2565 pub ret_msg: String,
2566 pub result: Empty, #[serde(rename = "retExtInfo")]
2568 pub ret_ext_info: Empty, pub time: u64,
2570}
2571
2572#[derive(Clone, Default)]
2573pub struct SetRiskLimit<'a> {
2574 pub category: Category,
2575 pub symbol: Cow<'a, str>,
2576 pub risk_id: i8,
2577 pub position_idx: Option<i32>,
2578}
2579
2580impl<'a> SetRiskLimit<'a> {
2581 pub fn new(
2582 category: Category,
2583 symbol: &'a str,
2584 risk_id: i8,
2585 position_idx: Option<i32>,
2586 ) -> Self {
2587 Self {
2588 category,
2589 symbol: Cow::Borrowed(symbol),
2590 risk_id,
2591 position_idx,
2592 }
2593 }
2594 pub fn default() -> SetRiskLimit<'a> {
2595 SetRiskLimit::new(Category::Linear, "BTCUSDT", 1, None)
2596 }
2597}
2598
2599#[derive(Serialize, Deserialize, Clone, Debug)]
2600#[serde(rename_all = "camelCase")]
2601pub struct SetRiskLimitResponse {
2602 #[serde(rename = "retCode")]
2603 pub ret_code: i32,
2604 #[serde(rename = "retMsg")]
2605 pub ret_msg: String,
2606 pub result: SetRiskLimitResult,
2607 #[serde(rename = "retExtInfo")]
2608 pub ret_ext_info: Empty, pub time: u64,
2610}
2611
2612#[derive(Serialize, Deserialize, Clone, Debug)]
2613pub struct SetRiskLimitResult {
2614 #[serde(rename = "riskId")]
2615 pub risk_id: i32,
2616 #[serde(rename = "riskLimitValue", with = "string_to_u64")]
2617 pub risk_limit_value: u64,
2618 pub category: String,
2619}
2620
2621#[derive(Clone, Default)]
2622pub struct TradingStopRequest<'a> {
2623 pub category: Category,
2624 pub symbol: Cow<'a, str>,
2625 pub take_profit: Option<f64>,
2626 pub stop_loss: Option<f64>,
2627 pub tp_trigger_by: Option<Cow<'a, str>>,
2628 pub sl_trigger_by: Option<Cow<'a, str>>,
2629 pub tpsl_mode: Option<Cow<'a, str>>,
2630 pub tp_order_type: Option<OrderType>,
2631 pub sl_order_type: Option<OrderType>,
2632 pub tp_size: Option<f64>,
2633 pub sl_size: Option<f64>,
2634 pub tp_limit_price: Option<f64>,
2635 pub sl_limit_price: Option<f64>,
2636 pub position_idx: i32,
2637}
2638
2639impl<'a> TradingStopRequest<'a> {
2640 pub fn new(
2641 category: Category,
2642 symbol: &'a str,
2643 take_profit: Option<f64>,
2644 stop_loss: Option<f64>,
2645 tp_trigger_by: Option<&'a str>,
2646 sl_trigger_by: Option<&'a str>,
2647 tpsl_mode: Option<&'a str>,
2648 tp_order_type: Option<OrderType>,
2649 sl_order_type: Option<OrderType>,
2650 tp_size: Option<f64>,
2651 sl_size: Option<f64>,
2652 tp_limit_price: Option<f64>,
2653 sl_limit_price: Option<f64>,
2654 position_idx: i32,
2655 ) -> Self {
2656 Self {
2657 category,
2658 symbol: Cow::Borrowed(symbol),
2659 take_profit,
2660 stop_loss,
2661 tp_trigger_by: tp_trigger_by.map(|s| Cow::Borrowed(s)),
2662 sl_trigger_by: sl_trigger_by.map(|s| Cow::Borrowed(s)),
2663 tpsl_mode: tpsl_mode.map(|s| Cow::Borrowed(s)),
2664 tp_order_type,
2665 sl_order_type,
2666 tp_size,
2667 sl_size,
2668 tp_limit_price,
2669 sl_limit_price,
2670 position_idx,
2671 }
2672 }
2673
2674 pub fn default() -> TradingStopRequest<'a> {
2675 TradingStopRequest::new(
2676 Category::Linear,
2677 "BTCUSDT",
2678 None,
2679 None,
2680 None,
2681 None,
2682 None,
2683 None,
2684 None,
2685 None,
2686 None,
2687 None,
2688 None,
2689 1,
2690 )
2691 }
2692}
2693
2694#[derive(Serialize, Deserialize, Clone, Debug)]
2695#[serde(rename_all = "camelCase")]
2696pub struct TradingStopResponse {
2697 #[serde(rename = "retCode")]
2698 pub ret_code: i32,
2699 #[serde(rename = "retMsg")]
2700 pub ret_msg: String,
2701 pub result: Empty, #[serde(rename = "retExtInfo")]
2703 pub ret_ext_info: Empty, pub time: u64,
2705}
2706
2707#[derive(Clone, Default)]
2708pub struct AddMarginRequest<'a> {
2709 pub category: Category,
2710 pub symbol: Cow<'a, str>,
2711 pub auto_add: bool,
2712 pub position_idx: Option<i32>,
2713}
2714
2715impl<'a> AddMarginRequest<'a> {
2716 pub fn new(
2717 category: Category,
2718 symbol: &'a str,
2719 auto_add: bool,
2720 position_idx: Option<i32>,
2721 ) -> Self {
2722 Self {
2723 category,
2724 symbol: Cow::Borrowed(symbol),
2725 auto_add,
2726 position_idx,
2727 }
2728 }
2729 pub fn default() -> AddMarginRequest<'a> {
2730 AddMarginRequest::new(Category::Linear, "BTCUSDT", false, None)
2731 }
2732}
2733
2734#[derive(Serialize, Deserialize, Clone, Debug)]
2735#[serde(rename_all = "camelCase")]
2736pub struct AddMarginResponse {
2737 #[serde(rename = "retCode")]
2738 pub ret_code: i32,
2739 #[serde(rename = "retMsg")]
2740 pub ret_msg: String,
2741 pub result: Empty, #[serde(rename = "retExtInfo")]
2743 pub ret_ext_info: Empty, pub time: u64,
2745}
2746
2747#[derive(Clone, Default)]
2748pub struct AddReduceMarginRequest<'a> {
2749 pub category: Category,
2750 pub symbol: Cow<'a, str>,
2751 pub margin: f64,
2752 pub position_idx: Option<i32>,
2753}
2754
2755impl<'a> AddReduceMarginRequest<'a> {
2756 pub fn new(
2757 category: Category,
2758 symbol: &'a str,
2759 margin: f64,
2760 position_idx: Option<i32>,
2761 ) -> Self {
2762 Self {
2763 category,
2764 symbol: Cow::Borrowed(symbol),
2765 margin,
2766 position_idx,
2767 }
2768 }
2769 pub fn default() -> AddReduceMarginRequest<'a> {
2770 AddReduceMarginRequest::new(Category::Linear, "BTCUSDT", 1.0, None)
2771 }
2772}
2773
2774#[derive(Serialize, Deserialize, Clone, Debug)]
2775#[serde(rename_all = "camelCase")]
2776pub struct AddReduceMarginResponse {
2777 #[serde(rename = "retCode")]
2778 pub ret_code: i32,
2779 #[serde(rename = "retMsg")]
2780 pub ret_msg: String,
2781 pub result: AddReduceMarginResult,
2782 #[serde(rename = "retExtInfo")]
2783 pub ret_ext_info: Empty, pub time: u64,
2785}
2786
2787#[derive(Serialize, Deserialize, Clone, Debug)]
2788#[serde(rename_all = "camelCase")]
2789pub struct AddReduceMarginResult {
2790 pub category: String,
2791 pub symbol: String,
2792 pub position_idx: i32,
2793 #[serde(rename = "riskId")]
2794 pub risk_id: i32,
2795 #[serde(rename = "riskLimitValue")]
2796 pub risk_limit_value: String,
2797 pub size: String,
2798 #[serde(rename = "positionValue")]
2799 pub position_value: String,
2800 #[serde(rename = "avgPrice")]
2801 pub avg_price: String,
2802 #[serde(rename = "liqPrice")]
2803 pub liq_price: String,
2804 #[serde(rename = "bustPrice")]
2805 pub bust_price: String,
2806 #[serde(rename = "markPrice")]
2807 pub mark_price: String,
2808 pub leverage: String,
2809 #[serde(rename = "autoAddMargin")]
2810 pub auto_add_margin: i32,
2811 #[serde(rename = "positionStatus")]
2812 pub position_status: String,
2813 #[serde(rename = "positionIM")]
2814 pub position_im: String,
2815 #[serde(rename = "positionMM")]
2816 pub position_mm: String,
2817 #[serde(rename = "unrealisedPnl")]
2818 pub unrealised_pnl: String,
2819 #[serde(rename = "cumRealisedPnl")]
2820 pub cum_realised_pnl: String,
2821 #[serde(rename = "stopLoss")]
2822 pub stop_loss: String,
2823 #[serde(rename = "takeProfit")]
2824 pub take_profit: String,
2825 #[serde(rename = "trailingStop")]
2826 pub trailing_stop: String,
2827 #[serde(rename = "createdTime")]
2828 pub created_time: String,
2829 #[serde(rename = "updatedTime")]
2830 pub updated_time: String,
2831}
2832
2833#[derive(Clone, Default)]
2834pub struct ClosedPnlRequest<'a> {
2835 pub category: Category,
2836 pub symbol: Option<Cow<'a, str>>,
2837 pub start_time: Option<Cow<'a, str>>,
2838 pub end_time: Option<Cow<'a, str>>,
2839 pub limit: Option<u64>,
2840}
2841
2842impl<'a> ClosedPnlRequest<'a> {
2843 pub fn new(
2844 category: Category,
2845 symbol: Option<&'a str>,
2846 start_time: Option<&'a str>,
2847 end_time: Option<&'a str>,
2848 limit: Option<u64>,
2849 ) -> Self {
2850 Self {
2851 category,
2852 symbol: symbol.map(|s| Cow::Borrowed(s)),
2853 start_time: start_time.map(|s| Cow::Borrowed(s)),
2854 end_time: end_time.map(|s| Cow::Borrowed(s)),
2855 limit,
2856 }
2857 }
2858 pub fn default() -> ClosedPnlRequest<'a> {
2859 ClosedPnlRequest::new(Category::Linear, None, None, None, None)
2860 }
2861}
2862
2863#[derive(Serialize, Deserialize, Clone, Debug)]
2864#[serde(rename_all = "camelCase")]
2865pub struct ClosedPnlResponse {
2866 pub ret_code: i32,
2867 pub ret_msg: String,
2868 pub result: ClosedPnlResult,
2869 pub ret_ext_info: Empty,
2870 pub time: u64,
2871}
2872
2873#[derive(Serialize, Deserialize, Clone, Debug)]
2874#[serde(rename_all = "camelCase")]
2875pub struct ClosedPnlResult {
2876 #[serde(skip_serializing_if = "Option::is_none")]
2877 pub next_page_cursor: Option<String>,
2878 pub category: String,
2879 pub list: Vec<ClosedPnlItem>,
2880}
2881
2882#[derive(Serialize, Deserialize, Clone, Debug)]
2883#[serde(rename_all = "camelCase")]
2884pub struct ClosedPnlItem {
2885 pub symbol: String,
2886 pub order_type: String,
2887 pub leverage: String,
2888 pub updated_time: String,
2889 pub side: String,
2890 pub order_id: String,
2891 #[serde(with = "string_to_float")]
2892 pub closed_pnl: f64,
2893 #[serde(rename = "avgEntryPrice", with = "string_to_float")]
2894 pub avg_entry_price: f64,
2895 pub qty: String,
2896 #[serde(with = "string_to_float")]
2897 pub cum_entry_value: f64,
2898 pub created_time: String,
2899 #[serde(with = "string_to_float")]
2900 pub order_price: f64,
2901 pub closed_size: String,
2902 #[serde(rename = "avgExitPrice", with = "string_to_float")]
2903 pub avg_exit_price: f64,
2904 pub exec_type: String,
2905 pub fill_count: String,
2906 #[serde(with = "string_to_float")]
2907 pub cum_exit_value: f64,
2908}
2909
2910#[derive(Clone, Default, Serialize)]
2911pub struct MovePositionRequest<'a> {
2912 pub from_uid: u64,
2913 pub to_uid: u64,
2914 pub list: Vec<PositionItem<'a>>,
2915}
2916
2917#[derive(Clone, Default, Serialize)]
2918pub struct PositionItem<'a> {
2919 pub category: Category,
2920 pub symbol: Cow<'a, str>,
2921 pub price: f64,
2922 pub side: Side,
2923 pub qty: f64,
2924}
2925
2926impl<'a> MovePositionRequest<'a> {
2927 pub fn new(from_uid: u64, to_uid: u64, list: Vec<PositionItem<'a>>) -> Self {
2928 Self {
2929 from_uid,
2930 to_uid,
2931 list,
2932 }
2933 }
2934 pub fn default() -> MovePositionRequest<'a> {
2935 MovePositionRequest::new(0, 0, vec![])
2936 }
2937}
2938impl<'a> PositionItem<'a> {
2939 pub fn new(category: Category, symbol: &'a str, price: f64, side: Side, qty: f64) -> Self {
2940 Self {
2941 category,
2942 symbol: Cow::Borrowed(symbol),
2943 price,
2944 side,
2945 qty,
2946 }
2947 }
2948 pub fn default() -> PositionItem<'a> {
2949 PositionItem::new(Category::Linear, "BTCUSDT", 0.0, Side::Buy, 0.0)
2950 }
2951}
2952
2953#[derive(Deserialize, Serialize, Clone, Debug)]
2954pub struct MovePositionResponse {
2955 pub ret_code: i32,
2956 pub ret_msg: String,
2957 pub result: MovePositionResult,
2958}
2959
2960#[derive(Deserialize, Serialize, Clone, Debug)]
2961pub struct MovePositionResult {
2962 pub block_trade_id: String,
2963 pub status: String,
2964 pub reject_party: String,
2965}
2966
2967#[derive(Serialize, Clone, Default)]
2968pub struct MoveHistoryRequest<'a> {
2969 pub category: Option<Category>,
2970 pub symbol: Option<Cow<'a, str>>,
2971 pub start_time: Option<Cow<'a, str>>,
2972 pub end_time: Option<Cow<'a, str>>,
2973 pub status: Option<Cow<'a, str>>,
2974 pub block_trade_id: Option<Cow<'a, str>>,
2975 pub limit: Option<Cow<'a, str>>,
2976}
2977
2978impl<'a> MoveHistoryRequest<'a> {
2979 pub fn new(
2980 category: Option<Category>,
2981 symbol: Option<&'a str>,
2982 start_time: Option<&'a str>,
2983 end_time: Option<&'a str>,
2984 status: Option<&'a str>,
2985 block_trade_id: Option<&'a str>,
2986 limit: Option<&'a str>,
2987 ) -> Self {
2988 Self {
2989 category,
2990 symbol: symbol.map(|s| Cow::Borrowed(s)),
2991 start_time: start_time.map(|s| Cow::Borrowed(s)),
2992 end_time: end_time.map(|s| Cow::Borrowed(s)),
2993 status: status.map(|s| Cow::Borrowed(s)),
2994 block_trade_id: block_trade_id.map(|s| Cow::Borrowed(s)),
2995 limit: limit.map(|s| Cow::Borrowed(s)),
2996 }
2997 }
2998 pub fn default() -> MoveHistoryRequest<'a> {
2999 MoveHistoryRequest::new(None, None, None, None, None, None, None)
3000 }
3001}
3002
3003#[derive(Serialize, Deserialize, Clone, Debug)]
3004#[serde(rename_all = "camelCase")]
3005pub struct MoveHistoryResponse {
3006 #[serde(rename = "retCode")]
3007 pub ret_code: i16,
3008 #[serde(rename = "retMsg")]
3009 pub ret_msg: String,
3010 pub result: MoveHistoryResult,
3011 #[serde(rename = "retExtInfo")]
3012 pub ret_ext_info: Empty,
3013 pub time: u64,
3014}
3015
3016#[derive(Serialize, Deserialize, Clone, Debug)]
3017#[serde(rename_all = "camelCase")]
3018pub struct MoveHistoryResult {
3019 pub list: Vec<MoveHistoryEntry>,
3020 #[serde(rename = "nextPageCursor")]
3021 pub next_page_cursor: String,
3022}
3023
3024#[derive(Serialize, Deserialize, Clone, Debug)]
3025#[serde(rename_all = "camelCase")]
3026pub struct MoveHistoryEntry {
3027 #[serde(rename = "blockTradeId")]
3028 pub block_trade_id: String,
3029 pub category: String,
3030 #[serde(rename = "orderId")]
3031 pub order_id: String,
3032 #[serde(rename = "userId")]
3033 pub user_id: u64,
3034 pub symbol: String,
3035 pub side: String,
3036 pub price: String,
3037 pub qty: String,
3038 #[serde(rename = "execFee")]
3039 pub exec_fee: String,
3040 pub status: String,
3041 #[serde(rename = "execId")]
3042 pub exec_id: String,
3043 #[serde(rename = "resultCode")]
3044 pub result_code: i16,
3045 #[serde(rename = "resultMessage")]
3046 pub result_message: String,
3047 #[serde(rename = "createdAt")]
3048 pub created_at: u64,
3049 #[serde(rename = "updatedAt")]
3050 pub updated_at: u64,
3051 #[serde(rename = "rejectParty")]
3052 pub reject_party: String,
3053}
3054
3055#[derive(Deserialize, Serialize, Clone, Debug)]
3062#[serde(rename_all = "camelCase")]
3063pub struct WalletResponse {
3064 #[serde(rename = "retCode")]
3065 pub ret_code: i32,
3066 #[serde(rename = "retMsg")]
3067 pub ret_msg: String,
3068 pub result: WalletList,
3069 #[serde(rename = "retExtInfo")]
3070 pub ret_ext_info: Empty,
3071 pub time: u64,
3072}
3073
3074#[derive(Deserialize, Serialize, Clone, Debug)]
3075pub struct WalletList {
3076 pub list: Vec<WalletData>,
3077}
3078
3079#[derive(Deserialize, Serialize, Clone, Debug)]
3080#[serde(rename_all = "camelCase")]
3081pub struct UTAResponse {
3082 #[serde(rename = "retCode")]
3083 pub ret_code: i32,
3084 #[serde(rename = "retMsg")]
3085 pub ret_msg: String,
3086 pub result: UTAUpdateStatus,
3087 #[serde(rename = "retExtInfo")]
3088 pub ret_ext_info: Empty,
3089 pub time: u64,
3090}
3091
3092#[derive(Deserialize, Serialize, Clone, Debug)]
3093#[serde(rename_all = "camelCase")]
3094pub struct UTAUpdateStatus {
3095 #[serde(rename = "unifiedUpdateStatus")]
3096 pub unified_update_status: String,
3097 #[serde(rename = "unifiedUpdateMsg")]
3098 pub unified_update_msg: UnifiedUpdateMsg,
3099}
3100
3101#[derive(Deserialize, Serialize, Clone, Debug)]
3102pub struct UnifiedUpdateMsg {
3103 pub msg: Vec<String>,
3104}
3105
3106#[derive(Clone, Debug, Default)]
3107pub struct BorrowHistoryRequest<'a> {
3108 pub coin: Option<Cow<'a, str>>,
3109 pub start_time: Option<Cow<'a, str>>,
3110 pub end_time: Option<Cow<'a, str>>,
3111 pub limit: Option<Cow<'a, str>>,
3112}
3113
3114impl<'a> BorrowHistoryRequest<'a> {
3115 pub fn new(
3116 coin: Option<&'a str>,
3117 start_time: Option<&'a str>,
3118 end_time: Option<&'a str>,
3119 limit: Option<&'a str>,
3120 ) -> Self {
3121 Self {
3122 coin: coin.map(|s| Cow::Borrowed(s)),
3123 start_time: start_time.map(|s| Cow::Borrowed(s)),
3124 end_time: end_time.map(|s| Cow::Borrowed(s)),
3125 limit: limit.map(|s| Cow::Borrowed(s)),
3126 }
3127 }
3128 pub fn default() -> BorrowHistoryRequest<'a> {
3129 BorrowHistoryRequest::new(None, None, None, None)
3130 }
3131}
3132
3133#[derive(Debug, Serialize, Deserialize, Clone)]
3134#[serde(rename_all = "camelCase")]
3135pub struct BorrowHistoryResponse {
3136 pub ret_code: i32,
3137 pub ret_msg: String,
3138 pub result: BorrowHistory,
3139 pub ret_ext_info: Empty,
3140 pub time: u64,
3141}
3142
3143#[derive(Debug, Serialize, Deserialize, Clone)]
3144#[serde(rename_all = "camelCase")]
3145pub struct BorrowHistory {
3146 pub next_page_cursor: String,
3147 pub rows: Vec<BorrowHistoryEntry>,
3148}
3149
3150#[derive(Debug, Serialize, Deserialize, Clone)]
3151#[serde(rename_all = "camelCase")]
3152pub struct BorrowHistoryEntry {
3153 #[serde(rename = "borrowAmount")]
3154 pub borrow_amount: String,
3155 #[serde(rename = "costExemption")]
3156 pub cost_exemption: String,
3157 #[serde(rename = "freeBorrowedAmount")]
3158 pub free_borrowed_amount: String,
3159 #[serde(rename = "createdTime")]
3160 pub created_time: u64,
3161 #[serde(rename = "InterestBearingBorrowSize")]
3162 pub interest_bearing_borrow_size: String,
3163 pub currency: String,
3164 #[serde(rename = "unrealisedLoss")]
3165 pub unrealised_loss: String,
3166 #[serde(rename = "hourlyBorrowRate")]
3167 pub hourly_borrow_rate: String,
3168 #[serde(rename = "borrowCost")]
3169 pub borrow_cost: String,
3170}
3171
3172#[derive(Debug, Serialize, Deserialize, Clone)]
3173#[serde(rename_all = "camelCase")]
3174pub struct RepayLiabilityResponse {
3175 pub ret_code: i32,
3176 pub ret_msg: String,
3177 pub result: LiabilityQty,
3178 pub ret_ext_info: Empty,
3179 pub time: u64,
3180}
3181
3182#[derive(Debug, Serialize, Deserialize, Clone)]
3183pub struct LiabilityQty {
3184 pub list: Vec<LiabilityQtyData>,
3185}
3186
3187#[derive(Debug, Serialize, Deserialize, Clone)]
3188#[serde(rename_all = "camelCase")]
3189pub struct LiabilityQtyData {
3190 pub coin: String,
3191 pub repayment_qty: String,
3192}
3193
3194#[derive(Debug, Serialize, Deserialize, Clone)]
3195#[serde(rename_all = "camelCase")]
3196pub struct SetCollateralCoinResponse {
3197 pub ret_code: i32,
3198 pub ret_msg: String,
3199 pub result: Empty,
3200 pub ret_ext_info: Empty,
3201 pub time: u64,
3202}
3203
3204#[derive(Debug, Serialize, Deserialize, Clone)]
3205#[serde(rename_all = "camelCase")]
3206pub struct BatchSetCollateralCoinResponse {
3207 pub ret_code: i32,
3208 pub ret_msg: String,
3209 pub result: SwitchList,
3210 pub ret_ext_info: Empty,
3211 pub time: u64,
3212}
3213
3214#[derive(Debug, Serialize, Deserialize, Clone)]
3215#[serde(rename_all = "camelCase")]
3216pub struct SwitchList {
3217 pub list: Vec<SwitchListData>,
3218}
3219
3220#[derive(Debug, Serialize, Deserialize, Clone)]
3221#[serde(rename_all = "camelCase")]
3222pub struct SwitchListData {
3223 pub coin: String,
3224 pub collateral_switch: String,
3225}
3226
3227#[derive(Debug, Serialize, Deserialize, Clone)]
3228#[serde(rename_all = "camelCase")]
3229pub struct CollateralInfoResponse {
3230 pub ret_code: i32,
3231 pub ret_msg: String,
3232 pub result: CollateralInfoList,
3233 pub ret_ext_info: Empty,
3234 pub time: u64,
3235}
3236
3237#[derive(Debug, Serialize, Deserialize, Clone)]
3238#[serde(rename_all = "camelCase")]
3239pub struct CollateralInfoList {
3240 pub list: Vec<CollateralInfo>,
3241}
3242
3243#[derive(Debug, Serialize, Deserialize, Clone)]
3244#[serde(rename_all = "camelCase")]
3245pub struct CollateralInfo {
3246 #[serde(rename = "availableToBorrow")]
3247 pub available_to_borrow: String,
3248 #[serde(rename = "freeBorrowingAmount")]
3249 pub free_borrowing_amount: String,
3250 #[serde(rename = "freeBorrowAmount")]
3251 pub free_borrow_amount: String,
3252 #[serde(rename = "maxBorrowingAmount")]
3253 pub max_borrowing_amount: String,
3254 #[serde(rename = "hourlyBorrowRate")]
3255 pub hourly_borrow_rate: String,
3256 #[serde(rename = "borrowUsageRate")]
3257 pub borrow_usage_rate: String,
3258 #[serde(rename = "collateralSwitch")]
3259 pub collateral_switch: bool,
3260 #[serde(rename = "borrowAmount")]
3261 pub borrow_amount: String,
3262 #[serde(rename = "borrowable")]
3263 pub borrowable: bool,
3264 pub currency: String,
3265 #[serde(rename = "marginCollateral")]
3266 pub margin_collateral: bool,
3267 #[serde(rename = "freeBorrowingLimit")]
3268 pub free_borrowing_limit: String,
3269 #[serde(rename = "collateralRatio")]
3270 pub collateral_ratio: String,
3271}
3272
3273#[derive(Debug, Serialize, Deserialize, Clone)]
3274#[serde(rename_all = "camelCase")]
3275pub struct FeeRateResponse {
3276 pub ret_code: i32,
3277 pub ret_msg: String,
3278 pub result: FeeRateList,
3279 pub ret_ext_info: Empty,
3280 pub time: u64,
3281}
3282
3283#[derive(Debug, Serialize, Deserialize, Clone)]
3284#[serde(rename_all = "camelCase")]
3285pub struct FeeRateList {
3286 pub list: Vec<FeeRate>,
3287}
3288
3289#[derive(Debug, Serialize, Deserialize, Clone)]
3290#[serde(rename_all = "camelCase")]
3291pub struct FeeRate {
3292 pub symbol: String,
3293 pub maker_fee_rate: String,
3294 pub taker_fee_rate: String,
3295}
3296
3297#[derive(Debug, Serialize, Deserialize, Clone)]
3298#[serde(rename_all = "camelCase")]
3299pub struct AccountInfoResponse {
3300 pub ret_code: i32,
3301 pub ret_msg: String,
3302 pub result: AccountInfo,
3303 #[serde(default)]
3304 pub ret_ext_info: Empty,
3305 #[serde(default)]
3306 pub time: Option<u64>,
3307}
3308
3309#[derive(Debug, Serialize, Deserialize, Clone)]
3310#[serde(rename_all = "camelCase")]
3311pub struct AccountInfo {
3312 pub margin_mode: String,
3313 pub updated_time: String,
3314 pub unified_margin_status: i8,
3315 pub dcp_status: String,
3316 pub time_window: i32,
3317 pub smp_group: i8,
3318 pub is_master_trader: bool,
3319 pub spot_hedging_status: String,
3320}
3321
3322#[derive(Clone, Default)]
3323pub struct TransactionLogRequest<'a> {
3324 pub account_type: Option<Cow<'a, str>>,
3325 pub category: Option<Category>,
3326 pub currency: Option<Cow<'a, str>>,
3327 pub base_coin: Option<Cow<'a, str>>,
3328 pub log_type: Option<Cow<'a, str>>,
3329 pub start_time: Option<Cow<'a, str>>,
3330 pub end_time: Option<Cow<'a, str>>,
3331 pub limit: Option<u32>,
3332}
3333
3334impl<'a> TransactionLogRequest<'a> {
3335 pub fn new(
3336 account_type: Option<&'a str>,
3337 category: Option<Category>,
3338 currency: Option<&'a str>,
3339 base_coin: Option<&'a str>,
3340 log_type: Option<&'a str>,
3341 start_time: Option<&'a str>,
3342 end_time: Option<&'a str>,
3343 limit: Option<u32>,
3344 ) -> Self {
3345 Self {
3346 account_type: account_type.map(|s| Cow::Borrowed(s)),
3347 category,
3348 currency: currency.map(|s| Cow::Borrowed(s)),
3349 base_coin: base_coin.map(|s| Cow::Borrowed(s)),
3350 log_type: log_type.map(|s| Cow::Borrowed(s)),
3351 start_time: start_time.map(|s| Cow::Borrowed(s)),
3352 end_time: end_time.map(|s| Cow::Borrowed(s)),
3353 limit,
3354 }
3355 }
3356 pub fn default() -> Self {
3357 Self::new(None, None, None, None, None, None, None, None)
3358 }
3359}
3360
3361#[derive(Debug, Serialize, Deserialize, Clone)]
3362#[serde(rename_all = "camelCase")]
3363pub struct TransactionLogEntry {
3364 pub id: String,
3365 pub symbol: String,
3366 pub side: String,
3367 pub funding: Option<String>,
3368 pub order_link_id: Option<String>,
3369 pub order_id: String,
3370 pub fee: String,
3371 pub change: String,
3372 pub cash_flow: String,
3373 pub transaction_time: String,
3374 pub type_field: String,
3375 #[serde(rename = "feeRate")]
3376 pub fee_rate: String,
3377 pub bonus_change: Option<String>,
3378 pub size: String,
3379 pub qty: String,
3380 pub cash_balance: String,
3381 pub currency: String,
3382 pub category: String,
3383 pub trade_price: String,
3384 pub trade_id: String,
3385}
3386
3387#[derive(Debug, Serialize, Deserialize, Clone)]
3388#[serde(rename_all = "camelCase")]
3389pub struct TransactionLogResult {
3390 pub next_page_cursor: String,
3391 pub list: Vec<TransactionLogEntry>,
3392}
3393
3394#[derive(Debug, Serialize, Deserialize, Clone)]
3395#[serde(rename_all = "camelCase")]
3396pub struct TransactionLogResponse {
3397 pub ret_code: i32,
3398 pub ret_msg: String,
3399 pub result: TransactionLogResult,
3400 pub ret_ext_info: Empty,
3401 pub time: u64,
3402}
3403
3404#[derive(Debug, Serialize, Deserialize, Clone)]
3405#[serde(rename_all = "camelCase")]
3406pub struct SmpResponse {
3407 pub ret_code: i32,
3408 pub ret_msg: String,
3409 pub result: SmpResult,
3410 pub ret_ext_info: Empty,
3411 pub time: u64,
3412}
3413
3414#[derive(Debug, Serialize, Deserialize, Clone)]
3415#[serde(rename_all = "camelCase")]
3416pub struct SmpResult {
3417 pub smp_group: u8,
3418}
3419
3420#[derive(Debug, Serialize, Deserialize, Clone)]
3421#[serde(rename_all = "camelCase")]
3422pub struct SetMarginModeResponse {
3423 pub ret_code: i32,
3424 pub ret_msg: String,
3425 pub result: MarginModeResult,
3426 pub ret_ext_info: Empty,
3427 pub time: u64,
3428}
3429
3430#[derive(Debug, Serialize, Deserialize, Clone)]
3431#[serde(rename_all = "camelCase")]
3432pub struct MarginModeResult {
3433 pub reason: Vec<ReasonObject>,
3434}
3435
3436#[derive(Debug, Serialize, Deserialize, Clone)]
3437#[serde(rename_all = "camelCase")]
3438pub struct ReasonObject {
3439 pub reason_code: String,
3440 pub reason_msg: String,
3441}
3442
3443#[derive(Debug, Serialize, Deserialize, Clone)]
3444#[serde(rename_all = "camelCase")]
3445pub struct SpotHedgingResponse {
3446 pub ret_code: i32,
3447 pub ret_msg: String,
3448}
3449
3450#[derive(Debug, Serialize, Deserialize, Clone)]
3455pub struct Header {
3456 #[serde(rename = "X-Bapi-Limit")]
3457 pub x_bapi_limit: String,
3458 #[serde(rename = "X-Bapi-Limit-Status")]
3459 pub x_bapi_limit_status: String,
3460 #[serde(rename = "X-Bapi-Limit-Reset-Timestamp")]
3461 pub x_bapi_limit_reset_timestamp: String,
3462 #[serde(rename = "Traceid")]
3463 pub traceid: String,
3464 #[serde(rename = "Timenow")]
3465 pub timenow: String,
3466}
3467
3468#[derive(Clone, Debug, Default)]
3475pub struct Subscription<'a> {
3476 pub op: &'a str,
3477 pub args: Vec<&'a str>,
3478}
3479
3480impl<'a> Subscription<'a> {
3481 pub fn new(op: &'a str, args: Vec<&'a str>) -> Self {
3482 Self { op, args }
3483 }
3484 pub fn default() -> Subscription<'a> {
3485 Subscription::new("subscribe", vec![])
3486 }
3487}
3488
3489#[derive(Debug, Serialize, Deserialize, Clone)]
3490#[serde(untagged)]
3491pub enum WebsocketEvents {
3492 OrderBookEvent(OrderBookUpdate),
3493 TradeEvent(TradeUpdate),
3494 TickerEvent(WsTicker),
3495 LiquidationEvent(Liquidation),
3496 KlineEvent(WsKline),
3497 PositionEvent(PositionEvent),
3498 ExecutionEvent(Execution),
3499 OrderEvent(OrderEvent),
3500 Wallet(WalletEvent),
3501 TradeStream(TradeStreamEvent),
3502 FastExecEvent(FastExecution),
3503}
3504
3505#[derive(Debug, Serialize, Deserialize, Clone)]
3506#[serde(untagged)]
3507pub enum Tickers {
3508 Linear(LinearTickerData),
3509 Spot(SpotTickerData),
3510}
3511
3512#[derive(Debug, Serialize, Deserialize, Clone)]
3513#[serde(untagged)]
3514pub enum PongResponse {
3515 PublicPong(PongData),
3516 PrivatePong(PongData),
3517}
3518
3519#[derive(Debug, Serialize, Deserialize, Clone)]
3520pub struct PongData {
3521 #[serde(skip_serializing_if = "Option::is_none")]
3522 pub ret_code: Option<i32>,
3523 #[serde(skip_serializing_if = "Option::is_none")]
3524 pub success: Option<bool>,
3525 pub ret_msg: String,
3526 pub conn_id: String,
3527 #[serde(skip_serializing_if = "Option::is_none")]
3528 pub req_id: Option<String>,
3529 #[serde(skip_serializing_if = "Option::is_none")]
3530 pub args: Option<Vec<String>>,
3531 #[serde(skip_serializing_if = "Option::is_none")]
3532 pub data: Option<Vec<String>>,
3533 pub op: String,
3534}
3535
3536unsafe impl Send for PongData {}
3537unsafe impl Sync for PongData {}
3538
3539#[derive(Serialize, Deserialize, Debug, Clone)]
3540#[serde(rename_all = "camelCase")]
3541pub struct TradeStreamEvent {
3542 #[serde(skip_serializing_if = "Option::is_none")]
3543 pub req_id: Option<String>,
3544 pub ret_code: i32,
3545 pub ret_msg: String,
3546 pub op: String,
3547 pub data: OrderStatus,
3548 pub header: Header,
3549 pub conn_id: String,
3550}
3551
3552unsafe impl Send for TradeStreamEvent {}
3553unsafe impl Sync for TradeStreamEvent {}
3554
3555#[derive(Serialize, Deserialize, Debug, Clone)]
3556#[serde(rename_all = "camelCase")]
3557pub struct OrderBookUpdate {
3558 #[serde(rename = "topic")]
3559 pub topic: String,
3560 #[serde(rename = "type")]
3561 pub event_type: String,
3562 #[serde(rename = "ts")]
3563 pub timestamp: u64,
3564 pub data: WsOrderBook,
3565 pub cts: u64,
3566}
3567
3568unsafe impl Send for OrderBookUpdate {}
3569unsafe impl Sync for OrderBookUpdate {}
3570
3571#[derive(Serialize, Deserialize, Debug, Clone)]
3572#[serde(rename_all = "camelCase")]
3573pub struct WsOrderBook {
3574 #[serde(rename = "s")]
3575 pub symbol: String,
3576 #[serde(rename = "a")]
3577 pub asks: Vec<Ask>,
3578 #[serde(rename = "b")]
3579 pub bids: Vec<Bid>,
3580 #[serde(rename = "u")]
3581 pub update_id: u64,
3582 pub seq: u64,
3583}
3584
3585unsafe impl Send for WsOrderBook {}
3586unsafe impl Sync for WsOrderBook {}
3587
3588#[derive(Serialize, Deserialize, Debug, Clone)]
3589pub struct TradeUpdate {
3590 #[serde(rename = "topic")]
3591 pub topic: String,
3592 #[serde(rename = "type")]
3593 pub event_type: String,
3594 #[serde(rename = "ts")]
3595 pub timestamp: u64,
3596 pub data: Vec<WsTrade>,
3597}
3598
3599unsafe impl Send for TradeUpdate {}
3600unsafe impl Sync for TradeUpdate {}
3601
3602#[derive(Serialize, Deserialize, Debug, Clone)]
3603pub struct WsTrade {
3604 #[serde(rename = "T")]
3605 pub timestamp: u64,
3606 #[serde(rename = "s")]
3607 pub symbol: String,
3608 #[serde(rename = "S")]
3609 pub side: String,
3610 #[serde(rename = "v", with = "string_to_float")]
3611 pub volume: f64,
3612 #[serde(rename = "p", with = "string_to_float")]
3613 pub price: f64,
3614 #[serde(rename = "L")]
3615 pub tick_direction: String,
3616 #[serde(rename = "i")]
3617 pub id: String,
3618 #[serde(rename = "BT")]
3619 pub buyer_is_maker: bool,
3620}
3621
3622unsafe impl Send for WsTrade {}
3623unsafe impl Sync for WsTrade {}
3624
3625#[derive(Serialize, Deserialize, Debug, Clone)]
3626pub struct WsTicker {
3627 pub topic: String,
3628 #[serde(rename = "type")]
3629 pub event_type: String,
3630 pub data: Tickers,
3631 pub cs: u64,
3632 pub ts: u64,
3633}
3634
3635unsafe impl Send for WsTicker {}
3636unsafe impl Sync for WsTicker {}
3637
3638#[derive(Serialize, Deserialize, Debug, Clone)]
3639pub struct LinearTickerData {
3640 pub symbol: String,
3641 #[serde(rename = "tickDirection")]
3642 pub tick_direction: String,
3643 #[serde(rename = "price24hPcnt")]
3644 pub price_24h_pcnt: String,
3645 #[serde(rename = "lastPrice")]
3646 pub last_price: String,
3647 #[serde(rename = "prevPrice24h")]
3648 pub prev_price_24h: String,
3649 #[serde(rename = "highPrice24h")]
3650 pub high_price_24h: String,
3651 #[serde(rename = "lowPrice24h")]
3652 pub low_price_24h: String,
3653 #[serde(rename = "prevPrice1h")]
3654 pub prev_price_1h: String,
3655 #[serde(rename = "markPrice")]
3656 pub mark_price: String,
3657 #[serde(rename = "indexPrice")]
3658 pub index_price: String,
3659 #[serde(rename = "openInterest")]
3660 pub open_interest: String,
3661 #[serde(rename = "openInterestValue")]
3662 pub open_interest_value: String,
3663 #[serde(rename = "turnover24h")]
3664 pub turnover_24h: String,
3665 #[serde(rename = "volume24h")]
3666 pub volume_24h: String,
3667 #[serde(rename = "nextFundingTime")]
3668 pub next_funding_time: String,
3669 #[serde(rename = "fundingRate")]
3670 pub funding_rate: String,
3671 #[serde(rename = "bid1Price")]
3672 pub bid_price: String,
3673 #[serde(rename = "bid1Size")]
3674 pub bid_size: String,
3675 #[serde(rename = "ask1Price")]
3676 pub ask_price: String,
3677 #[serde(rename = "ask1Size")]
3678 pub ask_size: String,
3679}
3680
3681unsafe impl Send for LinearTickerData {}
3682unsafe impl Sync for LinearTickerData {}
3683
3684#[derive(Serialize, Deserialize, Debug, Clone)]
3685pub struct SpotTickerData {
3686 #[serde(rename = "symbol")]
3687 pub symbol: String,
3688 #[serde(rename = "lastPrice")]
3689 pub last_price: String,
3690 #[serde(rename = "highPrice24h")]
3691 pub high_price_24h: String,
3692 #[serde(rename = "lowPrice24h")]
3693 pub low_price_24h: String,
3694 #[serde(rename = "prevPrice24h")]
3695 pub prev_price_24h: String,
3696 #[serde(rename = "volume24h")]
3697 pub volume_24h: String,
3698 #[serde(rename = "turnover24h")]
3699 pub turnover_24h: String,
3700 #[serde(rename = "price24hPcnt")]
3701 pub price_24h_pcnt: String,
3702 #[serde(rename = "usdIndexPrice")]
3703 pub usd_index_price: String,
3704}
3705
3706unsafe impl Send for SpotTickerData {}
3707unsafe impl Sync for SpotTickerData {}
3708
3709#[derive(Serialize, Deserialize, Debug, Clone)]
3710pub struct Liquidation {
3711 #[serde(rename = "topic")]
3712 pub topic: String,
3713 #[serde(rename = "type")]
3714 pub event_type: String,
3715 #[serde(rename = "ts")]
3716 pub ts: u64,
3717 #[serde(rename = "data")]
3718 pub data: LiquidationData,
3719}
3720
3721unsafe impl Send for Liquidation {}
3722unsafe impl Sync for Liquidation {}
3723
3724#[derive(Serialize, Deserialize, Debug, Clone)]
3725pub struct LiquidationData {
3726 #[serde(rename = "updatedTime")]
3727 pub updated_time: u64,
3728 #[serde(rename = "symbol")]
3729 pub symbol: String,
3730 #[serde(rename = "side")]
3731 pub side: String,
3732 #[serde(with = "string_to_float")]
3733 pub size: f64,
3734 #[serde(with = "string_to_float")]
3735 pub price: f64,
3736}
3737
3738unsafe impl Send for LiquidationData {}
3739unsafe impl Sync for LiquidationData {}
3740
3741#[derive(Serialize, Deserialize, Debug, Clone)]
3742pub struct WsKline {
3743 pub topic: String,
3744 pub data: Vec<KlineData>,
3745 #[serde(rename = "ts")]
3746 pub timestamp: u64,
3747 #[serde(rename = "type")]
3748 pub event_type: String,
3749}
3750
3751unsafe impl Send for WsKline {}
3752unsafe impl Sync for WsKline {}
3753
3754#[derive(Serialize, Deserialize, Debug, Clone)]
3755pub struct KlineData {
3756 pub start: u64,
3757 pub end: u64,
3758 pub interval: String,
3759 pub open: String,
3760 pub close: String,
3761 pub high: String,
3762 pub low: String,
3763 pub volume: String,
3764 pub turnover: String,
3765 pub confirm: bool,
3766 pub timestamp: u64,
3767}
3768
3769unsafe impl Send for KlineData {}
3770unsafe impl Sync for KlineData {}
3771
3772#[derive(Serialize, Deserialize, Debug, Clone)]
3773pub struct PositionEvent {
3774 pub id: String,
3775 pub topic: String,
3776 #[serde(rename = "creationTime")]
3777 pub creation_time: u64,
3778 pub data: Vec<PositionData>,
3779}
3780
3781unsafe impl Send for PositionEvent {}
3782unsafe impl Sync for PositionEvent {}
3783
3784#[derive(Serialize, Deserialize, Debug, Clone)]
3785pub struct PositionData {
3786 #[serde(rename = "positionIdx")]
3787 pub position_idx: u8,
3788 #[serde(rename = "tradeMode")]
3789 pub trade_mode: u8,
3790 #[serde(rename = "riskId")]
3791 pub risk_id: u8,
3792 #[serde(rename = "riskLimitValue")]
3793 pub risk_limit_value: String,
3794 pub symbol: String,
3795 pub side: String,
3796 pub size: String,
3797 #[serde(rename = "entryPrice")]
3798 pub entry_price: String,
3799 pub leverage: String,
3800 #[serde(rename = "positionValue")]
3801 pub position_value: String,
3802 #[serde(rename = "positionBalance")]
3803 pub position_balance: String,
3804 #[serde(rename = "markPrice")]
3805 pub mark_price: String,
3806 #[serde(rename = "positionIM")]
3807 pub position_im: String,
3808 #[serde(rename = "positionMM")]
3809 pub position_mm: String,
3810 #[serde(rename = "takeProfit")]
3811 pub take_profit: String,
3812 #[serde(rename = "stopLoss")]
3813 pub stop_loss: String,
3814 #[serde(rename = "trailingStop")]
3815 pub trailing_stop: String,
3816 #[serde(rename = "unrealisedPnl")]
3817 pub unrealised_pnl: String,
3818 #[serde(rename = "cumRealisedPnl")]
3819 pub cum_realised_pnl: String,
3820 #[serde(rename = "createdTime")]
3821 pub created_time: String,
3822 #[serde(rename = "updatedTime")]
3823 pub updated_time: String,
3824 #[serde(rename = "tpslMode")]
3825 pub tpsl_mode: String,
3826 #[serde(rename = "liqPrice")]
3827 pub liq_price: String,
3828 #[serde(rename = "bustPrice")]
3829 pub bust_price: String,
3830 pub category: String,
3831 #[serde(rename = "positionStatus")]
3832 pub position_status: String,
3833 #[serde(rename = "adlRankIndicator")]
3834 pub adl_rank_indicator: u8,
3835 #[serde(rename = "autoAddMargin")]
3836 pub auto_add_margin: u8,
3837 #[serde(rename = "leverageSysUpdatedTime")]
3838 pub leverage_sys_updated_time: String,
3839 #[serde(rename = "mmrSysUpdatedTime")]
3840 pub mmr_sys_updated_time: String,
3841 pub seq: u64,
3842 #[serde(rename = "isReduceOnly")]
3843 pub is_reduce_only: bool,
3844}
3845
3846unsafe impl Send for PositionData {}
3847unsafe impl Sync for PositionData {}
3848
3849#[derive(Serialize, Deserialize, Debug, Clone)]
3850pub struct Execution {
3851 #[serde(rename = "id")]
3852 pub id: String,
3853 #[serde(rename = "topic")]
3854 pub topic: String,
3855 #[serde(rename = "creationTime")]
3856 pub creation_time: u64,
3857 #[serde(rename = "data")]
3858 pub data: Vec<ExecutionData>,
3859}
3860
3861unsafe impl Send for Execution {}
3862unsafe impl Sync for Execution {}
3863
3864#[derive(Serialize, Deserialize, Debug, Clone)]
3865pub struct ExecutionData {
3866 #[serde(rename = "category")]
3867 pub category: String,
3868 #[serde(rename = "symbol")]
3869 pub symbol: String,
3870 #[serde(rename = "execFee")]
3871 pub exec_fee: String,
3872 #[serde(rename = "execId")]
3873 pub exec_id: String,
3874 #[serde(rename = "execPrice")]
3875 pub exec_price: String,
3876 #[serde(rename = "execQty")]
3877 pub exec_qty: String,
3878 #[serde(rename = "execType")]
3879 pub exec_type: String,
3880 #[serde(rename = "execValue")]
3881 pub exec_value: String,
3882 #[serde(rename = "isMaker")]
3883 pub is_maker: bool,
3884 #[serde(rename = "feeRate")]
3885 pub fee_rate: String,
3886 #[serde(rename = "tradeIv")]
3887 pub trade_iv: String,
3888 #[serde(rename = "markIv")]
3889 pub mark_iv: String,
3890 #[serde(rename = "blockTradeId")]
3891 pub block_trade_id: String,
3892 #[serde(rename = "markPrice")]
3893 pub mark_price: String,
3894 #[serde(rename = "indexPrice")]
3895 pub index_price: String,
3896 #[serde(rename = "underlyingPrice")]
3897 pub underlying_price: String,
3898 #[serde(rename = "leavesQty")]
3899 pub leaves_qty: String,
3900 #[serde(rename = "orderId")]
3901 pub order_id: String,
3902 #[serde(rename = "orderLinkId")]
3903 pub order_link_id: String,
3904 #[serde(rename = "orderPrice")]
3905 pub order_price: String,
3906 #[serde(rename = "orderQty")]
3907 pub order_qty: String,
3908 #[serde(rename = "orderType")]
3909 pub order_type: String,
3910 #[serde(rename = "stopOrderType")]
3911 pub stop_order_type: String,
3912 #[serde(rename = "side")]
3913 pub side: String,
3914 #[serde(rename = "execTime")]
3915 pub exec_time: String,
3916 #[serde(rename = "isLeverage")]
3917 pub is_leverage: String,
3918 #[serde(rename = "closedSize")]
3919 pub closed_size: String,
3920 #[serde(rename = "seq")]
3921 pub seq: u64,
3922}
3923
3924unsafe impl Send for ExecutionData {}
3925unsafe impl Sync for ExecutionData {}
3926
3927#[derive(Serialize, Deserialize, Debug, Clone)]
3928pub struct FastExecution {
3929 pub topic: String,
3930 #[serde(rename = "creationTime")]
3931 pub creation_time: u64,
3932 pub data: Vec<FastExecData>,
3933}
3934
3935unsafe impl Send for FastExecution {}
3936unsafe impl Sync for FastExecution {}
3937
3938#[derive(Serialize, Deserialize, Debug, Clone)]
3939pub struct FastExecData {
3940 pub category: String,
3941 pub symbol: String,
3942 #[serde(rename = "execId")]
3943 pub exec_id: String,
3944 #[serde(rename = "execPrice")]
3945 pub exec_price: String,
3946 #[serde(rename = "execQty")]
3947 pub exec_qty: String,
3948 #[serde(rename = "orderId")]
3949 pub order_id: String,
3950 #[serde(rename = "orderLinkId")]
3951 pub order_link_id: String,
3952 pub side: String,
3953 #[serde(rename = "execTime")]
3954 pub exec_time: String,
3955 pub seq: u64,
3956}
3957
3958unsafe impl Send for FastExecData {}
3959unsafe impl Sync for FastExecData {}
3960
3961#[derive(Serialize, Deserialize, Debug, Clone)]
3962pub struct OrderData {
3963 pub symbol: String,
3964 #[serde(rename = "orderId")]
3965 pub order_id: String,
3966 pub side: String,
3967 #[serde(rename = "orderType")]
3968 pub order_type: String,
3969 #[serde(rename = "cancelType")]
3970 pub cancel_type: String,
3971 pub price: String,
3972 pub qty: String,
3973 #[serde(rename = "orderIv")]
3974 pub order_iv: String,
3975 #[serde(rename = "timeInForce")]
3976 pub time_in_force: String,
3977 #[serde(rename = "orderStatus")]
3978 pub order_status: String,
3979 #[serde(rename = "orderLinkId")]
3980 pub order_link_id: String,
3981 #[serde(rename = "lastPriceOnCreated")]
3982 pub last_price_on_created: String,
3983 #[serde(rename = "reduceOnly")]
3984 pub reduce_only: bool,
3985 #[serde(rename = "leavesQty")]
3986 pub leaves_qty: String,
3987 #[serde(rename = "leavesValue")]
3988 pub leaves_value: String,
3989 #[serde(rename = "cumExecQty")]
3990 pub cum_exec_qty: String,
3991 #[serde(rename = "cumExecValue")]
3992 pub cum_exec_value: String,
3993 #[serde(rename = "avgPrice")]
3994 pub avg_price: String,
3995 #[serde(rename = "blockTradeId")]
3996 pub block_trade_id: String,
3997 #[serde(rename = "positionIdx")]
3998 pub position_idx: u8,
3999 #[serde(rename = "cumExecFee")]
4000 pub cum_exec_fee: String,
4001 #[serde(rename = "createdTime")]
4002 pub created_time: String,
4003 #[serde(rename = "updatedTime")]
4004 pub updated_time: String,
4005 #[serde(rename = "rejectReason")]
4006 pub reject_reason: String,
4007 #[serde(rename = "stopOrderType")]
4008 pub stop_order_type: String,
4009 #[serde(rename = "tpslMode")]
4010 pub tpsl_mode: String,
4011 #[serde(rename = "triggerPrice")]
4012 pub trigger_price: String,
4013 #[serde(rename = "takeProfit")]
4014 pub take_profit: String,
4015 #[serde(rename = "stopLoss")]
4016 pub stop_loss: String,
4017 #[serde(rename = "tpTriggerBy")]
4018 pub tp_trigger_by: String,
4019 #[serde(rename = "slTriggerBy")]
4020 pub sl_trigger_by: String,
4021 #[serde(rename = "tpLimitPrice")]
4022 pub tp_limit_price: String,
4023 #[serde(rename = "slLimitPrice")]
4024 pub sl_limit_price: String,
4025 #[serde(rename = "triggerDirection")]
4026 pub trigger_direction: u8,
4027 #[serde(rename = "triggerBy")]
4028 pub trigger_by: String,
4029 #[serde(rename = "closeOnTrigger")]
4030 pub close_on_trigger: bool,
4031 pub category: String,
4032 #[serde(rename = "placeType")]
4033 pub place_type: String,
4034 #[serde(rename = "smpType")]
4035 pub smp_type: String,
4036 #[serde(rename = "smpGroup")]
4037 pub smp_group: u8,
4038 #[serde(rename = "smpOrderId")]
4039 pub smp_order_id: String,
4040 #[serde(rename = "feeCurrency")]
4041 pub fee_currency: String,
4042}
4043
4044unsafe impl Send for OrderData {}
4045unsafe impl Sync for OrderData {}
4046
4047#[derive(Serialize, Deserialize, Debug, Clone)]
4048pub struct OrderEvent {
4049 pub id: String,
4050 pub topic: String,
4051 #[serde(rename = "creationTime")]
4052 pub creation_time: u64,
4053 pub data: Vec<OrderData>,
4054}
4055
4056unsafe impl Send for OrderEvent {}
4057unsafe impl Sync for OrderEvent {}
4058
4059#[derive(Serialize, Deserialize, Debug, Clone)]
4060pub struct WalletEvent {
4061 pub id: String,
4062 pub topic: String,
4063 #[serde(rename = "creationTime")]
4064 pub creation_time: u64,
4065 pub data: Vec<WalletData>,
4066}
4067unsafe impl Send for WalletEvent {}
4068unsafe impl Sync for WalletEvent {}
4069
4070#[derive(Serialize, Deserialize, Debug, Clone)]
4071pub struct WalletData {
4072 #[serde(rename = "accountIMRate")]
4073 pub account_im_rate: String,
4074 #[serde(rename = "accountMMRate")]
4075 pub account_mm_rate: String,
4076 #[serde(rename = "totalEquity")]
4077 pub total_equity: String,
4078 #[serde(rename = "totalWalletBalance")]
4079 pub total_wallet_balance: String,
4080 #[serde(rename = "totalMarginBalance")]
4081 pub total_margin_balance: String,
4082 #[serde(rename = "totalAvailableBalance")]
4083 pub total_available_balance: String,
4084 #[serde(rename = "totalPerpUPL")]
4085 pub total_perp_upl: String,
4086 #[serde(rename = "totalInitialMargin")]
4087 pub total_initial_margin: String,
4088 #[serde(rename = "totalMaintenanceMargin")]
4089 pub total_maintenance_margin: String,
4090 #[serde(rename = "coin")]
4091 pub coin: Vec<CoinData>,
4092 #[serde(rename = "accountLTV")]
4093 pub account_ltv: String,
4094 #[serde(rename = "accountType", skip_serializing_if = "Option::is_none")]
4095 pub account_type: Option<String>,
4096}
4097unsafe impl Send for WalletData {}
4098unsafe impl Sync for WalletData {}
4099#[derive(Serialize, Deserialize, Debug, Clone)]
4100pub struct CoinData {
4101 #[serde(rename = "coin")]
4102 pub coin: String,
4103 #[serde(rename = "equity")]
4104 pub equity: String,
4105 #[serde(rename = "usdValue")]
4106 pub usd_value: String,
4107 #[serde(rename = "walletBalance")]
4108 pub wallet_balance: String,
4109 #[serde(rename = "availableToWithdraw")]
4110 pub available_to_withdraw: String,
4111 #[serde(rename = "availableToBorrow")]
4112 pub available_to_borrow: String,
4113 #[serde(rename = "borrowAmount")]
4114 pub borrow_amount: String,
4115 #[serde(rename = "accruedInterest")]
4116 pub accrued_interest: String,
4117 #[serde(rename = "totalOrderIM")]
4118 pub total_order_im: String,
4119 #[serde(rename = "totalPositionIM")]
4120 pub total_position_im: String,
4121 #[serde(rename = "totalPositionMM")]
4122 pub total_position_mm: String,
4123 #[serde(rename = "unrealisedPnl")]
4124 pub unrealised_pnl: String,
4125 #[serde(rename = "cumRealisedPnl")]
4126 pub cum_realised_pnl: String,
4127 pub bonus: String,
4128 #[serde(rename = "collateralSwitch")]
4129 pub collateral_switch: bool,
4130 #[serde(rename = "marginCollateral")]
4131 pub margin_collateral: bool,
4132 #[serde(rename = "locked")]
4133 pub locked: String,
4134 #[serde(rename = "spotHedgingQty")]
4135 pub spot_hedging_qty: String,
4136}
4137
4138unsafe impl Send for CoinData {}
4139unsafe impl Sync for CoinData {}
4140
4141mod string_to_u64 {
4142 use std::default;
4143
4144 use serde::{self, Deserialize, Deserializer, Serializer};
4145
4146 pub fn serialize<S>(value: &u64, serializer: S) -> Result<S::Ok, S::Error>
4148 where
4149 S: Serializer,
4150 {
4151 let s = value.to_string();
4152 serializer.serialize_str(&s)
4153 }
4154
4155 pub fn deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error>
4157 where
4158 D: Deserializer<'de>,
4159 {
4160 let s = String::deserialize(deserializer)?;
4161 s.parse::<u64>().map_err(serde::de::Error::custom)
4162 }
4163}
4164
4165pub mod string_to_float {
4166 use serde::{self, Deserialize, Deserializer, Serializer};
4167
4168 pub fn serialize<S>(value: &f64, serializer: S) -> Result<S::Ok, S::Error>
4170 where
4171 S: Serializer,
4172 {
4173 let s = value.to_string();
4174 serializer.serialize_str(&s)
4175 }
4176
4177 pub fn deserialize<'de, D>(deserializer: D) -> Result<f64, D::Error>
4179 where
4180 D: Deserializer<'de>,
4181 {
4182 let s = String::deserialize(deserializer)?;
4183 s.parse::<f64>().map_err(serde::de::Error::custom)
4184 }
4185}
4186
4187mod string_to_u64_optional {
4188 use serde::{Deserialize, Deserializer, Serializer};
4189 use std::str::FromStr;
4190
4191 pub fn serialize<S>(value: &Option<u64>, serializer: S) -> Result<S::Ok, S::Error>
4193 where
4194 S: Serializer,
4195 {
4196 match value {
4197 Some(v) => serializer.serialize_str(&v.to_string()),
4198 None => serializer.serialize_str(""),
4199 }
4200 }
4201
4202 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
4204 where
4205 D: Deserializer<'de>,
4206 {
4207 let s = String::deserialize(deserializer)?;
4208 if s.is_empty() {
4209 Ok(None) } else {
4211 u64::from_str(&s)
4212 .map(Some)
4213 .map_err(serde::de::Error::custom)
4214 }
4215 }
4216}