import yfinance as yf import logging from typing import Optional, Dict, Any from .base import StockAPIBase logger = logging.getLogger(__name__) class YahooFinanceAPI(StockAPIBase): """Yahoo Finance implementation of stock price provider.""" def get_stock_price(self, ticker: str) -> Optional[Dict[str, Any]]: """ Retrieve stock price data from Yahoo Finance. Args: ticker: Stock ticker symbol Returns: Dictionary with stock data or None if unavailable """ try: stock = yf.Ticker(ticker) # Use history() method instead of info to avoid rate limiting # Get last 2 days of data to calculate change hist = stock.history(period="2d") if hist.empty or len(hist) < 1: logger.warning(f"No historical data available for ticker: {ticker}") return None # Get most recent price data current_price = float(hist['Close'].iloc[-1]) # Get previous close (either from previous day or use current data) if len(hist) >= 2: previous_close = float(hist['Close'].iloc[-2]) else: previous_close = float(hist['Open'].iloc[-1]) change_dollar = current_price - previous_close change_percent = (change_dollar / previous_close) * 100 # Market is considered open if we have today's data market_open = True # Simplified - actual market status requires additional API call return { 'ticker': ticker.upper(), 'current_price': round(current_price, 2), 'previous_close': round(previous_close, 2), 'change_dollar': round(change_dollar, 2), 'change_percent': round(change_percent, 2), 'market_open': market_open } except Exception as e: logger.error(f"Error fetching data for {ticker}: {e}") return None def is_available(self) -> bool: """ Check if Yahoo Finance API is accessible. Returns: True if accessible, False otherwise """ try: test_stock = yf.Ticker("AAPL") info = test_stock.info return info is not None and len(info) > 0 except Exception as e: logger.error(f"Yahoo Finance API unavailable: {e}") return False