feat: add fundamental data providers (Alpha Vantage, FMP, Yahoo Finance) with rotation
This commit is contained in:
parent
2398e8faf6
commit
aa47e896dd
7 changed files with 704 additions and 0 deletions
50
shared/fundamentals/rotating.py
Normal file
50
shared/fundamentals/rotating.py
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
"""Rotating (fallback) wrapper over multiple fundamental data providers."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from shared.fundamentals.base import FundamentalsProvider, FundamentalsSnapshot
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RotatingProvider(FundamentalsProvider):
|
||||
"""Tries each provider in order and returns the first successful result.
|
||||
|
||||
If a provider raises an exception it is caught, logged, and the next
|
||||
provider is attempted. Returns ``None`` only when every provider either
|
||||
returned ``None`` or raised.
|
||||
"""
|
||||
|
||||
def __init__(self, providers: list[FundamentalsProvider]) -> None:
|
||||
if not providers:
|
||||
raise ValueError("RotatingProvider requires at least one provider")
|
||||
self._providers = providers
|
||||
|
||||
async def fetch(self, ticker: str) -> FundamentalsSnapshot | None:
|
||||
"""Try each provider in sequence; return the first non-None result."""
|
||||
for provider in self._providers:
|
||||
provider_name = type(provider).__name__
|
||||
try:
|
||||
result = await provider.fetch(ticker)
|
||||
if result is not None:
|
||||
logger.info(
|
||||
"Provider %s succeeded for %s",
|
||||
provider_name,
|
||||
ticker,
|
||||
)
|
||||
return result
|
||||
logger.debug(
|
||||
"Provider %s returned None for %s, trying next",
|
||||
provider_name,
|
||||
ticker,
|
||||
)
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Provider %s raised for %s, trying next",
|
||||
provider_name,
|
||||
ticker,
|
||||
)
|
||||
logger.warning("All providers exhausted for %s", ticker)
|
||||
return None
|
||||
Loading…
Add table
Add a link
Reference in a new issue