optimization-hashira's picture
demo
3f43e82
Raw
History Blame Contribute Delete
3.68 kB
import requests
from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel
from typing import List, Dict, Optional, Any
from data_ingestion.api_loader import get_daily_adjusted_prices, DataIngestionError
import logging
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)
app = FastAPI(title="API Agent")
class MarketDataRequest(BaseModel):
tickers: List[str]
start_date: Optional[str] = None
end_date: Optional[str] = None
data_type: Optional[str] = "adjClose"
@app.post("/get_market_data")
def get_market_data(request: MarketDataRequest):
"""
Fetches daily adjusted market data by calling the data_ingestion layer (FMP).
Returns adjusted close prices per ticker per date.
"""
result: Dict[str, Dict[str, float]] = {}
errors: Dict[str, str] = {}
warnings: Dict[str, str] = {}
key = (
request.data_type
if request.data_type in ["open", "high", "low", "close", "adjClose", "volume"]
else "adjClose"
)
for ticker in request.tickers:
try:
raw = get_daily_adjusted_prices(ticker)
time_series: Dict[str, Any] = {}
if isinstance(raw, dict):
time_series = raw
elif isinstance(raw, list):
logger.warning(
f"Loader returned list for {ticker}; filtering dict entries."
)
for rec in raw:
if isinstance(rec, dict) and "date" in rec:
date_val = rec["date"]
time_series[date_val] = rec
else:
logger.warning(
f"Skipping non-dict or missing-date entry for {ticker}: {rec}"
)
else:
raise DataIngestionError(
f"Unexpected format from loader for {ticker}: {type(raw)}"
)
ticker_prices: Dict[str, float] = {}
for date_str, values in time_series.items():
if not isinstance(values, dict):
warnings.setdefault(ticker, "")
warnings[ticker] += f" Non-dict for {date_str}; skipped."
continue
if key not in values:
warnings.setdefault(ticker, "")
warnings[ticker] += f" Missing '{key}' on {date_str}."
continue
try:
ticker_prices[date_str] = float(values[key])
except (TypeError, ValueError):
warnings.setdefault(ticker, "")
warnings[ticker] += f" Invalid '{key}' value on {date_str}."
if ticker_prices:
result[ticker] = ticker_prices
logger.info(f"Fetched {len(ticker_prices)} points for {ticker}.")
else:
warnings.setdefault(ticker, "")
warnings[ticker] += " No valid data points found."
except (requests.RequestException, DataIngestionError) as err:
errors[ticker] = str(err)
logger.error(f"Error fetching {ticker}: {err}")
except Exception as err:
errors[ticker] = f"Unexpected error for {ticker}: {err}"
logger.error(errors[ticker])
if not result and errors:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to fetch market data for all tickers.",
)
return {"result": result, "errors": errors, "warnings": warnings}