Skip to main content

finance_query/providers/adapter/
markets.rs

1//! Capability traits over markets rather than a single equity symbol.
2
3use super::super::Operation;
4use crate::error::Result;
5
6use super::ProviderCore;
7
8/// [`crate::Capability::DISCOVERY`] — symbol search, reference data, exchanges,
9/// screeners.
10#[async_trait::async_trait]
11pub trait DiscoveryProvider: ProviderCore {
12    /// Fetch an independently numbered delisted page; callers validate scan progress.
13    async fn fetch_delisted_stocks_page_at(
14        &self,
15        _page: u32,
16        _limit: u32,
17    ) -> Result<Vec<crate::SymbolMatch>> {
18        Err(self.not_supported(Operation::DelistedStocksPageAt))
19    }
20    /// Fetch one delisted-stock page, bound to this provider and page size.
21    async fn fetch_delisted_stocks_page(
22        &self,
23        _limit: u32,
24        _cursor: Option<&crate::PageCursor>,
25    ) -> Result<crate::ProviderPage<crate::SymbolMatch>> {
26        Err(self.not_supported(Operation::DelistedStocksPage))
27    }
28    /// Fetch the current full directory, without assuming active status.
29    async fn fetch_stock_list(&self) -> Result<Vec<crate::SymbolMatch>> {
30        Err(self.not_supported(Operation::StockList))
31    }
32
33    /// Fetch one provider-defined bulk-profile part, not the entire directory.
34    async fn fetch_company_profiles_bulk(&self, _part: u32) -> Result<Vec<crate::CompanyProfile>> {
35        Err(self.not_supported(Operation::CompanyProfilesBulk))
36    }
37
38    /// Fetch one dated stock-directory page.
39    async fn fetch_stock_listings_page(
40        &self,
41        _request: &crate::StockListingRequest,
42        _cursor: Option<&crate::PageCursor>,
43    ) -> Result<crate::ProviderPage<crate::StockListing>> {
44        Err(self.not_supported(Operation::StockListingsPage))
45    }
46
47    /// Fetch company details as of a calendar date.
48    async fn fetch_symbol_details_at(
49        &self,
50        _symbol: &str,
51        _date: &str,
52    ) -> Result<crate::SymbolDetails> {
53        Err(self.not_supported(Operation::SymbolDetailsAt))
54    }
55
56    /// Fetch the dated ticker changes of one security, oldest first.
57    async fn fetch_ticker_changes(&self, _id: &str) -> Result<Vec<crate::TickerChange>> {
58        Err(self.not_supported(Operation::TickerChanges))
59    }
60
61    /// Fetch the provider's stock-type vocabulary.
62    async fn fetch_stock_types(&self, _locale: &str) -> Result<Vec<crate::StockType>> {
63        Err(self.not_supported(Operation::StockTypes))
64    }
65    /// Search the provider's symbol universe by free-text query.
66    async fn fetch_symbol_search(
67        &self,
68        query: &str,
69        limit: u32,
70    ) -> Result<Vec<crate::models::discovery::reference::SymbolMatch>>;
71
72    /// Fetch detailed reference data for a single symbol.
73    async fn fetch_symbol_details(
74        &self,
75        _symbol: &str,
76    ) -> Result<crate::models::discovery::reference::SymbolDetails> {
77        Err(self.not_supported(Operation::SymbolDetails))
78    }
79
80    /// Fetch the provider's tradable exchange listing.
81    async fn fetch_exchanges(
82        &self,
83    ) -> Result<Vec<crate::models::discovery::reference::ExchangeInfo>> {
84        Err(self.not_supported(Operation::Exchanges))
85    }
86
87    /// Run a screener query over the provider's universe.
88    async fn fetch_screener(
89        &self,
90        _filters: &crate::models::discovery::reference::ScreenerFilters,
91    ) -> Result<Vec<crate::models::discovery::reference::ScreenerMatch>> {
92        Err(self.not_supported(Operation::Screener))
93    }
94
95    /// Fetch the provider's whole listed-security universe.
96    ///
97    /// `active = false` asks for delisted securities instead. Unlike
98    /// [`fetch_symbol_search`](Self::fetch_symbol_search) this is an unfiltered
99    /// dump, so expect thousands of rows in one response.
100    async fn fetch_listing_status(
101        &self,
102        _active: bool,
103    ) -> Result<Vec<crate::models::discovery::reference::SymbolMatch>> {
104        Err(self.not_supported(Operation::ListingStatus))
105    }
106}
107
108/// [`crate::Capability::CALENDAR`] — market-wide calendars.
109#[async_trait::async_trait]
110pub trait CalendarProvider: ProviderCore {
111    /// Fetch a market-wide calendar over `[from, to]` (`YYYY-MM-DD` dates).
112    ///
113    /// One method rather than one per kind — providers serve all kinds from the
114    /// same calendar family, and `kind.operation()` still reports the precise
115    /// [`Operation`] in `NotSupported` errors.
116    async fn fetch_market_calendar(
117        &self,
118        kind: crate::models::calendar::market::CalendarKind,
119        from: &str,
120        to: &str,
121    ) -> Result<Vec<crate::models::calendar::market::MarketCalendarEntry>>;
122}
123
124/// [`crate::Capability::MARKET`] — sector/industry performance and movers.
125///
126/// Movers is the required primary (every current implementor serves it);
127/// the sector/industry statistics default to `NotSupported` since coverage
128/// is ragged (FMP serves all of them; Yahoo and Alpha Vantage only movers).
129#[async_trait::async_trait]
130pub trait MarketProvider: ProviderCore {
131    /// Fetch the market movers list for `direction`.
132    async fn fetch_market_movers(
133        &self,
134        direction: crate::models::market::performance::MoverDirection,
135    ) -> Result<Vec<crate::models::market::performance::MoverQuote>>;
136
137    /// Fetch aggregate performance for every sector.
138    async fn fetch_sector_performance(
139        &self,
140    ) -> Result<Vec<crate::models::market::performance::SectorPerformance>> {
141        Err(self.not_supported(Operation::SectorPerformance))
142    }
143
144    /// Fetch historical aggregate sector performance, most recent first.
145    async fn fetch_sector_performance_history(
146        &self,
147        _limit: u32,
148    ) -> Result<Vec<crate::models::market::performance::SectorPerformanceHistory>> {
149        Err(self.not_supported(Operation::SectorPerformanceHistory))
150    }
151
152    /// Fetch sector price/earnings ratios.
153    async fn fetch_sector_pe(&self) -> Result<Vec<crate::models::market::performance::SectorPe>> {
154        Err(self.not_supported(Operation::SectorPerformance))
155    }
156
157    /// Fetch industry price/earnings ratios.
158    ///
159    /// NOTE: FMP is the only route among the providers integrated here.
160    /// Yahoo's screener fan-out backs `fetch_sector_pe` across 11 sectors,
161    /// but industries run to roughly 160 and the thin ones carry too few
162    /// sampled P/Es to aggregate into a publishable number.
163    async fn fetch_industry_pe(
164        &self,
165    ) -> Result<Vec<crate::models::market::performance::IndustryPe>> {
166        Err(self.not_supported(Operation::SectorPerformance))
167    }
168}
169
170/// [`crate::Capability::CRYPTO`] — cryptocurrency quotes.
171#[async_trait::async_trait]
172pub trait CryptoProvider: ProviderCore {
173    /// Fetch a quote for one coin, priced in `vs_currency`.
174    async fn fetch_crypto_quote(
175        &self,
176        id: &str,
177        vs_currency: &str,
178    ) -> Result<crate::models::crypto::CryptoQuote>;
179
180    /// Fetch total value locked in a DeFi protocol.
181    #[cfg(feature = "defi")]
182    async fn fetch_protocol_tvl(
183        &self,
184        _protocol: &str,
185    ) -> Result<crate::models::crypto::defi::ProtocolTvl> {
186        Err(self.not_supported(Operation::ProtocolTvl))
187    }
188
189    /// Fetch a DeFi protocol's TVL history, oldest first.
190    #[cfg(feature = "defi")]
191    async fn fetch_protocol_tvl_history(
192        &self,
193        _protocol: &str,
194    ) -> Result<Vec<crate::models::crypto::defi::TvlPoint>> {
195        Err(self.not_supported(Operation::ProtocolTvlHistory))
196    }
197
198    /// Fetch coins/nfts/categories trending in the last 24h (CoinGecko only).
199    #[cfg(feature = "crypto")]
200    async fn fetch_crypto_trending(&self) -> Result<Vec<crate::models::crypto::TrendingCoin>> {
201        Err(self.not_supported(Operation::CryptoTrending))
202    }
203
204    /// Fetch aggregate global cryptocurrency market statistics (CoinGecko only).
205    #[cfg(feature = "crypto")]
206    async fn fetch_crypto_global(&self) -> Result<crate::models::crypto::GlobalCryptoStats> {
207        Err(self.not_supported(Operation::CryptoGlobal))
208    }
209
210    /// Fetch market-wide crypto news, newest first.
211    async fn fetch_crypto_news(
212        &self,
213        _limit: u32,
214    ) -> Result<Vec<crate::models::corporate::news::News>> {
215        Err(self.not_supported(Operation::CryptoNews))
216    }
217}
218
219/// [`crate::Capability::ECONOMIC`] — macro-economic data series.
220#[async_trait::async_trait]
221pub trait EconomicProvider: ProviderCore {
222    /// Fetch observations for one macro-economic series.
223    async fn fetch_economic_series(
224        &self,
225        series_id: &str,
226    ) -> Result<crate::models::economic::EconomicSeries>;
227
228    /// Fetch a series as it stood on `date` (`YYYY-MM-DD`) rather than as
229    /// currently revised — the point-in-time view backtests need.
230    ///
231    /// NOTE: this vintage/realtime-window concept is unique to FRED/ALFRED
232    /// among the providers integrated here — WorldBank, FiscalData, and BLS
233    /// all serve only the latest value per period, with no revision
234    /// history. Stays FRED-only.
235    async fn fetch_economic_series_as_of(
236        &self,
237        _series_id: &str,
238        _date: &str,
239    ) -> Result<crate::models::economic::EconomicSeries> {
240        Err(self.not_supported(Operation::EconomicSeriesAsOf))
241    }
242
243    /// Search the provider's series catalog by free text.
244    ///
245    /// NOTE: WorldBank and BLS treat series ids as opaque, live-validated
246    /// strings with no local catalog; FiscalData carries only 7 curated
247    /// series. None is a meaningful substitute for FRED's live full-text
248    /// search over its ~800k series, so this stays FRED-only.
249    async fn fetch_economic_search(
250        &self,
251        _query: &str,
252        _limit: u32,
253    ) -> Result<Vec<crate::models::economic::EconomicSeriesMatch>> {
254        Err(self.not_supported(Operation::EconomicSearch))
255    }
256
257    /// List the child categories of `parent_id` in the series category tree.
258    ///
259    /// NOTE: none of WorldBank/FiscalData/BLS models a category/topic tree
260    /// in this crate. Stays FRED-only.
261    async fn fetch_economic_categories(
262        &self,
263        _parent_id: i64,
264    ) -> Result<Vec<crate::models::economic::EconomicCategory>> {
265        Err(self.not_supported(Operation::EconomicCategories))
266    }
267
268    /// List the provider's scheduled data releases.
269    ///
270    /// NOTE: no keyless provider integrated here models a scheduled-release
271    /// entity. Stays FRED-only.
272    async fn fetch_economic_releases(
273        &self,
274    ) -> Result<Vec<crate::models::economic::EconomicRelease>> {
275        Err(self.not_supported(Operation::EconomicReleases))
276    }
277
278    /// Fetch US Treasury securities auctions matching `query`, most recent
279    /// auction date first.
280    ///
281    /// NOTE: Treasury publishes the auction record itself through FiscalData;
282    /// no other provider integrated here carries per-auction bidder
283    /// breakdowns. Stays FiscalData-only.
284    #[cfg(feature = "fiscaldata")]
285    async fn fetch_treasury_auctions(
286        &self,
287        _query: &crate::models::economic::TreasuryAuctionQuery,
288    ) -> Result<Vec<crate::models::economic::TreasuryAuction>> {
289        Err(self.not_supported(Operation::TreasuryAuctions))
290    }
291
292    /// Fetch the US Treasury auctions scheduled but not yet held, soonest
293    /// first.
294    ///
295    /// NOTE: FiscalData-only for the same reason as
296    /// [`fetch_treasury_auctions`](Self::fetch_treasury_auctions).
297    #[cfg(feature = "fiscaldata")]
298    async fn fetch_upcoming_auctions(
299        &self,
300    ) -> Result<Vec<crate::models::economic::UpcomingAuction>> {
301        Err(self.not_supported(Operation::UpcomingAuctions))
302    }
303}
304
305/// [`crate::Capability::FOREX`] — currency-pair quotes.
306#[async_trait::async_trait]
307pub trait ForexProvider: ProviderCore {
308    /// Fetch the exchange rate for one currency pair.
309    async fn fetch_forex_quote(
310        &self,
311        from: &str,
312        to: &str,
313    ) -> Result<crate::models::forex::ForexQuote>;
314
315    /// Fetch market-wide forex news, newest first.
316    async fn fetch_forex_news(
317        &self,
318        _limit: u32,
319    ) -> Result<Vec<crate::models::corporate::news::News>> {
320        Err(self.not_supported(Operation::ForexNews))
321    }
322}
323
324/// [`crate::Capability::INDICES`] — stock market index quotes.
325#[async_trait::async_trait]
326pub trait IndicesProvider: ProviderCore {
327    /// Fetch a quote for one market index.
328    async fn fetch_indices_quote(&self, symbol: &str)
329    -> Result<crate::models::indices::IndexQuote>;
330
331    /// Fetch the current constituents of a major index.
332    async fn fetch_index_constituents(
333        &self,
334        _index: crate::models::indices::MajorIndex,
335    ) -> Result<Vec<crate::models::indices::IndexConstituent>> {
336        Err(self.not_supported(Operation::IndexConstituents))
337    }
338
339    /// Fetch historical constituent changes of a major index.
340    async fn fetch_index_constituent_changes(
341        &self,
342        _index: crate::models::indices::MajorIndex,
343    ) -> Result<Vec<crate::models::indices::IndexConstituentChange>> {
344        Err(self.not_supported(Operation::IndexConstituentChanges))
345    }
346}
347
348/// [`crate::Capability::FUTURES`] — futures contract quotes.
349#[async_trait::async_trait]
350pub trait FuturesProvider: ProviderCore {
351    /// Fetch a quote for one futures contract.
352    async fn fetch_futures_quote(
353        &self,
354        symbol: &str,
355    ) -> Result<crate::models::futures::FuturesQuote>;
356
357    /// Fetch weekly CFTC Commitments of Traders positioning for a futures
358    /// symbol, broken down by trader category.
359    #[cfg(feature = "cftc")]
360    async fn fetch_commitments_of_traders(
361        &self,
362        _symbol: &str,
363    ) -> Result<crate::models::futures::cot::CommitmentsOfTraders> {
364        Err(self.not_supported(Operation::CommitmentsOfTraders))
365    }
366}
367
368/// [`crate::Capability::COMMODITIES`] — commodity price quotes.
369#[async_trait::async_trait]
370pub trait CommoditiesProvider: ProviderCore {
371    /// Fetch a quote for one commodity.
372    async fn fetch_commodities_quote(
373        &self,
374        symbol: &str,
375    ) -> Result<crate::models::commodities::CommodityQuote>;
376}