finance_query/finance.rs
1//! Non-symbol-specific Yahoo Finance operations
2//!
3//! This module provides functions for operations that don't require a specific stock symbol,
4//! such as searching for symbols and fetching screener data.
5
6use crate::client::{ClientConfig, YahooClient};
7use crate::constants::Region;
8use crate::constants::screeners::Screener;
9use crate::constants::sectors::Sector;
10use crate::error::Result;
11use crate::models::industries::IndustryData;
12use crate::models::screeners::ScreenerResults;
13use crate::models::search::SearchResults;
14use crate::models::sectors::SectorData;
15use crate::models::transcript::{Transcript, TranscriptWithMeta};
16
17// Re-export options for convenience
18pub use crate::endpoints::lookup::{LookupOptions, LookupType};
19pub use crate::endpoints::search::SearchOptions;
20
21/// Search for stock symbols and companies
22///
23/// # Arguments
24///
25/// * `query` - Search term (company name, symbol, etc.)
26/// * `options` - Search configuration options
27///
28/// # Examples
29///
30/// ```no_run
31/// use finance_query::{finance, SearchOptions, Region};
32///
33/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
34/// // Simple search with defaults
35/// let results = finance::search("Apple", &SearchOptions::default()).await?;
36/// println!("Found {} results", results.result_count());
37///
38/// // Search with custom options
39/// let options = SearchOptions::new()
40/// .quotes_count(10)
41/// .news_count(5)
42/// .enable_research_reports(true)
43/// .region(Region::Canada);
44/// let results = finance::search("NVDA", &options).await?;
45/// println!("Found {} quotes", results.quotes.len());
46/// # Ok(())
47/// # }
48/// ```
49pub async fn search(query: &str, options: &SearchOptions) -> Result<SearchResults> {
50 let client = YahooClient::new(ClientConfig::default()).await?;
51 client.search(query, options).await
52}
53
54/// Look up symbols by type (equity, ETF, mutual fund, index, future, currency, cryptocurrency)
55///
56/// Unlike search, lookup specializes in discovering tickers filtered by asset type.
57/// Optionally fetches logo URLs via an additional API call.
58///
59/// # Arguments
60///
61/// * `query` - Search term (company name, symbol, etc.)
62/// * `options` - Lookup configuration options
63///
64/// # Examples
65///
66/// ```no_run
67/// use finance_query::{finance, LookupOptions, LookupType, Region};
68///
69/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
70/// // Simple lookup with defaults
71/// let results = finance::lookup("Apple", &LookupOptions::default()).await?;
72/// println!("Found {} results", results.result_count());
73///
74/// // Lookup equities with logos
75/// let options = LookupOptions::new()
76/// .lookup_type(LookupType::Equity)
77/// .count(10)
78/// .include_logo(true);
79/// let results = finance::lookup("NVDA", &options).await?;
80/// for quote in &results.quotes {
81/// println!("{}: {:?}", quote.symbol, quote.logo_url);
82/// }
83/// # Ok(())
84/// # }
85/// ```
86pub async fn lookup(
87 query: &str,
88 options: &LookupOptions,
89) -> Result<crate::models::lookup::LookupResults> {
90 let client = YahooClient::new(ClientConfig::default()).await?;
91 client.lookup(query, options).await
92}
93
94/// Fetch data from a predefined Yahoo Finance screener
95///
96/// Returns stocks/funds matching the criteria of the specified screener type.
97///
98/// # Arguments
99///
100/// * `screener_type` - The predefined screener to use
101/// * `count` - Number of results to return (max 250)
102///
103/// # Examples
104///
105/// ```no_run
106/// use finance_query::{finance, Screener};
107///
108/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
109/// // Get top gainers
110/// let gainers = finance::screener(Screener::DayGainers, 25).await?;
111/// println!("Top gainers: {:#?}", gainers);
112///
113/// // Get most shorted stocks
114/// let shorted = finance::screener(Screener::MostShortedStocks, 25).await?;
115///
116/// // Get growth technology stocks
117/// let tech = finance::screener(Screener::GrowthTechnologyStocks, 25).await?;
118/// # Ok(())
119/// # }
120/// ```
121pub async fn screener(screener_type: Screener, count: u32) -> Result<ScreenerResults> {
122 let client = YahooClient::new(ClientConfig::default()).await?;
123 client.get_screener(screener_type, count).await
124}
125
126/// Execute a custom screener query
127///
128/// Allows flexible filtering of stocks/funds/ETFs based on various criteria.
129/// Use [`EquityScreenerQuery`][crate::EquityScreenerQuery] for stock screeners
130/// or [`FundScreenerQuery`][crate::FundScreenerQuery] for mutual fund screeners.
131///
132/// # Arguments
133///
134/// * `query` - The custom screener query to execute
135///
136/// # Examples
137///
138/// ```no_run
139/// use finance_query::{finance, EquityField, EquityScreenerQuery, ScreenerFieldExt};
140///
141/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
142/// // Find US large-cap stocks with high volume
143/// let query = EquityScreenerQuery::new()
144/// .size(25)
145/// .sort_by(EquityField::IntradayMarketCap, false)
146/// .add_condition(EquityField::Region.eq_str("us"))
147/// .add_condition(EquityField::AvgDailyVol3M.gt(200_000.0))
148/// .add_condition(EquityField::IntradayMarketCap.gt(10_000_000_000.0));
149///
150/// let result = finance::custom_screener(query).await?;
151/// println!("Found {} stocks", result.quotes.len());
152/// # Ok(())
153/// # }
154/// ```
155pub async fn custom_screener<F: crate::models::screeners::ScreenerField>(
156 query: crate::models::screeners::ScreenerQuery<F>,
157) -> Result<ScreenerResults> {
158 let client = YahooClient::new(ClientConfig::default()).await?;
159 client.custom_screener(query).await
160}
161
162/// Get general market news
163///
164/// # Examples
165///
166/// ```no_run
167/// use finance_query::finance;
168///
169/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
170/// let news = finance::news().await?;
171/// for article in news {
172/// println!("{}: {}", article.source, article.title);
173/// }
174/// # Ok(())
175/// # }
176/// ```
177pub async fn news() -> Result<Vec<crate::models::news::News>> {
178 crate::scrapers::stockanalysis::scrape_general_news().await
179}
180
181/// Get earnings transcript for a symbol
182///
183/// Fetches the earnings call transcript, handling all the complexity internally:
184/// 1. Gets the company ID (quartrId) from the quote_type endpoint
185/// 2. Scrapes available earnings calls
186/// 3. Fetches the requested transcript
187///
188/// # Arguments
189///
190/// * `symbol` - Stock symbol (e.g., "AAPL", "MSFT")
191/// * `quarter` - Optional fiscal quarter (Q1, Q2, Q3, Q4). If None, gets latest.
192/// * `year` - Optional fiscal year. If None, gets latest.
193///
194/// # Examples
195///
196/// ```no_run
197/// use finance_query::finance;
198///
199/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
200/// // Get the latest transcript
201/// let latest = finance::earnings_transcript("AAPL", None, None).await?;
202/// println!("Quarter: {} {}", latest.quarter(), latest.year());
203///
204/// // Get a specific quarter
205/// let q4_2024 = finance::earnings_transcript("AAPL", Some("Q4"), Some(2024)).await?;
206/// # Ok(())
207/// # }
208/// ```
209pub async fn earnings_transcript(
210 symbol: &str,
211 quarter: Option<&str>,
212 year: Option<i32>,
213) -> Result<Transcript> {
214 let client = YahooClient::new(ClientConfig::default()).await?;
215 crate::endpoints::transcripts::fetch_for_symbol(&client, symbol, quarter, year).await
216}
217
218/// Get all earnings transcripts for a symbol
219///
220/// Fetches transcripts for all available earnings calls.
221///
222/// # Arguments
223///
224/// * `symbol` - Stock symbol (e.g., "AAPL", "MSFT")
225/// * `limit` - Optional maximum number of transcripts. If None, fetches all.
226///
227/// # Examples
228///
229/// ```no_run
230/// use finance_query::finance;
231///
232/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
233/// // Get all transcripts
234/// let all = finance::earnings_transcripts("AAPL", None).await?;
235///
236/// // Get only the 5 most recent
237/// let recent = finance::earnings_transcripts("AAPL", Some(5)).await?;
238/// for t in &recent {
239/// println!("{}: {} {}", t.title, t.transcript.quarter(), t.transcript.year());
240/// }
241/// # Ok(())
242/// # }
243/// ```
244pub async fn earnings_transcripts(
245 symbol: &str,
246 limit: Option<usize>,
247) -> Result<Vec<TranscriptWithMeta>> {
248 let client = YahooClient::new(ClientConfig::default()).await?;
249 crate::endpoints::transcripts::fetch_all_for_symbol(&client, symbol, limit).await
250}
251
252/// Get market hours/status
253///
254/// Returns the current status for various markets.
255///
256/// # Arguments
257///
258/// * `region` - Optional region override (e.g., "US", "JP", "GB"). If None, uses default (US).
259///
260/// # Examples
261///
262/// ```no_run
263/// use finance_query::finance;
264///
265/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
266/// // Get US market hours (default)
267/// let hours = finance::hours(None).await?;
268///
269/// // Get Japan market hours
270/// let jp_hours = finance::hours(Some("JP")).await?;
271/// # Ok(())
272/// # }
273/// ```
274pub async fn hours(region: Option<&str>) -> Result<crate::models::hours::MarketHours> {
275 let client = YahooClient::new(ClientConfig::default()).await?;
276 client.get_hours(region).await
277}
278
279/// Get world market indices quotes
280///
281/// Returns quotes for major world indices, optionally filtered by region.
282///
283/// # Arguments
284///
285/// * `region` - Optional region filter. If None, returns all world indices.
286///
287/// # Examples
288///
289/// ```no_run
290/// use finance_query::{finance, IndicesRegion};
291///
292/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
293/// // Get all world indices
294/// let all = finance::indices(None).await?;
295/// println!("Fetched {} indices", all.success_count());
296///
297/// // Get only Americas indices
298/// let americas = finance::indices(Some(IndicesRegion::Americas)).await?;
299/// # Ok(())
300/// # }
301/// ```
302pub async fn indices(
303 region: Option<crate::constants::indices::Region>,
304) -> Result<crate::tickers::BatchQuotesResponse> {
305 use crate::Tickers;
306 use crate::constants::indices::all_symbols;
307
308 let symbols: Vec<&str> = match region {
309 Some(r) => r.symbols().to_vec(),
310 None => all_symbols(),
311 };
312
313 let tickers = Tickers::new(symbols).await?;
314 tickers.quotes().await
315}
316
317/// Fetch detailed sector data from Yahoo Finance
318///
319/// Returns comprehensive sector information including overview, performance,
320/// top companies, ETFs, mutual funds, industries, and research reports.
321///
322/// # Arguments
323///
324/// * `sector_type` - The sector to fetch data for
325///
326/// # Examples
327///
328/// ```no_run
329/// use finance_query::{finance, Sector};
330///
331/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
332/// let sector = finance::sector(Sector::Technology).await?;
333/// println!("Sector: {} ({} companies)", sector.name,
334/// sector.overview.as_ref().map(|o| o.companies_count.unwrap_or(0)).unwrap_or(0));
335///
336/// for company in sector.top_companies.iter().take(5) {
337/// println!(" {} - {:?}", company.symbol, company.name);
338/// }
339/// # Ok(())
340/// # }
341/// ```
342pub async fn sector(sector_type: Sector) -> Result<SectorData> {
343 let client = YahooClient::new(ClientConfig::default()).await?;
344 client.get_sector(sector_type).await
345}
346
347/// Fetch detailed industry data from Yahoo Finance
348///
349/// Returns comprehensive industry information including overview, performance,
350/// top companies, top performing companies, top growth companies, and research reports.
351///
352/// # Arguments
353///
354/// * `industry_key` - The industry key/slug (e.g., "semiconductors", "software-infrastructure")
355///
356/// # Examples
357///
358/// ```no_run
359/// use finance_query::finance;
360///
361/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
362/// let industry = finance::industry("semiconductors").await?;
363/// println!("Industry: {} ({} companies)", industry.name,
364/// industry.overview.as_ref().map(|o| o.companies_count.unwrap_or(0)).unwrap_or(0));
365///
366/// for company in industry.top_companies.iter().take(5) {
367/// println!(" {} - {:?}", company.symbol, company.name);
368/// }
369/// # Ok(())
370/// # }
371/// ```
372pub async fn industry(industry_key: impl AsRef<str>) -> Result<IndustryData> {
373 let client = YahooClient::new(ClientConfig::default()).await?;
374 client.get_industry(industry_key.as_ref()).await
375}
376
377/// Get list of available currencies
378///
379/// Returns currency information from Yahoo Finance.
380///
381/// # Examples
382///
383/// ```no_run
384/// use finance_query::finance;
385///
386/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
387/// let currencies = finance::currencies().await?;
388/// # Ok(())
389/// # }
390/// ```
391pub async fn currencies() -> Result<Vec<crate::models::currencies::Currency>> {
392 let client = YahooClient::new(ClientConfig::default()).await?;
393 client.get_currencies().await
394}
395
396/// Get list of supported exchanges
397///
398/// Scrapes the Yahoo Finance help page for a list of supported exchanges
399/// with their symbol suffixes and data delay information.
400///
401/// # Examples
402///
403/// ```no_run
404/// use finance_query::finance;
405///
406/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
407/// let exchanges = finance::exchanges().await?;
408/// for exchange in &exchanges {
409/// println!("{} - {} ({})", exchange.country, exchange.market, exchange.suffix);
410/// }
411/// # Ok(())
412/// # }
413/// ```
414pub async fn exchanges() -> Result<Vec<crate::models::exchanges::Exchange>> {
415 crate::scrapers::yahoo_exchanges::scrape_exchanges().await
416}
417
418/// Get market summary
419///
420/// Returns market summary with major indices, currencies, and commodities.
421///
422/// # Arguments
423///
424/// * `region` - Optional region for localization. If None, uses default (US).
425///
426/// # Examples
427///
428/// ```no_run
429/// use finance_query::{finance, Region};
430///
431/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
432/// // Use default (US)
433/// let summary = finance::market_summary(None).await?;
434/// // Or specify a region
435/// let summary = finance::market_summary(Some(Region::Canada)).await?;
436/// # Ok(())
437/// # }
438/// ```
439pub async fn market_summary(
440 region: Option<Region>,
441) -> Result<Vec<crate::models::market_summary::MarketSummaryQuote>> {
442 let client = YahooClient::new(ClientConfig::default()).await?;
443 client.get_market_summary(region).await
444}
445
446/// Get trending tickers for a region
447///
448/// Returns trending stocks for a specific region.
449///
450/// # Arguments
451///
452/// * `region` - Optional region for localization. If None, uses default (US).
453///
454/// # Examples
455///
456/// ```no_run
457/// use finance_query::{finance, Region};
458///
459/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
460/// // Use default (US)
461/// let trending = finance::trending(None).await?;
462/// // Or specify a region
463/// let trending = finance::trending(Some(Region::Canada)).await?;
464/// # Ok(())
465/// # }
466/// ```
467pub async fn trending(
468 region: Option<Region>,
469) -> Result<Vec<crate::models::trending::TrendingQuote>> {
470 let client = YahooClient::new(ClientConfig::default()).await?;
471 client.get_trending(region).await
472}
473
474/// Fetch the current CNN Fear & Greed Index from Alternative.me.
475///
476/// Returns a 0–100 sentiment score and its classification. No API key required.
477///
478/// # Examples
479///
480/// ```no_run
481/// use finance_query::finance;
482///
483/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
484/// let fg = finance::fear_and_greed().await?;
485/// println!("Fear & Greed: {} ({})", fg.value, fg.classification.as_str());
486/// # Ok(())
487/// # }
488/// ```
489pub async fn fear_and_greed() -> Result<crate::models::sentiment::FearAndGreed> {
490 crate::endpoints::fear_and_greed::fetch().await
491}