Provider abstraction: providers/ package with BaseDataProvider template
One class per provider (TwelveData, Oanda, Tiingo), all subclassing BaseDataProvider which owns cache, validation/cleaning, freshness + boundary guarantees, fetch_range pagination, and streaming stubs — subclasses implement only _fetch_raw. config.json data_providers.active selects the live feed; data_provider.py / oanda_provider.py stay as back-compat shims. Module 16 provider-abstraction tests (253 total green). Claude-Session: https://claude.ai/code/session_01Mc7XKYyPySVXiUpcN82QEK
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
ForexBot2 — Data-provider package
|
||||
==================================
|
||||
One class per provider, all subclassing `BaseDataProvider` (which owns
|
||||
caching, validation, boundary guarantees, and range pagination — the
|
||||
behavior the signal pipeline depends on).
|
||||
|
||||
Adding a provider = one module implementing `_fetch_raw` + one registry
|
||||
entry + one config.json `data_providers` block. The live feed is selected
|
||||
by config.json `data_providers.active`; registration alone changes
|
||||
nothing.
|
||||
"""
|
||||
|
||||
from typing import Dict
|
||||
|
||||
from app_config import AppConfigError, get_app_config
|
||||
from config import PlatformConfig
|
||||
|
||||
from providers.base import BaseDataProvider, DataIntegrityError, _is_forex_weekend
|
||||
from providers.twelve_data import TwelveDataProvider
|
||||
from providers.oanda import OandaDataError, OandaDataProvider
|
||||
from providers.tiingo import TiingoDataError, TiingoDataProvider
|
||||
|
||||
#: config.json data_providers.active selects from here.
|
||||
PROVIDER_REGISTRY: Dict[str, type] = {
|
||||
"twelve_data": TwelveDataProvider,
|
||||
"oanda": OandaDataProvider,
|
||||
"tiingo": TiingoDataProvider,
|
||||
}
|
||||
|
||||
|
||||
def make_data_provider(config: PlatformConfig) -> BaseDataProvider:
|
||||
"""Build the ACTIVE data provider (config.json: data_providers.active)."""
|
||||
name = get_app_config().active_provider
|
||||
cls = PROVIDER_REGISTRY.get(name)
|
||||
if cls is None:
|
||||
raise AppConfigError(
|
||||
f'Unknown data provider "{name}"; '
|
||||
f"registered: {sorted(PROVIDER_REGISTRY)}")
|
||||
return cls(config)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"BaseDataProvider",
|
||||
"DataIntegrityError",
|
||||
"OandaDataError",
|
||||
"OandaDataProvider",
|
||||
"TiingoDataError",
|
||||
"TiingoDataProvider",
|
||||
"TwelveDataProvider",
|
||||
"PROVIDER_REGISTRY",
|
||||
"make_data_provider",
|
||||
"_is_forex_weekend",
|
||||
]
|
||||
Reference in New Issue
Block a user