Adisri99's picture
Upload 13 files
e98cfad verified
from __future__ import annotations
from typing import List, Dict
import pandas as pd
import yfinance as yf
DEFAULT_UNIVERSE = [
"AAPL", "MSFT", "NVDA", "AMZN", "GOOGL", "META",
"JPM", "XOM", "AVGO", "LLY", "AMD", "COST"
]
def sanitize_tickers(tickers: List[str]) -> List[str]:
cleaned = []
for t in tickers:
t = (t or "").strip().upper().replace('"', "").replace("'", "")
if t and t.isascii() and t.replace("-", "").replace(".", "").isalnum():
cleaned.append(t)
return list(dict.fromkeys(cleaned))[:20]
def fetch_price_history(tickers: List[str], lookback_days: int = 365) -> pd.DataFrame:
tickers = sanitize_tickers(tickers)
if len(tickers) < 2:
raise ValueError("Need at least 2 valid tickers")
period = "2y" if lookback_days > 365 else "1y"
data = yf.download(
tickers=tickers,
period=period,
interval="1d",
auto_adjust=True,
progress=False,
threads=True,
group_by="ticker",
)
rows = []
if isinstance(data.columns, pd.MultiIndex):
for ticker in tickers:
try:
block = data[ticker].copy()
except Exception:
continue
if block.empty or "Close" not in block.columns:
continue
block = block.reset_index()
date_col = "Date" if "Date" in block.columns else block.columns[0]
for _, row in block.iterrows():
close_val = row.get("Close")
if pd.isna(close_val):
continue
rows.append({
"date": pd.Timestamp(row[date_col]).normalize(),
"ticker": ticker,
"close": float(close_val),
"volume": float(row.get("Volume", 0.0) or 0.0),
})
else:
if len(tickers) != 1:
raise ValueError("Unexpected Yahoo Finance schema for multiple tickers")
ticker = tickers[0]
block = data.copy()
if block.empty or "Close" not in block.columns:
raise ValueError("No usable market data returned")
block = block.reset_index()
date_col = "Date" if "Date" in block.columns else block.columns[0]
for _, row in block.iterrows():
close_val = row.get("Close")
if pd.isna(close_val):
continue
rows.append({
"date": pd.Timestamp(row[date_col]).normalize(),
"ticker": ticker,
"close": float(close_val),
"volume": float(row.get("Volume", 0.0) or 0.0),
})
out = pd.DataFrame(rows)
if out.empty:
raise ValueError("No market data returned")
if "ticker" not in out.columns:
raise ValueError(f"Ticker column missing from market data. Columns: {list(out.columns)}")
out = out.sort_values(["ticker", "date"]).reset_index(drop=True)
return out
def fetch_quotes(tickers: List[str]) -> List[Dict[str, float]]:
tickers = sanitize_tickers(tickers)
result = []
for ticker in tickers:
try:
hist = yf.Ticker(ticker).history(period="5d", interval="1d", auto_adjust=True)
if hist.empty:
continue
last = float(hist["Close"].iloc[-1])
prev = float(hist["Close"].iloc[-2]) if len(hist) > 1 else last
chg = 0.0 if prev == 0 else (last / prev - 1.0)
result.append({
"ticker": ticker,
"price": last,
"day_change_pct": chg,
})
except Exception:
continue
return result
def infer_sectors(tickers: List[str]) -> Dict[str, str]:
return {ticker: "Unknown" for ticker in sanitize_tickers(tickers)}