binance_client/http_api_v3/
mod.rs

1//!
2//! The Binance API v3 HTTP client.
3//!
4
5pub mod data;
6pub mod response;
7
8use chrono::prelude::Utc;
9use hmac::Hmac;
10use hmac::Mac;
11use reqwest::Method;
12use reqwest::Url;
13use sha2::Sha256;
14
15use self::data::account::get::request::Query as AccountGetQuery;
16use self::data::account::get::response::Response as AccountGetResponse;
17use self::data::depth::get::request::Query as DepthGetQuery;
18use self::data::depth::get::response::Response as DepthGetResponse;
19use self::data::exchange_info::get::response::Response as ExchangeInfoGetResponse;
20use self::data::klines::get::request::Query as KlinesGetQuery;
21use self::data::klines::get::response::Response as KlinesGetResponse;
22use self::data::open_orders::delete::request::Query as OpenOrdersDeleteQuery;
23use self::data::open_orders::delete::response::Response as OpenOrdersDeleteResponse;
24use self::data::open_orders::get::request::Query as OpenOrdersGetQuery;
25use self::data::open_orders::get::response::Response as OpenOrdersGetResponse;
26use self::data::order::delete::request::Query as OrderDeleteQuery;
27use self::data::order::delete::response::Response as OrderDeleteResponse;
28use self::data::order::get::request::Query as OrderGetQuery;
29use self::data::order::get::response::Response as OrderGetResponse;
30use self::data::order::post::request::Query as OrderPostQuery;
31use self::data::order::post::response::Response as OrderPostResponse;
32use self::data::time::get::response::Response as TimeGetResponse;
33
34use crate::error::Error;
35
36use self::response::Response;
37
38///
39/// The Binance API v3 HTTP client.
40///
41#[derive(Debug, Clone)]
42pub struct Client {
43    /// The inner HTTP client.
44    inner: reqwest::Client,
45    /// The Binance authorization API key.
46    api_key: Option<String>,
47    /// The Binance authorization secret key.
48    secret_key: Option<String>,
49    /// The request time offset.
50    timestamp_offset: i64,
51}
52
53impl Default for Client {
54    fn default() -> Self {
55        Self::new()
56    }
57}
58
59type Result<T> = ::std::result::Result<T, Error>;
60
61impl Client {
62    /// The API base URL.
63    const BASE_URL: &'static str = "https://api.binance.com";
64    /// The request timestamp offset, which is substituted from the request time to prevent
65    /// the `request window missed` error.
66    const REQUEST_TIMESTAMP_OFFSET: i64 = 1000;
67
68    ///
69    /// Creates an unauthorized client instance.
70    ///
71    pub fn new() -> Self {
72        let mut client = Self {
73            inner: reqwest::Client::new(),
74            api_key: None,
75            secret_key: None,
76            timestamp_offset: 0,
77        };
78
79        client.timestamp_offset = client.timestamp_offset();
80        client
81    }
82
83    ///
84    /// Creates an authorized client instance.
85    ///
86    pub fn new_with_auth(api_key: String, secret_key: String) -> Self {
87        let mut client = Self {
88            inner: reqwest::Client::new(),
89            api_key: Some(api_key),
90            secret_key: Some(secret_key),
91            timestamp_offset: 0,
92        };
93
94        client.timestamp_offset = client.timestamp_offset();
95        client
96    }
97
98    ///
99    /// Test connectivity to the Rest API.
100    ///
101    pub fn ping(&self) -> Result<()> {
102        self.execute::<()>(Method::GET, "/api/v3/ping".to_owned())
103    }
104
105    ///
106    /// Test connectivity to the Rest API and get the current server time.
107    ///
108    pub fn time(&self) -> Result<TimeGetResponse> {
109        self.execute::<TimeGetResponse>(Method::GET, "/api/v3/time".to_owned())
110    }
111
112    ///
113    /// Current exchange trading rules and symbol information.
114    ///
115    pub fn exchange_info(&self) -> Result<ExchangeInfoGetResponse> {
116        self.execute::<ExchangeInfoGetResponse>(Method::GET, "/api/v3/exchangeInfo".to_owned())
117    }
118
119    ///
120    /// Kline/candlestick bars for a symbol.
121    /// Klines are uniquely identified by their open time.
122    ///
123    pub fn klines(&self, request: KlinesGetQuery) -> Result<KlinesGetResponse> {
124        self.execute::<KlinesGetResponse>(
125            Method::GET,
126            format!("/api/v3/klines?{}", request.to_string()),
127        )
128    }
129
130    ///
131    /// The real-time market depth.
132    ///
133    pub fn depth(&self, request: DepthGetQuery) -> Result<DepthGetResponse> {
134        self.execute::<DepthGetResponse>(
135            Method::GET,
136            format!("/api/v3/depth?{}", request.to_string()),
137        )
138    }
139
140    ///
141    /// Get the account info and balances.
142    ///
143    pub fn account_get(&self, mut request: AccountGetQuery) -> Result<AccountGetResponse> {
144        let secret_key = self
145            .secret_key
146            .as_ref()
147            .ok_or(Error::AuthorizationKeysMissing)?;
148
149        request.timestamp -= self.timestamp_offset;
150
151        let mut params = request.to_string();
152        params += &format!("&signature={}", Self::signature(&params, secret_key));
153
154        self.execute_signed::<AccountGetResponse>(
155            Method::GET,
156            format!("/api/v3/account?{}", params),
157        )
158    }
159
160    ///
161    /// Get the account open orders.
162    ///
163    pub fn open_orders_get(
164        &self,
165        mut request: OpenOrdersGetQuery,
166    ) -> Result<OpenOrdersGetResponse> {
167        let secret_key = self
168            .secret_key
169            .as_ref()
170            .ok_or(Error::AuthorizationKeysMissing)?;
171
172        request.timestamp -= self.timestamp_offset;
173
174        let mut params = request.to_string();
175        params += &format!("&signature={}", Self::signature(&params, secret_key));
176
177        self.execute_signed::<OpenOrdersGetResponse>(
178            Method::GET,
179            format!("/api/v3/openOrders?{}", params),
180        )
181    }
182
183    ///
184    /// Delete the account open orders.
185    ///
186    pub fn open_orders_delete(
187        &self,
188        mut request: OpenOrdersDeleteQuery,
189    ) -> Result<OpenOrdersDeleteResponse> {
190        let secret_key = self
191            .secret_key
192            .as_ref()
193            .ok_or(Error::AuthorizationKeysMissing)?;
194
195        request.timestamp -= self.timestamp_offset;
196
197        let mut params = request.to_string();
198        params += &format!("&signature={}", Self::signature(&params, secret_key));
199
200        self.execute_signed::<OpenOrdersDeleteResponse>(
201            Method::DELETE,
202            format!("/api/v3/openOrders?{}", params),
203        )
204    }
205
206    ///
207    /// Check an order's status.
208    ///
209    pub fn order_get(&self, mut request: OrderGetQuery) -> Result<OrderGetResponse> {
210        let secret_key = self
211            .secret_key
212            .as_ref()
213            .ok_or(Error::AuthorizationKeysMissing)?;
214
215        request.timestamp -= self.timestamp_offset;
216
217        let mut params = request.to_string();
218        params += &format!("&signature={}", Self::signature(&params, secret_key));
219
220        self.execute_signed::<OrderGetResponse>(Method::GET, format!("/api/v3/order?{}", params))
221    }
222
223    ///
224    /// Send in a new order.
225    ///
226    pub fn order_post(&self, mut request: OrderPostQuery) -> Result<OrderPostResponse> {
227        let secret_key = self
228            .secret_key
229            .as_ref()
230            .ok_or(Error::AuthorizationKeysMissing)?;
231
232        request.timestamp -= self.timestamp_offset;
233
234        let mut params = request.to_string();
235        params += &format!("&signature={}", Self::signature(&params, secret_key));
236
237        self.execute_signed::<OrderPostResponse>(Method::POST, format!("/api/v3/order?{}", params))
238    }
239
240    ///
241    /// Cancel an active order.
242    ///
243    pub fn order_delete(&self, mut request: OrderDeleteQuery) -> Result<OrderDeleteResponse> {
244        let secret_key = self
245            .secret_key
246            .as_ref()
247            .ok_or(Error::AuthorizationKeysMissing)?;
248
249        request.timestamp -= self.timestamp_offset;
250
251        let mut params = request.to_string();
252        params += &format!("&signature={}", Self::signature(&params, secret_key));
253
254        self.execute_signed::<OrderDeleteResponse>(
255            Method::DELETE,
256            format!("/api/v3/order?{}", params),
257        )
258    }
259
260    ///
261    /// Test new order creation and signature/recvWindow long.
262    /// Creates and validates a new order but does not send it into the matching engine.
263    ///
264    pub fn order_post_test(&self, mut request: OrderPostQuery) -> Result<OrderPostResponse> {
265        let secret_key = self
266            .secret_key
267            .as_ref()
268            .ok_or(Error::AuthorizationKeysMissing)?;
269
270        request.timestamp -= self.timestamp_offset;
271
272        let mut params = request.to_string();
273        params += &format!("&signature={}", Self::signature(&params, secret_key));
274
275        self.execute_signed::<OrderPostResponse>(
276            Method::POST,
277            format!("/api/v3/order/test?{}", params),
278        )
279    }
280
281    ///
282    /// Executes an unauthorized request.
283    ///
284    fn execute<T>(&self, method: Method, url: String) -> Result<T>
285    where
286        T: serde::de::DeserializeOwned,
287    {
288        let url = Self::BASE_URL.to_owned() + url.as_str();
289
290        let response = self
291            .inner
292            .execute(
293                self.inner
294                    .request(
295                        method,
296                        Url::parse(&url).map_err(|error| Error::UrlParsing(error, url))?,
297                    )
298                    .build()
299                    .map_err(Error::RequestBuilding)?,
300            )
301            .map_err(Error::RequestExecution)?
302            .text()
303            .map_err(Error::ResponseReading)?;
304        let response: Response<T> = serde_json::from_str(response.as_str())
305            .map_err(|error| Error::ResponseParsing(error, response))?;
306
307        match response {
308            Response::Ok(response) => Ok(response),
309            Response::Error(error) => Err(Error::ResponseError(error)),
310        }
311    }
312
313    ///
314    /// Executes an authorized request.
315    ///
316    fn execute_signed<T>(&self, method: Method, url: String) -> Result<T>
317    where
318        T: serde::de::DeserializeOwned,
319    {
320        let api_key = self
321            .api_key
322            .as_ref()
323            .ok_or(Error::AuthorizationKeysMissing)?;
324
325        let url = Self::BASE_URL.to_owned() + url.as_str();
326
327        let response = self
328            .inner
329            .execute(
330                self.inner
331                    .request(
332                        method,
333                        Url::parse(&url).map_err(|error| Error::UrlParsing(error, url))?,
334                    )
335                    .header("X-MBX-APIKEY", api_key.to_owned())
336                    .build()
337                    .map_err(Error::RequestBuilding)?,
338            )
339            .map_err(Error::RequestExecution)?
340            .text()
341            .map_err(Error::ResponseReading)?;
342        let response: Response<T> = serde_json::from_str(response.as_str())
343            .map_err(|error| Error::ResponseParsing(error, response))?;
344
345        match response {
346            Response::Ok(response) => Ok(response),
347            Response::Error(error) => Err(Error::ResponseError(error)),
348        }
349    }
350
351    ///
352    /// Generates an HMAC signature for authorized requests.
353    ///
354    fn signature(params: &str, secret_key: &str) -> String {
355        hex::encode({
356            let mut hmac: Hmac<Sha256> =
357                Hmac::new_from_slice(secret_key.as_bytes()).expect("HMAC is valid");
358            hmac.update(params.as_bytes());
359            hmac.finalize().into_bytes()
360        })
361    }
362
363    ///
364    /// Calculates the request timestamp offsets between the system time and Binance time.
365    ///
366    fn timestamp_offset(&self) -> i64 {
367        let system_time = Utc::now().timestamp_millis();
368        let request_time = std::time::Instant::now();
369        let binance_time = self.time().expect("Time request").server_time
370            - (request_time.elapsed().as_millis() as i64) / 2;
371
372        (system_time - binance_time) + Self::REQUEST_TIMESTAMP_OFFSET
373    }
374}