Skip to main content

finance_query/domains/
economic.rs

1//! Macro-economic indicator query handle.
2//!
3//! Created via [`Providers::economic`](crate::Providers::economic).
4
5use std::sync::Arc;
6
7use crate::error::Result;
8use crate::models::economic::{EconomicCategory, EconomicRelease, EconomicSeriesMatch};
9use crate::providers::{Capability, Operation, ProviderSet};
10
11domain_handle! {
12    /// A macro-economic data series backed by configured data providers.
13    ///
14    /// Created via [`Providers::economic`](crate::Providers::economic).
15    pub struct EconomicIndicator { series_id, series_id }
16    cache: crate::models::economic::EconomicSeries
17}
18
19impl EconomicIndicator {
20    /// Fetch the full data series for this economic indicator.
21    pub async fn series(&self) -> Result<crate::models::economic::EconomicSeries> {
22        fetch_via!(
23            self,
24            series_id,
25            ECONOMIC,
26            as_economic,
27            EconomicSeries,
28            fetch_economic_series,
29            crate::models::economic::EconomicSeries
30        )
31    }
32
33    /// Fetch this series as it stood on `date` (`YYYY-MM-DD`) instead of as
34    /// currently revised (FRED only, via ALFRED's realtime window).
35    ///
36    /// Macro data is revised after publication, so backtesting a rule against
37    /// today's series is look-ahead bias: the values it trades on were not
38    /// knowable at the time. This returns the vintage actually published as of
39    /// `date`. Cached per date.
40    pub async fn as_of(&self, date: &str) -> Result<crate::models::economic::EconomicSeries> {
41        let series_id: String = self.series_id().to_string();
42        let date = date.to_string();
43        let providers = Arc::clone(&self.providers);
44        self.cache
45            .get_or_try(format!("as_of\u{1f}{date}"), move || async move {
46                providers
47                    .fetch(Capability::ECONOMIC, move |p| {
48                        let (series_id, date) = (series_id.clone(), date.clone());
49                        let p = p.clone();
50                        async move {
51                            p.as_economic()
52                                .ok_or_else(|| p.not_supported(Operation::EconomicSeriesAsOf))?
53                                .fetch_economic_series_as_of(&series_id, &date)
54                                .await
55                        }
56                    })
57                    .await
58            })
59            .await
60    }
61}
62
63/// The macro-economic series catalog: search and browse rather than fetch.
64///
65/// Routes through [`Capability::ECONOMIC`]. [`EconomicIndicator`] needs a
66/// series id you already know; this handle is how you find one. FRED is
67/// currently the only provider.
68///
69/// Created via [`Providers::economic_catalog`](crate::Providers::economic_catalog).
70pub struct EconomicCatalog {
71    providers: Arc<ProviderSet>,
72}
73
74impl EconomicCatalog {
75    pub(crate) fn with_providers(providers: Arc<ProviderSet>) -> Self {
76        Self { providers }
77    }
78
79    /// Search the series catalog by free text, most popular first.
80    pub async fn search(&self, query: &str, limit: u32) -> Result<Vec<EconomicSeriesMatch>> {
81        let query = query.to_string();
82        dispatch_via!(
83            self,
84            ECONOMIC,
85            as_economic,
86            EconomicSearch,
87            fetch_economic_search,
88            [query],
89            &query,
90            limit
91        )
92    }
93
94    /// List the child categories of `parent_id`. Pass `0` for the root.
95    pub async fn categories(&self, parent_id: i64) -> Result<Vec<EconomicCategory>> {
96        dispatch_via!(
97            self,
98            ECONOMIC,
99            as_economic,
100            EconomicCategories,
101            fetch_economic_categories,
102            [],
103            parent_id
104        )
105    }
106
107    /// List every scheduled data release the provider publishes.
108    pub async fn releases(&self) -> Result<Vec<EconomicRelease>> {
109        dispatch_via!(
110            self,
111            ECONOMIC,
112            as_economic,
113            EconomicReleases,
114            fetch_economic_releases,
115            []
116        )
117    }
118}