binance_client/http_api_v3/
mod.rs1pub 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#[derive(Debug, Clone)]
42pub struct Client {
43 inner: reqwest::Client,
45 api_key: Option<String>,
47 secret_key: Option<String>,
49 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 const BASE_URL: &'static str = "https://api.binance.com";
64 const REQUEST_TIMESTAMP_OFFSET: i64 = 1000;
67
68 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 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 pub fn ping(&self) -> Result<()> {
102 self.execute::<()>(Method::GET, "/api/v3/ping".to_owned())
103 }
104
105 pub fn time(&self) -> Result<TimeGetResponse> {
109 self.execute::<TimeGetResponse>(Method::GET, "/api/v3/time".to_owned())
110 }
111
112 pub fn exchange_info(&self) -> Result<ExchangeInfoGetResponse> {
116 self.execute::<ExchangeInfoGetResponse>(Method::GET, "/api/v3/exchangeInfo".to_owned())
117 }
118
119 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 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 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(¶ms, secret_key));
153
154 self.execute_signed::<AccountGetResponse>(
155 Method::GET,
156 format!("/api/v3/account?{}", params),
157 )
158 }
159
160 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(¶ms, secret_key));
176
177 self.execute_signed::<OpenOrdersGetResponse>(
178 Method::GET,
179 format!("/api/v3/openOrders?{}", params),
180 )
181 }
182
183 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(¶ms, secret_key));
199
200 self.execute_signed::<OpenOrdersDeleteResponse>(
201 Method::DELETE,
202 format!("/api/v3/openOrders?{}", params),
203 )
204 }
205
206 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(¶ms, secret_key));
219
220 self.execute_signed::<OrderGetResponse>(Method::GET, format!("/api/v3/order?{}", params))
221 }
222
223 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(¶ms, secret_key));
236
237 self.execute_signed::<OrderPostResponse>(Method::POST, format!("/api/v3/order?{}", params))
238 }
239
240 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(¶ms, secret_key));
253
254 self.execute_signed::<OrderDeleteResponse>(
255 Method::DELETE,
256 format!("/api/v3/order?{}", params),
257 )
258 }
259
260 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(¶ms, secret_key));
274
275 self.execute_signed::<OrderPostResponse>(
276 Method::POST,
277 format!("/api/v3/order/test?{}", params),
278 )
279 }
280
281 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 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 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 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}