1use crate::client::{Client, Response};
2use crate::error::Error;
3use crate::exchanges::Fiat;
4use chrono::prelude::*;
5use reqwest_middleware::RequestBuilder;
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9#[derive(Debug, Serialize, Deserialize)]
10pub struct Coin {
12 pub id: String,
14
15 pub name: String,
17
18 pub symbol: String,
20
21 pub rank: isize,
23
24 pub is_new: bool,
26
27 pub is_active: bool,
30
31 #[serde(rename = "type")]
32 pub coin_type: String,
34}
35
36#[derive(Debug, Serialize, Deserialize)]
37pub struct Parent {
39 pub id: String,
40 pub name: String,
41 pub symbol: String,
42}
43
44#[derive(Debug, Serialize, Deserialize)]
45pub struct CoinTag {
47 pub id: String,
49
50 pub name: String,
52
53 pub coin_counter: i32,
55
56 pub ico_counter: i32,
58}
59
60#[derive(Debug, Serialize, Deserialize)]
61pub struct Team {
63 pub id: String,
64 pub name: String,
65 pub position: String,
66}
67
68#[derive(Debug, Serialize, Deserialize)]
69pub struct Contract {
71 pub contract: String,
73
74 pub platform: String,
77
78 #[serde(rename = "type")]
79 pub contract_type: String,
82}
83
84#[derive(Debug, Serialize, Deserialize)]
85pub struct Whitepaper {
87 pub link: String,
89
90 pub thumbnail: String,
92}
93
94#[derive(Debug, Serialize, Deserialize)]
95pub struct CoinDetails {
97 pub id: String,
99
100 pub name: String,
102
103 pub symbol: String,
105
106 pub parent: Option<Parent>,
108
109 pub rank: isize,
111
112 pub is_new: bool,
114
115 pub is_active: bool,
118
119 #[serde(rename = "type")]
120 pub coin_type: String,
122
123 pub logo: String,
125
126 pub tags: Vec<CoinTag>,
128
129 pub team: Vec<Team>,
131
132 pub description: Option<String>,
134
135 pub message: String,
137
138 pub open_source: bool,
140
141 pub hardware_wallet: bool,
143
144 pub started_at: Option<String>,
146
147 pub development_status: Option<String>,
150
151 pub proof_type: Option<String>,
153
154 pub org_structure: Option<String>,
157
158 pub hash_algorithm: Option<String>,
160
161 pub contract: Option<String>,
163
164 pub platform: Option<String>,
166
167 pub contracts: Option<Vec<Contract>>,
169
170 pub links: Value,
172
173 pub links_extended: Value,
177
178 pub whitepaper: Value,
180
181 pub first_data_at: String,
183
184 pub last_data_at: String,
186}
187
188#[derive(Debug, Serialize, Deserialize)]
189pub struct Tweet {
191 pub date: String,
193
194 pub user_name: String,
196
197 pub user_image_link: String,
199
200 pub status: String,
202
203 pub is_retweet: bool,
205
206 pub retweet_count: i32,
208
209 pub like_count: i32,
211
212 pub status_link: String,
214
215 pub status_id: String,
217
218 pub media_link: Option<String>,
219
220 pub youtube_link: Option<String>,
222}
223
224#[derive(Debug, Serialize, Deserialize)]
225pub struct CoinEvent {
227 pub id: String,
228 pub date: String,
229 pub date_to: Option<String>,
230 pub name: String,
231 pub description: String,
232 pub is_conference: bool,
233 pub link: Option<String>,
234 pub proof_image_link: Option<String>,
235}
236
237#[derive(Debug, Serialize, Deserialize)]
238pub struct CoinExchange {
240 pub id: String,
241 pub name: String,
242 pub fiats: Vec<Fiat>,
243 pub adjusted_volume_24h_share: f64,
244}
245
246#[derive(Debug, Serialize, Deserialize)]
247pub struct CoinMarket {
249 pub exchange_id: String,
250 pub exchange_name: String,
251 pub pair: String,
252 pub base_currency_id: String,
253 pub base_currency_name: String,
254 pub quote_currency_id: String,
255 pub quote_currency_name: String,
256 pub market_url: Option<String>,
257 pub category: String,
258 pub fee_type: String,
259 pub outlier: bool,
260 pub adjusted_volume_24h_share: f64,
261 pub quotes: Value,
262 pub last_updated: String,
263}
264
265#[derive(Debug, Serialize, Deserialize)]
266pub struct CoinOHLC {
268 pub time_open: String,
270
271 pub time_close: String,
273
274 pub open: Option<f64>,
275 pub high: Option<f64>,
276 pub low: Option<f64>,
277 pub close: Option<f64>,
278 pub volume: Option<i64>,
279 pub market_cap: Option<i64>,
280}
281
282pub struct GetCoinsRequest<'a> {
285 client: &'a Client,
286}
287
288impl<'a> GetCoinsRequest<'a> {
289 pub fn new(client: &'a Client) -> Self {
290 Self { client }
291 }
292
293 pub async fn send(&self) -> Result<Vec<Coin>, Error> {
294 let request: RequestBuilder = self
295 .client
296 .client
297 .get(format!("{}/coins", self.client.api_url));
298
299 let response: Response = self.client.request(request).await?;
300
301 let data: Vec<Coin> = response.response.json().await?;
302
303 Ok(data)
304 }
305}
306
307pub struct GetCoinRequest<'a> {
311 client: &'a Client,
312 coin_id: String,
313}
314
315impl<'a> GetCoinRequest<'a> {
316 pub fn new(client: &'a Client, coin_id: &str) -> Self {
317 Self {
318 client,
319 coin_id: String::from(coin_id),
320 }
321 }
322
323 pub async fn send(&self) -> Result<CoinDetails, Error> {
324 let request: RequestBuilder = self
325 .client
326 .client
327 .get(format!("{}/coins/{}", self.client.api_url, self.coin_id));
328
329 let response: Response = self.client.request(request).await?;
330
331 let data: CoinDetails = response.response.json().await?;
332
333 Ok(data)
334 }
335}
336
337pub struct GetTwitterRequest<'a> {
340 client: &'a Client,
341 coin_id: String,
342}
343
344impl<'a> GetTwitterRequest<'a> {
345 pub fn new(client: &'a Client, coin_id: &str) -> Self {
346 Self {
347 client,
348 coin_id: String::from(coin_id),
349 }
350 }
351
352 pub async fn send(&self) -> Result<Vec<Tweet>, Error> {
353 let request: RequestBuilder = self.client.client.get(format!(
354 "{}/coins/{}/twitter",
355 self.client.api_url, self.coin_id
356 ));
357
358 let response: Response = self.client.request(request).await?;
359
360 let data: Vec<Tweet> = response.response.json().await?;
361
362 Ok(data)
363 }
364}
365
366pub struct GetCoinEventsRequest<'a> {
369 client: &'a Client,
370 coin_id: String,
371}
372
373impl<'a> GetCoinEventsRequest<'a> {
374 pub fn new(client: &'a Client, coin_id: &str) -> Self {
375 Self {
376 client,
377 coin_id: String::from(coin_id),
378 }
379 }
380
381 pub async fn send(&self) -> Result<Vec<CoinEvent>, Error> {
382 let request: RequestBuilder = self.client.client.get(format!(
383 "{}/coins/{}/events",
384 self.client.api_url, self.coin_id
385 ));
386
387 let response: Response = self.client.request(request).await?;
388
389 let data: Vec<CoinEvent> = response.response.json().await?;
390
391 Ok(data)
392 }
393}
394
395pub struct GetCoinExchangesRequest<'a> {
398 client: &'a Client,
399 coin_id: String,
400}
401
402impl<'a> GetCoinExchangesRequest<'a> {
403 pub fn new(client: &'a Client, coin_id: &str) -> Self {
404 Self {
405 client,
406 coin_id: String::from(coin_id),
407 }
408 }
409
410 pub async fn send(&self) -> Result<Vec<CoinExchange>, Error> {
411 let request: RequestBuilder = self.client.client.get(format!(
412 "{}/coins/{}/exchanges",
413 self.client.api_url, self.coin_id
414 ));
415
416 let response: Response = self.client.request(request).await?;
417
418 let data: Vec<CoinExchange> = response.response.json().await?;
419
420 Ok(data)
421 }
422}
423
424pub struct GetCoinMarketsRequest<'a> {
427 client: &'a Client,
428 coin_id: String,
429 quotes: Vec<String>,
430}
431
432impl<'a> GetCoinMarketsRequest<'a> {
433 pub fn new(client: &'a Client, coin_id: &str) -> Self {
434 Self {
435 client,
436 coin_id: String::from(coin_id),
437 quotes: vec![],
438 }
439 }
440
441 pub fn quotes(&mut self, quotes: Vec<&str>) -> &'a mut GetCoinMarketsRequest {
446 self.quotes = quotes.iter().map(|&q| String::from(q)).collect();
447 self
448 }
449
450 pub async fn send(&self) -> Result<Vec<CoinMarket>, Error> {
451 let query = match self.quotes.len() {
452 0 => vec![],
453 _ => vec![("quotes", self.quotes.join(","))],
454 };
455
456 let request: RequestBuilder = self
457 .client
458 .client
459 .get(format!(
460 "{}/coins/{}/markets",
461 self.client.api_url, self.coin_id
462 ))
463 .query(&query);
464
465 let response: Response = self.client.request(request).await?;
466
467 let data: Vec<CoinMarket> = response.response.json().await?;
468
469 Ok(data)
470 }
471}
472
473pub struct GetCoinOHLCLastFullDayRequest<'a> {
477 client: &'a Client,
478 coin_id: String,
479 quote: Option<String>,
480}
481
482impl<'a> GetCoinOHLCLastFullDayRequest<'a> {
483 pub fn new(client: &'a Client, coin_id: &str) -> Self {
484 Self {
485 client,
486 coin_id: String::from(coin_id),
487 quote: None,
488 }
489 }
490 pub fn quote(&mut self, quote: &str) -> &'a mut GetCoinOHLCLastFullDayRequest {
494 self.quote = Some(String::from(quote));
495 self
496 }
497
498 pub async fn send(&self) -> Result<Vec<CoinOHLC>, Error> {
499 let mut query: Vec<(&str, &str)> = Vec::new();
500
501 if let Some(quote) = &self.quote {
502 query.push(("quote", quote));
503 }
504
505 let request: RequestBuilder = self
506 .client
507 .client
508 .get(format!(
509 "{}/coins/{}/ohlcv/latest",
510 self.client.api_url, self.coin_id
511 ))
512 .query(&query);
513
514 let response: Response = self.client.request(request).await?;
515
516 let data: Vec<CoinOHLC> = response.response.json().await?;
517
518 Ok(data)
519 }
520}
521
522pub struct GetCoinOHLCHistoricalRequest<'a> {
527 client: &'a Client,
528 coin_id: String,
529 start: String,
530 end: Option<String>,
531 limit: Option<String>,
532 quote: Option<String>,
533}
534
535impl<'a> GetCoinOHLCHistoricalRequest<'a> {
536 pub fn new(client: &'a Client, coin_id: &str) -> Self {
537 let now: DateTime<Utc> = Utc::now(); Self {
540 client,
541 coin_id: String::from(coin_id),
542 start: format!("{}-{}-{}", now.year(), now.month(), now.day()),
543 end: None,
544 limit: None,
545 quote: None,
546 }
547 }
548
549 pub fn start(&mut self, start: &str) -> &'a mut GetCoinOHLCHistoricalRequest {
556 self.start = String::from(start);
557 self
558 }
559
560 pub fn end(&mut self, end: &str) -> &'a mut GetCoinOHLCHistoricalRequest {
569 self.end = Some(String::from(end));
570 self
571 }
572
573 pub fn limit(&mut self, limit: i32) -> &'a mut GetCoinOHLCHistoricalRequest {
577 self.limit = Some(limit.to_string());
578 self
579 }
580
581 pub fn quote(&mut self, quote: &str) -> &'a mut GetCoinOHLCHistoricalRequest {
585 self.quote = Some(String::from(quote));
586 self
587 }
588
589 pub async fn send(&self) -> Result<Vec<CoinOHLC>, Error> {
590 let mut query: Vec<(&str, &str)> = vec![("start", self.start.as_ref())];
591
592 if let Some(end) = &self.end {
593 query.push(("end", end));
594 }
595
596 if let Some(limit) = &self.limit {
597 query.push(("limit", limit));
598 }
599
600 if let Some(quote) = &self.quote {
601 query.push(("quote", quote));
602 }
603
604 let request: RequestBuilder = self
605 .client
606 .client
607 .get(format!(
608 "{}/coins/{}/ohlcv/historical",
609 self.client.api_url, self.coin_id
610 ))
611 .query(&query);
612
613 let response: Response = self.client.request(request).await?;
614
615 let data: Vec<CoinOHLC> = response.response.json().await?;
616
617 Ok(data)
618 }
619}
620
621pub struct GetCoinOHLCTodayRequest<'a> {
625 client: &'a Client,
626 coin_id: String,
627 quote: Option<String>,
628}
629
630impl<'a> GetCoinOHLCTodayRequest<'a> {
631 pub fn new(client: &'a Client, coin_id: &str) -> Self {
632 Self {
633 client,
634 coin_id: String::from(coin_id),
635 quote: None,
636 }
637 }
638
639 pub fn quote(&mut self, quote: &str) -> &'a mut GetCoinOHLCTodayRequest {
643 self.quote = Some(String::from(quote));
644 self
645 }
646
647 pub async fn send(&self) -> Result<Vec<CoinOHLC>, Error> {
648 let mut query: Vec<(&str, &str)> = Vec::new();
649
650 if let Some(quote) = &self.quote {
651 query.push(("quote", quote));
652 }
653
654 let request: RequestBuilder = self
655 .client
656 .client
657 .get(format!(
658 "{}/coins/{}/ohlcv/today",
659 self.client.api_url, self.coin_id
660 ))
661 .query(&query);
662
663 let response: Response = self.client.request(request).await?;
664
665 let data: Vec<CoinOHLC> = response.response.json().await?;
666
667 Ok(data)
668 }
669}