bybit/
model.rs

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/// ----------------------------------------
12///  RESPONSE STRUCTS FOR MARKET REQUESTS
13/// ----------------------------------------
14
15#[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    // #[serde(rename = "isPreListing" )]
288    // pub is_pre_listing: bool,
289    // #[serde(rename = "preListingInfo")]
290    // pub pre_listing_info: PreListingInfo,
291}
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/// --------------------------------------------------
1022///  REQUEST & RESPONSE STRUCTS FOR TRADE
1023/// --------------------------------------------------
1024#[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,                 // String
1097    pub symbol: Cow<'a, str>,               // String
1098    pub is_leverage: Option<bool>,          // Integer
1099    pub side: Side,                         // String
1100    pub order_type: OrderType,              // String
1101    pub qty: f64,                           // String
1102    pub market_unit: Option<f64>,           // String
1103    pub price: Option<f64>,                 // String
1104    pub trigger_direction: Option<bool>,    // String
1105    pub order_filter: Option<Cow<'a, str>>, // String
1106    pub trigger_price: Option<f64>,
1107    pub trigger_by: Option<Cow<'a, str>>,    // String
1108    pub order_iv: Option<f64>,               // String
1109    pub time_in_force: Option<Cow<'a, str>>, // String
1110    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,   // String
1444    pub symbol: Cow<'a, str>, // String
1445    pub order_id: Option<Cow<'a, str>>,
1446    pub order_link_id: Option<Cow<'a, str>>,
1447    pub order_iv: Option<f64>, // String
1448    pub trigger_price: Option<f64>,
1449    pub qty: f64,           // String
1450    pub price: Option<f64>, // String
1451    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>>, // String
1457    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// ----------------------------------------------------------
2218// POSITION STRUCTS SECTION
2219// ------------------------------------------------------
2220
2221#[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    // Serialization: Convert f64 to string
2274    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    // Deserialization: Parse string to f64, return 0.0 for empty string
2282    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) // Return 0.0 for empty string
2289        } 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    // Serialization: Convert Option<f64> to string
2300    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    // Deserialization: Parse string to Option<f64>, return None for empty string
2311    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) // Return None for empty string
2318        } 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, // Assuming result is an empty struct as per provided JSON
2488    #[serde(rename = "retExtInfo")]
2489    pub ret_ext_info: Empty, // Assuming retExtInfo is an empty struct as per provided JSON
2490    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, // Assuming result is an empty struct as per provided JSON
2527    #[serde(rename = "retExtInfo")]
2528    pub ret_ext_info: Empty, // Assuming retExtInfo is an empty struct as per provided JSON
2529    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, // Assuming result is an empty struct as per provided JSON
2567    #[serde(rename = "retExtInfo")]
2568    pub ret_ext_info: Empty, // Assuming retExtInfo is an empty struct as per provided JSON
2569    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, // Assuming retExtInfo is a JSON value as per provided JSON
2609    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, // Assuming result is an empty struct as per provided JSON
2702    #[serde(rename = "retExtInfo")]
2703    pub ret_ext_info: Empty, // Assuming retExtInfo is an empty struct as per provided JSON
2704    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, // Assuming result is an empty struct as per provided JSON
2742    #[serde(rename = "retExtInfo")]
2743    pub ret_ext_info: Empty, // Assuming retExtInfo is an empty struct as per provided JSON
2744    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, // Assuming retExtInfo is an empty struct as per provided JSON
2784    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// = = = = = = = = =  ==  = = == = = == =  = = = = = = = = = = = = = = = =
3056//
3057//  ACCOUNT STRUCTS AND RESPONSES
3058//
3059// = = = = = = = = = = = = = = = = = = ==  = = = = ==  = = == = =  = = = =
3060
3061#[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// = = = = = = = = = = = = ==  = == = =  =  = = = = ==
3451// HEADER STRUCT FOR TRADESTREM RESPONSE
3452// = = = = = = = = = = = = ==  = == = =  =  = = = = ==
3453
3454#[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// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
3469//
3470// WEBSOCKET STRUCTS AND RESPONSES
3471//
3472// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
3473
3474#[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    // Serialize a u64 as a string.
4147    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    // Deserialize a string to a u64.
4156    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    // Serialize a u64 as a string.
4169    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    // Deserialize a string as an f64.
4178    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    // Serialization: Convert Option<u64> to string
4192    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    // Deserialization: Parse string to Option<u64>, return None for empty string
4203    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) // Return None for empty string
4210        } else {
4211            u64::from_str(&s)
4212                .map(Some)
4213                .map_err(serde::de::Error::custom)
4214        }
4215    }
4216}