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).

Claude-Session: https://claude.ai/code/session_01Mc7XKYyPySVXiUpcN82QEK
This commit is contained in:
Harwinder Sekhon
2026-07-28 20:12:59 -04:00
parent 083a4e8d63
commit 637c39e201
4 changed files with 33 additions and 6 deletions
+18
View File
@@ -4291,6 +4291,24 @@ def _():
"aggregator must not depend on a concrete provider class"
@test("providers: backtest parquet cache is keyed per provider")
def _():
# Bars differ between feeds (Oanda/TD divergence study 2026-07-24) —
# a provider switch must never serve another feed's cached bars.
# twelve_data keeps the legacy un-prefixed name so pinned-book caches
# stay valid.
from datetime import datetime
from backtest.gpu_backtest import _cache_path
s, e = datetime(2026, 1, 1), datetime(2026, 2, 1)
td = _cache_path(XAUUSD, Timeframe.M15, s, e, "twelve_data")
oa = _cache_path(XAUUSD, Timeframe.M15, s, e, "oanda")
legacy = _cache_path(XAUUSD, Timeframe.M15, s, e)
assert td.name == "XAU_USD_15min_20260101_20260201.parquet", td.name
assert oa.name == "oanda_XAU_USD_15min_20260101_20260201.parquet", oa.name
assert legacy == td, "default must stay the legacy twelve_data key"
assert td != oa, "providers must not share cache files"
# ══════════════════════════════════════════════════════════════════════
# SUMMARY
# ══════════════════════════════════════════════════════════════════════