finance_query/adapters/polygon/stocks/
fundamentals.rs1use serde::{Deserialize, Serialize};
4
5use crate::adapters::common::encode_path_segment;
6use crate::error::Result;
7
8use super::super::build_client;
9use super::super::models::PaginatedResponse;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13#[non_exhaustive]
14pub struct FinancialResult {
15 pub tickers: Option<Vec<String>>,
17 pub company_name: Option<String>,
19 pub cik: Option<String>,
21 pub filing_date: Option<String>,
23 pub period_of_report_date: Option<String>,
25 pub fiscal_period: Option<String>,
27 pub fiscal_year: Option<String>,
29 pub source_filing_url: Option<String>,
31 pub financials: Option<serde_json::Value>,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37#[non_exhaustive]
38pub struct ShortInterest {
39 pub settlement_date: Option<String>,
41 pub short_interest: Option<f64>,
43 pub avg_daily_volume: Option<f64>,
45 pub days_to_cover: Option<f64>,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51#[non_exhaustive]
52pub struct ShortVolume {
53 pub date: Option<String>,
55 pub short_volume: Option<f64>,
57 pub short_exempt_volume: Option<f64>,
59 pub total_volume: Option<f64>,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65#[non_exhaustive]
66pub struct FloatData {
67 pub ticker: Option<String>,
69 pub float_shares: Option<f64>,
71 pub outstanding_shares: Option<f64>,
73 pub date: Option<String>,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
79#[non_exhaustive]
80pub struct FinancialRatios {
81 pub ticker: Option<String>,
83 pub period: Option<String>,
85 pub fiscal_year: Option<String>,
87 #[serde(flatten)]
89 pub ratios: std::collections::HashMap<String, serde_json::Value>,
90}
91
92pub async fn stock_financials(
97 ticker: &str,
98 params: &[(&str, &str)],
99) -> Result<PaginatedResponse<FinancialResult>> {
100 let client = build_client()?;
101 let path = "/vX/reference/financials".to_string();
102 let mut query: Vec<(&str, &str)> = vec![("ticker", ticker)];
103 query.extend_from_slice(params);
104 client.get(&path, &query).await
105}
106
107pub async fn stock_short_interest(
109 ticker: &str,
110 params: &[(&str, &str)],
111) -> Result<PaginatedResponse<ShortInterest>> {
112 let client = build_client()?;
113 let path = format!(
114 "/v3/reference/short-interest/{}",
115 encode_path_segment(ticker)
116 );
117 client.get(&path, params).await
118}
119
120pub async fn stock_short_volume(
122 ticker: &str,
123 params: &[(&str, &str)],
124) -> Result<PaginatedResponse<ShortVolume>> {
125 let client = build_client()?;
126 let path = format!("/v3/reference/short-volume/{}", encode_path_segment(ticker));
127 client.get(&path, params).await
128}
129
130pub async fn stock_float(ticker: &str) -> Result<PaginatedResponse<FloatData>> {
132 let client = build_client()?;
133 let path = format!("/v3/reference/float/{}", encode_path_segment(ticker));
134 client.get(&path, &[]).await
135}
136
137pub async fn stock_ratios(
139 ticker: &str,
140 params: &[(&str, &str)],
141) -> Result<PaginatedResponse<FinancialRatios>> {
142 let client = build_client()?;
143 let path = "/vX/reference/financials/ratios".to_string();
144 let mut query: Vec<(&str, &str)> = vec![("ticker", ticker)];
145 query.extend_from_slice(params);
146 client.get(&path, &query).await
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[tokio::test]
154 async fn test_stock_financials_mock() {
155 let mut server = mockito::Server::new_async().await;
156 let _mock = server
157 .mock("GET", "/vX/reference/financials")
158 .match_query(mockito::Matcher::AllOf(vec![
159 mockito::Matcher::UrlEncoded("apiKey".into(), "test-key".into()),
160 mockito::Matcher::UrlEncoded("ticker".into(), "AAPL".into()),
161 ]))
162 .with_status(200)
163 .with_body(
164 serde_json::json!({
165 "status": "OK",
166 "request_id": "abc",
167 "results": [{
168 "tickers": ["AAPL"],
169 "company_name": "Apple Inc",
170 "fiscal_period": "Q1",
171 "fiscal_year": "2024",
172 "filing_date": "2024-02-01"
173 }]
174 })
175 .to_string(),
176 )
177 .create_async()
178 .await;
179
180 let client = super::super::super::build_test_client(&server.url()).unwrap();
181 let resp: PaginatedResponse<FinancialResult> = client
182 .get("/vX/reference/financials", &[("ticker", "AAPL")])
183 .await
184 .unwrap();
185 let results = resp.results.unwrap();
186 assert_eq!(results[0].company_name.as_deref(), Some("Apple Inc"));
187 }
188}