Skip to main content

finance_query/providers/adapter/
equity.rs

1//! Capability traits over a single equity symbol.
2
3use super::super::Operation;
4use crate::error::Result;
5use crate::models::quote::QuoteSummaryResponse;
6
7use super::ProviderCore;
8
9/// [`crate::Capability::QUOTE`] — single and batch equity quotes.
10#[async_trait::async_trait]
11pub trait QuoteProvider: ProviderCore {
12    /// Fetch every quote module this provider serves for one symbol.
13    async fn fetch_quote(&self, symbol: &str) -> Result<QuoteSummaryResponse>;
14
15    /// Fetch quotes for multiple symbols in a single request.
16    /// Returns `(symbol, QuoteSummaryResponse)` pairs — only partially populated
17    /// (price module only) since batch endpoints don't return full quoteSummary data.
18    async fn fetch_quotes_batch(&self, _: &[&str]) -> Result<Vec<(String, QuoteSummaryResponse)>> {
19        Err(self.not_supported(Operation::QuotesBatch))
20    }
21
22    /// Fetch a snapshot for symbols spanning several asset classes in one
23    /// request. Rows the provider could not resolve are returned with
24    /// `error` set rather than dropped.
25    ///
26    /// NOTE: Polygon is the only cross-asset snapshot among the providers
27    /// integrated here. The keyless sources are each single-asset-class, so
28    /// reproducing this means fanning out per class and inventing a merge.
29    async fn fetch_unified_snapshot(
30        &self,
31        _symbols: &[&str],
32    ) -> Result<Vec<crate::models::quote::snapshot::MarketSnapshot>> {
33        Err(self.not_supported(Operation::UnifiedSnapshot))
34    }
35}
36
37/// [`crate::Capability::CHART`] — historical OHLCV candles and sparklines.
38#[async_trait::async_trait]
39pub trait ChartProvider: ProviderCore {
40    /// Fetch OHLCV candles at one interval over one range.
41    async fn fetch_chart(
42        &self,
43        symbol: &str,
44        interval: crate::Interval,
45        range: crate::TimeRange,
46    ) -> Result<crate::models::chart::Chart>;
47
48    /// Fetch OHLCV candles between two Unix timestamps.
49    async fn fetch_chart_range(
50        &self,
51        _symbol: &str,
52        _interval: crate::Interval,
53        _start: i64,
54        _end: i64,
55    ) -> Result<crate::models::chart::Chart> {
56        Err(self.not_supported(Operation::ChartRange))
57    }
58
59    /// Fetch lightweight sparkline data for multiple symbols in a single request.
60    /// Returns successfully-parsed `(symbol, Spark)` pairs; callers fill in
61    /// missing-symbol errors for any symbol absent from the result.
62    async fn fetch_spark(
63        &self,
64        _symbols: &[&str],
65        _interval: crate::Interval,
66        _range: crate::TimeRange,
67    ) -> Result<Vec<(String, crate::models::chart::spark::Spark)>> {
68        Err(self.not_supported(Operation::Spark))
69    }
70
71    /// Fetch grouped daily OHLCV bars for every stock ticker on `date`
72    /// (`YYYY-MM-DD`) in a single request — market-wide rather than
73    /// symbol-scoped. Returns `(symbol, candle)` pairs.
74    ///
75    /// NOTE: no keyless provider in this crate publishes a market-wide bulk
76    /// EOD file for stocks; this stays a Polygon-only capability.
77    async fn fetch_grouped_daily(
78        &self,
79        _date: &str,
80    ) -> Result<Vec<(String, crate::models::chart::Candle)>> {
81        Err(self.not_supported(Operation::GroupedDaily))
82    }
83
84    /// Fetch grouped daily OHLCV bars for every crypto ticker on `date`
85    /// (`YYYY-MM-DD`) in a single request. Returns `(symbol, candle)` pairs.
86    ///
87    /// NOTE: Binance's 24hr ticker endpoint covers every symbol in one call
88    /// but only as a rolling now-minus-24h window, not an arbitrary
89    /// historical `date` — the wrong shape for this operation, so it stays
90    /// Polygon-only.
91    async fn fetch_crypto_grouped_daily(
92        &self,
93        _date: &str,
94    ) -> Result<Vec<(String, crate::models::chart::Candle)>> {
95        Err(self.not_supported(Operation::CryptoGroupedDaily))
96    }
97
98    /// Fetch grouped daily OHLCV bars for every forex ticker on `date`
99    /// (`YYYY-MM-DD`) in a single request. Returns `(symbol, candle)` pairs.
100    ///
101    /// NOTE: Frankfurter serves every ECB reference rate for a historical
102    /// `date` in one call, but only a single daily fixing rate, not OHLCV
103    /// candles — the wrong shape for this operation, so it stays
104    /// Polygon-only.
105    async fn fetch_forex_grouped_daily(
106        &self,
107        _date: &str,
108    ) -> Result<Vec<(String, crate::models::chart::Candle)>> {
109        Err(self.not_supported(Operation::ForexGroupedDaily))
110    }
111}
112
113/// [`crate::Capability::FUNDAMENTALS`] — financial statements and share-supply data.
114#[async_trait::async_trait]
115pub trait FundamentalsProvider: ProviderCore {
116    /// Fetch one financial statement at one reporting frequency.
117    async fn fetch_financials(
118        &self,
119        symbol: &str,
120        stmt_type: crate::StatementType,
121        frequency: crate::Frequency,
122    ) -> Result<crate::models::fundamentals::FinancialStatement>;
123
124    /// Fetch bi-monthly short-interest settlement reports.
125    async fn fetch_short_interest(
126        &self,
127        _symbol: &str,
128    ) -> Result<Vec<crate::models::fundamentals::ShortInterest>> {
129        Err(self.not_supported(Operation::ShortInterest))
130    }
131
132    /// Fetch daily short-volume data.
133    async fn fetch_short_volume(
134        &self,
135        _symbol: &str,
136    ) -> Result<Vec<crate::models::fundamentals::ShortVolume>> {
137        Err(self.not_supported(Operation::ShortVolume))
138    }
139
140    /// Fetch share float and shares outstanding.
141    async fn fetch_share_float(
142        &self,
143        _symbol: &str,
144    ) -> Result<crate::models::fundamentals::ShareFloat> {
145        Err(self.not_supported(Operation::ShareFloat))
146    }
147
148    /// Fetch the company's identity/classification profile.
149    async fn fetch_company_profile(
150        &self,
151        _symbol: &str,
152    ) -> Result<crate::models::fundamentals::CompanyProfile> {
153        Err(self.not_supported(Operation::CompanyProfile))
154    }
155
156    /// Fetch the aggregated analyst price-target consensus.
157    async fn fetch_price_target_consensus(
158        &self,
159        _symbol: &str,
160    ) -> Result<crate::models::fundamentals::PriceTargetConsensus> {
161        Err(self.not_supported(Operation::PriceTargetConsensus))
162    }
163
164    /// Fetch price-target publication activity over trailing windows.
165    ///
166    /// NOTE: analyst price targets aren't SEC-filed data — no keyless
167    /// provider in this crate publishes trailing-window target-publication
168    /// counts, so this stays FMP-only.
169    async fn fetch_price_target_summary(
170        &self,
171        _symbol: &str,
172    ) -> Result<crate::models::fundamentals::PriceTargetSummary> {
173        Err(self.not_supported(Operation::PriceTargetSummary))
174    }
175
176    /// Fetch the aggregated analyst rating consensus.
177    async fn fetch_rating_consensus(
178        &self,
179        _symbol: &str,
180    ) -> Result<crate::models::fundamentals::RatingConsensus> {
181        Err(self.not_supported(Operation::RatingConsensus))
182    }
183
184    /// Fetch the trailing-twelve-month key-metrics snapshot.
185    async fn fetch_key_metrics_ttm(
186        &self,
187        _symbol: &str,
188    ) -> Result<crate::models::fundamentals::KeyMetricsTtm> {
189        Err(self.not_supported(Operation::KeyMetricsTtm))
190    }
191
192    /// Fetch the trailing-twelve-month ratios snapshot.
193    async fn fetch_ratios_ttm(
194        &self,
195        _symbol: &str,
196    ) -> Result<crate::models::fundamentals::FinancialRatiosTtm> {
197        Err(self.not_supported(Operation::RatiosTtm))
198    }
199
200    /// Fetch an ETF's profile and portfolio holdings.
201    async fn fetch_etf_profile(
202        &self,
203        _symbol: &str,
204    ) -> Result<crate::models::fundamentals::EtfProfile> {
205        Err(self.not_supported(Operation::EtfProfile))
206    }
207
208    /// Fetch earnings-surprise history, newest first.
209    async fn fetch_earnings_surprises(
210        &self,
211        _symbol: &str,
212    ) -> Result<Vec<crate::models::fundamentals::EarningsSurprise>> {
213        Err(self.not_supported(Operation::EarningsSurprises))
214    }
215
216    /// Fetch the raw per-analyst grade-action history behind
217    /// [`fetch_rating_consensus`](Self::fetch_rating_consensus)'s rollup.
218    async fn fetch_grading_history(
219        &self,
220        _symbol: &str,
221    ) -> Result<Vec<crate::models::fundamentals::GradingAction>> {
222        Err(self.not_supported(Operation::GradingHistory))
223    }
224}
225
226/// [`crate::Capability::CORPORATE`] — news, corporate events, similar-symbol
227/// recommendations.
228#[async_trait::async_trait]
229pub trait CorporateProvider: ProviderCore {
230    /// Fetch recent news articles mentioning one symbol.
231    async fn fetch_news(&self, symbol: &str) -> Result<Vec<crate::models::corporate::news::News>>;
232
233    /// Fetch dividends, splits, and capital gains for one symbol.
234    async fn fetch_events(&self, symbol: &str)
235    -> Result<crate::models::chart::events::ChartEvents>;
236
237    /// Symbols this provider considers comparable to `symbol`.
238    async fn fetch_similar_symbols(
239        &self,
240        _symbol: &str,
241        _limit: u32,
242    ) -> Result<Vec<crate::models::corporate::recommendation::SimilarSymbol>> {
243        Err(self.not_supported(Operation::Recommendations))
244    }
245
246    /// Fetch the company's own press releases.
247    async fn fetch_press_releases(
248        &self,
249        _symbol: &str,
250        _limit: u32,
251    ) -> Result<Vec<crate::models::corporate::press_release::PressRelease>> {
252        Err(self.not_supported(Operation::PressReleases))
253    }
254
255    /// Fetch an earnings call transcript, provider-neutral shape. `quarter`
256    /// and `year` narrow to a specific call; a provider with no "latest"
257    /// shortcut requires both.
258    async fn fetch_earnings_transcript(
259        &self,
260        _symbol: &str,
261        _quarter: Option<&str>,
262        _year: Option<i32>,
263    ) -> Result<crate::models::corporate::earnings_transcript::EarningsTranscript> {
264        Err(self.not_supported(Operation::EarningsTranscript))
265    }
266
267    /// Fetch reported executive compensation, most recent fiscal year first.
268    async fn fetch_executive_compensation(
269        &self,
270        _symbol: &str,
271    ) -> Result<Vec<crate::models::corporate::governance::ExecutiveCompensation>> {
272        Err(self.not_supported(Operation::ExecutiveCompensation))
273    }
274
275    /// Fetch reported employee headcount history, most recent period first.
276    async fn fetch_employee_count(
277        &self,
278        _symbol: &str,
279    ) -> Result<Vec<crate::models::corporate::governance::EmployeeCount>> {
280        Err(self.not_supported(Operation::EmployeeCount))
281    }
282}
283
284/// [`crate::Capability::OPTIONS`] — options chains.
285#[async_trait::async_trait]
286pub trait OptionsProvider: ProviderCore {
287    /// Fetch the options chain for one symbol.
288    async fn fetch_options(
289        &self,
290        symbol: &str,
291        date: Option<i64>,
292    ) -> Result<crate::models::options::Options>;
293}
294
295/// [`crate::Capability::FILINGS`] — SEC filing data.
296#[async_trait::async_trait]
297pub trait FilingsProvider: ProviderCore {
298    /// Fetch regulatory filings for one symbol.
299    async fn fetch_filings(&self, symbol: &str) -> Result<crate::models::filings::ProviderFilings>;
300
301    /// Fetch the sectioned text of one filing by accession number.
302    async fn fetch_filing_sections(
303        &self,
304        _accession_number: &str,
305        _form: crate::models::filings::FilingSectionForm,
306    ) -> Result<Vec<crate::models::filings::FilingSection>> {
307        Err(self.not_supported(Operation::FilingSections))
308    }
309
310    /// Fetch risk factors extracted from a symbol's SEC filings.
311    async fn fetch_risk_factors(
312        &self,
313        _symbol: &str,
314    ) -> Result<Vec<crate::models::filings::RiskFactor>> {
315        Err(self.not_supported(Operation::RiskFactors))
316    }
317
318    /// Search filing *text* rather than looking filings up by filer.
319    ///
320    /// `symbol` scopes the search to one filer; the provider resolves it to
321    /// whatever identifier its own index is keyed by (a CIK, for EDGAR).
322    /// `None` searches every filer.
323    async fn fetch_filing_search(
324        &self,
325        _symbol: Option<&str>,
326        _query: &str,
327        _filters: &crate::models::filings::FilingSearchFilters,
328    ) -> Result<Vec<crate::models::filings::FilingSearchHit>> {
329        Err(self.not_supported(Operation::FilingSearch))
330    }
331
332    /// Fetch insider transactions reported on Forms 3/4/5, newest filing first.
333    async fn fetch_insider_trades(
334        &self,
335        _symbol: &str,
336        _limit: u32,
337    ) -> Result<Vec<crate::models::filings::InsiderTrade>> {
338        Err(self.not_supported(Operation::InsiderTrades))
339    }
340
341    /// Fetch the latest reported 13F institutional holdings for a filer.
342    async fn fetch_institutional_holdings(
343        &self,
344        _symbol: &str,
345    ) -> Result<Vec<crate::models::filings::InstitutionalHolding>> {
346        Err(self.not_supported(Operation::InstitutionalHoldings))
347    }
348
349    /// Fetch congressional (senate) stock-trade disclosures for a symbol.
350    async fn fetch_congressional_trades(
351        &self,
352        _symbol: &str,
353    ) -> Result<Vec<crate::models::filings::CongressionalTrade>> {
354        Err(self.not_supported(Operation::CongressionalTrades))
355    }
356
357    /// Fetch SEC fails-to-deliver data for a symbol.
358    async fn fetch_fails_to_deliver(
359        &self,
360        _symbol: &str,
361    ) -> Result<Vec<crate::models::filings::FailToDeliver>> {
362        Err(self.not_supported(Operation::FailsToDeliver))
363    }
364}