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