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::screener_types::ScreenerType;
9use crate::constants::sector_types::SectorType;
10use crate::error::Result;
11use crate::models::industries::Industry;
12use crate::models::screeners::ScreenerResults;
13use crate::models::search::SearchResults;
14use crate::models::sectors::Sector;
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, ScreenerType};
107///
108/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
109/// // Get top gainers
110/// let gainers = finance::screener(ScreenerType::DayGainers, 25).await?;
111/// println!("Top gainers: {:#?}", gainers);
112///
113/// // Get most shorted stocks
114/// let shorted = finance::screener(ScreenerType::MostShortedStocks, 25).await?;
115///
116/// // Get growth technology stocks
117/// let tech = finance::screener(ScreenerType::GrowthTechnologyStocks, 25).await?;
118/// # Ok(())
119/// # }
120/// ```
121pub async fn screener(screener_type: ScreenerType, 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///
130/// # Arguments
131///
132/// * `query` - The custom screener query to execute
133///
134/// # Examples
135///
136/// ```no_run
137/// use finance_query::{finance, ScreenerQuery, QueryCondition, screener_query::Operator};
138///
139/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
140/// // Find US stocks with high volume sorted by market cap
141/// let query = ScreenerQuery::new()
142///     .size(25)
143///     .sort_by("intradaymarketcap", false)
144///     .add_condition(QueryCondition::new("region", Operator::Eq).value_str("us"))
145///     .add_condition(QueryCondition::new("avgdailyvol3m", Operator::Gt).value(200000));
146///
147/// let result = finance::custom_screener(query).await?;
148/// println!("Found {} stocks", result.quotes.len());
149/// # Ok(())
150/// # }
151/// ```
152pub async fn custom_screener(
153    query: crate::models::screeners::ScreenerQuery,
154) -> Result<ScreenerResults> {
155    let client = YahooClient::new(ClientConfig::default()).await?;
156    client.custom_screener(query).await
157}
158
159/// Get general market news
160///
161/// # Examples
162///
163/// ```no_run
164/// use finance_query::finance;
165///
166/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
167/// let news = finance::news().await?;
168/// for article in news {
169///     println!("{}: {}", article.source, article.title);
170/// }
171/// # Ok(())
172/// # }
173/// ```
174pub async fn news() -> Result<Vec<crate::models::news::News>> {
175    crate::scrapers::stockanalysis::scrape_general_news().await
176}
177
178/// Get earnings transcript for a symbol
179///
180/// Fetches the earnings call transcript, handling all the complexity internally:
181/// 1. Gets the company ID (quartrId) from the quote_type endpoint
182/// 2. Scrapes available earnings calls
183/// 3. Fetches the requested transcript
184///
185/// # Arguments
186///
187/// * `symbol` - Stock symbol (e.g., "AAPL", "MSFT")
188/// * `quarter` - Optional fiscal quarter (Q1, Q2, Q3, Q4). If None, gets latest.
189/// * `year` - Optional fiscal year. If None, gets latest.
190///
191/// # Examples
192///
193/// ```no_run
194/// use finance_query::finance;
195///
196/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
197/// // Get the latest transcript
198/// let latest = finance::earnings_transcript("AAPL", None, None).await?;
199/// println!("Quarter: {} {}", latest.quarter(), latest.year());
200///
201/// // Get a specific quarter
202/// let q4_2024 = finance::earnings_transcript("AAPL", Some("Q4"), Some(2024)).await?;
203/// # Ok(())
204/// # }
205/// ```
206pub async fn earnings_transcript(
207    symbol: &str,
208    quarter: Option<&str>,
209    year: Option<i32>,
210) -> Result<Transcript> {
211    let client = YahooClient::new(ClientConfig::default()).await?;
212    crate::endpoints::transcripts::fetch_for_symbol(&client, symbol, quarter, year).await
213}
214
215/// Get all earnings transcripts for a symbol
216///
217/// Fetches transcripts for all available earnings calls.
218///
219/// # Arguments
220///
221/// * `symbol` - Stock symbol (e.g., "AAPL", "MSFT")
222/// * `limit` - Optional maximum number of transcripts. If None, fetches all.
223///
224/// # Examples
225///
226/// ```no_run
227/// use finance_query::finance;
228///
229/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
230/// // Get all transcripts
231/// let all = finance::earnings_transcripts("AAPL", None).await?;
232///
233/// // Get only the 5 most recent
234/// let recent = finance::earnings_transcripts("AAPL", Some(5)).await?;
235/// for t in &recent {
236///     println!("{}: {} {}", t.title, t.transcript.quarter(), t.transcript.year());
237/// }
238/// # Ok(())
239/// # }
240/// ```
241pub async fn earnings_transcripts(
242    symbol: &str,
243    limit: Option<usize>,
244) -> Result<Vec<TranscriptWithMeta>> {
245    let client = YahooClient::new(ClientConfig::default()).await?;
246    crate::endpoints::transcripts::fetch_all_for_symbol(&client, symbol, limit).await
247}
248
249/// Get market hours/status
250///
251/// Returns the current status for various markets.
252///
253/// # Arguments
254///
255/// * `region` - Optional region override (e.g., "US", "JP", "GB"). If None, uses default (US).
256///
257/// # Examples
258///
259/// ```no_run
260/// use finance_query::finance;
261///
262/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
263/// // Get US market hours (default)
264/// let hours = finance::hours(None).await?;
265///
266/// // Get Japan market hours
267/// let jp_hours = finance::hours(Some("JP")).await?;
268/// # Ok(())
269/// # }
270/// ```
271pub async fn hours(region: Option<&str>) -> Result<crate::models::hours::MarketHours> {
272    let client = YahooClient::new(ClientConfig::default()).await?;
273    client.get_hours(region).await
274}
275
276/// Get world market indices quotes
277///
278/// Returns quotes for major world indices, optionally filtered by region.
279///
280/// # Arguments
281///
282/// * `region` - Optional region filter. If None, returns all world indices.
283///
284/// # Examples
285///
286/// ```no_run
287/// use finance_query::{finance, IndicesRegion};
288///
289/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
290/// // Get all world indices
291/// let all = finance::indices(None).await?;
292/// println!("Fetched {} indices", all.success_count());
293///
294/// // Get only Americas indices
295/// let americas = finance::indices(Some(IndicesRegion::Americas)).await?;
296/// # Ok(())
297/// # }
298/// ```
299pub async fn indices(
300    region: Option<crate::constants::indices::Region>,
301) -> Result<crate::tickers::BatchQuotesResponse> {
302    use crate::Tickers;
303    use crate::constants::indices::all_symbols;
304
305    let symbols: Vec<&str> = match region {
306        Some(r) => r.symbols().to_vec(),
307        None => all_symbols(),
308    };
309
310    let tickers = Tickers::new(symbols).await?;
311    tickers.quotes(false).await
312}
313
314/// Fetch detailed sector data from Yahoo Finance
315///
316/// Returns comprehensive sector information including overview, performance,
317/// top companies, ETFs, mutual funds, industries, and research reports.
318///
319/// # Arguments
320///
321/// * `sector_type` - The sector to fetch data for
322///
323/// # Examples
324///
325/// ```no_run
326/// use finance_query::{finance, SectorType};
327///
328/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
329/// let sector = finance::sector(SectorType::Technology).await?;
330/// println!("Sector: {} ({} companies)", sector.name,
331///     sector.overview.as_ref().map(|o| o.companies_count.unwrap_or(0)).unwrap_or(0));
332///
333/// for company in sector.top_companies.iter().take(5) {
334///     println!("  {} - {:?}", company.symbol, company.name);
335/// }
336/// # Ok(())
337/// # }
338/// ```
339pub async fn sector(sector_type: SectorType) -> Result<Sector> {
340    let client = YahooClient::new(ClientConfig::default()).await?;
341    client.get_sector(sector_type).await
342}
343
344/// Fetch detailed industry data from Yahoo Finance
345///
346/// Returns comprehensive industry information including overview, performance,
347/// top companies, top performing companies, top growth companies, and research reports.
348///
349/// # Arguments
350///
351/// * `industry_key` - The industry key/slug (e.g., "semiconductors", "software-infrastructure")
352///
353/// # Examples
354///
355/// ```no_run
356/// use finance_query::finance;
357///
358/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
359/// let industry = finance::industry("semiconductors").await?;
360/// println!("Industry: {} ({} companies)", industry.name,
361///     industry.overview.as_ref().map(|o| o.companies_count.unwrap_or(0)).unwrap_or(0));
362///
363/// for company in industry.top_companies.iter().take(5) {
364///     println!("  {} - {:?}", company.symbol, company.name);
365/// }
366/// # Ok(())
367/// # }
368/// ```
369pub async fn industry(industry_key: &str) -> Result<Industry> {
370    let client = YahooClient::new(ClientConfig::default()).await?;
371    client.get_industry(industry_key).await
372}
373
374/// Get list of available currencies
375///
376/// Returns currency information from Yahoo Finance.
377///
378/// # Examples
379///
380/// ```no_run
381/// use finance_query::finance;
382///
383/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
384/// let currencies = finance::currencies().await?;
385/// # Ok(())
386/// # }
387/// ```
388pub async fn currencies() -> Result<Vec<crate::models::currencies::Currency>> {
389    let client = YahooClient::new(ClientConfig::default()).await?;
390    client.get_currencies().await
391}
392
393/// Get list of supported exchanges
394///
395/// Scrapes the Yahoo Finance help page for a list of supported exchanges
396/// with their symbol suffixes and data delay information.
397///
398/// # Examples
399///
400/// ```no_run
401/// use finance_query::finance;
402///
403/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
404/// let exchanges = finance::exchanges().await?;
405/// for exchange in &exchanges {
406///     println!("{} - {} ({})", exchange.country, exchange.market, exchange.suffix);
407/// }
408/// # Ok(())
409/// # }
410/// ```
411pub async fn exchanges() -> Result<Vec<crate::models::exchanges::Exchange>> {
412    crate::scrapers::yahoo_exchanges::scrape_exchanges().await
413}
414
415/// Get market summary
416///
417/// Returns market summary with major indices, currencies, and commodities.
418///
419/// # Arguments
420///
421/// * `region` - Optional region for localization. If None, uses default (US).
422///
423/// # Examples
424///
425/// ```no_run
426/// use finance_query::{finance, Region};
427///
428/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
429/// // Use default (US)
430/// let summary = finance::market_summary(None).await?;
431/// // Or specify a region
432/// let summary = finance::market_summary(Some(Region::Canada)).await?;
433/// # Ok(())
434/// # }
435/// ```
436pub async fn market_summary(
437    region: Option<Region>,
438) -> Result<Vec<crate::models::market_summary::MarketSummaryQuote>> {
439    let client = YahooClient::new(ClientConfig::default()).await?;
440    client.get_market_summary(region).await
441}
442
443/// Get trending tickers for a region
444///
445/// Returns trending stocks for a specific region.
446///
447/// # Arguments
448///
449/// * `region` - Optional region for localization. If None, uses default (US).
450///
451/// # Examples
452///
453/// ```no_run
454/// use finance_query::{finance, Region};
455///
456/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
457/// // Use default (US)
458/// let trending = finance::trending(None).await?;
459/// // Or specify a region
460/// let trending = finance::trending(Some(Region::Canada)).await?;
461/// # Ok(())
462/// # }
463/// ```
464pub async fn trending(
465    region: Option<Region>,
466) -> Result<Vec<crate::models::trending::TrendingQuote>> {
467    let client = YahooClient::new(ClientConfig::default()).await?;
468    client.get_trending(region).await
469}