Spaces:
Sleeping
Sleeping
| from typing import Tuple | |
| import pandas as pd | |
| import requests | |
| from fastapi import HTTPException | |
| from app.config import get_settings | |
| from app.indicators import add_technical_indicators | |
| settings = get_settings() | |
| ALPHA_VANTAGE_URL = "https://www.alphavantage.co/query" | |
| def fetch_raw_history(ticker: str) -> pd.DataFrame: | |
| """ | |
| Fetch OHLCV daily data from Alpha Vantage (FREE endpoint). | |
| Replaces yfinance for HF Spaces compatibility. | |
| """ | |
| params = { | |
| "function": "TIME_SERIES_DAILY", | |
| "symbol": ticker, | |
| "apikey": settings.alpha_vantage_api_key, | |
| "outputsize": "compact", | |
| } | |
| try: | |
| response = requests.get(ALPHA_VANTAGE_URL, params=params, timeout=10) | |
| data = response.json() | |
| except Exception: | |
| raise HTTPException( | |
| status_code=503, | |
| detail="Market data provider unavailable", | |
| ) | |
| if "Time Series (Daily)" not in data: | |
| raise HTTPException( | |
| status_code=400, | |
| detail="Invalid ticker or API rate limit exceeded", | |
| ) | |
| ts = data["Time Series (Daily)"] | |
| df = pd.DataFrame.from_dict(ts, orient="index").astype(float) | |
| df.index = pd.to_datetime(df.index) | |
| df.sort_index(inplace=True) | |
| df.rename( | |
| columns={ | |
| "1. open": "Open", | |
| "2. high": "High", | |
| "3. low": "Low", | |
| "4. close": "Close", | |
| "5. volume": "Volume", | |
| }, | |
| inplace=True, | |
| ) | |
| if df.empty or len(df) < settings.history_window + 60: | |
| raise HTTPException( | |
| status_code=400, | |
| detail="Not enough historical data for this ticker.", | |
| ) | |
| return df[["Open", "High", "Low", "Close", "Volume"]] | |
| def get_enriched_history(ticker: str) -> Tuple[pd.DataFrame, pd.DataFrame]: | |
| """ | |
| Returns: | |
| - Raw OHLCV dataframe | |
| - Technical-indicator-enriched dataframe | |
| """ | |
| df_raw = fetch_raw_history(ticker) | |
| df_tech = add_technical_indicators(df_raw) | |
| return df_raw, df_tech | |
| def last_n_candles(df: pd.DataFrame, n: int) -> list[dict]: | |
| """ | |
| Used by frontend for recent price chart | |
| """ | |
| tail = df.tail(n) | |
| return [ | |
| { | |
| "date": idx.strftime("%Y-%m-%d"), | |
| "price": float(row["Close"]), | |
| } | |
| for idx, row in tail.iterrows() | |
| ] | |