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    /// Search the provider's symbol universe by free-text query.
13    async fn fetch_symbol_search(
14        &self,
15        query: &str,
16        limit: u32,
17    ) -> Result<Vec<crate::models::discovery::reference::SymbolMatch>>;
18
19    /// Fetch detailed reference data for a single symbol.
20    async fn fetch_symbol_details(
21        &self,
22        _symbol: &str,
23    ) -> Result<crate::models::discovery::reference::SymbolDetails> {
24        Err(self.not_supported(Operation::SymbolDetails))
25    }
26
27    /// Fetch the provider's tradable exchange listing.
28    async fn fetch_exchanges(
29        &self,
30    ) -> Result<Vec<crate::models::discovery::reference::ExchangeInfo>> {
31        Err(self.not_supported(Operation::Exchanges))
32    }
33
34    /// Run a screener query over the provider's universe.
35    async fn fetch_screener(
36        &self,
37        _filters: &crate::models::discovery::reference::ScreenerFilters,
38    ) -> Result<Vec<crate::models::discovery::reference::ScreenerMatch>> {
39        Err(self.not_supported(Operation::Screener))
40    }
41
42    /// Fetch the provider's whole listed-security universe.
43    ///
44    /// `active = false` asks for delisted securities instead. Unlike
45    /// [`fetch_symbol_search`](Self::fetch_symbol_search) this is an unfiltered
46    /// dump, so expect thousands of rows in one response.
47    async fn fetch_listing_status(
48        &self,
49        _active: bool,
50    ) -> Result<Vec<crate::models::discovery::reference::SymbolMatch>> {
51        Err(self.not_supported(Operation::ListingStatus))
52    }
53}
54
55/// [`crate::Capability::CALENDAR`] — market-wide calendars.
56#[async_trait::async_trait]
57pub trait CalendarProvider: ProviderCore {
58    /// Fetch a market-wide calendar over `[from, to]` (`YYYY-MM-DD` dates).
59    ///
60    /// One method rather than one per kind — providers serve all kinds from the
61    /// same calendar family, and `kind.operation()` still reports the precise
62    /// [`Operation`] in `NotSupported` errors.
63    async fn fetch_market_calendar(
64        &self,
65        kind: crate::models::calendar::market::CalendarKind,
66        from: &str,
67        to: &str,
68    ) -> Result<Vec<crate::models::calendar::market::MarketCalendarEntry>>;
69}
70
71/// [`crate::Capability::MARKET`] — sector/industry performance and movers.
72///
73/// Movers is the required primary (every current implementor serves it);
74/// the sector/industry statistics default to `NotSupported` since coverage
75/// is ragged (FMP serves all of them; Yahoo and Alpha Vantage only movers).
76#[async_trait::async_trait]
77pub trait MarketProvider: ProviderCore {
78    /// Fetch the market movers list for `direction`.
79    async fn fetch_market_movers(
80        &self,
81        direction: crate::models::market::performance::MoverDirection,
82    ) -> Result<Vec<crate::models::market::performance::MoverQuote>>;
83
84    /// Fetch aggregate performance for every sector.
85    async fn fetch_sector_performance(
86        &self,
87    ) -> Result<Vec<crate::models::market::performance::SectorPerformance>> {
88        Err(self.not_supported(Operation::SectorPerformance))
89    }
90
91    /// Fetch historical aggregate sector performance, most recent first.
92    async fn fetch_sector_performance_history(
93        &self,
94        _limit: u32,
95    ) -> Result<Vec<crate::models::market::performance::SectorPerformanceHistory>> {
96        Err(self.not_supported(Operation::SectorPerformanceHistory))
97    }
98
99    /// Fetch sector price/earnings ratios.
100    async fn fetch_sector_pe(&self) -> Result<Vec<crate::models::market::performance::SectorPe>> {
101        Err(self.not_supported(Operation::SectorPerformance))
102    }
103
104    /// Fetch industry price/earnings ratios.
105    ///
106    /// NOTE: FMP is the only route among the providers integrated here.
107    /// Yahoo's screener fan-out backs `fetch_sector_pe` across 11 sectors,
108    /// but industries run to roughly 160 and the thin ones carry too few
109    /// sampled P/Es to aggregate into a publishable number.
110    async fn fetch_industry_pe(
111        &self,
112    ) -> Result<Vec<crate::models::market::performance::IndustryPe>> {
113        Err(self.not_supported(Operation::SectorPerformance))
114    }
115}
116
117/// [`crate::Capability::CRYPTO`] — cryptocurrency quotes.
118#[async_trait::async_trait]
119pub trait CryptoProvider: ProviderCore {
120    /// Fetch a quote for one coin, priced in `vs_currency`.
121    async fn fetch_crypto_quote(
122        &self,
123        id: &str,
124        vs_currency: &str,
125    ) -> Result<crate::models::crypto::CryptoQuote>;
126
127    /// Fetch total value locked in a DeFi protocol.
128    #[cfg(feature = "defi")]
129    async fn fetch_protocol_tvl(
130        &self,
131        _protocol: &str,
132    ) -> Result<crate::models::crypto::defi::ProtocolTvl> {
133        Err(self.not_supported(Operation::ProtocolTvl))
134    }
135
136    /// Fetch a DeFi protocol's TVL history, oldest first.
137    #[cfg(feature = "defi")]
138    async fn fetch_protocol_tvl_history(
139        &self,
140        _protocol: &str,
141    ) -> Result<Vec<crate::models::crypto::defi::TvlPoint>> {
142        Err(self.not_supported(Operation::ProtocolTvlHistory))
143    }
144
145    /// Fetch coins/nfts/categories trending in the last 24h (CoinGecko only).
146    #[cfg(feature = "crypto")]
147    async fn fetch_crypto_trending(&self) -> Result<Vec<crate::models::crypto::TrendingCoin>> {
148        Err(self.not_supported(Operation::CryptoTrending))
149    }
150
151    /// Fetch aggregate global cryptocurrency market statistics (CoinGecko only).
152    #[cfg(feature = "crypto")]
153    async fn fetch_crypto_global(&self) -> Result<crate::models::crypto::GlobalCryptoStats> {
154        Err(self.not_supported(Operation::CryptoGlobal))
155    }
156
157    /// Fetch market-wide crypto news, newest first.
158    async fn fetch_crypto_news(
159        &self,
160        _limit: u32,
161    ) -> Result<Vec<crate::models::corporate::news::News>> {
162        Err(self.not_supported(Operation::CryptoNews))
163    }
164}
165
166/// [`crate::Capability::ECONOMIC`] — macro-economic data series.
167#[async_trait::async_trait]
168pub trait EconomicProvider: ProviderCore {
169    /// Fetch observations for one macro-economic series.
170    async fn fetch_economic_series(
171        &self,
172        series_id: &str,
173    ) -> Result<crate::models::economic::EconomicSeries>;
174
175    /// Fetch a series as it stood on `date` (`YYYY-MM-DD`) rather than as
176    /// currently revised — the point-in-time view backtests need.
177    ///
178    /// NOTE: this vintage/realtime-window concept is unique to FRED/ALFRED
179    /// among the providers integrated here — WorldBank, FiscalData, and BLS
180    /// all serve only the latest value per period, with no revision
181    /// history. Stays FRED-only.
182    async fn fetch_economic_series_as_of(
183        &self,
184        _series_id: &str,
185        _date: &str,
186    ) -> Result<crate::models::economic::EconomicSeries> {
187        Err(self.not_supported(Operation::EconomicSeriesAsOf))
188    }
189
190    /// Search the provider's series catalog by free text.
191    ///
192    /// NOTE: WorldBank and BLS treat series ids as opaque, live-validated
193    /// strings with no local catalog; FiscalData carries only 7 curated
194    /// series. None is a meaningful substitute for FRED's live full-text
195    /// search over its ~800k series, so this stays FRED-only.
196    async fn fetch_economic_search(
197        &self,
198        _query: &str,
199        _limit: u32,
200    ) -> Result<Vec<crate::models::economic::EconomicSeriesMatch>> {
201        Err(self.not_supported(Operation::EconomicSearch))
202    }
203
204    /// List the child categories of `parent_id` in the series category tree.
205    ///
206    /// NOTE: none of WorldBank/FiscalData/BLS models a category/topic tree
207    /// in this crate. Stays FRED-only.
208    async fn fetch_economic_categories(
209        &self,
210        _parent_id: i64,
211    ) -> Result<Vec<crate::models::economic::EconomicCategory>> {
212        Err(self.not_supported(Operation::EconomicCategories))
213    }
214
215    /// List the provider's scheduled data releases.
216    ///
217    /// NOTE: no keyless provider integrated here models a scheduled-release
218    /// entity. Stays FRED-only.
219    async fn fetch_economic_releases(
220        &self,
221    ) -> Result<Vec<crate::models::economic::EconomicRelease>> {
222        Err(self.not_supported(Operation::EconomicReleases))
223    }
224}
225
226/// [`crate::Capability::FOREX`] — currency-pair quotes.
227#[async_trait::async_trait]
228pub trait ForexProvider: ProviderCore {
229    /// Fetch the exchange rate for one currency pair.
230    async fn fetch_forex_quote(
231        &self,
232        from: &str,
233        to: &str,
234    ) -> Result<crate::models::forex::ForexQuote>;
235
236    /// Fetch market-wide forex news, newest first.
237    async fn fetch_forex_news(
238        &self,
239        _limit: u32,
240    ) -> Result<Vec<crate::models::corporate::news::News>> {
241        Err(self.not_supported(Operation::ForexNews))
242    }
243}
244
245/// [`crate::Capability::INDICES`] — stock market index quotes.
246#[async_trait::async_trait]
247pub trait IndicesProvider: ProviderCore {
248    /// Fetch a quote for one market index.
249    async fn fetch_indices_quote(&self, symbol: &str)
250    -> Result<crate::models::indices::IndexQuote>;
251
252    /// Fetch the current constituents of a major index.
253    async fn fetch_index_constituents(
254        &self,
255        _index: crate::models::indices::MajorIndex,
256    ) -> Result<Vec<crate::models::indices::IndexConstituent>> {
257        Err(self.not_supported(Operation::IndexConstituents))
258    }
259
260    /// Fetch historical constituent changes of a major index.
261    async fn fetch_index_constituent_changes(
262        &self,
263        _index: crate::models::indices::MajorIndex,
264    ) -> Result<Vec<crate::models::indices::IndexConstituentChange>> {
265        Err(self.not_supported(Operation::IndexConstituentChanges))
266    }
267}
268
269/// [`crate::Capability::FUTURES`] — futures contract quotes.
270#[async_trait::async_trait]
271pub trait FuturesProvider: ProviderCore {
272    /// Fetch a quote for one futures contract.
273    async fn fetch_futures_quote(
274        &self,
275        symbol: &str,
276    ) -> Result<crate::models::futures::FuturesQuote>;
277
278    /// Fetch weekly CFTC Commitments of Traders positioning for a futures
279    /// symbol, broken down by trader category.
280    #[cfg(feature = "cftc")]
281    async fn fetch_commitments_of_traders(
282        &self,
283        _symbol: &str,
284    ) -> Result<crate::models::futures::cot::CommitmentsOfTraders> {
285        Err(self.not_supported(Operation::CommitmentsOfTraders))
286    }
287}
288
289/// [`crate::Capability::COMMODITIES`] — commodity price quotes.
290#[async_trait::async_trait]
291pub trait CommoditiesProvider: ProviderCore {
292    /// Fetch a quote for one commodity.
293    async fn fetch_commodities_quote(
294        &self,
295        symbol: &str,
296    ) -> Result<crate::models::commodities::CommodityQuote>;
297}