yfinance-rs 0.9.1

Ergonomic Rust client for Yahoo Finance, supporting historical prices, real-time streaming, options, fundamentals, and more.
Documentation
use std::fmt::Display;
use yfinance_rs::{Action, Ticker, YfClient, YfError};

fn display_opt<T: Display>(value: Option<&T>) -> String {
    value.map_or_else(|| "N/A".to_string(), ToString::to_string)
}

#[tokio::main]
async fn main() -> Result<(), YfError> {
    let client = YfClient::default();

    let symbol = "AAPL";
    let ticker_aapl = Ticker::new(&client, symbol);
    section_earnings_and_shares(symbol, &ticker_aapl).await?;
    section_capital_gains().await?;
    section_price_target(symbol, &ticker_aapl).await?;
    section_recommendations(symbol, &ticker_aapl).await?;
    section_isin_calendar(symbol, &ticker_aapl).await?;
    Ok(())
}

async fn section_earnings_and_shares(symbol: &str, ticker: &Ticker) -> Result<(), YfError> {
    println!("--- Fetching Advanced Analysis for {symbol} ---");
    let earnings_trend = ticker.earnings_trend(None).await?;
    println!("Earnings Trend ({} periods):", earnings_trend.len());
    if let Some(trend) = earnings_trend.first() {
        println!(
            "  {}: Earnings Est. Avg: {}, Revenue Est. Avg: {}",
            trend.period,
            display_opt(trend.earnings_estimate.avg.as_ref()),
            display_opt(trend.revenue_estimate.avg.as_ref())
        );
    }
    println!();

    println!("--- Fetching Historical Shares for {symbol} ---");
    let shares = ticker.shares().await?;
    println!("Annual Shares Outstanding ({} periods):", shares.len());
    if let Some(share_count) = shares.first() {
        println!(
            "  Latest Period ({}): {} shares",
            share_count.date, share_count.shares
        );
    }
    println!();
    Ok(())
}

async fn section_capital_gains() -> Result<(), YfError> {
    println!("--- Fetching Capital Gains for VFINX (Vanguard 500 Index Fund) ---");
    let client = YfClient::default();
    let ticker_vfinx = Ticker::new(&client, "VFINX");
    let actions = ticker_vfinx.actions(None).await?;
    let capital_gains = actions
        .iter()
        .filter(|action| matches!(action, Action::CapitalGain { .. }))
        .count();
    println!("Capital Gains Distributions ({capital_gains} periods):");
    if let Some(Action::CapitalGain { date, gain }) = actions
        .iter()
        .rev()
        .find(|action| matches!(action, Action::CapitalGain { .. }))
    {
        println!("  Most Recent Gain: {gain} on {date}");
    }
    Ok(())
}

async fn section_price_target(symbol: &str, ticker: &Ticker) -> Result<(), YfError> {
    println!("--- Analyst Price Target for {symbol} ---");
    let price_target = ticker.analyst_price_target(None).await?;
    println!(
        "  Target: avg={}, high={}, low={} (from {} analysts)",
        display_opt(price_target.mean.as_ref()),
        display_opt(price_target.high.as_ref()),
        display_opt(price_target.low.as_ref()),
        price_target.number_of_analysts.unwrap_or_default()
    );
    println!();
    Ok(())
}

async fn section_recommendations(symbol: &str, ticker: &Ticker) -> Result<(), YfError> {
    println!("--- Recommendation Summary for {symbol} ---");
    let rec_summary = ticker.recommendations_summary().await?;
    println!(
        "  Mean score: {:.2} ({})",
        rec_summary.mean.unwrap_or_default(),
        rec_summary.mean_rating_text.as_deref().unwrap_or("N/A")
    );
    println!();
    Ok(())
}

async fn section_isin_calendar(symbol: &str, ticker: &Ticker) -> Result<(), YfError> {
    println!("--- ISIN for {symbol} ---");
    let isin = ticker.isin().await?;
    println!(
        "  ISIN: {}",
        isin.unwrap_or_else(|| "Not found".to_string())
    );
    println!();

    println!("--- Upcoming Calendar Events for {symbol} ---");
    let calendar = ticker.calendar().await?;
    if let Some(date) = calendar.earnings_dates.first() {
        println!("  Next earnings date (approx): {}", date.date_naive());
    }
    if let Some(date) = calendar.ex_dividend_date {
        println!("  Ex-dividend date: {date}");
    }
    println!();
    Ok(())
}