1#![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::spot::rest_api::models;
29
30const HAS_TIME_UNIT: bool = true;
31
32#[async_trait]
33pub trait MarketApi: Send + Sync {
34 async fn agg_trades(
35 &self,
36 params: AggTradesParams,
37 ) -> anyhow::Result<RestApiResponse<Vec<models::AggTradesResponseInner>>>;
38 async fn avg_price(
39 &self,
40 params: AvgPriceParams,
41 ) -> anyhow::Result<RestApiResponse<models::AvgPriceResponse>>;
42 async fn depth(
43 &self,
44 params: DepthParams,
45 ) -> anyhow::Result<RestApiResponse<models::DepthResponse>>;
46 async fn get_trades(
47 &self,
48 params: GetTradesParams,
49 ) -> anyhow::Result<RestApiResponse<Vec<models::GetTradesResponseInner>>>;
50 async fn historical_block_trades(
51 &self,
52 params: HistoricalBlockTradesParams,
53 ) -> anyhow::Result<RestApiResponse<Vec<models::HistoricalBlockTradesResponseInner>>>;
54 async fn historical_trades(
55 &self,
56 params: HistoricalTradesParams,
57 ) -> anyhow::Result<RestApiResponse<Vec<models::GetTradesResponseInner>>>;
58 async fn klines(
59 &self,
60 params: KlinesParams,
61 ) -> anyhow::Result<RestApiResponse<Vec<Vec<models::KlinesItemInner>>>>;
62 async fn reference_price(
63 &self,
64 params: ReferencePriceParams,
65 ) -> anyhow::Result<RestApiResponse<models::ReferencePriceResponse>>;
66 async fn reference_price_calculation(
67 &self,
68 params: ReferencePriceCalculationParams,
69 ) -> anyhow::Result<RestApiResponse<models::ReferencePriceCalculationResponse>>;
70 async fn ticker(
71 &self,
72 params: TickerParams,
73 ) -> anyhow::Result<RestApiResponse<models::TickerResponse>>;
74 async fn ticker24hr(
75 &self,
76 params: Ticker24hrParams,
77 ) -> anyhow::Result<RestApiResponse<models::Ticker24hrResponse>>;
78 async fn ticker_book_ticker(
79 &self,
80 params: TickerBookTickerParams,
81 ) -> anyhow::Result<RestApiResponse<models::TickerBookTickerResponse>>;
82 async fn ticker_price(
83 &self,
84 params: TickerPriceParams,
85 ) -> anyhow::Result<RestApiResponse<models::TickerPriceResponse>>;
86 async fn ticker_trading_day(
87 &self,
88 params: TickerTradingDayParams,
89 ) -> anyhow::Result<RestApiResponse<models::TickerTradingDayResponse>>;
90 async fn ui_klines(
91 &self,
92 params: UiKlinesParams,
93 ) -> anyhow::Result<RestApiResponse<Vec<Vec<models::KlinesItemInner>>>>;
94}
95
96#[derive(Debug, Clone)]
97pub struct MarketApiClient {
98 configuration: ConfigurationRestApi,
99}
100
101impl MarketApiClient {
102 pub fn new(configuration: ConfigurationRestApi) -> Self {
103 Self { configuration }
104 }
105}
106
107#[allow(non_camel_case_types)]
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub enum DepthSymbolStatusEnum {
110 #[serde(rename = "TRADING")]
111 Trading,
112 #[serde(rename = "HALT")]
113 Halt,
114 #[serde(rename = "BREAK")]
115 Break,
116}
117
118impl DepthSymbolStatusEnum {
119 #[must_use]
120 pub fn as_str(&self) -> &'static str {
121 match self {
122 Self::Trading => "TRADING",
123 Self::Halt => "HALT",
124 Self::Break => "BREAK",
125 }
126 }
127}
128
129impl std::str::FromStr for DepthSymbolStatusEnum {
130 type Err = Box<dyn std::error::Error + Send + Sync>;
131
132 fn from_str(s: &str) -> Result<Self, Self::Err> {
133 match s {
134 "TRADING" => Ok(Self::Trading),
135 "HALT" => Ok(Self::Halt),
136 "BREAK" => Ok(Self::Break),
137 other => Err(format!("invalid DepthSymbolStatusEnum: {}", other).into()),
138 }
139 }
140}
141
142#[allow(non_camel_case_types)]
143#[derive(Debug, Clone, Serialize, Deserialize)]
144pub enum KlinesIntervalEnum {
145 #[serde(rename = "1s")]
146 Interval1s,
147 #[serde(rename = "1m")]
148 Interval1m,
149 #[serde(rename = "3m")]
150 Interval3m,
151 #[serde(rename = "5m")]
152 Interval5m,
153 #[serde(rename = "15m")]
154 Interval15m,
155 #[serde(rename = "30m")]
156 Interval30m,
157 #[serde(rename = "1h")]
158 Interval1h,
159 #[serde(rename = "2h")]
160 Interval2h,
161 #[serde(rename = "4h")]
162 Interval4h,
163 #[serde(rename = "6h")]
164 Interval6h,
165 #[serde(rename = "8h")]
166 Interval8h,
167 #[serde(rename = "12h")]
168 Interval12h,
169 #[serde(rename = "1d")]
170 Interval1d,
171 #[serde(rename = "3d")]
172 Interval3d,
173 #[serde(rename = "1w")]
174 Interval1w,
175 #[serde(rename = "1M")]
176 Interval1M,
177}
178
179impl KlinesIntervalEnum {
180 #[must_use]
181 pub fn as_str(&self) -> &'static str {
182 match self {
183 Self::Interval1s => "1s",
184 Self::Interval1m => "1m",
185 Self::Interval3m => "3m",
186 Self::Interval5m => "5m",
187 Self::Interval15m => "15m",
188 Self::Interval30m => "30m",
189 Self::Interval1h => "1h",
190 Self::Interval2h => "2h",
191 Self::Interval4h => "4h",
192 Self::Interval6h => "6h",
193 Self::Interval8h => "8h",
194 Self::Interval12h => "12h",
195 Self::Interval1d => "1d",
196 Self::Interval3d => "3d",
197 Self::Interval1w => "1w",
198 Self::Interval1M => "1M",
199 }
200 }
201}
202
203impl std::str::FromStr for KlinesIntervalEnum {
204 type Err = Box<dyn std::error::Error + Send + Sync>;
205
206 fn from_str(s: &str) -> Result<Self, Self::Err> {
207 match s {
208 "1s" => Ok(Self::Interval1s),
209 "1m" => Ok(Self::Interval1m),
210 "3m" => Ok(Self::Interval3m),
211 "5m" => Ok(Self::Interval5m),
212 "15m" => Ok(Self::Interval15m),
213 "30m" => Ok(Self::Interval30m),
214 "1h" => Ok(Self::Interval1h),
215 "2h" => Ok(Self::Interval2h),
216 "4h" => Ok(Self::Interval4h),
217 "6h" => Ok(Self::Interval6h),
218 "8h" => Ok(Self::Interval8h),
219 "12h" => Ok(Self::Interval12h),
220 "1d" => Ok(Self::Interval1d),
221 "3d" => Ok(Self::Interval3d),
222 "1w" => Ok(Self::Interval1w),
223 "1M" => Ok(Self::Interval1M),
224 other => Err(format!("invalid KlinesIntervalEnum: {}", other).into()),
225 }
226 }
227}
228
229#[allow(non_camel_case_types)]
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub enum ReferencePriceCalculationSymbolStatusEnum {
232 #[serde(rename = "TRADING")]
233 Trading,
234 #[serde(rename = "HALT")]
235 Halt,
236 #[serde(rename = "BREAK")]
237 Break,
238}
239
240impl ReferencePriceCalculationSymbolStatusEnum {
241 #[must_use]
242 pub fn as_str(&self) -> &'static str {
243 match self {
244 Self::Trading => "TRADING",
245 Self::Halt => "HALT",
246 Self::Break => "BREAK",
247 }
248 }
249}
250
251impl std::str::FromStr for ReferencePriceCalculationSymbolStatusEnum {
252 type Err = Box<dyn std::error::Error + Send + Sync>;
253
254 fn from_str(s: &str) -> Result<Self, Self::Err> {
255 match s {
256 "TRADING" => Ok(Self::Trading),
257 "HALT" => Ok(Self::Halt),
258 "BREAK" => Ok(Self::Break),
259 other => Err(format!(
260 "invalid ReferencePriceCalculationSymbolStatusEnum: {}",
261 other
262 )
263 .into()),
264 }
265 }
266}
267
268#[allow(non_camel_case_types)]
269#[derive(Debug, Clone, Serialize, Deserialize)]
270pub enum TickerWindowSizeEnum {
271 #[serde(rename = "1m")]
272 WindowSize1m,
273 #[serde(rename = "2m")]
274 WindowSize2m,
275 #[serde(rename = "3m")]
276 WindowSize3m,
277 #[serde(rename = "4m")]
278 WindowSize4m,
279 #[serde(rename = "5m")]
280 WindowSize5m,
281 #[serde(rename = "6m")]
282 WindowSize6m,
283 #[serde(rename = "7m")]
284 WindowSize7m,
285 #[serde(rename = "8m")]
286 WindowSize8m,
287 #[serde(rename = "9m")]
288 WindowSize9m,
289 #[serde(rename = "10m")]
290 WindowSize10m,
291 #[serde(rename = "11m")]
292 WindowSize11m,
293 #[serde(rename = "12m")]
294 WindowSize12m,
295 #[serde(rename = "13m")]
296 WindowSize13m,
297 #[serde(rename = "14m")]
298 WindowSize14m,
299 #[serde(rename = "15m")]
300 WindowSize15m,
301 #[serde(rename = "16m")]
302 WindowSize16m,
303 #[serde(rename = "17m")]
304 WindowSize17m,
305 #[serde(rename = "18m")]
306 WindowSize18m,
307 #[serde(rename = "19m")]
308 WindowSize19m,
309 #[serde(rename = "20m")]
310 WindowSize20m,
311 #[serde(rename = "21m")]
312 WindowSize21m,
313 #[serde(rename = "22m")]
314 WindowSize22m,
315 #[serde(rename = "23m")]
316 WindowSize23m,
317 #[serde(rename = "24m")]
318 WindowSize24m,
319 #[serde(rename = "25m")]
320 WindowSize25m,
321 #[serde(rename = "26m")]
322 WindowSize26m,
323 #[serde(rename = "27m")]
324 WindowSize27m,
325 #[serde(rename = "28m")]
326 WindowSize28m,
327 #[serde(rename = "29m")]
328 WindowSize29m,
329 #[serde(rename = "30m")]
330 WindowSize30m,
331 #[serde(rename = "31m")]
332 WindowSize31m,
333 #[serde(rename = "32m")]
334 WindowSize32m,
335 #[serde(rename = "33m")]
336 WindowSize33m,
337 #[serde(rename = "34m")]
338 WindowSize34m,
339 #[serde(rename = "35m")]
340 WindowSize35m,
341 #[serde(rename = "36m")]
342 WindowSize36m,
343 #[serde(rename = "37m")]
344 WindowSize37m,
345 #[serde(rename = "38m")]
346 WindowSize38m,
347 #[serde(rename = "39m")]
348 WindowSize39m,
349 #[serde(rename = "40m")]
350 WindowSize40m,
351 #[serde(rename = "41m")]
352 WindowSize41m,
353 #[serde(rename = "42m")]
354 WindowSize42m,
355 #[serde(rename = "43m")]
356 WindowSize43m,
357 #[serde(rename = "44m")]
358 WindowSize44m,
359 #[serde(rename = "45m")]
360 WindowSize45m,
361 #[serde(rename = "46m")]
362 WindowSize46m,
363 #[serde(rename = "47m")]
364 WindowSize47m,
365 #[serde(rename = "48m")]
366 WindowSize48m,
367 #[serde(rename = "49m")]
368 WindowSize49m,
369 #[serde(rename = "50m")]
370 WindowSize50m,
371 #[serde(rename = "51m")]
372 WindowSize51m,
373 #[serde(rename = "52m")]
374 WindowSize52m,
375 #[serde(rename = "53m")]
376 WindowSize53m,
377 #[serde(rename = "54m")]
378 WindowSize54m,
379 #[serde(rename = "55m")]
380 WindowSize55m,
381 #[serde(rename = "56m")]
382 WindowSize56m,
383 #[serde(rename = "57m")]
384 WindowSize57m,
385 #[serde(rename = "58m")]
386 WindowSize58m,
387 #[serde(rename = "59m")]
388 WindowSize59m,
389 #[serde(rename = "1h")]
390 WindowSize1h,
391 #[serde(rename = "2h")]
392 WindowSize2h,
393 #[serde(rename = "3h")]
394 WindowSize3h,
395 #[serde(rename = "4h")]
396 WindowSize4h,
397 #[serde(rename = "5h")]
398 WindowSize5h,
399 #[serde(rename = "6h")]
400 WindowSize6h,
401 #[serde(rename = "7h")]
402 WindowSize7h,
403 #[serde(rename = "8h")]
404 WindowSize8h,
405 #[serde(rename = "9h")]
406 WindowSize9h,
407 #[serde(rename = "10h")]
408 WindowSize10h,
409 #[serde(rename = "11h")]
410 WindowSize11h,
411 #[serde(rename = "12h")]
412 WindowSize12h,
413 #[serde(rename = "13h")]
414 WindowSize13h,
415 #[serde(rename = "14h")]
416 WindowSize14h,
417 #[serde(rename = "15h")]
418 WindowSize15h,
419 #[serde(rename = "16h")]
420 WindowSize16h,
421 #[serde(rename = "17h")]
422 WindowSize17h,
423 #[serde(rename = "18h")]
424 WindowSize18h,
425 #[serde(rename = "19h")]
426 WindowSize19h,
427 #[serde(rename = "20h")]
428 WindowSize20h,
429 #[serde(rename = "21h")]
430 WindowSize21h,
431 #[serde(rename = "22h")]
432 WindowSize22h,
433 #[serde(rename = "23h")]
434 WindowSize23h,
435 #[serde(rename = "1d")]
436 WindowSize1d,
437 #[serde(rename = "2d")]
438 WindowSize2d,
439 #[serde(rename = "3d")]
440 WindowSize3d,
441 #[serde(rename = "4d")]
442 WindowSize4d,
443 #[serde(rename = "5d")]
444 WindowSize5d,
445 #[serde(rename = "6d")]
446 WindowSize6d,
447 #[serde(rename = "7d")]
448 WindowSize7d,
449}
450
451impl TickerWindowSizeEnum {
452 #[must_use]
453 pub fn as_str(&self) -> &'static str {
454 match self {
455 Self::WindowSize1m => "1m",
456 Self::WindowSize2m => "2m",
457 Self::WindowSize3m => "3m",
458 Self::WindowSize4m => "4m",
459 Self::WindowSize5m => "5m",
460 Self::WindowSize6m => "6m",
461 Self::WindowSize7m => "7m",
462 Self::WindowSize8m => "8m",
463 Self::WindowSize9m => "9m",
464 Self::WindowSize10m => "10m",
465 Self::WindowSize11m => "11m",
466 Self::WindowSize12m => "12m",
467 Self::WindowSize13m => "13m",
468 Self::WindowSize14m => "14m",
469 Self::WindowSize15m => "15m",
470 Self::WindowSize16m => "16m",
471 Self::WindowSize17m => "17m",
472 Self::WindowSize18m => "18m",
473 Self::WindowSize19m => "19m",
474 Self::WindowSize20m => "20m",
475 Self::WindowSize21m => "21m",
476 Self::WindowSize22m => "22m",
477 Self::WindowSize23m => "23m",
478 Self::WindowSize24m => "24m",
479 Self::WindowSize25m => "25m",
480 Self::WindowSize26m => "26m",
481 Self::WindowSize27m => "27m",
482 Self::WindowSize28m => "28m",
483 Self::WindowSize29m => "29m",
484 Self::WindowSize30m => "30m",
485 Self::WindowSize31m => "31m",
486 Self::WindowSize32m => "32m",
487 Self::WindowSize33m => "33m",
488 Self::WindowSize34m => "34m",
489 Self::WindowSize35m => "35m",
490 Self::WindowSize36m => "36m",
491 Self::WindowSize37m => "37m",
492 Self::WindowSize38m => "38m",
493 Self::WindowSize39m => "39m",
494 Self::WindowSize40m => "40m",
495 Self::WindowSize41m => "41m",
496 Self::WindowSize42m => "42m",
497 Self::WindowSize43m => "43m",
498 Self::WindowSize44m => "44m",
499 Self::WindowSize45m => "45m",
500 Self::WindowSize46m => "46m",
501 Self::WindowSize47m => "47m",
502 Self::WindowSize48m => "48m",
503 Self::WindowSize49m => "49m",
504 Self::WindowSize50m => "50m",
505 Self::WindowSize51m => "51m",
506 Self::WindowSize52m => "52m",
507 Self::WindowSize53m => "53m",
508 Self::WindowSize54m => "54m",
509 Self::WindowSize55m => "55m",
510 Self::WindowSize56m => "56m",
511 Self::WindowSize57m => "57m",
512 Self::WindowSize58m => "58m",
513 Self::WindowSize59m => "59m",
514 Self::WindowSize1h => "1h",
515 Self::WindowSize2h => "2h",
516 Self::WindowSize3h => "3h",
517 Self::WindowSize4h => "4h",
518 Self::WindowSize5h => "5h",
519 Self::WindowSize6h => "6h",
520 Self::WindowSize7h => "7h",
521 Self::WindowSize8h => "8h",
522 Self::WindowSize9h => "9h",
523 Self::WindowSize10h => "10h",
524 Self::WindowSize11h => "11h",
525 Self::WindowSize12h => "12h",
526 Self::WindowSize13h => "13h",
527 Self::WindowSize14h => "14h",
528 Self::WindowSize15h => "15h",
529 Self::WindowSize16h => "16h",
530 Self::WindowSize17h => "17h",
531 Self::WindowSize18h => "18h",
532 Self::WindowSize19h => "19h",
533 Self::WindowSize20h => "20h",
534 Self::WindowSize21h => "21h",
535 Self::WindowSize22h => "22h",
536 Self::WindowSize23h => "23h",
537 Self::WindowSize1d => "1d",
538 Self::WindowSize2d => "2d",
539 Self::WindowSize3d => "3d",
540 Self::WindowSize4d => "4d",
541 Self::WindowSize5d => "5d",
542 Self::WindowSize6d => "6d",
543 Self::WindowSize7d => "7d",
544 }
545 }
546}
547
548impl std::str::FromStr for TickerWindowSizeEnum {
549 type Err = Box<dyn std::error::Error + Send + Sync>;
550
551 fn from_str(s: &str) -> Result<Self, Self::Err> {
552 match s {
553 "1m" => Ok(Self::WindowSize1m),
554 "2m" => Ok(Self::WindowSize2m),
555 "3m" => Ok(Self::WindowSize3m),
556 "4m" => Ok(Self::WindowSize4m),
557 "5m" => Ok(Self::WindowSize5m),
558 "6m" => Ok(Self::WindowSize6m),
559 "7m" => Ok(Self::WindowSize7m),
560 "8m" => Ok(Self::WindowSize8m),
561 "9m" => Ok(Self::WindowSize9m),
562 "10m" => Ok(Self::WindowSize10m),
563 "11m" => Ok(Self::WindowSize11m),
564 "12m" => Ok(Self::WindowSize12m),
565 "13m" => Ok(Self::WindowSize13m),
566 "14m" => Ok(Self::WindowSize14m),
567 "15m" => Ok(Self::WindowSize15m),
568 "16m" => Ok(Self::WindowSize16m),
569 "17m" => Ok(Self::WindowSize17m),
570 "18m" => Ok(Self::WindowSize18m),
571 "19m" => Ok(Self::WindowSize19m),
572 "20m" => Ok(Self::WindowSize20m),
573 "21m" => Ok(Self::WindowSize21m),
574 "22m" => Ok(Self::WindowSize22m),
575 "23m" => Ok(Self::WindowSize23m),
576 "24m" => Ok(Self::WindowSize24m),
577 "25m" => Ok(Self::WindowSize25m),
578 "26m" => Ok(Self::WindowSize26m),
579 "27m" => Ok(Self::WindowSize27m),
580 "28m" => Ok(Self::WindowSize28m),
581 "29m" => Ok(Self::WindowSize29m),
582 "30m" => Ok(Self::WindowSize30m),
583 "31m" => Ok(Self::WindowSize31m),
584 "32m" => Ok(Self::WindowSize32m),
585 "33m" => Ok(Self::WindowSize33m),
586 "34m" => Ok(Self::WindowSize34m),
587 "35m" => Ok(Self::WindowSize35m),
588 "36m" => Ok(Self::WindowSize36m),
589 "37m" => Ok(Self::WindowSize37m),
590 "38m" => Ok(Self::WindowSize38m),
591 "39m" => Ok(Self::WindowSize39m),
592 "40m" => Ok(Self::WindowSize40m),
593 "41m" => Ok(Self::WindowSize41m),
594 "42m" => Ok(Self::WindowSize42m),
595 "43m" => Ok(Self::WindowSize43m),
596 "44m" => Ok(Self::WindowSize44m),
597 "45m" => Ok(Self::WindowSize45m),
598 "46m" => Ok(Self::WindowSize46m),
599 "47m" => Ok(Self::WindowSize47m),
600 "48m" => Ok(Self::WindowSize48m),
601 "49m" => Ok(Self::WindowSize49m),
602 "50m" => Ok(Self::WindowSize50m),
603 "51m" => Ok(Self::WindowSize51m),
604 "52m" => Ok(Self::WindowSize52m),
605 "53m" => Ok(Self::WindowSize53m),
606 "54m" => Ok(Self::WindowSize54m),
607 "55m" => Ok(Self::WindowSize55m),
608 "56m" => Ok(Self::WindowSize56m),
609 "57m" => Ok(Self::WindowSize57m),
610 "58m" => Ok(Self::WindowSize58m),
611 "59m" => Ok(Self::WindowSize59m),
612 "1h" => Ok(Self::WindowSize1h),
613 "2h" => Ok(Self::WindowSize2h),
614 "3h" => Ok(Self::WindowSize3h),
615 "4h" => Ok(Self::WindowSize4h),
616 "5h" => Ok(Self::WindowSize5h),
617 "6h" => Ok(Self::WindowSize6h),
618 "7h" => Ok(Self::WindowSize7h),
619 "8h" => Ok(Self::WindowSize8h),
620 "9h" => Ok(Self::WindowSize9h),
621 "10h" => Ok(Self::WindowSize10h),
622 "11h" => Ok(Self::WindowSize11h),
623 "12h" => Ok(Self::WindowSize12h),
624 "13h" => Ok(Self::WindowSize13h),
625 "14h" => Ok(Self::WindowSize14h),
626 "15h" => Ok(Self::WindowSize15h),
627 "16h" => Ok(Self::WindowSize16h),
628 "17h" => Ok(Self::WindowSize17h),
629 "18h" => Ok(Self::WindowSize18h),
630 "19h" => Ok(Self::WindowSize19h),
631 "20h" => Ok(Self::WindowSize20h),
632 "21h" => Ok(Self::WindowSize21h),
633 "22h" => Ok(Self::WindowSize22h),
634 "23h" => Ok(Self::WindowSize23h),
635 "1d" => Ok(Self::WindowSize1d),
636 "2d" => Ok(Self::WindowSize2d),
637 "3d" => Ok(Self::WindowSize3d),
638 "4d" => Ok(Self::WindowSize4d),
639 "5d" => Ok(Self::WindowSize5d),
640 "6d" => Ok(Self::WindowSize6d),
641 "7d" => Ok(Self::WindowSize7d),
642 other => Err(format!("invalid TickerWindowSizeEnum: {}", other).into()),
643 }
644 }
645}
646
647#[allow(non_camel_case_types)]
648#[derive(Debug, Clone, Serialize, Deserialize)]
649pub enum TickerTypeEnum {
650 #[serde(rename = "FULL")]
651 Full,
652 #[serde(rename = "MINI")]
653 Mini,
654}
655
656impl TickerTypeEnum {
657 #[must_use]
658 pub fn as_str(&self) -> &'static str {
659 match self {
660 Self::Full => "FULL",
661 Self::Mini => "MINI",
662 }
663 }
664}
665
666impl std::str::FromStr for TickerTypeEnum {
667 type Err = Box<dyn std::error::Error + Send + Sync>;
668
669 fn from_str(s: &str) -> Result<Self, Self::Err> {
670 match s {
671 "FULL" => Ok(Self::Full),
672 "MINI" => Ok(Self::Mini),
673 other => Err(format!("invalid TickerTypeEnum: {}", other).into()),
674 }
675 }
676}
677
678#[allow(non_camel_case_types)]
679#[derive(Debug, Clone, Serialize, Deserialize)]
680pub enum TickerSymbolStatusEnum {
681 #[serde(rename = "TRADING")]
682 Trading,
683 #[serde(rename = "HALT")]
684 Halt,
685 #[serde(rename = "BREAK")]
686 Break,
687}
688
689impl TickerSymbolStatusEnum {
690 #[must_use]
691 pub fn as_str(&self) -> &'static str {
692 match self {
693 Self::Trading => "TRADING",
694 Self::Halt => "HALT",
695 Self::Break => "BREAK",
696 }
697 }
698}
699
700impl std::str::FromStr for TickerSymbolStatusEnum {
701 type Err = Box<dyn std::error::Error + Send + Sync>;
702
703 fn from_str(s: &str) -> Result<Self, Self::Err> {
704 match s {
705 "TRADING" => Ok(Self::Trading),
706 "HALT" => Ok(Self::Halt),
707 "BREAK" => Ok(Self::Break),
708 other => Err(format!("invalid TickerSymbolStatusEnum: {}", other).into()),
709 }
710 }
711}
712
713#[allow(non_camel_case_types)]
714#[derive(Debug, Clone, Serialize, Deserialize)]
715pub enum Ticker24hrTypeEnum {
716 #[serde(rename = "FULL")]
717 Full,
718 #[serde(rename = "MINI")]
719 Mini,
720}
721
722impl Ticker24hrTypeEnum {
723 #[must_use]
724 pub fn as_str(&self) -> &'static str {
725 match self {
726 Self::Full => "FULL",
727 Self::Mini => "MINI",
728 }
729 }
730}
731
732impl std::str::FromStr for Ticker24hrTypeEnum {
733 type Err = Box<dyn std::error::Error + Send + Sync>;
734
735 fn from_str(s: &str) -> Result<Self, Self::Err> {
736 match s {
737 "FULL" => Ok(Self::Full),
738 "MINI" => Ok(Self::Mini),
739 other => Err(format!("invalid Ticker24hrTypeEnum: {}", other).into()),
740 }
741 }
742}
743
744#[allow(non_camel_case_types)]
745#[derive(Debug, Clone, Serialize, Deserialize)]
746pub enum Ticker24hrSymbolStatusEnum {
747 #[serde(rename = "TRADING")]
748 Trading,
749 #[serde(rename = "HALT")]
750 Halt,
751 #[serde(rename = "BREAK")]
752 Break,
753}
754
755impl Ticker24hrSymbolStatusEnum {
756 #[must_use]
757 pub fn as_str(&self) -> &'static str {
758 match self {
759 Self::Trading => "TRADING",
760 Self::Halt => "HALT",
761 Self::Break => "BREAK",
762 }
763 }
764}
765
766impl std::str::FromStr for Ticker24hrSymbolStatusEnum {
767 type Err = Box<dyn std::error::Error + Send + Sync>;
768
769 fn from_str(s: &str) -> Result<Self, Self::Err> {
770 match s {
771 "TRADING" => Ok(Self::Trading),
772 "HALT" => Ok(Self::Halt),
773 "BREAK" => Ok(Self::Break),
774 other => Err(format!("invalid Ticker24hrSymbolStatusEnum: {}", other).into()),
775 }
776 }
777}
778
779#[allow(non_camel_case_types)]
780#[derive(Debug, Clone, Serialize, Deserialize)]
781pub enum TickerBookTickerSymbolStatusEnum {
782 #[serde(rename = "TRADING")]
783 Trading,
784 #[serde(rename = "HALT")]
785 Halt,
786 #[serde(rename = "BREAK")]
787 Break,
788}
789
790impl TickerBookTickerSymbolStatusEnum {
791 #[must_use]
792 pub fn as_str(&self) -> &'static str {
793 match self {
794 Self::Trading => "TRADING",
795 Self::Halt => "HALT",
796 Self::Break => "BREAK",
797 }
798 }
799}
800
801impl std::str::FromStr for TickerBookTickerSymbolStatusEnum {
802 type Err = Box<dyn std::error::Error + Send + Sync>;
803
804 fn from_str(s: &str) -> Result<Self, Self::Err> {
805 match s {
806 "TRADING" => Ok(Self::Trading),
807 "HALT" => Ok(Self::Halt),
808 "BREAK" => Ok(Self::Break),
809 other => Err(format!("invalid TickerBookTickerSymbolStatusEnum: {}", other).into()),
810 }
811 }
812}
813
814#[allow(non_camel_case_types)]
815#[derive(Debug, Clone, Serialize, Deserialize)]
816pub enum TickerPriceSymbolStatusEnum {
817 #[serde(rename = "TRADING")]
818 Trading,
819 #[serde(rename = "HALT")]
820 Halt,
821 #[serde(rename = "BREAK")]
822 Break,
823}
824
825impl TickerPriceSymbolStatusEnum {
826 #[must_use]
827 pub fn as_str(&self) -> &'static str {
828 match self {
829 Self::Trading => "TRADING",
830 Self::Halt => "HALT",
831 Self::Break => "BREAK",
832 }
833 }
834}
835
836impl std::str::FromStr for TickerPriceSymbolStatusEnum {
837 type Err = Box<dyn std::error::Error + Send + Sync>;
838
839 fn from_str(s: &str) -> Result<Self, Self::Err> {
840 match s {
841 "TRADING" => Ok(Self::Trading),
842 "HALT" => Ok(Self::Halt),
843 "BREAK" => Ok(Self::Break),
844 other => Err(format!("invalid TickerPriceSymbolStatusEnum: {}", other).into()),
845 }
846 }
847}
848
849#[allow(non_camel_case_types)]
850#[derive(Debug, Clone, Serialize, Deserialize)]
851pub enum TickerTradingDayTypeEnum {
852 #[serde(rename = "FULL")]
853 Full,
854 #[serde(rename = "MINI")]
855 Mini,
856}
857
858impl TickerTradingDayTypeEnum {
859 #[must_use]
860 pub fn as_str(&self) -> &'static str {
861 match self {
862 Self::Full => "FULL",
863 Self::Mini => "MINI",
864 }
865 }
866}
867
868impl std::str::FromStr for TickerTradingDayTypeEnum {
869 type Err = Box<dyn std::error::Error + Send + Sync>;
870
871 fn from_str(s: &str) -> Result<Self, Self::Err> {
872 match s {
873 "FULL" => Ok(Self::Full),
874 "MINI" => Ok(Self::Mini),
875 other => Err(format!("invalid TickerTradingDayTypeEnum: {}", other).into()),
876 }
877 }
878}
879
880#[allow(non_camel_case_types)]
881#[derive(Debug, Clone, Serialize, Deserialize)]
882pub enum TickerTradingDaySymbolStatusEnum {
883 #[serde(rename = "TRADING")]
884 Trading,
885 #[serde(rename = "HALT")]
886 Halt,
887 #[serde(rename = "BREAK")]
888 Break,
889}
890
891impl TickerTradingDaySymbolStatusEnum {
892 #[must_use]
893 pub fn as_str(&self) -> &'static str {
894 match self {
895 Self::Trading => "TRADING",
896 Self::Halt => "HALT",
897 Self::Break => "BREAK",
898 }
899 }
900}
901
902impl std::str::FromStr for TickerTradingDaySymbolStatusEnum {
903 type Err = Box<dyn std::error::Error + Send + Sync>;
904
905 fn from_str(s: &str) -> Result<Self, Self::Err> {
906 match s {
907 "TRADING" => Ok(Self::Trading),
908 "HALT" => Ok(Self::Halt),
909 "BREAK" => Ok(Self::Break),
910 other => Err(format!("invalid TickerTradingDaySymbolStatusEnum: {}", other).into()),
911 }
912 }
913}
914
915#[allow(non_camel_case_types)]
916#[derive(Debug, Clone, Serialize, Deserialize)]
917pub enum UiKlinesIntervalEnum {
918 #[serde(rename = "1s")]
919 Interval1s,
920 #[serde(rename = "1m")]
921 Interval1m,
922 #[serde(rename = "3m")]
923 Interval3m,
924 #[serde(rename = "5m")]
925 Interval5m,
926 #[serde(rename = "15m")]
927 Interval15m,
928 #[serde(rename = "30m")]
929 Interval30m,
930 #[serde(rename = "1h")]
931 Interval1h,
932 #[serde(rename = "2h")]
933 Interval2h,
934 #[serde(rename = "4h")]
935 Interval4h,
936 #[serde(rename = "6h")]
937 Interval6h,
938 #[serde(rename = "8h")]
939 Interval8h,
940 #[serde(rename = "12h")]
941 Interval12h,
942 #[serde(rename = "1d")]
943 Interval1d,
944 #[serde(rename = "3d")]
945 Interval3d,
946 #[serde(rename = "1w")]
947 Interval1w,
948 #[serde(rename = "1M")]
949 Interval1M,
950}
951
952impl UiKlinesIntervalEnum {
953 #[must_use]
954 pub fn as_str(&self) -> &'static str {
955 match self {
956 Self::Interval1s => "1s",
957 Self::Interval1m => "1m",
958 Self::Interval3m => "3m",
959 Self::Interval5m => "5m",
960 Self::Interval15m => "15m",
961 Self::Interval30m => "30m",
962 Self::Interval1h => "1h",
963 Self::Interval2h => "2h",
964 Self::Interval4h => "4h",
965 Self::Interval6h => "6h",
966 Self::Interval8h => "8h",
967 Self::Interval12h => "12h",
968 Self::Interval1d => "1d",
969 Self::Interval3d => "3d",
970 Self::Interval1w => "1w",
971 Self::Interval1M => "1M",
972 }
973 }
974}
975
976impl std::str::FromStr for UiKlinesIntervalEnum {
977 type Err = Box<dyn std::error::Error + Send + Sync>;
978
979 fn from_str(s: &str) -> Result<Self, Self::Err> {
980 match s {
981 "1s" => Ok(Self::Interval1s),
982 "1m" => Ok(Self::Interval1m),
983 "3m" => Ok(Self::Interval3m),
984 "5m" => Ok(Self::Interval5m),
985 "15m" => Ok(Self::Interval15m),
986 "30m" => Ok(Self::Interval30m),
987 "1h" => Ok(Self::Interval1h),
988 "2h" => Ok(Self::Interval2h),
989 "4h" => Ok(Self::Interval4h),
990 "6h" => Ok(Self::Interval6h),
991 "8h" => Ok(Self::Interval8h),
992 "12h" => Ok(Self::Interval12h),
993 "1d" => Ok(Self::Interval1d),
994 "3d" => Ok(Self::Interval3d),
995 "1w" => Ok(Self::Interval1w),
996 "1M" => Ok(Self::Interval1M),
997 other => Err(format!("invalid UiKlinesIntervalEnum: {}", other).into()),
998 }
999 }
1000}
1001
1002#[derive(Clone, Debug, Builder, Deserialize)]
1007#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1008pub struct AggTradesParams {
1009 #[builder(setter(into))]
1014 #[serde(rename = "symbol")]
1015 pub symbol: String,
1016 #[builder(setter(into), default)]
1020 #[serde(rename = "fromId", default)]
1021 pub from_id: Option<i64>,
1022 #[builder(setter(into), default)]
1026 #[serde(rename = "startTime", default)]
1027 pub start_time: Option<i64>,
1028 #[builder(setter(into), default)]
1032 #[serde(rename = "endTime", default)]
1033 pub end_time: Option<i64>,
1034 #[builder(setter(into), default)]
1039 #[serde(rename = "limit", default)]
1040 pub limit: Option<i32>,
1041}
1042
1043impl AggTradesParams {
1044 #[must_use]
1051 pub fn builder(symbol: String) -> AggTradesParamsBuilder {
1052 AggTradesParamsBuilder::default().symbol(symbol)
1053 }
1054}
1055#[derive(Clone, Debug, Builder, Deserialize)]
1060#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1061pub struct AvgPriceParams {
1062 #[builder(setter(into))]
1067 #[serde(rename = "symbol")]
1068 pub symbol: String,
1069}
1070
1071impl AvgPriceParams {
1072 #[must_use]
1079 pub fn builder(symbol: String) -> AvgPriceParamsBuilder {
1080 AvgPriceParamsBuilder::default().symbol(symbol)
1081 }
1082}
1083#[derive(Clone, Debug, Builder, Deserialize)]
1088#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1089pub struct DepthParams {
1090 #[builder(setter(into))]
1095 #[serde(rename = "symbol")]
1096 pub symbol: String,
1097 #[builder(setter(into), default)]
1101 #[serde(rename = "limit", default)]
1102 pub limit: Option<i32>,
1103 #[builder(setter(into), default)]
1108 #[serde(rename = "symbolStatus", default)]
1109 pub symbol_status: Option<DepthSymbolStatusEnum>,
1110}
1111
1112impl DepthParams {
1113 #[must_use]
1120 pub fn builder(symbol: String) -> DepthParamsBuilder {
1121 DepthParamsBuilder::default().symbol(symbol)
1122 }
1123}
1124#[derive(Clone, Debug, Builder, Deserialize)]
1129#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1130pub struct GetTradesParams {
1131 #[builder(setter(into))]
1136 #[serde(rename = "symbol")]
1137 pub symbol: String,
1138 #[builder(setter(into), default)]
1143 #[serde(rename = "limit", default)]
1144 pub limit: Option<i32>,
1145}
1146
1147impl GetTradesParams {
1148 #[must_use]
1155 pub fn builder(symbol: String) -> GetTradesParamsBuilder {
1156 GetTradesParamsBuilder::default().symbol(symbol)
1157 }
1158}
1159#[derive(Clone, Debug, Builder, Deserialize)]
1164#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1165pub struct HistoricalBlockTradesParams {
1166 #[builder(setter(into))]
1171 #[serde(rename = "symbol")]
1172 pub symbol: String,
1173 #[builder(setter(into))]
1177 #[serde(rename = "fromId")]
1178 pub from_id: i64,
1179 #[builder(setter(into), default)]
1183 #[serde(rename = "limit", default)]
1184 pub limit: Option<i64>,
1185}
1186
1187impl HistoricalBlockTradesParams {
1188 #[must_use]
1196 pub fn builder(symbol: String, from_id: i64) -> HistoricalBlockTradesParamsBuilder {
1197 HistoricalBlockTradesParamsBuilder::default()
1198 .symbol(symbol)
1199 .from_id(from_id)
1200 }
1201}
1202#[derive(Clone, Debug, Builder, Deserialize)]
1207#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1208pub struct HistoricalTradesParams {
1209 #[builder(setter(into))]
1214 #[serde(rename = "symbol")]
1215 pub symbol: String,
1216 #[builder(setter(into), default)]
1221 #[serde(rename = "limit", default)]
1222 pub limit: Option<i32>,
1223 #[builder(setter(into), default)]
1227 #[serde(rename = "fromId", default)]
1228 pub from_id: Option<i64>,
1229}
1230
1231impl HistoricalTradesParams {
1232 #[must_use]
1239 pub fn builder(symbol: String) -> HistoricalTradesParamsBuilder {
1240 HistoricalTradesParamsBuilder::default().symbol(symbol)
1241 }
1242}
1243#[derive(Clone, Debug, Builder, Deserialize)]
1248#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1249pub struct KlinesParams {
1250 #[builder(setter(into))]
1255 #[serde(rename = "symbol")]
1256 pub symbol: String,
1257 #[builder(setter(into))]
1262 #[serde(rename = "interval")]
1263 pub interval: KlinesIntervalEnum,
1264 #[builder(setter(into), default)]
1269 #[serde(rename = "startTime", default)]
1270 pub start_time: Option<i64>,
1271 #[builder(setter(into), default)]
1276 #[serde(rename = "endTime", default)]
1277 pub end_time: Option<i64>,
1278 #[builder(setter(into), default)]
1282 #[serde(rename = "timeZone", default)]
1283 pub time_zone: Option<String>,
1284 #[builder(setter(into), default)]
1289 #[serde(rename = "limit", default)]
1290 pub limit: Option<i32>,
1291}
1292
1293impl KlinesParams {
1294 #[must_use]
1302 pub fn builder(symbol: String, interval: KlinesIntervalEnum) -> KlinesParamsBuilder {
1303 KlinesParamsBuilder::default()
1304 .symbol(symbol)
1305 .interval(interval)
1306 }
1307}
1308#[derive(Clone, Debug, Builder, Deserialize)]
1313#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1314pub struct ReferencePriceParams {
1315 #[builder(setter(into))]
1320 #[serde(rename = "symbol")]
1321 pub symbol: String,
1322}
1323
1324impl ReferencePriceParams {
1325 #[must_use]
1332 pub fn builder(symbol: String) -> ReferencePriceParamsBuilder {
1333 ReferencePriceParamsBuilder::default().symbol(symbol)
1334 }
1335}
1336#[derive(Clone, Debug, Builder, Deserialize)]
1341#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1342pub struct ReferencePriceCalculationParams {
1343 #[builder(setter(into))]
1348 #[serde(rename = "symbol")]
1349 pub symbol: String,
1350 #[builder(setter(into), default)]
1354 #[serde(rename = "symbolStatus", default)]
1355 pub symbol_status: Option<ReferencePriceCalculationSymbolStatusEnum>,
1356}
1357
1358impl ReferencePriceCalculationParams {
1359 #[must_use]
1366 pub fn builder(symbol: String) -> ReferencePriceCalculationParamsBuilder {
1367 ReferencePriceCalculationParamsBuilder::default().symbol(symbol)
1368 }
1369}
1370#[derive(Clone, Debug, Builder, Deserialize, Default)]
1375#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1376pub struct TickerParams {
1377 #[builder(setter(into), default)]
1381 #[serde(rename = "symbol", default)]
1382 pub symbol: Option<String>,
1383 #[builder(setter(into), default)]
1391 #[serde(rename = "symbols", default)]
1392 pub symbols: Option<Vec<String>>,
1393 #[builder(setter(into), default)]
1397 #[serde(rename = "windowSize", default)]
1398 pub window_size: Option<TickerWindowSizeEnum>,
1399 #[builder(setter(into), default)]
1404 #[serde(rename = "type", default)]
1405 pub r#type: Option<TickerTypeEnum>,
1406 #[builder(setter(into), default)]
1411 #[serde(rename = "symbolStatus", default)]
1412 pub symbol_status: Option<TickerSymbolStatusEnum>,
1413}
1414
1415impl TickerParams {
1416 #[must_use]
1419 pub fn builder() -> TickerParamsBuilder {
1420 TickerParamsBuilder::default()
1421 }
1422}
1423#[derive(Clone, Debug, Builder, Deserialize, Default)]
1428#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1429pub struct Ticker24hrParams {
1430 #[builder(setter(into), default)]
1434 #[serde(rename = "symbol", default)]
1435 pub symbol: Option<String>,
1436 #[builder(setter(into), default)]
1444 #[serde(rename = "symbols", default)]
1445 pub symbols: Option<Vec<String>>,
1446 #[builder(setter(into), default)]
1451 #[serde(rename = "type", default)]
1452 pub r#type: Option<Ticker24hrTypeEnum>,
1453 #[builder(setter(into), default)]
1458 #[serde(rename = "symbolStatus", default)]
1459 pub symbol_status: Option<Ticker24hrSymbolStatusEnum>,
1460}
1461
1462impl Ticker24hrParams {
1463 #[must_use]
1466 pub fn builder() -> Ticker24hrParamsBuilder {
1467 Ticker24hrParamsBuilder::default()
1468 }
1469}
1470#[derive(Clone, Debug, Builder, Deserialize, Default)]
1475#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1476pub struct TickerBookTickerParams {
1477 #[builder(setter(into), default)]
1482 #[serde(rename = "symbol", default)]
1483 pub symbol: Option<String>,
1484 #[builder(setter(into), default)]
1490 #[serde(rename = "symbols", default)]
1491 pub symbols: Option<Vec<String>>,
1492 #[builder(setter(into), default)]
1498 #[serde(rename = "symbolStatus", default)]
1499 pub symbol_status: Option<TickerBookTickerSymbolStatusEnum>,
1500}
1501
1502impl TickerBookTickerParams {
1503 #[must_use]
1506 pub fn builder() -> TickerBookTickerParamsBuilder {
1507 TickerBookTickerParamsBuilder::default()
1508 }
1509}
1510#[derive(Clone, Debug, Builder, Deserialize, Default)]
1515#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1516pub struct TickerPriceParams {
1517 #[builder(setter(into), default)]
1522 #[serde(rename = "symbol", default)]
1523 pub symbol: Option<String>,
1524 #[builder(setter(into), default)]
1530 #[serde(rename = "symbols", default)]
1531 pub symbols: Option<Vec<String>>,
1532 #[builder(setter(into), default)]
1538 #[serde(rename = "symbolStatus", default)]
1539 pub symbol_status: Option<TickerPriceSymbolStatusEnum>,
1540}
1541
1542impl TickerPriceParams {
1543 #[must_use]
1546 pub fn builder() -> TickerPriceParamsBuilder {
1547 TickerPriceParamsBuilder::default()
1548 }
1549}
1550#[derive(Clone, Debug, Builder, Deserialize, Default)]
1555#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1556pub struct TickerTradingDayParams {
1557 #[builder(setter(into), default)]
1561 #[serde(rename = "symbol", default)]
1562 pub symbol: Option<String>,
1563 #[builder(setter(into), default)]
1569 #[serde(rename = "symbols", default)]
1570 pub symbols: Option<Vec<String>>,
1571 #[builder(setter(into), default)]
1575 #[serde(rename = "timeZone", default)]
1576 pub time_zone: Option<String>,
1577 #[builder(setter(into), default)]
1582 #[serde(rename = "type", default)]
1583 pub r#type: Option<TickerTradingDayTypeEnum>,
1584 #[builder(setter(into), default)]
1590 #[serde(rename = "symbolStatus", default)]
1591 pub symbol_status: Option<TickerTradingDaySymbolStatusEnum>,
1592}
1593
1594impl TickerTradingDayParams {
1595 #[must_use]
1598 pub fn builder() -> TickerTradingDayParamsBuilder {
1599 TickerTradingDayParamsBuilder::default()
1600 }
1601}
1602#[derive(Clone, Debug, Builder, Deserialize)]
1607#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1608pub struct UiKlinesParams {
1609 #[builder(setter(into))]
1614 #[serde(rename = "symbol")]
1615 pub symbol: String,
1616 #[builder(setter(into))]
1621 #[serde(rename = "interval")]
1622 pub interval: UiKlinesIntervalEnum,
1623 #[builder(setter(into), default)]
1628 #[serde(rename = "startTime", default)]
1629 pub start_time: Option<i64>,
1630 #[builder(setter(into), default)]
1635 #[serde(rename = "endTime", default)]
1636 pub end_time: Option<i64>,
1637 #[builder(setter(into), default)]
1641 #[serde(rename = "timeZone", default)]
1642 pub time_zone: Option<String>,
1643 #[builder(setter(into), default)]
1648 #[serde(rename = "limit", default)]
1649 pub limit: Option<i32>,
1650}
1651
1652impl UiKlinesParams {
1653 #[must_use]
1661 pub fn builder(symbol: String, interval: UiKlinesIntervalEnum) -> UiKlinesParamsBuilder {
1662 UiKlinesParamsBuilder::default()
1663 .symbol(symbol)
1664 .interval(interval)
1665 }
1666}
1667
1668#[async_trait]
1669impl MarketApi for MarketApiClient {
1670 async fn agg_trades(
1671 &self,
1672 params: AggTradesParams,
1673 ) -> anyhow::Result<RestApiResponse<Vec<models::AggTradesResponseInner>>> {
1674 let AggTradesParams {
1675 symbol,
1676 from_id,
1677 start_time,
1678 end_time,
1679 limit,
1680 } = params;
1681
1682 let mut query_params = BTreeMap::new();
1683 let body_params = BTreeMap::new();
1684
1685 query_params.insert("symbol".to_string(), json!(symbol));
1686
1687 if let Some(rw) = from_id {
1688 query_params.insert("fromId".to_string(), json!(rw));
1689 }
1690
1691 if let Some(rw) = start_time {
1692 query_params.insert("startTime".to_string(), json!(rw));
1693 }
1694
1695 if let Some(rw) = end_time {
1696 query_params.insert("endTime".to_string(), json!(rw));
1697 }
1698
1699 if let Some(rw) = limit {
1700 query_params.insert("limit".to_string(), json!(rw));
1701 }
1702
1703 send_request::<Vec<models::AggTradesResponseInner>>(
1704 &self.configuration,
1705 "/api/v3/aggTrades",
1706 reqwest::Method::GET,
1707 query_params,
1708 body_params,
1709 if HAS_TIME_UNIT {
1710 self.configuration.time_unit
1711 } else {
1712 None
1713 },
1714 false,
1715 )
1716 .await
1717 }
1718
1719 async fn avg_price(
1720 &self,
1721 params: AvgPriceParams,
1722 ) -> anyhow::Result<RestApiResponse<models::AvgPriceResponse>> {
1723 let AvgPriceParams { symbol } = params;
1724
1725 let mut query_params = BTreeMap::new();
1726 let body_params = BTreeMap::new();
1727
1728 query_params.insert("symbol".to_string(), json!(symbol));
1729
1730 send_request::<models::AvgPriceResponse>(
1731 &self.configuration,
1732 "/api/v3/avgPrice",
1733 reqwest::Method::GET,
1734 query_params,
1735 body_params,
1736 if HAS_TIME_UNIT {
1737 self.configuration.time_unit
1738 } else {
1739 None
1740 },
1741 false,
1742 )
1743 .await
1744 }
1745
1746 async fn depth(
1747 &self,
1748 params: DepthParams,
1749 ) -> anyhow::Result<RestApiResponse<models::DepthResponse>> {
1750 let DepthParams {
1751 symbol,
1752 limit,
1753 symbol_status,
1754 } = params;
1755
1756 let mut query_params = BTreeMap::new();
1757 let body_params = BTreeMap::new();
1758
1759 query_params.insert("symbol".to_string(), json!(symbol));
1760
1761 if let Some(rw) = limit {
1762 query_params.insert("limit".to_string(), json!(rw));
1763 }
1764
1765 if let Some(rw) = symbol_status {
1766 query_params.insert("symbolStatus".to_string(), json!(rw));
1767 }
1768
1769 send_request::<models::DepthResponse>(
1770 &self.configuration,
1771 "/api/v3/depth",
1772 reqwest::Method::GET,
1773 query_params,
1774 body_params,
1775 if HAS_TIME_UNIT {
1776 self.configuration.time_unit
1777 } else {
1778 None
1779 },
1780 false,
1781 )
1782 .await
1783 }
1784
1785 async fn get_trades(
1786 &self,
1787 params: GetTradesParams,
1788 ) -> anyhow::Result<RestApiResponse<Vec<models::GetTradesResponseInner>>> {
1789 let GetTradesParams { symbol, limit } = params;
1790
1791 let mut query_params = BTreeMap::new();
1792 let body_params = BTreeMap::new();
1793
1794 query_params.insert("symbol".to_string(), json!(symbol));
1795
1796 if let Some(rw) = limit {
1797 query_params.insert("limit".to_string(), json!(rw));
1798 }
1799
1800 send_request::<Vec<models::GetTradesResponseInner>>(
1801 &self.configuration,
1802 "/api/v3/trades",
1803 reqwest::Method::GET,
1804 query_params,
1805 body_params,
1806 if HAS_TIME_UNIT {
1807 self.configuration.time_unit
1808 } else {
1809 None
1810 },
1811 false,
1812 )
1813 .await
1814 }
1815
1816 async fn historical_block_trades(
1817 &self,
1818 params: HistoricalBlockTradesParams,
1819 ) -> anyhow::Result<RestApiResponse<Vec<models::HistoricalBlockTradesResponseInner>>> {
1820 let HistoricalBlockTradesParams {
1821 symbol,
1822 from_id,
1823 limit,
1824 } = params;
1825
1826 let mut query_params = BTreeMap::new();
1827 let body_params = BTreeMap::new();
1828
1829 query_params.insert("symbol".to_string(), json!(symbol));
1830
1831 query_params.insert("fromId".to_string(), json!(from_id));
1832
1833 if let Some(rw) = limit {
1834 query_params.insert("limit".to_string(), json!(rw));
1835 }
1836
1837 send_request::<Vec<models::HistoricalBlockTradesResponseInner>>(
1838 &self.configuration,
1839 "/api/v3/historicalBlockTrades",
1840 reqwest::Method::GET,
1841 query_params,
1842 body_params,
1843 if HAS_TIME_UNIT {
1844 self.configuration.time_unit
1845 } else {
1846 None
1847 },
1848 false,
1849 )
1850 .await
1851 }
1852
1853 async fn historical_trades(
1854 &self,
1855 params: HistoricalTradesParams,
1856 ) -> anyhow::Result<RestApiResponse<Vec<models::GetTradesResponseInner>>> {
1857 let HistoricalTradesParams {
1858 symbol,
1859 limit,
1860 from_id,
1861 } = params;
1862
1863 let mut query_params = BTreeMap::new();
1864 let body_params = BTreeMap::new();
1865
1866 query_params.insert("symbol".to_string(), json!(symbol));
1867
1868 if let Some(rw) = limit {
1869 query_params.insert("limit".to_string(), json!(rw));
1870 }
1871
1872 if let Some(rw) = from_id {
1873 query_params.insert("fromId".to_string(), json!(rw));
1874 }
1875
1876 send_request::<Vec<models::GetTradesResponseInner>>(
1877 &self.configuration,
1878 "/api/v3/historicalTrades",
1879 reqwest::Method::GET,
1880 query_params,
1881 body_params,
1882 if HAS_TIME_UNIT {
1883 self.configuration.time_unit
1884 } else {
1885 None
1886 },
1887 false,
1888 )
1889 .await
1890 }
1891
1892 async fn klines(
1893 &self,
1894 params: KlinesParams,
1895 ) -> anyhow::Result<RestApiResponse<Vec<Vec<models::KlinesItemInner>>>> {
1896 let KlinesParams {
1897 symbol,
1898 interval,
1899 start_time,
1900 end_time,
1901 time_zone,
1902 limit,
1903 } = params;
1904
1905 let mut query_params = BTreeMap::new();
1906 let body_params = BTreeMap::new();
1907
1908 query_params.insert("symbol".to_string(), json!(symbol));
1909
1910 query_params.insert("interval".to_string(), json!(interval));
1911
1912 if let Some(rw) = start_time {
1913 query_params.insert("startTime".to_string(), json!(rw));
1914 }
1915
1916 if let Some(rw) = end_time {
1917 query_params.insert("endTime".to_string(), json!(rw));
1918 }
1919
1920 if let Some(rw) = time_zone {
1921 query_params.insert("timeZone".to_string(), json!(rw));
1922 }
1923
1924 if let Some(rw) = limit {
1925 query_params.insert("limit".to_string(), json!(rw));
1926 }
1927
1928 send_request::<Vec<Vec<models::KlinesItemInner>>>(
1929 &self.configuration,
1930 "/api/v3/klines",
1931 reqwest::Method::GET,
1932 query_params,
1933 body_params,
1934 if HAS_TIME_UNIT {
1935 self.configuration.time_unit
1936 } else {
1937 None
1938 },
1939 false,
1940 )
1941 .await
1942 }
1943
1944 async fn reference_price(
1945 &self,
1946 params: ReferencePriceParams,
1947 ) -> anyhow::Result<RestApiResponse<models::ReferencePriceResponse>> {
1948 let ReferencePriceParams { symbol } = params;
1949
1950 let mut query_params = BTreeMap::new();
1951 let body_params = BTreeMap::new();
1952
1953 query_params.insert("symbol".to_string(), json!(symbol));
1954
1955 send_request::<models::ReferencePriceResponse>(
1956 &self.configuration,
1957 "/api/v3/referencePrice",
1958 reqwest::Method::GET,
1959 query_params,
1960 body_params,
1961 if HAS_TIME_UNIT {
1962 self.configuration.time_unit
1963 } else {
1964 None
1965 },
1966 false,
1967 )
1968 .await
1969 }
1970
1971 async fn reference_price_calculation(
1972 &self,
1973 params: ReferencePriceCalculationParams,
1974 ) -> anyhow::Result<RestApiResponse<models::ReferencePriceCalculationResponse>> {
1975 let ReferencePriceCalculationParams {
1976 symbol,
1977 symbol_status,
1978 } = params;
1979
1980 let mut query_params = BTreeMap::new();
1981 let body_params = BTreeMap::new();
1982
1983 query_params.insert("symbol".to_string(), json!(symbol));
1984
1985 if let Some(rw) = symbol_status {
1986 query_params.insert("symbolStatus".to_string(), json!(rw));
1987 }
1988
1989 send_request::<models::ReferencePriceCalculationResponse>(
1990 &self.configuration,
1991 "/api/v3/referencePrice/calculation",
1992 reqwest::Method::GET,
1993 query_params,
1994 body_params,
1995 if HAS_TIME_UNIT {
1996 self.configuration.time_unit
1997 } else {
1998 None
1999 },
2000 false,
2001 )
2002 .await
2003 }
2004
2005 async fn ticker(
2006 &self,
2007 params: TickerParams,
2008 ) -> anyhow::Result<RestApiResponse<models::TickerResponse>> {
2009 let TickerParams {
2010 symbol,
2011 symbols,
2012 window_size,
2013 r#type,
2014 symbol_status,
2015 } = params;
2016
2017 let mut query_params = BTreeMap::new();
2018 let body_params = BTreeMap::new();
2019
2020 if let Some(rw) = symbol {
2021 query_params.insert("symbol".to_string(), json!(rw));
2022 }
2023
2024 if let Some(rw) = symbols {
2025 query_params.insert("symbols".to_string(), json!(rw));
2026 }
2027
2028 if let Some(rw) = window_size {
2029 query_params.insert("windowSize".to_string(), json!(rw));
2030 }
2031
2032 if let Some(rw) = r#type {
2033 query_params.insert("type".to_string(), json!(rw));
2034 }
2035
2036 if let Some(rw) = symbol_status {
2037 query_params.insert("symbolStatus".to_string(), json!(rw));
2038 }
2039
2040 send_request::<models::TickerResponse>(
2041 &self.configuration,
2042 "/api/v3/ticker",
2043 reqwest::Method::GET,
2044 query_params,
2045 body_params,
2046 if HAS_TIME_UNIT {
2047 self.configuration.time_unit
2048 } else {
2049 None
2050 },
2051 false,
2052 )
2053 .await
2054 }
2055
2056 async fn ticker24hr(
2057 &self,
2058 params: Ticker24hrParams,
2059 ) -> anyhow::Result<RestApiResponse<models::Ticker24hrResponse>> {
2060 let Ticker24hrParams {
2061 symbol,
2062 symbols,
2063 r#type,
2064 symbol_status,
2065 } = params;
2066
2067 let mut query_params = BTreeMap::new();
2068 let body_params = BTreeMap::new();
2069
2070 if let Some(rw) = symbol {
2071 query_params.insert("symbol".to_string(), json!(rw));
2072 }
2073
2074 if let Some(rw) = symbols {
2075 query_params.insert("symbols".to_string(), json!(rw));
2076 }
2077
2078 if let Some(rw) = r#type {
2079 query_params.insert("type".to_string(), json!(rw));
2080 }
2081
2082 if let Some(rw) = symbol_status {
2083 query_params.insert("symbolStatus".to_string(), json!(rw));
2084 }
2085
2086 send_request::<models::Ticker24hrResponse>(
2087 &self.configuration,
2088 "/api/v3/ticker/24hr",
2089 reqwest::Method::GET,
2090 query_params,
2091 body_params,
2092 if HAS_TIME_UNIT {
2093 self.configuration.time_unit
2094 } else {
2095 None
2096 },
2097 false,
2098 )
2099 .await
2100 }
2101
2102 async fn ticker_book_ticker(
2103 &self,
2104 params: TickerBookTickerParams,
2105 ) -> anyhow::Result<RestApiResponse<models::TickerBookTickerResponse>> {
2106 let TickerBookTickerParams {
2107 symbol,
2108 symbols,
2109 symbol_status,
2110 } = params;
2111
2112 let mut query_params = BTreeMap::new();
2113 let body_params = BTreeMap::new();
2114
2115 if let Some(rw) = symbol {
2116 query_params.insert("symbol".to_string(), json!(rw));
2117 }
2118
2119 if let Some(rw) = symbols {
2120 query_params.insert("symbols".to_string(), json!(rw));
2121 }
2122
2123 if let Some(rw) = symbol_status {
2124 query_params.insert("symbolStatus".to_string(), json!(rw));
2125 }
2126
2127 send_request::<models::TickerBookTickerResponse>(
2128 &self.configuration,
2129 "/api/v3/ticker/bookTicker",
2130 reqwest::Method::GET,
2131 query_params,
2132 body_params,
2133 if HAS_TIME_UNIT {
2134 self.configuration.time_unit
2135 } else {
2136 None
2137 },
2138 false,
2139 )
2140 .await
2141 }
2142
2143 async fn ticker_price(
2144 &self,
2145 params: TickerPriceParams,
2146 ) -> anyhow::Result<RestApiResponse<models::TickerPriceResponse>> {
2147 let TickerPriceParams {
2148 symbol,
2149 symbols,
2150 symbol_status,
2151 } = params;
2152
2153 let mut query_params = BTreeMap::new();
2154 let body_params = BTreeMap::new();
2155
2156 if let Some(rw) = symbol {
2157 query_params.insert("symbol".to_string(), json!(rw));
2158 }
2159
2160 if let Some(rw) = symbols {
2161 query_params.insert("symbols".to_string(), json!(rw));
2162 }
2163
2164 if let Some(rw) = symbol_status {
2165 query_params.insert("symbolStatus".to_string(), json!(rw));
2166 }
2167
2168 send_request::<models::TickerPriceResponse>(
2169 &self.configuration,
2170 "/api/v3/ticker/price",
2171 reqwest::Method::GET,
2172 query_params,
2173 body_params,
2174 if HAS_TIME_UNIT {
2175 self.configuration.time_unit
2176 } else {
2177 None
2178 },
2179 false,
2180 )
2181 .await
2182 }
2183
2184 async fn ticker_trading_day(
2185 &self,
2186 params: TickerTradingDayParams,
2187 ) -> anyhow::Result<RestApiResponse<models::TickerTradingDayResponse>> {
2188 let TickerTradingDayParams {
2189 symbol,
2190 symbols,
2191 time_zone,
2192 r#type,
2193 symbol_status,
2194 } = params;
2195
2196 let mut query_params = BTreeMap::new();
2197 let body_params = BTreeMap::new();
2198
2199 if let Some(rw) = symbol {
2200 query_params.insert("symbol".to_string(), json!(rw));
2201 }
2202
2203 if let Some(rw) = symbols {
2204 query_params.insert("symbols".to_string(), json!(rw));
2205 }
2206
2207 if let Some(rw) = time_zone {
2208 query_params.insert("timeZone".to_string(), json!(rw));
2209 }
2210
2211 if let Some(rw) = r#type {
2212 query_params.insert("type".to_string(), json!(rw));
2213 }
2214
2215 if let Some(rw) = symbol_status {
2216 query_params.insert("symbolStatus".to_string(), json!(rw));
2217 }
2218
2219 send_request::<models::TickerTradingDayResponse>(
2220 &self.configuration,
2221 "/api/v3/ticker/tradingDay",
2222 reqwest::Method::GET,
2223 query_params,
2224 body_params,
2225 if HAS_TIME_UNIT {
2226 self.configuration.time_unit
2227 } else {
2228 None
2229 },
2230 false,
2231 )
2232 .await
2233 }
2234
2235 async fn ui_klines(
2236 &self,
2237 params: UiKlinesParams,
2238 ) -> anyhow::Result<RestApiResponse<Vec<Vec<models::KlinesItemInner>>>> {
2239 let UiKlinesParams {
2240 symbol,
2241 interval,
2242 start_time,
2243 end_time,
2244 time_zone,
2245 limit,
2246 } = params;
2247
2248 let mut query_params = BTreeMap::new();
2249 let body_params = BTreeMap::new();
2250
2251 query_params.insert("symbol".to_string(), json!(symbol));
2252
2253 query_params.insert("interval".to_string(), json!(interval));
2254
2255 if let Some(rw) = start_time {
2256 query_params.insert("startTime".to_string(), json!(rw));
2257 }
2258
2259 if let Some(rw) = end_time {
2260 query_params.insert("endTime".to_string(), json!(rw));
2261 }
2262
2263 if let Some(rw) = time_zone {
2264 query_params.insert("timeZone".to_string(), json!(rw));
2265 }
2266
2267 if let Some(rw) = limit {
2268 query_params.insert("limit".to_string(), json!(rw));
2269 }
2270
2271 send_request::<Vec<Vec<models::KlinesItemInner>>>(
2272 &self.configuration,
2273 "/api/v3/uiKlines",
2274 reqwest::Method::GET,
2275 query_params,
2276 body_params,
2277 if HAS_TIME_UNIT {
2278 self.configuration.time_unit
2279 } else {
2280 None
2281 },
2282 false,
2283 )
2284 .await
2285 }
2286}
2287
2288#[cfg(all(test, feature = "spot"))]
2289mod tests {
2290 use super::*;
2291 use crate::TOKIO_SHARED_RT;
2292 use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
2293 use async_trait::async_trait;
2294 use std::collections::HashMap;
2295
2296 struct DummyRestApiResponse<T> {
2297 inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
2298 status: u16,
2299 headers: HashMap<String, String>,
2300 rate_limits: Option<Vec<RestApiRateLimit>>,
2301 }
2302
2303 impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
2304 fn from(dummy: DummyRestApiResponse<T>) -> Self {
2305 Self {
2306 data_fn: dummy.inner,
2307 status: dummy.status,
2308 headers: dummy.headers,
2309 rate_limits: dummy.rate_limits,
2310 }
2311 }
2312 }
2313
2314 struct MockMarketApiClient {
2315 force_error: bool,
2316 }
2317
2318 #[async_trait]
2319 impl MarketApi for MockMarketApiClient {
2320 async fn agg_trades(
2321 &self,
2322 _params: AggTradesParams,
2323 ) -> anyhow::Result<RestApiResponse<Vec<models::AggTradesResponseInner>>> {
2324 if self.force_error {
2325 return Err(ConnectorError::ConnectorClientError {
2326 msg: "ResponseError".to_string(),
2327 code: None,
2328 }
2329 .into());
2330 }
2331
2332 let resp_json: Value = serde_json::from_str(r#"[{"a":26129,"p":"0.01633102","q":"4.70443515","f":27781,"l":27781,"T":1498793709153,"m":true,"M":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
2333 let dummy_response: Vec<models::AggTradesResponseInner> =
2334 serde_json::from_value(resp_json.clone())
2335 .expect("should parse into Vec<models::AggTradesResponseInner>");
2336
2337 let dummy = DummyRestApiResponse {
2338 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2339 status: 200,
2340 headers: HashMap::new(),
2341 rate_limits: None,
2342 };
2343
2344 Ok(dummy.into())
2345 }
2346
2347 async fn avg_price(
2348 &self,
2349 _params: AvgPriceParams,
2350 ) -> anyhow::Result<RestApiResponse<models::AvgPriceResponse>> {
2351 if self.force_error {
2352 return Err(ConnectorError::ConnectorClientError {
2353 msg: "ResponseError".to_string(),
2354 code: None,
2355 }
2356 .into());
2357 }
2358
2359 let resp_json: Value = serde_json::from_str(
2360 r#"{"mins":5,"price":"9.35751834","closeTime":1694061154503}"#,
2361 )
2362 .unwrap_or_else(|_| serde_json::json!({}));
2363 let dummy_response: models::AvgPriceResponse =
2364 serde_json::from_value(resp_json.clone())
2365 .expect("should parse into models::AvgPriceResponse");
2366
2367 let dummy = DummyRestApiResponse {
2368 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2369 status: 200,
2370 headers: HashMap::new(),
2371 rate_limits: None,
2372 };
2373
2374 Ok(dummy.into())
2375 }
2376
2377 async fn depth(
2378 &self,
2379 _params: DepthParams,
2380 ) -> anyhow::Result<RestApiResponse<models::DepthResponse>> {
2381 if self.force_error {
2382 return Err(ConnectorError::ConnectorClientError {
2383 msg: "ResponseError".to_string(),
2384 code: None,
2385 }
2386 .into());
2387 }
2388
2389 let resp_json: Value = serde_json::from_str(r#"{"lastUpdateId":1027024,"bids":[["4.00000000","431.00000000"]],"asks":[["4.00000200","12.00000000"]]}"#).unwrap_or_else(|_| serde_json::json!({}));
2390 let dummy_response: models::DepthResponse = serde_json::from_value(resp_json.clone())
2391 .expect("should parse into models::DepthResponse");
2392
2393 let dummy = DummyRestApiResponse {
2394 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2395 status: 200,
2396 headers: HashMap::new(),
2397 rate_limits: None,
2398 };
2399
2400 Ok(dummy.into())
2401 }
2402
2403 async fn get_trades(
2404 &self,
2405 _params: GetTradesParams,
2406 ) -> anyhow::Result<RestApiResponse<Vec<models::GetTradesResponseInner>>> {
2407 if self.force_error {
2408 return Err(ConnectorError::ConnectorClientError {
2409 msg: "ResponseError".to_string(),
2410 code: None,
2411 }
2412 .into());
2413 }
2414
2415 let resp_json: Value = serde_json::from_str(r#"[{"id":28457,"price":"4.00000100","qty":"12.00000000","quoteQty":"48.000012","time":1499865549590,"isBuyerMaker":true,"isBestMatch":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
2416 let dummy_response: Vec<models::GetTradesResponseInner> =
2417 serde_json::from_value(resp_json.clone())
2418 .expect("should parse into Vec<models::GetTradesResponseInner>");
2419
2420 let dummy = DummyRestApiResponse {
2421 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2422 status: 200,
2423 headers: HashMap::new(),
2424 rate_limits: None,
2425 };
2426
2427 Ok(dummy.into())
2428 }
2429
2430 async fn historical_block_trades(
2431 &self,
2432 _params: HistoricalBlockTradesParams,
2433 ) -> anyhow::Result<RestApiResponse<Vec<models::HistoricalBlockTradesResponseInner>>>
2434 {
2435 if self.force_error {
2436 return Err(ConnectorError::ConnectorClientError {
2437 msg: "ResponseError".to_string(),
2438 code: None,
2439 }
2440 .into());
2441 }
2442
2443 let resp_json: Value = serde_json::from_str(r#"[{"id":582,"price":"0.052","qty":"5838","quoteQty":"303.576","time":1772506983321,"isBuyerMaker":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
2444 let dummy_response: Vec<models::HistoricalBlockTradesResponseInner> =
2445 serde_json::from_value(resp_json.clone())
2446 .expect("should parse into Vec<models::HistoricalBlockTradesResponseInner>");
2447
2448 let dummy = DummyRestApiResponse {
2449 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2450 status: 200,
2451 headers: HashMap::new(),
2452 rate_limits: None,
2453 };
2454
2455 Ok(dummy.into())
2456 }
2457
2458 async fn historical_trades(
2459 &self,
2460 _params: HistoricalTradesParams,
2461 ) -> anyhow::Result<RestApiResponse<Vec<models::GetTradesResponseInner>>> {
2462 if self.force_error {
2463 return Err(ConnectorError::ConnectorClientError {
2464 msg: "ResponseError".to_string(),
2465 code: None,
2466 }
2467 .into());
2468 }
2469
2470 let resp_json: Value = serde_json::from_str(r#"[{"id":28457,"price":"4.00000100","qty":"12.00000000","quoteQty":"48.000012","time":1499865549590,"isBuyerMaker":true,"isBestMatch":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
2471 let dummy_response: Vec<models::GetTradesResponseInner> =
2472 serde_json::from_value(resp_json.clone())
2473 .expect("should parse into Vec<models::GetTradesResponseInner>");
2474
2475 let dummy = DummyRestApiResponse {
2476 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2477 status: 200,
2478 headers: HashMap::new(),
2479 rate_limits: None,
2480 };
2481
2482 Ok(dummy.into())
2483 }
2484
2485 async fn klines(
2486 &self,
2487 _params: KlinesParams,
2488 ) -> anyhow::Result<RestApiResponse<Vec<Vec<models::KlinesItemInner>>>> {
2489 if self.force_error {
2490 return Err(ConnectorError::ConnectorClientError {
2491 msg: "ResponseError".to_string(),
2492 code: None,
2493 }
2494 .into());
2495 }
2496
2497 let resp_json: Value = serde_json::from_str(r"[[1499040000000]]")
2498 .unwrap_or_else(|_| serde_json::json!({}));
2499 let dummy_response: Vec<Vec<models::KlinesItemInner>> =
2500 serde_json::from_value(resp_json.clone())
2501 .expect("should parse into Vec<Vec<models::KlinesItemInner>>");
2502
2503 let dummy = DummyRestApiResponse {
2504 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2505 status: 200,
2506 headers: HashMap::new(),
2507 rate_limits: None,
2508 };
2509
2510 Ok(dummy.into())
2511 }
2512
2513 async fn reference_price(
2514 &self,
2515 _params: ReferencePriceParams,
2516 ) -> anyhow::Result<RestApiResponse<models::ReferencePriceResponse>> {
2517 if self.force_error {
2518 return Err(ConnectorError::ConnectorClientError {
2519 msg: "ResponseError".to_string(),
2520 code: None,
2521 }
2522 .into());
2523 }
2524
2525 let resp_json: Value = serde_json::from_str(
2526 r#"{"symbol":"BAZUSD","referencePrice":"10.00","timestamp":1770736694138}"#,
2527 )
2528 .unwrap_or_else(|_| serde_json::json!({}));
2529 let dummy_response: models::ReferencePriceResponse =
2530 serde_json::from_value(resp_json.clone())
2531 .expect("should parse into models::ReferencePriceResponse");
2532
2533 let dummy = DummyRestApiResponse {
2534 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2535 status: 200,
2536 headers: HashMap::new(),
2537 rate_limits: None,
2538 };
2539
2540 Ok(dummy.into())
2541 }
2542
2543 async fn reference_price_calculation(
2544 &self,
2545 _params: ReferencePriceCalculationParams,
2546 ) -> anyhow::Result<RestApiResponse<models::ReferencePriceCalculationResponse>> {
2547 if self.force_error {
2548 return Err(ConnectorError::ConnectorClientError {
2549 msg: "ResponseError".to_string(),
2550 code: None,
2551 }
2552 .into());
2553 }
2554
2555 let resp_json: Value = serde_json::from_str(r#"{"symbol":"BAZUSD","calculationType":"ARITHMETIC_MEAN","bucketCount":10,"bucketWidthMs":1000,"externalCalculationId":42}"#).unwrap_or_else(|_| serde_json::json!({}));
2556 let dummy_response: models::ReferencePriceCalculationResponse =
2557 serde_json::from_value(resp_json.clone())
2558 .expect("should parse into models::ReferencePriceCalculationResponse");
2559
2560 let dummy = DummyRestApiResponse {
2561 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2562 status: 200,
2563 headers: HashMap::new(),
2564 rate_limits: None,
2565 };
2566
2567 Ok(dummy.into())
2568 }
2569
2570 async fn ticker(
2571 &self,
2572 _params: TickerParams,
2573 ) -> anyhow::Result<RestApiResponse<models::TickerResponse>> {
2574 if self.force_error {
2575 return Err(ConnectorError::ConnectorClientError {
2576 msg: "ResponseError".to_string(),
2577 code: None,
2578 }
2579 .into());
2580 }
2581
2582 let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC","openTime":1656986580000,"closeTime":1657001016795,"firstId":0,"lastId":34,"count":35}"#).unwrap_or_else(|_| serde_json::json!({}));
2583 let dummy_response: models::TickerResponse = serde_json::from_value(resp_json.clone())
2584 .expect("should parse into models::TickerResponse");
2585
2586 let dummy = DummyRestApiResponse {
2587 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2588 status: 200,
2589 headers: HashMap::new(),
2590 rate_limits: None,
2591 };
2592
2593 Ok(dummy.into())
2594 }
2595
2596 async fn ticker24hr(
2597 &self,
2598 _params: Ticker24hrParams,
2599 ) -> anyhow::Result<RestApiResponse<models::Ticker24hrResponse>> {
2600 if self.force_error {
2601 return Err(ConnectorError::ConnectorClientError {
2602 msg: "ResponseError".to_string(),
2603 code: None,
2604 }
2605 .into());
2606 }
2607
2608 let resp_json: Value = serde_json::from_str(r#"{"symbol":"BNBBTC","openTime":1499783499040,"closeTime":1499869899040,"firstId":28385,"lastId":28460,"count":76}"#).unwrap_or_else(|_| serde_json::json!({}));
2609 let dummy_response: models::Ticker24hrResponse =
2610 serde_json::from_value(resp_json.clone())
2611 .expect("should parse into models::Ticker24hrResponse");
2612
2613 let dummy = DummyRestApiResponse {
2614 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2615 status: 200,
2616 headers: HashMap::new(),
2617 rate_limits: None,
2618 };
2619
2620 Ok(dummy.into())
2621 }
2622
2623 async fn ticker_book_ticker(
2624 &self,
2625 _params: TickerBookTickerParams,
2626 ) -> anyhow::Result<RestApiResponse<models::TickerBookTickerResponse>> {
2627 if self.force_error {
2628 return Err(ConnectorError::ConnectorClientError {
2629 msg: "ResponseError".to_string(),
2630 code: None,
2631 }
2632 .into());
2633 }
2634
2635 let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC"}"#)
2636 .unwrap_or_else(|_| serde_json::json!({}));
2637 let dummy_response: models::TickerBookTickerResponse =
2638 serde_json::from_value(resp_json.clone())
2639 .expect("should parse into models::TickerBookTickerResponse");
2640
2641 let dummy = DummyRestApiResponse {
2642 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2643 status: 200,
2644 headers: HashMap::new(),
2645 rate_limits: None,
2646 };
2647
2648 Ok(dummy.into())
2649 }
2650
2651 async fn ticker_price(
2652 &self,
2653 _params: TickerPriceParams,
2654 ) -> anyhow::Result<RestApiResponse<models::TickerPriceResponse>> {
2655 if self.force_error {
2656 return Err(ConnectorError::ConnectorClientError {
2657 msg: "ResponseError".to_string(),
2658 code: None,
2659 }
2660 .into());
2661 }
2662
2663 let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC"}"#)
2664 .unwrap_or_else(|_| serde_json::json!({}));
2665 let dummy_response: models::TickerPriceResponse =
2666 serde_json::from_value(resp_json.clone())
2667 .expect("should parse into models::TickerPriceResponse");
2668
2669 let dummy = DummyRestApiResponse {
2670 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2671 status: 200,
2672 headers: HashMap::new(),
2673 rate_limits: None,
2674 };
2675
2676 Ok(dummy.into())
2677 }
2678
2679 async fn ticker_trading_day(
2680 &self,
2681 _params: TickerTradingDayParams,
2682 ) -> anyhow::Result<RestApiResponse<models::TickerTradingDayResponse>> {
2683 if self.force_error {
2684 return Err(ConnectorError::ConnectorClientError {
2685 msg: "ResponseError".to_string(),
2686 code: None,
2687 }
2688 .into());
2689 }
2690
2691 let resp_json: Value = serde_json::from_str(r#"{"symbol":"BTCUSDT","openTime":1695686400000,"closeTime":1695772799999,"firstId":3220151555,"lastId":3220849281,"count":697727}"#).unwrap_or_else(|_| serde_json::json!({}));
2692 let dummy_response: models::TickerTradingDayResponse =
2693 serde_json::from_value(resp_json.clone())
2694 .expect("should parse into models::TickerTradingDayResponse");
2695
2696 let dummy = DummyRestApiResponse {
2697 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2698 status: 200,
2699 headers: HashMap::new(),
2700 rate_limits: None,
2701 };
2702
2703 Ok(dummy.into())
2704 }
2705
2706 async fn ui_klines(
2707 &self,
2708 _params: UiKlinesParams,
2709 ) -> anyhow::Result<RestApiResponse<Vec<Vec<models::KlinesItemInner>>>> {
2710 if self.force_error {
2711 return Err(ConnectorError::ConnectorClientError {
2712 msg: "ResponseError".to_string(),
2713 code: None,
2714 }
2715 .into());
2716 }
2717
2718 let resp_json: Value = serde_json::from_str(r"[[1499040000000]]")
2719 .unwrap_or_else(|_| serde_json::json!({}));
2720 let dummy_response: Vec<Vec<models::KlinesItemInner>> =
2721 serde_json::from_value(resp_json.clone())
2722 .expect("should parse into Vec<Vec<models::KlinesItemInner>>");
2723
2724 let dummy = DummyRestApiResponse {
2725 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2726 status: 200,
2727 headers: HashMap::new(),
2728 rate_limits: None,
2729 };
2730
2731 Ok(dummy.into())
2732 }
2733 }
2734
2735 #[test]
2736 fn agg_trades_required_params_success() {
2737 TOKIO_SHARED_RT.block_on(async {
2738 let client = MockMarketApiClient { force_error: false };
2739
2740 let params = AggTradesParams::builder("BNBUSDT".to_string(),).build().unwrap();
2741
2742 let resp_json: Value = serde_json::from_str(r#"[{"a":26129,"p":"0.01633102","q":"4.70443515","f":27781,"l":27781,"T":1498793709153,"m":true,"M":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
2743 let expected_response : Vec<models::AggTradesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AggTradesResponseInner>");
2744
2745 let resp = client.agg_trades(params).await.expect("Expected a response");
2746 let data_future = resp.data();
2747 let actual_response = data_future.await.unwrap();
2748 assert_eq!(actual_response, expected_response);
2749 });
2750 }
2751
2752 #[test]
2753 fn agg_trades_optional_params_success() {
2754 TOKIO_SHARED_RT.block_on(async {
2755 let client = MockMarketApiClient { force_error: false };
2756
2757 let params = AggTradesParams::builder("BNBUSDT".to_string(),).from_id(1).start_time(1735693200000).end_time(1735693200000).limit(1).build().unwrap();
2758
2759 let resp_json: Value = serde_json::from_str(r#"[{"a":26129,"p":"0.01633102","q":"4.70443515","f":27781,"l":27781,"T":1498793709153,"m":true,"M":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
2760 let expected_response : Vec<models::AggTradesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::AggTradesResponseInner>");
2761
2762 let resp = client.agg_trades(params).await.expect("Expected a response");
2763 let data_future = resp.data();
2764 let actual_response = data_future.await.unwrap();
2765 assert_eq!(actual_response, expected_response);
2766 });
2767 }
2768
2769 #[test]
2770 fn agg_trades_response_error() {
2771 TOKIO_SHARED_RT.block_on(async {
2772 let client = MockMarketApiClient { force_error: true };
2773
2774 let params = AggTradesParams::builder("BNBUSDT".to_string())
2775 .build()
2776 .unwrap();
2777
2778 match client.agg_trades(params).await {
2779 Ok(_) => panic!("Expected an error"),
2780 Err(err) => {
2781 assert_eq!(err.to_string(), "Connector client error: ResponseError");
2782 }
2783 }
2784 });
2785 }
2786
2787 #[test]
2788 fn avg_price_required_params_success() {
2789 TOKIO_SHARED_RT.block_on(async {
2790 let client = MockMarketApiClient { force_error: false };
2791
2792 let params = AvgPriceParams::builder("BNBUSDT".to_string())
2793 .build()
2794 .unwrap();
2795
2796 let resp_json: Value = serde_json::from_str(
2797 r#"{"mins":5,"price":"9.35751834","closeTime":1694061154503}"#,
2798 )
2799 .unwrap_or_else(|_| serde_json::json!({}));
2800 let expected_response: models::AvgPriceResponse =
2801 serde_json::from_value(resp_json.clone())
2802 .expect("should parse into models::AvgPriceResponse");
2803
2804 let resp = client.avg_price(params).await.expect("Expected a response");
2805 let data_future = resp.data();
2806 let actual_response = data_future.await.unwrap();
2807 assert_eq!(actual_response, expected_response);
2808 });
2809 }
2810
2811 #[test]
2812 fn avg_price_optional_params_success() {
2813 TOKIO_SHARED_RT.block_on(async {
2814 let client = MockMarketApiClient { force_error: false };
2815
2816 let params = AvgPriceParams::builder("BNBUSDT".to_string())
2817 .build()
2818 .unwrap();
2819
2820 let resp_json: Value = serde_json::from_str(
2821 r#"{"mins":5,"price":"9.35751834","closeTime":1694061154503}"#,
2822 )
2823 .unwrap_or_else(|_| serde_json::json!({}));
2824 let expected_response: models::AvgPriceResponse =
2825 serde_json::from_value(resp_json.clone())
2826 .expect("should parse into models::AvgPriceResponse");
2827
2828 let resp = client.avg_price(params).await.expect("Expected a response");
2829 let data_future = resp.data();
2830 let actual_response = data_future.await.unwrap();
2831 assert_eq!(actual_response, expected_response);
2832 });
2833 }
2834
2835 #[test]
2836 fn avg_price_response_error() {
2837 TOKIO_SHARED_RT.block_on(async {
2838 let client = MockMarketApiClient { force_error: true };
2839
2840 let params = AvgPriceParams::builder("BNBUSDT".to_string())
2841 .build()
2842 .unwrap();
2843
2844 match client.avg_price(params).await {
2845 Ok(_) => panic!("Expected an error"),
2846 Err(err) => {
2847 assert_eq!(err.to_string(), "Connector client error: ResponseError");
2848 }
2849 }
2850 });
2851 }
2852
2853 #[test]
2854 fn depth_required_params_success() {
2855 TOKIO_SHARED_RT.block_on(async {
2856 let client = MockMarketApiClient { force_error: false };
2857
2858 let params = DepthParams::builder("BNBUSDT".to_string(),).build().unwrap();
2859
2860 let resp_json: Value = serde_json::from_str(r#"{"lastUpdateId":1027024,"bids":[["4.00000000","431.00000000"]],"asks":[["4.00000200","12.00000000"]]}"#).unwrap_or_else(|_| serde_json::json!({}));
2861 let expected_response : models::DepthResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DepthResponse");
2862
2863 let resp = client.depth(params).await.expect("Expected a response");
2864 let data_future = resp.data();
2865 let actual_response = data_future.await.unwrap();
2866 assert_eq!(actual_response, expected_response);
2867 });
2868 }
2869
2870 #[test]
2871 fn depth_optional_params_success() {
2872 TOKIO_SHARED_RT.block_on(async {
2873 let client = MockMarketApiClient { force_error: false };
2874
2875 let params = DepthParams::builder("BNBUSDT".to_string(),).limit(1).symbol_status(DepthSymbolStatusEnum::Trading).build().unwrap();
2876
2877 let resp_json: Value = serde_json::from_str(r#"{"lastUpdateId":1027024,"bids":[["4.00000000","431.00000000"]],"asks":[["4.00000200","12.00000000"]]}"#).unwrap_or_else(|_| serde_json::json!({}));
2878 let expected_response : models::DepthResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DepthResponse");
2879
2880 let resp = client.depth(params).await.expect("Expected a response");
2881 let data_future = resp.data();
2882 let actual_response = data_future.await.unwrap();
2883 assert_eq!(actual_response, expected_response);
2884 });
2885 }
2886
2887 #[test]
2888 fn depth_response_error() {
2889 TOKIO_SHARED_RT.block_on(async {
2890 let client = MockMarketApiClient { force_error: true };
2891
2892 let params = DepthParams::builder("BNBUSDT".to_string()).build().unwrap();
2893
2894 match client.depth(params).await {
2895 Ok(_) => panic!("Expected an error"),
2896 Err(err) => {
2897 assert_eq!(err.to_string(), "Connector client error: ResponseError");
2898 }
2899 }
2900 });
2901 }
2902
2903 #[test]
2904 fn get_trades_required_params_success() {
2905 TOKIO_SHARED_RT.block_on(async {
2906 let client = MockMarketApiClient { force_error: false };
2907
2908 let params = GetTradesParams::builder("BNBUSDT".to_string(),).build().unwrap();
2909
2910 let resp_json: Value = serde_json::from_str(r#"[{"id":28457,"price":"4.00000100","qty":"12.00000000","quoteQty":"48.000012","time":1499865549590,"isBuyerMaker":true,"isBestMatch":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
2911 let expected_response : Vec<models::GetTradesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetTradesResponseInner>");
2912
2913 let resp = client.get_trades(params).await.expect("Expected a response");
2914 let data_future = resp.data();
2915 let actual_response = data_future.await.unwrap();
2916 assert_eq!(actual_response, expected_response);
2917 });
2918 }
2919
2920 #[test]
2921 fn get_trades_optional_params_success() {
2922 TOKIO_SHARED_RT.block_on(async {
2923 let client = MockMarketApiClient { force_error: false };
2924
2925 let params = GetTradesParams::builder("BNBUSDT".to_string(),).limit(1).build().unwrap();
2926
2927 let resp_json: Value = serde_json::from_str(r#"[{"id":28457,"price":"4.00000100","qty":"12.00000000","quoteQty":"48.000012","time":1499865549590,"isBuyerMaker":true,"isBestMatch":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
2928 let expected_response : Vec<models::GetTradesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetTradesResponseInner>");
2929
2930 let resp = client.get_trades(params).await.expect("Expected a response");
2931 let data_future = resp.data();
2932 let actual_response = data_future.await.unwrap();
2933 assert_eq!(actual_response, expected_response);
2934 });
2935 }
2936
2937 #[test]
2938 fn get_trades_response_error() {
2939 TOKIO_SHARED_RT.block_on(async {
2940 let client = MockMarketApiClient { force_error: true };
2941
2942 let params = GetTradesParams::builder("BNBUSDT".to_string())
2943 .build()
2944 .unwrap();
2945
2946 match client.get_trades(params).await {
2947 Ok(_) => panic!("Expected an error"),
2948 Err(err) => {
2949 assert_eq!(err.to_string(), "Connector client error: ResponseError");
2950 }
2951 }
2952 });
2953 }
2954
2955 #[test]
2956 fn historical_block_trades_required_params_success() {
2957 TOKIO_SHARED_RT.block_on(async {
2958 let client = MockMarketApiClient { force_error: false };
2959
2960 let params = HistoricalBlockTradesParams::builder("BNBBTC".to_string(),582,).build().unwrap();
2961
2962 let resp_json: Value = serde_json::from_str(r#"[{"id":582,"price":"0.052","qty":"5838","quoteQty":"303.576","time":1772506983321,"isBuyerMaker":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
2963 let expected_response : Vec<models::HistoricalBlockTradesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::HistoricalBlockTradesResponseInner>");
2964
2965 let resp = client.historical_block_trades(params).await.expect("Expected a response");
2966 let data_future = resp.data();
2967 let actual_response = data_future.await.unwrap();
2968 assert_eq!(actual_response, expected_response);
2969 });
2970 }
2971
2972 #[test]
2973 fn historical_block_trades_optional_params_success() {
2974 TOKIO_SHARED_RT.block_on(async {
2975 let client = MockMarketApiClient { force_error: false };
2976
2977 let params = HistoricalBlockTradesParams::builder("BNBBTC".to_string(),582,).limit(500).build().unwrap();
2978
2979 let resp_json: Value = serde_json::from_str(r#"[{"id":582,"price":"0.052","qty":"5838","quoteQty":"303.576","time":1772506983321,"isBuyerMaker":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
2980 let expected_response : Vec<models::HistoricalBlockTradesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::HistoricalBlockTradesResponseInner>");
2981
2982 let resp = client.historical_block_trades(params).await.expect("Expected a response");
2983 let data_future = resp.data();
2984 let actual_response = data_future.await.unwrap();
2985 assert_eq!(actual_response, expected_response);
2986 });
2987 }
2988
2989 #[test]
2990 fn historical_block_trades_response_error() {
2991 TOKIO_SHARED_RT.block_on(async {
2992 let client = MockMarketApiClient { force_error: true };
2993
2994 let params = HistoricalBlockTradesParams::builder("BNBBTC".to_string(), 582)
2995 .build()
2996 .unwrap();
2997
2998 match client.historical_block_trades(params).await {
2999 Ok(_) => panic!("Expected an error"),
3000 Err(err) => {
3001 assert_eq!(err.to_string(), "Connector client error: ResponseError");
3002 }
3003 }
3004 });
3005 }
3006
3007 #[test]
3008 fn historical_trades_required_params_success() {
3009 TOKIO_SHARED_RT.block_on(async {
3010 let client = MockMarketApiClient { force_error: false };
3011
3012 let params = HistoricalTradesParams::builder("BNBUSDT".to_string(),).build().unwrap();
3013
3014 let resp_json: Value = serde_json::from_str(r#"[{"id":28457,"price":"4.00000100","qty":"12.00000000","quoteQty":"48.000012","time":1499865549590,"isBuyerMaker":true,"isBestMatch":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
3015 let expected_response : Vec<models::GetTradesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetTradesResponseInner>");
3016
3017 let resp = client.historical_trades(params).await.expect("Expected a response");
3018 let data_future = resp.data();
3019 let actual_response = data_future.await.unwrap();
3020 assert_eq!(actual_response, expected_response);
3021 });
3022 }
3023
3024 #[test]
3025 fn historical_trades_optional_params_success() {
3026 TOKIO_SHARED_RT.block_on(async {
3027 let client = MockMarketApiClient { force_error: false };
3028
3029 let params = HistoricalTradesParams::builder("BNBUSDT".to_string(),).limit(1).from_id(1).build().unwrap();
3030
3031 let resp_json: Value = serde_json::from_str(r#"[{"id":28457,"price":"4.00000100","qty":"12.00000000","quoteQty":"48.000012","time":1499865549590,"isBuyerMaker":true,"isBestMatch":true}]"#).unwrap_or_else(|_| serde_json::json!({}));
3032 let expected_response : Vec<models::GetTradesResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetTradesResponseInner>");
3033
3034 let resp = client.historical_trades(params).await.expect("Expected a response");
3035 let data_future = resp.data();
3036 let actual_response = data_future.await.unwrap();
3037 assert_eq!(actual_response, expected_response);
3038 });
3039 }
3040
3041 #[test]
3042 fn historical_trades_response_error() {
3043 TOKIO_SHARED_RT.block_on(async {
3044 let client = MockMarketApiClient { force_error: true };
3045
3046 let params = HistoricalTradesParams::builder("BNBUSDT".to_string())
3047 .build()
3048 .unwrap();
3049
3050 match client.historical_trades(params).await {
3051 Ok(_) => panic!("Expected an error"),
3052 Err(err) => {
3053 assert_eq!(err.to_string(), "Connector client error: ResponseError");
3054 }
3055 }
3056 });
3057 }
3058
3059 #[test]
3060 fn klines_required_params_success() {
3061 TOKIO_SHARED_RT.block_on(async {
3062 let client = MockMarketApiClient { force_error: false };
3063
3064 let params =
3065 KlinesParams::builder("BNBUSDT".to_string(), KlinesIntervalEnum::Interval1s)
3066 .build()
3067 .unwrap();
3068
3069 let resp_json: Value = serde_json::from_str(r"[[1499040000000]]")
3070 .unwrap_or_else(|_| serde_json::json!({}));
3071 let expected_response: Vec<Vec<models::KlinesItemInner>> =
3072 serde_json::from_value(resp_json.clone())
3073 .expect("should parse into Vec<Vec<models::KlinesItemInner>>");
3074
3075 let resp = client.klines(params).await.expect("Expected a response");
3076 let data_future = resp.data();
3077 let actual_response = data_future.await.unwrap();
3078 assert_eq!(actual_response, expected_response);
3079 });
3080 }
3081
3082 #[test]
3083 fn klines_optional_params_success() {
3084 TOKIO_SHARED_RT.block_on(async {
3085 let client = MockMarketApiClient { force_error: false };
3086
3087 let params =
3088 KlinesParams::builder("BNBUSDT".to_string(), KlinesIntervalEnum::Interval1s)
3089 .start_time(1735693200000)
3090 .end_time(1735693200000)
3091 .time_zone("0".to_string())
3092 .limit(1)
3093 .build()
3094 .unwrap();
3095
3096 let resp_json: Value = serde_json::from_str(r"[[1499040000000]]")
3097 .unwrap_or_else(|_| serde_json::json!({}));
3098 let expected_response: Vec<Vec<models::KlinesItemInner>> =
3099 serde_json::from_value(resp_json.clone())
3100 .expect("should parse into Vec<Vec<models::KlinesItemInner>>");
3101
3102 let resp = client.klines(params).await.expect("Expected a response");
3103 let data_future = resp.data();
3104 let actual_response = data_future.await.unwrap();
3105 assert_eq!(actual_response, expected_response);
3106 });
3107 }
3108
3109 #[test]
3110 fn klines_response_error() {
3111 TOKIO_SHARED_RT.block_on(async {
3112 let client = MockMarketApiClient { force_error: true };
3113
3114 let params =
3115 KlinesParams::builder("BNBUSDT".to_string(), KlinesIntervalEnum::Interval1s)
3116 .build()
3117 .unwrap();
3118
3119 match client.klines(params).await {
3120 Ok(_) => panic!("Expected an error"),
3121 Err(err) => {
3122 assert_eq!(err.to_string(), "Connector client error: ResponseError");
3123 }
3124 }
3125 });
3126 }
3127
3128 #[test]
3129 fn reference_price_required_params_success() {
3130 TOKIO_SHARED_RT.block_on(async {
3131 let client = MockMarketApiClient { force_error: false };
3132
3133 let params = ReferencePriceParams::builder("BNBUSDT".to_string())
3134 .build()
3135 .unwrap();
3136
3137 let resp_json: Value = serde_json::from_str(
3138 r#"{"symbol":"BAZUSD","referencePrice":"10.00","timestamp":1770736694138}"#,
3139 )
3140 .unwrap_or_else(|_| serde_json::json!({}));
3141 let expected_response: models::ReferencePriceResponse =
3142 serde_json::from_value(resp_json.clone())
3143 .expect("should parse into models::ReferencePriceResponse");
3144
3145 let resp = client
3146 .reference_price(params)
3147 .await
3148 .expect("Expected a response");
3149 let data_future = resp.data();
3150 let actual_response = data_future.await.unwrap();
3151 assert_eq!(actual_response, expected_response);
3152 });
3153 }
3154
3155 #[test]
3156 fn reference_price_optional_params_success() {
3157 TOKIO_SHARED_RT.block_on(async {
3158 let client = MockMarketApiClient { force_error: false };
3159
3160 let params = ReferencePriceParams::builder("BNBUSDT".to_string())
3161 .build()
3162 .unwrap();
3163
3164 let resp_json: Value = serde_json::from_str(
3165 r#"{"symbol":"BAZUSD","referencePrice":"10.00","timestamp":1770736694138}"#,
3166 )
3167 .unwrap_or_else(|_| serde_json::json!({}));
3168 let expected_response: models::ReferencePriceResponse =
3169 serde_json::from_value(resp_json.clone())
3170 .expect("should parse into models::ReferencePriceResponse");
3171
3172 let resp = client
3173 .reference_price(params)
3174 .await
3175 .expect("Expected a response");
3176 let data_future = resp.data();
3177 let actual_response = data_future.await.unwrap();
3178 assert_eq!(actual_response, expected_response);
3179 });
3180 }
3181
3182 #[test]
3183 fn reference_price_response_error() {
3184 TOKIO_SHARED_RT.block_on(async {
3185 let client = MockMarketApiClient { force_error: true };
3186
3187 let params = ReferencePriceParams::builder("BNBUSDT".to_string())
3188 .build()
3189 .unwrap();
3190
3191 match client.reference_price(params).await {
3192 Ok(_) => panic!("Expected an error"),
3193 Err(err) => {
3194 assert_eq!(err.to_string(), "Connector client error: ResponseError");
3195 }
3196 }
3197 });
3198 }
3199
3200 #[test]
3201 fn reference_price_calculation_required_params_success() {
3202 TOKIO_SHARED_RT.block_on(async {
3203 let client = MockMarketApiClient { force_error: false };
3204
3205 let params = ReferencePriceCalculationParams::builder("BNBUSDT".to_string(),).build().unwrap();
3206
3207 let resp_json: Value = serde_json::from_str(r#"{"symbol":"BAZUSD","calculationType":"ARITHMETIC_MEAN","bucketCount":10,"bucketWidthMs":1000,"externalCalculationId":42}"#).unwrap_or_else(|_| serde_json::json!({}));
3208 let expected_response : models::ReferencePriceCalculationResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::ReferencePriceCalculationResponse");
3209
3210 let resp = client.reference_price_calculation(params).await.expect("Expected a response");
3211 let data_future = resp.data();
3212 let actual_response = data_future.await.unwrap();
3213 assert_eq!(actual_response, expected_response);
3214 });
3215 }
3216
3217 #[test]
3218 fn reference_price_calculation_optional_params_success() {
3219 TOKIO_SHARED_RT.block_on(async {
3220 let client = MockMarketApiClient { force_error: false };
3221
3222 let params = ReferencePriceCalculationParams::builder("BNBUSDT".to_string(),).symbol_status(ReferencePriceCalculationSymbolStatusEnum::Trading).build().unwrap();
3223
3224 let resp_json: Value = serde_json::from_str(r#"{"symbol":"BAZUSD","calculationType":"ARITHMETIC_MEAN","bucketCount":10,"bucketWidthMs":1000,"externalCalculationId":42}"#).unwrap_or_else(|_| serde_json::json!({}));
3225 let expected_response : models::ReferencePriceCalculationResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::ReferencePriceCalculationResponse");
3226
3227 let resp = client.reference_price_calculation(params).await.expect("Expected a response");
3228 let data_future = resp.data();
3229 let actual_response = data_future.await.unwrap();
3230 assert_eq!(actual_response, expected_response);
3231 });
3232 }
3233
3234 #[test]
3235 fn reference_price_calculation_response_error() {
3236 TOKIO_SHARED_RT.block_on(async {
3237 let client = MockMarketApiClient { force_error: true };
3238
3239 let params = ReferencePriceCalculationParams::builder("BNBUSDT".to_string())
3240 .build()
3241 .unwrap();
3242
3243 match client.reference_price_calculation(params).await {
3244 Ok(_) => panic!("Expected an error"),
3245 Err(err) => {
3246 assert_eq!(err.to_string(), "Connector client error: ResponseError");
3247 }
3248 }
3249 });
3250 }
3251
3252 #[test]
3253 fn ticker_required_params_success() {
3254 TOKIO_SHARED_RT.block_on(async {
3255 let client = MockMarketApiClient { force_error: false };
3256
3257 let params = TickerParams::builder().build().unwrap();
3258
3259 let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC","openTime":1656986580000,"closeTime":1657001016795,"firstId":0,"lastId":34,"count":35}"#).unwrap_or_else(|_| serde_json::json!({}));
3260 let expected_response : models::TickerResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::TickerResponse");
3261
3262 let resp = client.ticker(params).await.expect("Expected a response");
3263 let data_future = resp.data();
3264 let actual_response = data_future.await.unwrap();
3265 assert_eq!(actual_response, expected_response);
3266 });
3267 }
3268
3269 #[test]
3270 fn ticker_optional_params_success() {
3271 TOKIO_SHARED_RT.block_on(async {
3272 let client = MockMarketApiClient { force_error: false };
3273
3274 let params = TickerParams::builder().symbol("BNBUSDT".to_string()).symbols(["BTCUSDT".to_string(),].to_vec()).window_size(TickerWindowSizeEnum::WindowSize1m).r#type(TickerTypeEnum::Full).symbol_status(TickerSymbolStatusEnum::Trading).build().unwrap();
3275
3276 let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC","openTime":1656986580000,"closeTime":1657001016795,"firstId":0,"lastId":34,"count":35}"#).unwrap_or_else(|_| serde_json::json!({}));
3277 let expected_response : models::TickerResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::TickerResponse");
3278
3279 let resp = client.ticker(params).await.expect("Expected a response");
3280 let data_future = resp.data();
3281 let actual_response = data_future.await.unwrap();
3282 assert_eq!(actual_response, expected_response);
3283 });
3284 }
3285
3286 #[test]
3287 fn ticker_response_error() {
3288 TOKIO_SHARED_RT.block_on(async {
3289 let client = MockMarketApiClient { force_error: true };
3290
3291 let params = TickerParams::builder().build().unwrap();
3292
3293 match client.ticker(params).await {
3294 Ok(_) => panic!("Expected an error"),
3295 Err(err) => {
3296 assert_eq!(err.to_string(), "Connector client error: ResponseError");
3297 }
3298 }
3299 });
3300 }
3301
3302 #[test]
3303 fn ticker24hr_required_params_success() {
3304 TOKIO_SHARED_RT.block_on(async {
3305 let client = MockMarketApiClient { force_error: false };
3306
3307 let params = Ticker24hrParams::builder().build().unwrap();
3308
3309 let resp_json: Value = serde_json::from_str(r#"{"symbol":"BNBBTC","openTime":1499783499040,"closeTime":1499869899040,"firstId":28385,"lastId":28460,"count":76}"#).unwrap_or_else(|_| serde_json::json!({}));
3310 let expected_response : models::Ticker24hrResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::Ticker24hrResponse");
3311
3312 let resp = client.ticker24hr(params).await.expect("Expected a response");
3313 let data_future = resp.data();
3314 let actual_response = data_future.await.unwrap();
3315 assert_eq!(actual_response, expected_response);
3316 });
3317 }
3318
3319 #[test]
3320 fn ticker24hr_optional_params_success() {
3321 TOKIO_SHARED_RT.block_on(async {
3322 let client = MockMarketApiClient { force_error: false };
3323
3324 let params = Ticker24hrParams::builder().symbol("BNBUSDT".to_string()).symbols(["BTCUSDT".to_string(),].to_vec()).r#type(Ticker24hrTypeEnum::Full).symbol_status(Ticker24hrSymbolStatusEnum::Trading).build().unwrap();
3325
3326 let resp_json: Value = serde_json::from_str(r#"{"symbol":"BNBBTC","openTime":1499783499040,"closeTime":1499869899040,"firstId":28385,"lastId":28460,"count":76}"#).unwrap_or_else(|_| serde_json::json!({}));
3327 let expected_response : models::Ticker24hrResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::Ticker24hrResponse");
3328
3329 let resp = client.ticker24hr(params).await.expect("Expected a response");
3330 let data_future = resp.data();
3331 let actual_response = data_future.await.unwrap();
3332 assert_eq!(actual_response, expected_response);
3333 });
3334 }
3335
3336 #[test]
3337 fn ticker24hr_response_error() {
3338 TOKIO_SHARED_RT.block_on(async {
3339 let client = MockMarketApiClient { force_error: true };
3340
3341 let params = Ticker24hrParams::builder().build().unwrap();
3342
3343 match client.ticker24hr(params).await {
3344 Ok(_) => panic!("Expected an error"),
3345 Err(err) => {
3346 assert_eq!(err.to_string(), "Connector client error: ResponseError");
3347 }
3348 }
3349 });
3350 }
3351
3352 #[test]
3353 fn ticker_book_ticker_required_params_success() {
3354 TOKIO_SHARED_RT.block_on(async {
3355 let client = MockMarketApiClient { force_error: false };
3356
3357 let params = TickerBookTickerParams::builder().build().unwrap();
3358
3359 let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC"}"#)
3360 .unwrap_or_else(|_| serde_json::json!({}));
3361 let expected_response: models::TickerBookTickerResponse =
3362 serde_json::from_value(resp_json.clone())
3363 .expect("should parse into models::TickerBookTickerResponse");
3364
3365 let resp = client
3366 .ticker_book_ticker(params)
3367 .await
3368 .expect("Expected a response");
3369 let data_future = resp.data();
3370 let actual_response = data_future.await.unwrap();
3371 assert_eq!(actual_response, expected_response);
3372 });
3373 }
3374
3375 #[test]
3376 fn ticker_book_ticker_optional_params_success() {
3377 TOKIO_SHARED_RT.block_on(async {
3378 let client = MockMarketApiClient { force_error: false };
3379
3380 let params = TickerBookTickerParams::builder()
3381 .symbol("BNBUSDT".to_string())
3382 .symbols(["BTCUSDT".to_string()].to_vec())
3383 .symbol_status(TickerBookTickerSymbolStatusEnum::Trading)
3384 .build()
3385 .unwrap();
3386
3387 let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC"}"#)
3388 .unwrap_or_else(|_| serde_json::json!({}));
3389 let expected_response: models::TickerBookTickerResponse =
3390 serde_json::from_value(resp_json.clone())
3391 .expect("should parse into models::TickerBookTickerResponse");
3392
3393 let resp = client
3394 .ticker_book_ticker(params)
3395 .await
3396 .expect("Expected a response");
3397 let data_future = resp.data();
3398 let actual_response = data_future.await.unwrap();
3399 assert_eq!(actual_response, expected_response);
3400 });
3401 }
3402
3403 #[test]
3404 fn ticker_book_ticker_response_error() {
3405 TOKIO_SHARED_RT.block_on(async {
3406 let client = MockMarketApiClient { force_error: true };
3407
3408 let params = TickerBookTickerParams::builder().build().unwrap();
3409
3410 match client.ticker_book_ticker(params).await {
3411 Ok(_) => panic!("Expected an error"),
3412 Err(err) => {
3413 assert_eq!(err.to_string(), "Connector client error: ResponseError");
3414 }
3415 }
3416 });
3417 }
3418
3419 #[test]
3420 fn ticker_price_required_params_success() {
3421 TOKIO_SHARED_RT.block_on(async {
3422 let client = MockMarketApiClient { force_error: false };
3423
3424 let params = TickerPriceParams::builder().build().unwrap();
3425
3426 let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC"}"#)
3427 .unwrap_or_else(|_| serde_json::json!({}));
3428 let expected_response: models::TickerPriceResponse =
3429 serde_json::from_value(resp_json.clone())
3430 .expect("should parse into models::TickerPriceResponse");
3431
3432 let resp = client
3433 .ticker_price(params)
3434 .await
3435 .expect("Expected a response");
3436 let data_future = resp.data();
3437 let actual_response = data_future.await.unwrap();
3438 assert_eq!(actual_response, expected_response);
3439 });
3440 }
3441
3442 #[test]
3443 fn ticker_price_optional_params_success() {
3444 TOKIO_SHARED_RT.block_on(async {
3445 let client = MockMarketApiClient { force_error: false };
3446
3447 let params = TickerPriceParams::builder()
3448 .symbol("BNBUSDT".to_string())
3449 .symbols(["BTCUSDT".to_string()].to_vec())
3450 .symbol_status(TickerPriceSymbolStatusEnum::Trading)
3451 .build()
3452 .unwrap();
3453
3454 let resp_json: Value = serde_json::from_str(r#"{"symbol":"LTCBTC"}"#)
3455 .unwrap_or_else(|_| serde_json::json!({}));
3456 let expected_response: models::TickerPriceResponse =
3457 serde_json::from_value(resp_json.clone())
3458 .expect("should parse into models::TickerPriceResponse");
3459
3460 let resp = client
3461 .ticker_price(params)
3462 .await
3463 .expect("Expected a response");
3464 let data_future = resp.data();
3465 let actual_response = data_future.await.unwrap();
3466 assert_eq!(actual_response, expected_response);
3467 });
3468 }
3469
3470 #[test]
3471 fn ticker_price_response_error() {
3472 TOKIO_SHARED_RT.block_on(async {
3473 let client = MockMarketApiClient { force_error: true };
3474
3475 let params = TickerPriceParams::builder().build().unwrap();
3476
3477 match client.ticker_price(params).await {
3478 Ok(_) => panic!("Expected an error"),
3479 Err(err) => {
3480 assert_eq!(err.to_string(), "Connector client error: ResponseError");
3481 }
3482 }
3483 });
3484 }
3485
3486 #[test]
3487 fn ticker_trading_day_required_params_success() {
3488 TOKIO_SHARED_RT.block_on(async {
3489 let client = MockMarketApiClient { force_error: false };
3490
3491 let params = TickerTradingDayParams::builder().build().unwrap();
3492
3493 let resp_json: Value = serde_json::from_str(r#"{"symbol":"BTCUSDT","openTime":1695686400000,"closeTime":1695772799999,"firstId":3220151555,"lastId":3220849281,"count":697727}"#).unwrap_or_else(|_| serde_json::json!({}));
3494 let expected_response : models::TickerTradingDayResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::TickerTradingDayResponse");
3495
3496 let resp = client.ticker_trading_day(params).await.expect("Expected a response");
3497 let data_future = resp.data();
3498 let actual_response = data_future.await.unwrap();
3499 assert_eq!(actual_response, expected_response);
3500 });
3501 }
3502
3503 #[test]
3504 fn ticker_trading_day_optional_params_success() {
3505 TOKIO_SHARED_RT.block_on(async {
3506 let client = MockMarketApiClient { force_error: false };
3507
3508 let params = TickerTradingDayParams::builder().symbol("BNBUSDT".to_string()).symbols(["BTCUSDT".to_string(),].to_vec()).time_zone("0".to_string()).r#type(TickerTradingDayTypeEnum::Full).symbol_status(TickerTradingDaySymbolStatusEnum::Trading).build().unwrap();
3509
3510 let resp_json: Value = serde_json::from_str(r#"{"symbol":"BTCUSDT","openTime":1695686400000,"closeTime":1695772799999,"firstId":3220151555,"lastId":3220849281,"count":697727}"#).unwrap_or_else(|_| serde_json::json!({}));
3511 let expected_response : models::TickerTradingDayResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::TickerTradingDayResponse");
3512
3513 let resp = client.ticker_trading_day(params).await.expect("Expected a response");
3514 let data_future = resp.data();
3515 let actual_response = data_future.await.unwrap();
3516 assert_eq!(actual_response, expected_response);
3517 });
3518 }
3519
3520 #[test]
3521 fn ticker_trading_day_response_error() {
3522 TOKIO_SHARED_RT.block_on(async {
3523 let client = MockMarketApiClient { force_error: true };
3524
3525 let params = TickerTradingDayParams::builder().build().unwrap();
3526
3527 match client.ticker_trading_day(params).await {
3528 Ok(_) => panic!("Expected an error"),
3529 Err(err) => {
3530 assert_eq!(err.to_string(), "Connector client error: ResponseError");
3531 }
3532 }
3533 });
3534 }
3535
3536 #[test]
3537 fn ui_klines_required_params_success() {
3538 TOKIO_SHARED_RT.block_on(async {
3539 let client = MockMarketApiClient { force_error: false };
3540
3541 let params =
3542 UiKlinesParams::builder("BNBUSDT".to_string(), UiKlinesIntervalEnum::Interval1s)
3543 .build()
3544 .unwrap();
3545
3546 let resp_json: Value = serde_json::from_str(r"[[1499040000000]]")
3547 .unwrap_or_else(|_| serde_json::json!({}));
3548 let expected_response: Vec<Vec<models::KlinesItemInner>> =
3549 serde_json::from_value(resp_json.clone())
3550 .expect("should parse into Vec<Vec<models::KlinesItemInner>>");
3551
3552 let resp = client.ui_klines(params).await.expect("Expected a response");
3553 let data_future = resp.data();
3554 let actual_response = data_future.await.unwrap();
3555 assert_eq!(actual_response, expected_response);
3556 });
3557 }
3558
3559 #[test]
3560 fn ui_klines_optional_params_success() {
3561 TOKIO_SHARED_RT.block_on(async {
3562 let client = MockMarketApiClient { force_error: false };
3563
3564 let params =
3565 UiKlinesParams::builder("BNBUSDT".to_string(), UiKlinesIntervalEnum::Interval1s)
3566 .start_time(1735693200000)
3567 .end_time(1735693200000)
3568 .time_zone("0".to_string())
3569 .limit(1)
3570 .build()
3571 .unwrap();
3572
3573 let resp_json: Value = serde_json::from_str(r"[[1499040000000]]")
3574 .unwrap_or_else(|_| serde_json::json!({}));
3575 let expected_response: Vec<Vec<models::KlinesItemInner>> =
3576 serde_json::from_value(resp_json.clone())
3577 .expect("should parse into Vec<Vec<models::KlinesItemInner>>");
3578
3579 let resp = client.ui_klines(params).await.expect("Expected a response");
3580 let data_future = resp.data();
3581 let actual_response = data_future.await.unwrap();
3582 assert_eq!(actual_response, expected_response);
3583 });
3584 }
3585
3586 #[test]
3587 fn ui_klines_response_error() {
3588 TOKIO_SHARED_RT.block_on(async {
3589 let client = MockMarketApiClient { force_error: true };
3590
3591 let params =
3592 UiKlinesParams::builder("BNBUSDT".to_string(), UiKlinesIntervalEnum::Interval1s)
3593 .build()
3594 .unwrap();
3595
3596 match client.ui_klines(params).await {
3597 Ok(_) => panic!("Expected an error"),
3598 Err(err) => {
3599 assert_eq!(err.to_string(), "Connector client error: ResponseError");
3600 }
3601 }
3602 });
3603 }
3604}