shindeaditya2313-spec
deploy: clean snapshot for HuggingFace Spaces - premium UI redesign + Created by aDi
6114f21
Raw History Blame Contribute Delete
2.53 kB
"""
Market Data Ingestion Module
Fetches real-time and historical OHLCV data from Yahoo Finance based on OCR-detected Tickers.
"""
import logging
from typing import Optional
import pandas as pd
import yfinance as yf
from src.config import DEFAULT_TICKER, DEFAULT_TIMEFRAME
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("MarketDataFetcher")
class MarketDataFetcher:
"""
Handles robust downloading and formatting of OHLCV financial data.
"""
@staticmethod
def fetch_data(
ticker: str = DEFAULT_TICKER,
period: str = "2y",
interval: str = DEFAULT_TIMEFRAME,
) -> pd.DataFrame:
"""
Downloads historical price data and returns a clean, single-level DataFrame
containing Open, High, Low, Close, Adj Close, and Volume.
"""
logger.info(f"Fetching market data for [{ticker}] | Period: {period} | Interval: {interval}...")
try:
data = yf.download(
tickers=ticker,
period=period,
interval=interval,
ignore_tz=True,
prepost=False,
auto_adjust=False, # Retain separate 'Adj Close' column
progress=False,
)
except Exception as e:
logger.error(f"Failed to download data for {ticker}: {e}")
return pd.DataFrame()
# Handle yfinance MultiIndex column behavior
if isinstance(data.columns, pd.MultiIndex):
data.columns = data.columns.get_level_values(0)
# Validate required columns
required_cols = {"Open", "High", "Low", "Close", "Adj Close", "Volume"}
if not required_cols.issubset(set(data.columns)) or len(data) == 0:
logger.warning(f"Insufficient data returned for {ticker}. Trying default fallback ({DEFAULT_TICKER})...")
if ticker != DEFAULT_TICKER:
return MarketDataFetcher.fetch_data(ticker=DEFAULT_TICKER, period=period, interval=interval)
return pd.DataFrame()
# Remove duplicate timestamps and sort ascending
data = data[~data.index.duplicated(keep="first")].sort_index()
logger.info(f"Successfully loaded {len(data)} rows of market data for {ticker}.")
return data
# --- Standalone Verification Block ---
if __name__ == "__main__":
df_test = MarketDataFetcher.fetch_data(ticker="BTC-USD", period="1y", interval="1d")
print("\n--- Market Data Fetcher Verification ---")
print(df_test.tail(3))