Feed Divergence Study — Oanda vs Tiingo vs Twelve Data (Phase 1)
Date: 2026-08-14
Test plan: docs/data_source_change_test_plan.md (removed 2026-09-06, in git history; the pending Phase 4 shadow scan is noted in CLAUDE.md)
Tool: scripts/feed_divergence_study.py (script removed 2026-09-06, in git history) (fetch_range over 365d, parquet-cached)
Window: 2025-08-14 → 2026-08-14 (12 months); Oanda-vs-TD truncated at TD cache head (2026-07-23)
Headline
Three mid-price feeds for the same XAU/USD instrument are not interchangeable:
| Pair |
mean |ΔClose| |
p95 |ΔClose| |
direction agree (M5/M15/H1) |
bias |
extra bars |
| Oanda vs Tiingo |
~$0.13 |
~$0.29 |
97.7% / 98.3% / 98.5% |
~0 |
Tiingo +3–5% (weekend) |
| Oanda vs Twelve Data |
~$3.0 |
~$11.9 |
81.0% / 88.7% / 92.7% |
−$1.06 (TD high) |
— |
- Oanda ↔ Tiingo are near-identical on shared bars (~1–2% of ATR on close), but Tiingo emits ~22 hours of Sunday bars/week that Oanda omits.
- Oanda ↔ Twelve Data diverge massively — ~$3 mean close gap (≈30% of M5 ATR, ~30% of M15 ATR), a systematic ~$1 bias (TD quoted ~$1 high), and 19% of M5 bars even disagree on bar direction. This is the documented "Oanda/TD divergence" that motivated re-pinning the books on Oanda bars.
Oanda vs Tiingo — detailed
Both feeds: same bar grid, same head/tail timestamps. Tiingo simply has more bars (Sunday bars).
Coverage (12 months)
| TF |
Oanda bars |
Tiingo bars |
shared |
Oanda-only |
Tiingo-only |
| M5 |
70,901 |
73,241 |
70,807 (96.6%) |
94 (0.13%) |
2,434 (3.32%) |
| M15 |
23,640 |
24,922 |
23,615 (94.7%) |
25 (0.11%) |
1,307 (5.24%) |
| H1 |
5,912 |
6,246 |
5,909 (94.6%) |
3 (0.05%) |
337 (5.40%) |
| H4 |
1,597 |
1,657 |
1,597 (96.4%) |
0 |
60 (3.62%) |
- Tiingo-only bars cluster exclusively on Sundays (e.g. M15: 88/Sunday; H1: 22/Sunday; H4: 5/Sunday). Tiingo's FX endpoint resamples continuously and does not apply the FX weekend calendar — it emits ~22h of flat/stale Sunday bars that Oanda omits.
- Oanda-only bars cluster on holidays (2025-11-27 Thanksgiving, 2025-12-10, 2026-06-25) — a handful of bars, negligible.
Per-bar OHLC diffs (Oanda − Tiingo, $)
| TF |
Close mean |
Close p95 |
Close max |
|ΔClose| / ATR14 (mean / p95) |
| M5 |
$0.123 |
$0.285 |
$26.10 |
2.1% / 5.0% |
| M15 |
$0.128 |
$0.290 |
$26.10 |
1.3% / 2.9% |
| H1 |
$0.145 |
$0.335 |
$26.10 |
0.7% / 1.6% |
| H4 |
$0.168 |
$0.340 |
$17.53 |
0.4% / 0.8% |
- Bias is ~zero on every TF (no systematic one-feed-high).
- Tail outliers (p99/max up to $26–88) occur during fast moves — the two feeds' bar extremes disagree on the exact tick, as expected.
- Direction agreement is 97.7–98.4%, return correlation 0.995–0.9997.
- Divergence is concentrated at the Friday-close / Sunday-reopen boundary (UTC hours 20–22; mean |ΔClose| ~2–4× the 08–19h baseline).
Phase 1 pass/fail vs plan thresholds
| Criterion |
Plan threshold |
Result |
Verdict |
| timestamp overlap |
≥ 99.5% |
94.6–96.6% |
FAIL (Tiingo weekend bars) |
| Close p95 |Δ| |
≤ 0.01% of price |
~0.0067% |
PASS |
| no systematic bias |
mean Δ ≈ 0 |
~0 |
PASS |
The overlap "failure" is a coverage difference, not a data-quality one: the shared bars agree tightly, but Tiingo's extra Sunday bars mean the feeds have a different bar count. The signal pipeline's own _is_forex_weekend filter (NY-anchored) gates those Sunday bars, so live impact depends on whether any code trusts the feed's raw bar set directly.
Oanda vs Twelve Data — detailed (M5/M15/H1, cached TD parquets)
| TF |
common |
mean |ΔClose| |
median |ΔClose| |
p95 |
max |
bias (TD−Oanda) |
dir agree |
| M5 |
66,246 |
$2.999 |
$1.118 |
$11.934 |
$101.85 |
+1.05 |
80.96% |
| M15 |
22,090 |
$2.951 |
$1.051 |
$11.848 |
$101.85 |
+1.08 |
88.71% |
| H1 |
5,526 |
$2.902 |
$0.985 |
$11.908 |
$70.94 |
+1.06 |
92.67% |
- The ~$3 mean / ~$1 median / ~$12 p95 gap is ~23× larger than the Oanda–Tiingo gap, and the ~$1 bias is systematic (Twelve Data quotes gold ~$1 high vs Oanda's true mid).
- M5 direction agreement of 81% means one bar in five disagrees on direction — M5 signals on TD bars are effectively a different instrument than on Oanda bars.
- This matches the prior Oanda/TD M15 study of 2026-07-24 (
oanda_td_divergence.py, removed 2026-09-06 as superseded by this report; mean |ΔClose| ~$3.3) and confirms the standing rule: pinned Twelve-Data books are not comparable to Oanda live signals without a re-pin.
Conclusions for the data-source switch
- Oanda → Tiingo (or back) is signal-safe in magnitude (price diffs ~1–2% of ATR, 98% direction agreement), provided the weekend-bar coverage difference is handled — Tiingo's Sunday bars must be gated by the aggregator's NY-anchored weekend filter, not by raw bar count.
- Oanda → Twelve Data is a recalibration, not a formality. Phase 2/3 must quantify the actual signal/book delta; the $3/$1 bias alone guarantees a large fraction of marginal bars flip.
- Re-pinning the books on Oanda bars (Phase 3) remains mandatory before any TD-pinned baseline is treated as a live expectation.
Next steps
- Phase 2: signal-level replay parity (
analyze_from_dataframes on both feeds) to turn price-diff stats into flip rates.
- Phase 3: backtest re-pin on Oanda bars at $0.30 and $0.65.