"""Yahoo Finance client for market benchmark data.""" from __future__ import annotations import pandas as pd import yfinance as yf from src.config import DATA_RAW_YAHOO, YAHOO_END, YAHOO_START, YAHOO_TICKERS from src.utils import setup_logging logger = setup_logging("yahoo") def fetch_yahoo_data( tickers: list[str] | None = None, start: str | None = None, end: str | None = None, ) -> pd.DataFrame: """Fetch daily OHLCV data for all configured tickers. Save to CSV.""" tickers = tickers or YAHOO_TICKERS start = start or YAHOO_START end = end or YAHOO_END DATA_RAW_YAHOO.mkdir(parents=True, exist_ok=True) all_frames: list[pd.DataFrame] = [] for ticker in tickers: try: logger.info("Fetching %s from Yahoo Finance", ticker) tk = yf.Ticker(ticker) df = tk.history(start=start, end=end, auto_adjust=True) if df.empty: logger.warning("No data returned for %s", ticker) continue df.index.name = "date" # Clean ticker name for filename (replace ^ and others) safe_name = ticker.replace("^", "").replace("-", "_") path = DATA_RAW_YAHOO / f"{safe_name}.csv" df.to_csv(path) logger.info("Saved %s (%d rows) to %s", ticker, len(df), path) all_frames.append(df.assign(ticker=ticker)) except Exception as exc: logger.error("Failed to fetch %s: %s", ticker, exc) if all_frames: combined = pd.concat(all_frames) combined.to_csv(DATA_RAW_YAHOO / "all_tickers.csv") logger.info("Saved combined dataset (%d rows)", len(combined)) return combined return pd.DataFrame() def fetch_all_yahoo_data() -> None: """Fetch all Yahoo data and save to data/raw/yahoo/.""" logger.info("=== Starting Yahoo Finance data acquisition ===") fetch_yahoo_data() logger.info("=== Yahoo Finance data acquisition complete ===")