Switch active data source to Oanda v20 (practice feed)
config.json.example: data_providers.active = "oanda" (credentials stay in env/.env or the top-level oanda block; TD and Tiingo remain registered fallbacks). Backtest parquet cache is now keyed per provider — Oanda and TD bars diverge (2026-07-24 study), so a feed switch must never serve another feed's cached bars; twelve_data keeps the legacy un-prefixed filename so pinned-book caches stay valid. 254 tests green; live smoke-tested against the practice API (66 contract checks: all scanned TFs, boundary/freshness guarantees, real spread $0.71, fetch_range pagination, typed error paths, CLI + backtest end-to-end). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mc7XKYyPySVXiUpcN82QEK
This commit is contained in:
@@ -935,9 +935,17 @@ class GPUTechnicalEngine(TechnicalEngine):
|
||||
CACHE_DIR = Path(__file__).resolve().parent / "cache"
|
||||
|
||||
|
||||
def _cache_path(symbol: str, tf: Timeframe, start: datetime, end: datetime) -> Path:
|
||||
def _cache_path(
|
||||
symbol: str, tf: Timeframe, start: datetime, end: datetime,
|
||||
provider_name: str = "twelve_data",
|
||||
) -> Path:
|
||||
safe_sym = symbol.replace("/", "_").replace("=X", "")
|
||||
return CACHE_DIR / f"{safe_sym}_{tf.value}_{start:%Y%m%d}_{end:%Y%m%d}.parquet"
|
||||
# Bars differ between feeds (Oanda vs TD divergence study 2026-07-24),
|
||||
# so the cache is keyed per provider. twelve_data keeps the legacy
|
||||
# un-prefixed filename so pinned-book caches stay valid.
|
||||
prefix = "" if provider_name == "twelve_data" else f"{provider_name}_"
|
||||
return CACHE_DIR / (
|
||||
f"{prefix}{safe_sym}_{tf.value}_{start:%Y%m%d}_{end:%Y%m%d}.parquet")
|
||||
|
||||
|
||||
def fetch_history(
|
||||
@@ -962,7 +970,7 @@ def fetch_history(
|
||||
cleaned data; a refetch is needed to restore dropped spike bars.)
|
||||
"""
|
||||
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
path = _cache_path(symbol, timeframe, start, end)
|
||||
path = _cache_path(symbol, timeframe, start, end, provider.name)
|
||||
if use_cache and path.exists():
|
||||
logger.info(f"Loading cached {symbol} {timeframe.value}: {path.name}")
|
||||
df = pd.read_parquet(path)
|
||||
|
||||
Reference in New Issue
Block a user