| import requests | |
| import os | |
| from dotenv import load_dotenv | |
| from typing import List, Dict, Any | |
| import logging | |
| load_dotenv() | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| FMP_API_KEY = os.getenv("FMP_API_KEY") | |
| if not FMP_API_KEY: | |
| logger.warning("FMP_API_KEY not found. FMP calls will fail.") | |
| FMP_BASE_URL = "https://financialmodelingprep.com/api/v3" | |
| class FMPError(Exception): | |
| """Custom exception for FMP API errors.""" | |
| pass | |
| def get_earnings_surprises(ticker: str) -> List[Dict[str, Any]]: | |
| """ | |
| Fetches earnings surprise data for a single ticker from Financial Modeling Prep. | |
| Returns a list of earnings surprise records. | |
| Raises FMPError on API-specific issues. | |
| Raises requests.RequestException on network issues. | |
| """ | |
| if not FMP_API_KEY: | |
| raise FMPError("FMP API Key not configured.") | |
| endpoint = f"{FMP_BASE_URL}/earning_surprise/{ticker}" | |
| params = {"apikey": FMP_API_KEY} | |
| logger.info(f"Fetching earnings surprise data for {ticker} from FMP.") | |
| response = requests.get(endpoint, params=params, timeout=30) | |
| response.raise_for_status() | |
| data = response.json() | |
| if isinstance(data, list): | |
| return data | |
| else: | |
| logger.error(f"Unexpected FMP response structure for {ticker}: {data}") | |
| if isinstance(data, dict) and data.get("error"): | |
| raise FMPError(f"FMP API returned error for {ticker}: {data['error']}") | |
| if isinstance(data, dict) and not data: | |
| logger.warning( | |
| f"FMP API returned empty response for {ticker}, potentially no data." | |
| ) | |
| return [] | |
| raise FMPError(f"Unexpected API response structure for {ticker}.") | |