Skip to main content

binance_sdk/copy_trading/rest_api/apis/
future_copy_trading_api.rs

1/*
2 * Binance Copy Trading REST API
3 *
4 * OpenAPI Specification for the Binance Copy Trading REST API
5 *
6 * The version of the OpenAPI document: 1.0.0
7 *
8 *
9 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
10 * https://openapi-generator.tech
11 * Do not edit the class manually.
12 */
13
14#![allow(unused_imports)]
15use async_trait::async_trait;
16use derive_builder::Builder;
17use reqwest;
18use rust_decimal::prelude::*;
19use serde::{Deserialize, Serialize};
20use serde_json::{Value, json};
21use std::collections::BTreeMap;
22
23use crate::common::{
24    config::ConfigurationRestApi,
25    models::{ParamBuildError, RestApiResponse},
26    utils::send_request,
27};
28use crate::copy_trading::rest_api::models;
29
30const HAS_TIME_UNIT: bool = false;
31
32#[async_trait]
33pub trait FutureCopyTradingApi: Send + Sync {
34    async fn get_futures_lead_trader_status(
35        &self,
36        params: GetFuturesLeadTraderStatusParams,
37    ) -> anyhow::Result<RestApiResponse<models::GetFuturesLeadTraderStatusResponse>>;
38    async fn get_futures_lead_trading_symbol_whitelist(
39        &self,
40        params: GetFuturesLeadTradingSymbolWhitelistParams,
41    ) -> anyhow::Result<RestApiResponse<models::GetFuturesLeadTradingSymbolWhitelistResponse>>;
42}
43
44#[derive(Debug, Clone)]
45pub struct FutureCopyTradingApiClient {
46    configuration: ConfigurationRestApi,
47}
48
49impl FutureCopyTradingApiClient {
50    pub fn new(configuration: ConfigurationRestApi) -> Self {
51        Self { configuration }
52    }
53}
54
55/// Request parameters for the [`get_futures_lead_trader_status`] operation.
56///
57/// This struct holds all of the inputs you can pass when calling
58/// [`get_futures_lead_trader_status`](#method.get_futures_lead_trader_status).
59#[derive(Clone, Debug, Builder, Default)]
60#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
61pub struct GetFuturesLeadTraderStatusParams {
62    ///
63    /// The `recv_window` parameter.
64    ///
65    /// This field is **optional.
66    #[builder(setter(into), default)]
67    pub recv_window: Option<i64>,
68}
69
70impl GetFuturesLeadTraderStatusParams {
71    /// Create a builder for [`get_futures_lead_trader_status`].
72    ///
73    #[must_use]
74    pub fn builder() -> GetFuturesLeadTraderStatusParamsBuilder {
75        GetFuturesLeadTraderStatusParamsBuilder::default()
76    }
77}
78/// Request parameters for the [`get_futures_lead_trading_symbol_whitelist`] operation.
79///
80/// This struct holds all of the inputs you can pass when calling
81/// [`get_futures_lead_trading_symbol_whitelist`](#method.get_futures_lead_trading_symbol_whitelist).
82#[derive(Clone, Debug, Builder, Default)]
83#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
84pub struct GetFuturesLeadTradingSymbolWhitelistParams {
85    ///
86    /// The `recv_window` parameter.
87    ///
88    /// This field is **optional.
89    #[builder(setter(into), default)]
90    pub recv_window: Option<i64>,
91}
92
93impl GetFuturesLeadTradingSymbolWhitelistParams {
94    /// Create a builder for [`get_futures_lead_trading_symbol_whitelist`].
95    ///
96    #[must_use]
97    pub fn builder() -> GetFuturesLeadTradingSymbolWhitelistParamsBuilder {
98        GetFuturesLeadTradingSymbolWhitelistParamsBuilder::default()
99    }
100}
101
102#[async_trait]
103impl FutureCopyTradingApi for FutureCopyTradingApiClient {
104    async fn get_futures_lead_trader_status(
105        &self,
106        params: GetFuturesLeadTraderStatusParams,
107    ) -> anyhow::Result<RestApiResponse<models::GetFuturesLeadTraderStatusResponse>> {
108        let GetFuturesLeadTraderStatusParams { recv_window } = params;
109
110        let mut query_params = BTreeMap::new();
111        let body_params = BTreeMap::new();
112
113        if let Some(rw) = recv_window {
114            query_params.insert("recvWindow".to_string(), json!(rw));
115        }
116
117        send_request::<models::GetFuturesLeadTraderStatusResponse>(
118            &self.configuration,
119            "/sapi/v1/copyTrading/futures/userStatus",
120            reqwest::Method::GET,
121            query_params,
122            body_params,
123            if HAS_TIME_UNIT {
124                self.configuration.time_unit
125            } else {
126                None
127            },
128            true,
129        )
130        .await
131    }
132
133    async fn get_futures_lead_trading_symbol_whitelist(
134        &self,
135        params: GetFuturesLeadTradingSymbolWhitelistParams,
136    ) -> anyhow::Result<RestApiResponse<models::GetFuturesLeadTradingSymbolWhitelistResponse>> {
137        let GetFuturesLeadTradingSymbolWhitelistParams { recv_window } = params;
138
139        let mut query_params = BTreeMap::new();
140        let body_params = BTreeMap::new();
141
142        if let Some(rw) = recv_window {
143            query_params.insert("recvWindow".to_string(), json!(rw));
144        }
145
146        send_request::<models::GetFuturesLeadTradingSymbolWhitelistResponse>(
147            &self.configuration,
148            "/sapi/v1/copyTrading/futures/leadSymbol",
149            reqwest::Method::GET,
150            query_params,
151            body_params,
152            if HAS_TIME_UNIT {
153                self.configuration.time_unit
154            } else {
155                None
156            },
157            true,
158        )
159        .await
160    }
161}
162
163#[cfg(all(test, feature = "copy_trading"))]
164mod tests {
165    use super::*;
166    use crate::TOKIO_SHARED_RT;
167    use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
168    use async_trait::async_trait;
169    use std::collections::HashMap;
170
171    struct DummyRestApiResponse<T> {
172        inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
173        status: u16,
174        headers: HashMap<String, String>,
175        rate_limits: Option<Vec<RestApiRateLimit>>,
176    }
177
178    impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
179        fn from(dummy: DummyRestApiResponse<T>) -> Self {
180            Self {
181                data_fn: dummy.inner,
182                status: dummy.status,
183                headers: dummy.headers,
184                rate_limits: dummy.rate_limits,
185            }
186        }
187    }
188
189    struct MockFutureCopyTradingApiClient {
190        force_error: bool,
191    }
192
193    #[async_trait]
194    impl FutureCopyTradingApi for MockFutureCopyTradingApiClient {
195        async fn get_futures_lead_trader_status(
196            &self,
197            _params: GetFuturesLeadTraderStatusParams,
198        ) -> anyhow::Result<RestApiResponse<models::GetFuturesLeadTraderStatusResponse>> {
199            if self.force_error {
200                return Err(ConnectorError::ConnectorClientError {
201                    msg: "ResponseError".to_string(),
202                    code: None,
203                }
204                .into());
205            }
206
207            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"isLeadTrader":true,"time":1717382310843},"success":true}"#).unwrap();
208            let dummy_response: models::GetFuturesLeadTraderStatusResponse =
209                serde_json::from_value(resp_json.clone())
210                    .expect("should parse into models::GetFuturesLeadTraderStatusResponse");
211
212            let dummy = DummyRestApiResponse {
213                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
214                status: 200,
215                headers: HashMap::new(),
216                rate_limits: None,
217            };
218
219            Ok(dummy.into())
220        }
221
222        async fn get_futures_lead_trading_symbol_whitelist(
223            &self,
224            _params: GetFuturesLeadTradingSymbolWhitelistParams,
225        ) -> anyhow::Result<RestApiResponse<models::GetFuturesLeadTradingSymbolWhitelistResponse>>
226        {
227            if self.force_error {
228                return Err(ConnectorError::ConnectorClientError {
229                    msg: "ResponseError".to_string(),
230                    code: None,
231                }
232                .into());
233            }
234
235            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":[{"symbol":"BTCUSDT","baseAsset":"BTC","quoteAsset":"USDT"},{"symbol":"ETHUSDT","baseAsset":"ETH","quoteAsset":"USDT"}]}"#).unwrap();
236            let dummy_response: models::GetFuturesLeadTradingSymbolWhitelistResponse =
237                serde_json::from_value(resp_json.clone()).expect(
238                    "should parse into models::GetFuturesLeadTradingSymbolWhitelistResponse",
239                );
240
241            let dummy = DummyRestApiResponse {
242                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
243                status: 200,
244                headers: HashMap::new(),
245                rate_limits: None,
246            };
247
248            Ok(dummy.into())
249        }
250    }
251
252    #[test]
253    fn get_futures_lead_trader_status_required_params_success() {
254        TOKIO_SHARED_RT.block_on(async {
255            let client = MockFutureCopyTradingApiClient { force_error: false };
256
257            let params = GetFuturesLeadTraderStatusParams::builder().build().unwrap();
258
259            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"isLeadTrader":true,"time":1717382310843},"success":true}"#).unwrap();
260            let expected_response : models::GetFuturesLeadTraderStatusResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFuturesLeadTraderStatusResponse");
261
262            let resp = client.get_futures_lead_trader_status(params).await.expect("Expected a response");
263            let data_future = resp.data();
264            let actual_response = data_future.await.unwrap();
265            assert_eq!(actual_response, expected_response);
266        });
267    }
268
269    #[test]
270    fn get_futures_lead_trader_status_optional_params_success() {
271        TOKIO_SHARED_RT.block_on(async {
272            let client = MockFutureCopyTradingApiClient { force_error: false };
273
274            let params = GetFuturesLeadTraderStatusParams::builder().recv_window(5000).build().unwrap();
275
276            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"isLeadTrader":true,"time":1717382310843},"success":true}"#).unwrap();
277            let expected_response : models::GetFuturesLeadTraderStatusResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFuturesLeadTraderStatusResponse");
278
279            let resp = client.get_futures_lead_trader_status(params).await.expect("Expected a response");
280            let data_future = resp.data();
281            let actual_response = data_future.await.unwrap();
282            assert_eq!(actual_response, expected_response);
283        });
284    }
285
286    #[test]
287    fn get_futures_lead_trader_status_response_error() {
288        TOKIO_SHARED_RT.block_on(async {
289            let client = MockFutureCopyTradingApiClient { force_error: true };
290
291            let params = GetFuturesLeadTraderStatusParams::builder().build().unwrap();
292
293            match client.get_futures_lead_trader_status(params).await {
294                Ok(_) => panic!("Expected an error"),
295                Err(err) => {
296                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
297                }
298            }
299        });
300    }
301
302    #[test]
303    fn get_futures_lead_trading_symbol_whitelist_required_params_success() {
304        TOKIO_SHARED_RT.block_on(async {
305            let client = MockFutureCopyTradingApiClient { force_error: false };
306
307            let params = GetFuturesLeadTradingSymbolWhitelistParams::builder().build().unwrap();
308
309            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":[{"symbol":"BTCUSDT","baseAsset":"BTC","quoteAsset":"USDT"},{"symbol":"ETHUSDT","baseAsset":"ETH","quoteAsset":"USDT"}]}"#).unwrap();
310            let expected_response : models::GetFuturesLeadTradingSymbolWhitelistResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFuturesLeadTradingSymbolWhitelistResponse");
311
312            let resp = client.get_futures_lead_trading_symbol_whitelist(params).await.expect("Expected a response");
313            let data_future = resp.data();
314            let actual_response = data_future.await.unwrap();
315            assert_eq!(actual_response, expected_response);
316        });
317    }
318
319    #[test]
320    fn get_futures_lead_trading_symbol_whitelist_optional_params_success() {
321        TOKIO_SHARED_RT.block_on(async {
322            let client = MockFutureCopyTradingApiClient { force_error: false };
323
324            let params = GetFuturesLeadTradingSymbolWhitelistParams::builder().recv_window(5000).build().unwrap();
325
326            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":[{"symbol":"BTCUSDT","baseAsset":"BTC","quoteAsset":"USDT"},{"symbol":"ETHUSDT","baseAsset":"ETH","quoteAsset":"USDT"}]}"#).unwrap();
327            let expected_response : models::GetFuturesLeadTradingSymbolWhitelistResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFuturesLeadTradingSymbolWhitelistResponse");
328
329            let resp = client.get_futures_lead_trading_symbol_whitelist(params).await.expect("Expected a response");
330            let data_future = resp.data();
331            let actual_response = data_future.await.unwrap();
332            assert_eq!(actual_response, expected_response);
333        });
334    }
335
336    #[test]
337    fn get_futures_lead_trading_symbol_whitelist_response_error() {
338        TOKIO_SHARED_RT.block_on(async {
339            let client = MockFutureCopyTradingApiClient { force_error: true };
340
341            let params = GetFuturesLeadTradingSymbolWhitelistParams::builder()
342                .build()
343                .unwrap();
344
345            match client
346                .get_futures_lead_trading_symbol_whitelist(params)
347                .await
348            {
349                Ok(_) => panic!("Expected an error"),
350                Err(err) => {
351                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
352                }
353            }
354        });
355    }
356}