1use std::sync::Arc;
7
8use crate::error::Result;
9use crate::models::calendar::market::{CalendarKind, MarketCalendarEntry};
10use crate::models::chart::Candle;
11use crate::models::market::performance::{
12 IndustryPe, MoverDirection, MoverQuote, SectorPe, SectorPerformance,
13};
14use crate::providers::Capability;
15use crate::providers::ProviderSet;
16
17domain_handle! {
18 pub struct MarketCalendar
26 caches: { cache: Vec<MarketCalendarEntry> }
27}
28
29impl MarketCalendar {
30 pub async fn fetch(
34 &self,
35 kind: CalendarKind,
36 from: &str,
37 to: &str,
38 ) -> Result<Vec<MarketCalendarEntry>> {
39 let key = format!("{kind:?}\u{1f}{from}\u{1f}{to}");
40 let providers = Arc::clone(&self.providers);
41 let (from, to) = (from.to_string(), to.to_string());
42 self.cache
43 .get_or_try(key, move || async move {
44 providers
45 .fetch(Capability::CALENDAR, move |p| {
46 let (from, to) = (from.clone(), to.clone());
47 let p = p.clone();
48 async move {
49 p.as_calendar()
50 .ok_or_else(|| p.not_supported(kind.operation()))?
51 .fetch_market_calendar(kind, &from, &to)
52 .await
53 }
54 })
55 .await
56 })
57 .await
58 }
59
60 pub async fn earnings(&self, from: &str, to: &str) -> Result<Vec<MarketCalendarEntry>> {
62 self.fetch(CalendarKind::Earnings, from, to).await
63 }
64
65 pub async fn ipos(&self, from: &str, to: &str) -> Result<Vec<MarketCalendarEntry>> {
67 self.fetch(CalendarKind::Ipo, from, to).await
68 }
69
70 pub async fn dividends(&self, from: &str, to: &str) -> Result<Vec<MarketCalendarEntry>> {
72 self.fetch(CalendarKind::Dividend, from, to).await
73 }
74
75 pub async fn splits(&self, from: &str, to: &str) -> Result<Vec<MarketCalendarEntry>> {
77 self.fetch(CalendarKind::Split, from, to).await
78 }
79
80 pub async fn economic(&self, from: &str, to: &str) -> Result<Vec<MarketCalendarEntry>> {
82 self.fetch(CalendarKind::Economic, from, to).await
83 }
84
85 pub async fn holidays(&self) -> Result<Vec<MarketCalendarEntry>> {
88 self.fetch(CalendarKind::MarketHoliday, "", "").await
89 }
90
91 pub async fn market_status(&self) -> Result<Vec<MarketCalendarEntry>> {
94 self.fetch(CalendarKind::MarketStatus, "", "").await
95 }
96}
97
98pub struct Market {
106 providers: Arc<ProviderSet>,
107}
108
109impl Market {
110 pub async fn stock_bars_page(
113 &self,
114 request: &crate::StockBarsRequest,
115 cursor: Option<&crate::PageCursor>,
116 ) -> Result<crate::ProviderPage<crate::StockBar>> {
117 self.providers
118 .fetch_paged(
119 crate::Capability::CHART,
120 crate::Operation::StockBarsPage,
121 &request.cursor_identity(),
122 cursor,
123 |p| {
124 let p = Arc::clone(p);
125 async move {
126 p.as_chart()
127 .ok_or_else(|| p.not_supported(crate::Operation::StockBarsPage))?
128 .fetch_stock_bars_page(request, cursor)
129 .await
130 }
131 },
132 )
133 .await
134 }
135
136 pub(crate) fn with_providers(providers: Arc<ProviderSet>) -> Self {
137 Self { providers }
138 }
139
140 pub async fn sector_performance(&self) -> Result<Vec<SectorPerformance>> {
142 dispatch_via!(
143 self,
144 MARKET,
145 as_market,
146 SectorPerformance,
147 fetch_sector_performance,
148 []
149 )
150 }
151
152 pub async fn sector_performance_history(
154 &self,
155 limit: u32,
156 ) -> Result<Vec<crate::models::market::performance::SectorPerformanceHistory>> {
157 dispatch_via!(
158 self,
159 MARKET,
160 as_market,
161 SectorPerformanceHistory,
162 fetch_sector_performance_history,
163 [],
164 limit
165 )
166 }
167
168 pub async fn sector_pe(&self) -> Result<Vec<SectorPe>> {
170 dispatch_via!(
171 self,
172 MARKET,
173 as_market,
174 SectorPerformance,
175 fetch_sector_pe,
176 []
177 )
178 }
179
180 pub async fn industry_pe(&self) -> Result<Vec<IndustryPe>> {
182 dispatch_via!(
183 self,
184 MARKET,
185 as_market,
186 SectorPerformance,
187 fetch_industry_pe,
188 []
189 )
190 }
191
192 pub async fn movers(&self, direction: MoverDirection) -> Result<Vec<MoverQuote>> {
194 dispatch_via!(
195 self,
196 MARKET,
197 as_market,
198 MarketMovers,
199 fetch_market_movers,
200 [],
201 direction
202 )
203 }
204
205 pub async fn gainers(&self) -> Result<Vec<MoverQuote>> {
207 self.movers(MoverDirection::Gainers).await
208 }
209
210 pub async fn losers(&self) -> Result<Vec<MoverQuote>> {
212 self.movers(MoverDirection::Losers).await
213 }
214
215 pub async fn most_active(&self) -> Result<Vec<MoverQuote>> {
217 self.movers(MoverDirection::MostActive).await
218 }
219
220 pub async fn grouped_daily(&self, date: &str) -> Result<Vec<(String, Candle)>> {
229 let date = date.to_string();
230 dispatch_via!(
231 self,
232 CHART,
233 as_chart,
234 GroupedDaily,
235 fetch_grouped_daily,
236 [date],
237 &date
238 )
239 }
240
241 pub async fn crypto_grouped_daily(&self, date: &str) -> Result<Vec<(String, Candle)>> {
244 let date = date.to_string();
245 dispatch_via!(
246 self,
247 CHART,
248 as_chart,
249 CryptoGroupedDaily,
250 fetch_crypto_grouped_daily,
251 [date],
252 &date
253 )
254 }
255
256 pub async fn forex_grouped_daily(&self, date: &str) -> Result<Vec<(String, Candle)>> {
259 let date = date.to_string();
260 dispatch_via!(
261 self,
262 CHART,
263 as_chart,
264 ForexGroupedDaily,
265 fetch_forex_grouped_daily,
266 [date],
267 &date
268 )
269 }
270
271 #[cfg(feature = "crypto")]
276 pub async fn crypto_trending(&self) -> Result<Vec<crate::models::crypto::TrendingCoin>> {
277 dispatch_via!(
278 self,
279 CRYPTO,
280 as_crypto,
281 CryptoTrending,
282 fetch_crypto_trending,
283 []
284 )
285 }
286
287 #[cfg(feature = "crypto")]
292 pub async fn crypto_global(&self) -> Result<crate::models::crypto::GlobalCryptoStats> {
293 dispatch_via!(
294 self,
295 CRYPTO,
296 as_crypto,
297 CryptoGlobal,
298 fetch_crypto_global,
299 []
300 )
301 }
302}