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