1use crate::{
2 Error, Timestamp,
3 crypto::{SensitiveString, Signer},
4 http::{
5 APIErrorResponse, APIKeyInformation, AccountInfo, AmendOrderBatchRequest,
6 AmendOrderBatchResult, AmendOrderRequest, AmendOrderResponse, CancelAllOrdersRequest,
7 CancelAllOrdersResponse, CancelOrderBatchRequest, CancelOrderBatchResult,
8 CancelOrderRequest, CancelOrderResponse, ClosedPnl, CursorPagination, DeliveryPrice,
9 EmptyResult, ExecutionEntry, FeeRateEntry, FundingRateHistory, GetClosedPnlParams,
10 GetDeliveryPriceParams, GetExecutionListParams, GetFeeRateParams,
11 GetFundingRateHistoryParams, GetHistoricalVolatilityParams, GetInstrumentsInfoParams,
12 GetInsuranceParams, GetKLinesParams, GetOpenClosedOrdersParams, GetOpenInterestParams,
13 GetOrderHistoryParams, GetOrderbookParams, GetPositionInfoParams, GetRiskLimitParams,
14 GetSpotBorrowCheckParams, GetTickersParams, GetTradesParams, GetTransactionLogParams,
15 GetWalletBalanceParams, Headers, HistoricalVolatilityEntry, InstrumentsInfo, Insurance,
16 KLine, List, OpenInterest, Order, Orderbook, PlaceOrderBatchRequest, PlaceOrderBatchResult,
17 PlaceOrderRequest, PlaceOrderResponse, Position, Resp, Response, RiskLimit, ServerTime,
18 SetAutoAddMarginRequest, SetLeverageRequest, SetMarginModeRequest, SetMarginModeResponse,
19 SetRiskLimitRequest, SetRiskLimitResponse, SetTradingStopRequest, SpotBorrowCheck,
20 SwitchCrossIsolatedMarginRequest, SwitchPositionModeRequest, Ticker, Trade, TransactionLog,
21 WalletBalance,
22 },
23 serde::{deserialize_json, serialize_json, serialize_query},
24 url::*,
25};
26use reqwest::{self, Method, RequestBuilder, header::HeaderMap};
27
28pub struct Config {
29 pub base_url: String,
30 pub api_key: Option<SensitiveString>,
31 pub api_secret: Option<SensitiveString>,
32 pub recv_window: Timestamp,
34 pub referer: Option<String>,
36}
37
38#[derive(Debug)]
40pub struct Client {
41 base_url: String,
42 headers: HeaderMap,
43 client: reqwest::Client,
44 signer: Option<Signer>,
45}
46
47impl Client {
48 pub fn new(cfg: Config) -> Result<Self, Error> {
49 let mut headers = HeaderMap::new();
50
51 if let Some(api_key) = cfg.api_key.as_ref() {
52 let api_key = api_key.expose().parse()?;
53 headers.append(HEADER_X_BAPI_API_KEY, api_key);
54 }
55
56 let recv_window = cfg.recv_window.to_string().parse()?;
57 headers.append(HEADER_X_BAPI_RECV_WINDOW, recv_window);
58
59 if let Some(referer) = cfg.referer {
60 let referer = referer.parse()?;
61 headers.append(HEADER_X_REFERER, referer);
62 }
63
64 let signer = cfg
65 .api_secret
66 .map(|api_secret| -> Result<Signer, Error> {
67 let api_key = cfg
68 .api_key
69 .ok_or_else(|| Error::from("api_key is required when api_secret is set"))?;
70 Ok(Signer::new(api_key, api_secret, cfg.recv_window, None))
71 })
72 .transpose()?;
73
74 Ok(Self {
75 base_url: cfg.base_url,
76 headers,
77 client: reqwest::Client::builder().build()?,
78 signer,
79 })
80 }
81
82 fn get_signed_headers(&self, s: &str) -> HeaderMap {
83 let mut headers = self.headers.clone();
84
85 let (signature, timestamp) = self.signer.as_ref().unwrap().sign(s);
86 let signature = signature.parse().unwrap();
87 headers.append(HEADER_X_BAPI_SIGN, signature);
88 let timestamp = timestamp.parse().unwrap();
89 headers.append(HEADER_X_BAPI_TIMESTAMP, timestamp);
90
91 headers
92 }
93}
94
95impl Client {
97 #[tracing::instrument(skip(self), err)]
98 pub async fn get_server_time(&self) -> Result<Response<ServerTime>, Error> {
99 let url = format!("{}{}", self.base_url, Path::MarketServerTime);
100
101 let request = self.client.request(Method::GET, url);
102
103 let response = send(request).await?;
104 Ok(response)
105 }
106
107 #[tracing::instrument(skip(self), err)]
108 pub async fn get_kline(&self, params: &GetKLinesParams) -> Result<Response<KLine>, Error> {
109 let url = format!("{}{}", self.base_url, Path::MarketKline);
110
111 let request = self.client.request(Method::GET, url).query(params);
112
113 let response = send(request).await?;
114 Ok(response)
115 }
116
117 #[tracing::instrument(skip(self), err)]
122 pub async fn get_mark_price_kline(
123 &self,
124 params: &GetKLinesParams,
125 ) -> Result<Response<KLine>, Error> {
126 let url = format!("{}{}", self.base_url, Path::MarketMarkPriceKline);
127
128 let request = self.client.request(Method::GET, url).query(params);
129
130 let response = send(request).await?;
131 Ok(response)
132 }
133
134 #[tracing::instrument(skip(self), err)]
139 pub async fn get_index_price_kline(
140 &self,
141 params: &GetKLinesParams,
142 ) -> Result<Response<KLine>, Error> {
143 let url = format!("{}{}", self.base_url, Path::MarketIndexPriceKline);
144
145 let request = self.client.request(Method::GET, url).query(params);
146
147 let response = send(request).await?;
148 Ok(response)
149 }
150
151 #[tracing::instrument(skip(self), err)]
156 pub async fn get_premium_index_price_kline(
157 &self,
158 params: &GetKLinesParams,
159 ) -> Result<Response<KLine>, Error> {
160 let url = format!("{}{}", self.base_url, Path::MarketPremiumIndexPriceKline);
161
162 let request = self.client.request(Method::GET, url).query(params);
163
164 let response = send(request).await?;
165 Ok(response)
166 }
167
168 #[tracing::instrument(skip(self), err)]
172 pub async fn get_tickers(&self, params: &GetTickersParams) -> Result<Response<Ticker>, Error> {
173 let url = format!("{}{}", self.base_url, Path::MarketTickers);
174
175 let request = self.client.request(Method::GET, url).query(params);
176
177 let response = send(request).await?;
178 Ok(response)
179 }
180
181 #[tracing::instrument(skip(self), err)]
186 pub async fn get_orderbook(
187 &self,
188 params: &GetOrderbookParams,
189 ) -> Result<Response<Orderbook>, Error> {
190 let url = format!("{}{}", self.base_url, Path::MarketOrderbook);
191
192 let request = self.client.request(Method::GET, url).query(params);
193
194 let response = send(request).await?;
195 Ok(response)
196 }
197
198 #[tracing::instrument(skip(self), err)]
199 pub async fn get_instruments_info(
200 &self,
201 params: &GetInstrumentsInfoParams,
202 ) -> Result<Response<InstrumentsInfo>, Error> {
203 let url = format!("{}{}", self.base_url, Path::MarketInstrumentsInfo);
204
205 let request = self.client.request(Method::GET, url).query(params);
206
207 let response = send(request).await?;
208 Ok(response)
209 }
210
211 #[tracing::instrument(skip(self), err)]
212 pub async fn get_public_recent_trading_history(
213 &self,
214 params: &GetTradesParams,
215 ) -> Result<Response<Trade>, Error> {
216 let url = format!("{}{}", self.base_url, Path::MarketRecentTrade);
217
218 let request = self.client.request(Method::GET, url).query(params);
219
220 let response = send(request).await?;
221 Ok(response)
222 }
223
224 #[tracing::instrument(skip(self), err)]
229 pub async fn get_funding_rate_history(
230 &self,
231 params: &GetFundingRateHistoryParams,
232 ) -> Result<Response<FundingRateHistory>, Error> {
233 let url = format!("{}{}", self.base_url, Path::MarketFundingHistory);
234
235 let request = self.client.request(Method::GET, url).query(params);
236
237 let response = send(request).await?;
238 Ok(response)
239 }
240
241 #[tracing::instrument(skip(self), err)]
246 pub async fn get_open_interest(
247 &self,
248 params: &GetOpenInterestParams,
249 ) -> Result<Response<OpenInterest>, Error> {
250 let url = format!("{}{}", self.base_url, Path::MarketOpenInterest);
251
252 let request = self.client.request(Method::GET, url).query(params);
253
254 let response = send(request).await?;
255 Ok(response)
256 }
257
258 #[tracing::instrument(skip(self), err)]
266 pub async fn get_historical_volatility(
267 &self,
268 params: &GetHistoricalVolatilityParams,
269 ) -> Result<Response<Vec<HistoricalVolatilityEntry>>, Error> {
270 let url = format!("{}{}", self.base_url, Path::MarketHistoricalVolatility);
271
272 let request = self.client.request(Method::GET, url).query(params);
273
274 let response = send(request).await?;
275 Ok(response)
276 }
277
278 #[tracing::instrument(skip(self), err)]
281 pub async fn get_insurance(
282 &self,
283 params: &GetInsuranceParams,
284 ) -> Result<Response<Insurance>, Error> {
285 let url = format!("{}{}", self.base_url, Path::MarketInsurance);
286
287 let request = self.client.request(Method::GET, url).query(params);
288
289 let response = send(request).await?;
290 Ok(response)
291 }
292
293 #[tracing::instrument(skip(self), err)]
298 pub async fn get_risk_limit(
299 &self,
300 params: &GetRiskLimitParams,
301 ) -> Result<Response<RiskLimit>, Error> {
302 let url = format!("{}{}", self.base_url, Path::MarketRiskLimit);
303
304 let request = self.client.request(Method::GET, url).query(params);
305
306 let response = send(request).await?;
307 Ok(response)
308 }
309
310 #[tracing::instrument(skip(self), err)]
315 pub async fn get_delivery_price(
316 &self,
317 params: &GetDeliveryPriceParams,
318 ) -> Result<Response<DeliveryPrice>, Error> {
319 let url = format!("{}{}", self.base_url, Path::MarketDeliveryPrice);
320
321 let request = self.client.request(Method::GET, url).query(params);
322
323 let response = send(request).await?;
324 Ok(response)
325 }
326}
327
328impl Client {
330 #[tracing::instrument(skip(self), err)]
377 pub async fn place_order(
378 &self,
379 request: &PlaceOrderRequest,
380 ) -> Result<Response<PlaceOrderResponse>, Error> {
381 let url = format!("{}{}", self.base_url, Path::TradeOrderCreate);
382 let json = serialize_json(request)?;
383 let headers = self.get_signed_headers(&json);
384
385 let request = self
386 .client
387 .request(Method::POST, url)
388 .headers(headers)
389 .body(json);
390
391 let response = send(request).await?;
392 Ok(response)
393 }
394
395 #[tracing::instrument(skip(self), err)]
399 pub async fn amend_order(
400 &self,
401 request: &AmendOrderRequest,
402 ) -> Result<Response<AmendOrderResponse>, Error> {
403 let url = format!("{}{}", self.base_url, Path::TradeOrderAmend);
404 let json = serialize_json(request)?;
405 let headers = self.get_signed_headers(&json);
406
407 let request = self
408 .client
409 .request(Method::POST, url)
410 .headers(headers)
411 .body(json);
412
413 let response = send(request).await?;
414 Ok(response)
415 }
416
417 #[tracing::instrument(skip(self), err)]
423 pub async fn cancel_order(
424 &self,
425 request: &CancelOrderRequest,
426 ) -> Result<Response<CancelOrderResponse>, Error> {
427 let url = format!("{}{}", self.base_url, Path::TradeOrderCancel);
428 let json = serialize_json(request)?;
429 let headers = self.get_signed_headers(&json);
430
431 let request = self
432 .client
433 .request(Method::POST, url)
434 .headers(headers)
435 .body(json);
436
437 let response = send(request).await?;
438 Ok(response)
439 }
440
441 #[tracing::instrument(skip(self), err)]
455 pub async fn get_open_closed_orders(
456 &self,
457 params: &GetOpenClosedOrdersParams,
458 ) -> Result<Response<CursorPagination<Order>>, Error> {
459 let query = serialize_query(params)?;
460 let url = format!("{}{}?{query}", self.base_url, Path::TradeOrderRealtime);
461 let headers = self.get_signed_headers(&query);
462
463 let request = self.client.request(Method::GET, url).headers(headers);
464
465 let response = send(request).await?;
466 Ok(response)
467 }
468
469 #[tracing::instrument(skip(self), err)]
473 pub async fn get_open_closed_orders_all(
474 &self,
475 params: &GetOpenClosedOrdersParams,
476 ) -> Result<Vec<Order>, Error> {
477 let mut all = Vec::new();
478 let mut p = params.clone();
479 loop {
480 let page = self.get_open_closed_orders(&p).await?;
481 all.extend(page.result.list);
482 match page.result.next_page_cursor {
483 Some(cursor) => p = p.with_cursor(cursor),
484 None => break,
485 }
486 }
487 Ok(all)
488 }
489
490 #[tracing::instrument(skip(self), err)]
493 pub async fn cancel_all_orders(
494 &self,
495 request: &CancelAllOrdersRequest,
496 ) -> Result<Response<CancelAllOrdersResponse>, Error> {
497 let url = format!("{}{}", self.base_url, Path::TradeOrderCancelAll);
498 let json = serialize_json(request)?;
499 let headers = self.get_signed_headers(&json);
500
501 let request = self
502 .client
503 .request(Method::POST, url)
504 .headers(headers)
505 .body(json);
506
507 let response = send(request).await?;
508 Ok(response)
509 }
510
511 #[tracing::instrument(skip(self), err)]
515 pub async fn get_order_history(
516 &self,
517 params: &GetOrderHistoryParams,
518 ) -> Result<Response<CursorPagination<Order>>, Error> {
519 let query = serialize_query(params)?;
520 let url = format!("{}{}?{query}", self.base_url, Path::TradeOrderHistory);
521 let headers = self.get_signed_headers(&query);
522
523 let request = self.client.request(Method::GET, url).headers(headers);
524
525 let response = send(request).await?;
526 Ok(response)
527 }
528
529 #[tracing::instrument(skip(self), err)]
531 pub async fn get_order_history_all(
532 &self,
533 params: &GetOrderHistoryParams,
534 ) -> Result<Vec<Order>, Error> {
535 let mut all = Vec::new();
536 let mut p = params.clone();
537 loop {
538 let page = self.get_order_history(&p).await?;
539 all.extend(page.result.list);
540 match page.result.next_page_cursor {
541 Some(cursor) => p = p.with_cursor(cursor),
542 None => break,
543 }
544 }
545 Ok(all)
546 }
547
548 #[tracing::instrument(skip(self), err)]
552 pub async fn place_orders_batch(
553 &self,
554 request: &PlaceOrderBatchRequest,
555 ) -> Result<Response<List<PlaceOrderBatchResult>>, Error> {
556 let url = format!("{}{}", self.base_url, Path::TradeOrderCreateBatch);
557 let json = serialize_json(request)?;
558 let headers = self.get_signed_headers(&json);
559
560 let request = self
561 .client
562 .request(Method::POST, url)
563 .headers(headers)
564 .body(json);
565
566 let response = send(request).await?;
567 Ok(response)
568 }
569
570 #[tracing::instrument(skip(self), err)]
574 pub async fn amend_orders_batch(
575 &self,
576 request: &AmendOrderBatchRequest,
577 ) -> Result<Response<List<AmendOrderBatchResult>>, Error> {
578 let url = format!("{}{}", self.base_url, Path::TradeOrderAmendBatch);
579 let json = serialize_json(request)?;
580 let headers = self.get_signed_headers(&json);
581
582 let request = self
583 .client
584 .request(Method::POST, url)
585 .headers(headers)
586 .body(json);
587
588 let response = send(request).await?;
589 Ok(response)
590 }
591
592 #[tracing::instrument(skip(self), err)]
596 pub async fn cancel_orders_batch(
597 &self,
598 request: &CancelOrderBatchRequest,
599 ) -> Result<Response<List<CancelOrderBatchResult>>, Error> {
600 let url = format!("{}{}", self.base_url, Path::TradeOrderCancelBatch);
601 let json = serialize_json(request)?;
602 let headers = self.get_signed_headers(&json);
603
604 let request = self
605 .client
606 .request(Method::POST, url)
607 .headers(headers)
608 .body(json);
609
610 let response = send(request).await?;
611 Ok(response)
612 }
613
614 #[tracing::instrument(skip(self), err)]
619 pub async fn get_spot_borrow_check(
620 &self,
621 params: &GetSpotBorrowCheckParams,
622 ) -> Result<Response<SpotBorrowCheck>, Error> {
623 let url = format!("{}{}", self.base_url, Path::TradeOrderSpotBorrowCheck);
624 let query = serialize_query(params)?;
625 let headers = self.get_signed_headers(&query);
626
627 let request = self
628 .client
629 .request(Method::GET, url)
630 .headers(headers)
631 .query(params);
632
633 let response = send(request).await?;
634 Ok(response)
635 }
636}
637
638impl Client {
640 #[tracing::instrument(skip(self), err)]
651 pub async fn get_position_info(
652 &self,
653 params: &GetPositionInfoParams,
654 ) -> Result<Response<CursorPagination<Position>>, Error> {
655 let query = serialize_query(params)?;
656 let url = format!("{}{}?{query}", self.base_url, Path::PositionList);
657 let headers = self.get_signed_headers(&query);
658
659 let request = self.client.request(Method::GET, url).headers(headers);
660
661 let response = send(request).await?;
662 Ok(response)
663 }
664
665 #[tracing::instrument(skip(self), err)]
669 pub async fn get_position_info_all(
670 &self,
671 params: &GetPositionInfoParams,
672 ) -> Result<Vec<Position>, Error> {
673 let mut all = Vec::new();
674 let mut p = params.clone();
675 loop {
676 let page = self.get_position_info(&p).await?;
677 all.extend(page.result.list);
678 match page.result.next_page_cursor {
679 Some(cursor) => p = p.with_cursor(cursor),
680 None => break,
681 }
682 }
683 Ok(all)
684 }
685
686 #[tracing::instrument(skip(self), err)]
689 pub async fn set_leverage(
690 &self,
691 request: &SetLeverageRequest,
692 ) -> Result<Response<EmptyResult>, Error> {
693 let url = format!("{}{}", self.base_url, Path::PositionSetLeverage);
694 let json = serialize_json(request)?;
695 let headers = self.get_signed_headers(&json);
696
697 let request = self
698 .client
699 .request(Method::POST, url)
700 .headers(headers)
701 .body(json);
702
703 let response = send(request).await?;
704 Ok(response)
705 }
706
707 #[tracing::instrument(skip(self), err)]
710 pub async fn set_trading_stop(
711 &self,
712 request: &SetTradingStopRequest,
713 ) -> Result<Response<EmptyResult>, Error> {
714 let url = format!("{}{}", self.base_url, Path::PositionTradingStop);
715 let json = serialize_json(request)?;
716 let headers = self.get_signed_headers(&json);
717
718 let request = self
719 .client
720 .request(Method::POST, url)
721 .headers(headers)
722 .body(json);
723
724 let response = send(request).await?;
725 Ok(response)
726 }
727
728 #[tracing::instrument(skip(self), err)]
731 pub async fn switch_cross_isolated_margin(
732 &self,
733 request: &SwitchCrossIsolatedMarginRequest,
734 ) -> Result<Response<EmptyResult>, Error> {
735 let url = format!("{}{}", self.base_url, Path::PositionSwitchIsolated);
736 let json = serialize_json(request)?;
737 let headers = self.get_signed_headers(&json);
738
739 let request = self
740 .client
741 .request(Method::POST, url)
742 .headers(headers)
743 .body(json);
744
745 let response = send(request).await?;
746 Ok(response)
747 }
748
749 #[tracing::instrument(skip(self), err)]
752 pub async fn switch_position_mode(
753 &self,
754 request: &SwitchPositionModeRequest,
755 ) -> Result<Response<EmptyResult>, Error> {
756 let url = format!("{}{}", self.base_url, Path::PositionSwitchMode);
757 let json = serialize_json(request)?;
758 let headers = self.get_signed_headers(&json);
759
760 let request = self
761 .client
762 .request(Method::POST, url)
763 .headers(headers)
764 .body(json);
765
766 let response = send(request).await?;
767 Ok(response)
768 }
769
770 #[tracing::instrument(skip(self), err)]
773 pub async fn set_auto_add_margin(
774 &self,
775 request: &SetAutoAddMarginRequest,
776 ) -> Result<Response<EmptyResult>, Error> {
777 let url = format!("{}{}", self.base_url, Path::PositionSetAutoAddMargin);
778 let json = serialize_json(request)?;
779 let headers = self.get_signed_headers(&json);
780
781 let request = self
782 .client
783 .request(Method::POST, url)
784 .headers(headers)
785 .body(json);
786
787 let response = send(request).await?;
788 Ok(response)
789 }
790
791 #[tracing::instrument(skip(self), err)]
794 pub async fn set_risk_limit(
795 &self,
796 request: &SetRiskLimitRequest,
797 ) -> Result<Response<SetRiskLimitResponse>, Error> {
798 let url = format!("{}{}", self.base_url, Path::PositionSetRiskLimit);
799 let json = serialize_json(request)?;
800 let headers = self.get_signed_headers(&json);
801
802 let request = self
803 .client
804 .request(Method::POST, url)
805 .headers(headers)
806 .body(json);
807
808 let response = send(request).await?;
809 Ok(response)
810 }
811
812 #[tracing::instrument(skip(self), err)]
815 pub async fn get_closed_pnl(
816 &self,
817 params: &GetClosedPnlParams,
818 ) -> Result<Response<CursorPagination<ClosedPnl>>, Error> {
819 let query = serialize_query(params)?;
820 let url = format!("{}{}?{query}", self.base_url, Path::PositionClosedPnl);
821 let headers = self.get_signed_headers(&query);
822
823 let request = self.client.request(Method::GET, url).headers(headers);
824
825 let response = send(request).await?;
826 Ok(response)
827 }
828
829 #[tracing::instrument(skip(self), err)]
831 pub async fn get_closed_pnl_all(
832 &self,
833 params: &GetClosedPnlParams,
834 ) -> Result<Vec<ClosedPnl>, Error> {
835 let mut all = Vec::new();
836 let mut p = params.clone();
837 loop {
838 let page = self.get_closed_pnl(&p).await?;
839 all.extend(page.result.list);
840 match page.result.next_page_cursor {
841 Some(cursor) => p = p.with_cursor(cursor),
842 None => break,
843 }
844 }
845 Ok(all)
846 }
847
848 #[tracing::instrument(skip(self), err)]
851 pub async fn get_execution_list(
852 &self,
853 params: &GetExecutionListParams,
854 ) -> Result<Response<CursorPagination<ExecutionEntry>>, Error> {
855 let query = serialize_query(params)?;
856 let url = format!("{}{}?{query}", self.base_url, Path::ExecutionList);
857 let headers = self.get_signed_headers(&query);
858
859 let request = self.client.request(Method::GET, url).headers(headers);
860
861 let response = send(request).await?;
862 Ok(response)
863 }
864
865 #[tracing::instrument(skip(self), err)]
867 pub async fn get_execution_list_all(
868 &self,
869 params: &GetExecutionListParams,
870 ) -> Result<Vec<ExecutionEntry>, Error> {
871 let mut all = Vec::new();
872 let mut p = params.clone();
873 loop {
874 let page = self.get_execution_list(&p).await?;
875 all.extend(page.result.list);
876 match page.result.next_page_cursor {
877 Some(cursor) => p = p.with_cursor(cursor),
878 None => break,
879 }
880 }
881 Ok(all)
882 }
883}
884
885impl Client {
887 #[tracing::instrument(skip(self), err)]
889 pub async fn get_wallet_balance(
890 &self,
891 params: &GetWalletBalanceParams,
892 ) -> Result<Response<List<WalletBalance>>, Error> {
893 let query = serialize_query(params)?;
894 let url = format!("{}{}?{query}", self.base_url, Path::AccountWalletBalance);
895 let headers = self.get_signed_headers(&query);
896
897 let request = self.client.request(Method::GET, url).headers(headers);
898
899 let response = send(request).await?;
900 Ok(response)
901 }
902
903 #[tracing::instrument(skip(self), err)]
906 pub async fn get_transaction_log(
907 &self,
908 params: &GetTransactionLogParams,
909 ) -> Result<Response<CursorPagination<TransactionLog>>, Error> {
910 let query = serialize_query(params)?;
911 let url = format!("{}{}?{query}", self.base_url, Path::AccountTransactionLog);
912 let headers = self.get_signed_headers(&query);
913
914 let request = self.client.request(Method::GET, url).headers(headers);
915
916 let response = send(request).await?;
917 Ok(response)
918 }
919
920 #[tracing::instrument(skip(self), err)]
924 pub async fn get_transaction_log_all(
925 &self,
926 params: &GetTransactionLogParams,
927 ) -> Result<Vec<TransactionLog>, Error> {
928 let mut all = Vec::new();
929 let mut p = params.clone();
930 loop {
931 let page = self.get_transaction_log(&p).await?;
932 all.extend(page.result.list);
933 match page.result.next_page_cursor {
934 Some(cursor) => p = p.with_cursor(cursor),
935 None => break,
936 }
937 }
938 Ok(all)
939 }
940
941 #[tracing::instrument(skip(self), err)]
943 pub async fn get_account_info(&self) -> Result<Response<AccountInfo>, Error> {
944 let url = format!("{}{}", self.base_url, Path::AccountInfo);
945 let query = "";
946 let headers = self.get_signed_headers(query);
947
948 let request = self.client.request(Method::GET, url).headers(headers);
949
950 let response = send(request).await?;
951 Ok(response)
952 }
953
954 #[tracing::instrument(skip(self), err)]
959 pub async fn get_fee_rate(
960 &self,
961 params: &GetFeeRateParams,
962 ) -> Result<Response<List<FeeRateEntry>>, Error> {
963 let url = format!("{}{}", self.base_url, Path::AccountFeeRate);
964 let query = serialize_query(params)?;
965 let headers = self.get_signed_headers(&query);
966
967 let request = self
968 .client
969 .request(Method::GET, url)
970 .headers(headers)
971 .query(params);
972
973 let response = send(request).await?;
974 Ok(response)
975 }
976
977 #[tracing::instrument(skip(self), err)]
982 pub async fn set_margin_mode(
983 &self,
984 request_body: &SetMarginModeRequest,
985 ) -> Result<Response<SetMarginModeResponse>, Error> {
986 let url = format!("{}{}", self.base_url, Path::AccountSetMarginMode);
987 let body = serialize_json(request_body)?;
988 let headers = self.get_signed_headers(&body);
989
990 let request = self
991 .client
992 .request(Method::POST, url)
993 .headers(headers)
994 .body(body);
995
996 let response = send(request).await?;
997 Ok(response)
998 }
999}
1000
1001impl Client {
1003 #[tracing::instrument(skip(self), err)]
1006 pub async fn get_api_key_information(&self) -> Result<Response<APIKeyInformation>, Error> {
1007 let url = format!("{}{}", self.base_url, Path::UserQueryApi);
1008 let query = "";
1009 let headers = self.get_signed_headers(query);
1010
1011 let request = self.client.request(Method::GET, url).headers(headers);
1012
1013 let response = send(request).await?;
1014 Ok(response)
1015 }
1016}
1017
1018async fn send<T>(request: RequestBuilder) -> Result<Response<T>, Error>
1019where
1020 T: serde::de::DeserializeOwned,
1021{
1022 let start = std::time::Instant::now();
1023 let response = request.send().await?;
1024 let elapsed_ms = start.elapsed().as_millis();
1025 let headers = parse_headers(response.headers());
1026 let json = response.text().await?;
1027 if !headers.is_ret_code_ok() {
1028 let msg: APIErrorResponse = deserialize_json(&json)?;
1029 tracing::debug!(elapsed_ms, ret_code = msg.ret_code, "api error response");
1030 return Err(msg.into());
1031 }
1032
1033 tracing::debug!(
1034 elapsed_ms,
1035 api_limit = headers.api_limit,
1036 api_limit_status = headers.api_limit_status,
1037 "api call completed"
1038 );
1039 let response: Resp<_> = deserialize_json(&json)?;
1040 let response = Response {
1041 result: response.result,
1042 time: response.time,
1043 headers,
1044 ret_ext_info: response.ret_ext_info,
1045 };
1046 Ok(response)
1047}
1048
1049fn parse_headers(headers: &HeaderMap) -> Headers {
1051 let ret_code = headers
1052 .get(HEADER_RET_CODE)
1053 .and_then(|h| h.to_str().unwrap_or_default().parse().ok());
1054 let trace_id = headers
1055 .get(HEADER_TRACE_ID)
1056 .and_then(|h| h.to_str().map(|str| str.into()).ok());
1057 let time_now = headers
1058 .get(HEADER_TIME_NOW)
1059 .and_then(|h| h.to_str().unwrap_or_default().parse().ok());
1060
1061 let api_limit = headers
1062 .get(HEADER_X_BAPI_LIMIT)
1063 .and_then(|h| h.to_str().unwrap_or_default().parse().ok());
1064 let api_limit_status = headers
1065 .get(HEADER_X_BAPI_LIMIT_STATUS)
1066 .and_then(|h| h.to_str().unwrap_or_default().parse().ok());
1067 let api_limit_reset_timestamp = headers
1068 .get(HEADER_X_BAPI_LIMIT_RESET_TIMESTAMP)
1069 .and_then(|h| h.to_str().unwrap_or_default().parse().ok());
1070
1071 Headers {
1072 ret_code,
1073 trace_id,
1074 time_now,
1075 api_limit,
1076 api_limit_status,
1077 api_limit_reset_timestamp,
1078 }
1079}