finance_query/adapters/fmp/
crypto.rs1use serde::{Deserialize, Serialize};
4
5use crate::adapters::common::encode_path_segment;
6use crate::error::Result;
7
8use super::build_client;
9use super::models::{FmpQuote, HistoricalPriceResponse, IntradayPrice};
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13#[non_exhaustive]
14pub struct AvailableSymbol {
15 pub symbol: Option<String>,
17 pub name: Option<String>,
19 pub currency: Option<String>,
21 #[serde(rename = "stockExchange")]
23 pub stock_exchange: Option<String>,
24 #[serde(rename = "exchangeShortName")]
26 pub exchange_short_name: Option<String>,
27}
28
29pub async fn crypto_quote(symbol: &str) -> Result<Vec<FmpQuote>> {
33 let client = build_client()?;
34 let path = format!("/api/v3/quote/{}", encode_path_segment(symbol));
35 client.get(&path, &[]).await
36}
37
38pub async fn crypto_available() -> Result<Vec<AvailableSymbol>> {
40 let client = build_client()?;
41 client
42 .get("/api/v3/symbol/available-cryptocurrencies", &[])
43 .await
44}
45
46pub async fn crypto_historical(
51 symbol: &str,
52 params: &[(&str, &str)],
53) -> Result<HistoricalPriceResponse> {
54 let client = build_client()?;
55 let path = format!(
56 "/api/v3/historical-price-full/{}",
57 encode_path_segment(symbol)
58 );
59 client.get(&path, params).await
60}
61
62pub async fn crypto_intraday(
68 symbol: &str,
69 interval: &str,
70 params: &[(&str, &str)],
71) -> Result<Vec<IntradayPrice>> {
72 let client = build_client()?;
73 let path = format!(
74 "/api/v3/historical-chart/{}/{}",
75 encode_path_segment(interval),
76 encode_path_segment(symbol)
77 );
78 client.get(&path, params).await
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[tokio::test]
86 async fn test_crypto_available_mock() {
87 let mut server = mockito::Server::new_async().await;
88 let _mock = server
89 .mock("GET", "/api/v3/symbol/available-cryptocurrencies")
90 .match_query(mockito::Matcher::AllOf(vec![mockito::Matcher::UrlEncoded(
91 "apikey".into(),
92 "test-key".into(),
93 )]))
94 .with_status(200)
95 .with_body(
96 serde_json::json!([
97 {
98 "symbol": "BTCUSD",
99 "name": "Bitcoin USD",
100 "currency": "USD",
101 "stockExchange": "CCC",
102 "exchangeShortName": "CRYPTO"
103 }
104 ])
105 .to_string(),
106 )
107 .create_async()
108 .await;
109
110 let client = super::super::build_test_client(&server.url()).unwrap();
111 let result: Vec<AvailableSymbol> = client
112 .get("/api/v3/symbol/available-cryptocurrencies", &[])
113 .await
114 .unwrap();
115 assert_eq!(result.len(), 1);
116 assert_eq!(result[0].symbol.as_deref(), Some("BTCUSD"));
117 }
118}