zfin/docs/explanation/data-providers.md
Emil Lerch 74fc219afd
All checks were successful
Generic zig build / build (push) Successful in 5m48s
Generic zig build / publish-macos (push) Successful in 11s
Generic zig build / deploy (push) Successful in 23s
add docs/guides
2026-06-22 14:53:53 -07:00

3.6 KiB

Why multiple data providers

No single free data source does everything well. zfin aggregates several, using each for what it's best at, and falls back gracefully when one is unavailable. This page explains the design; for signup links, limits, and the full table, see Data providers and API keys.

One source per job

Each data type has a primary provider chosen for coverage and quality:

Data Primary Notes
Daily candles Tiingo Deep history; stocks, ETFs, mutual funds
Real-time quotes Yahoo No key required
Dividends / splits Polygon Carries forward-looking declared events
Options chains CBOE No key; 15-minute delayed
Earnings FMP Actuals + analyst estimates
ETF profiles / classification SEC EDGAR + Wikidata Authoritative holdings; needs a contact email

The data service hides this behind one interface -- commands ask for "candles for VTI," not "call Tiingo." That's also what makes the cache and rate limiting uniform across providers.

Fallback, not single-point-of-failure

Where a second source can stand in, zfin uses it:

  • Candles: Tiingo is primary; Yahoo is the fallback if Tiingo is unavailable or lacks the symbol.
  • Quotes: Yahoo is primary; TwelveData is the fallback.
  • Dividends/splits: Polygon is primary, but Tiingo's price-series response carries per-row dividend and split data that zfin merges in to rescue events Polygon's reference endpoints occasionally miss.

How a failure propagates depends on its kind. Transient errors (server 5xx, connection drops) stop a refresh so you don't get a half-updated view. Permanent errors (not-found, parse failures) fall through to the next provider, and a rate-limit hit triggers a single backoff-and-retry.

Why some data needs a key and some doesn't

Quotes (Yahoo) and options (CBOE) are unauthenticated. The rest want a free API key, and SEC EDGAR wants a contact email in its User-Agent (set via ZFIN_USER_EMAIL) rather than a key. None are individually required -- missing a key just removes that one data type, and everything else keeps working. See which key unlocks what.

A few deliberate quirks

  • Yahoo is unofficial. Yahoo Finance has no public API; zfin reads an undocumented endpoint that needs no key but carries no guarantees -- it can change shape or stop responding at any time. Quotes (and the candle fallback) ride on it, so keeping TIINGO_API_KEY set for candles and TWELVEDATA_API_KEY for quote fallback cushions a Yahoo outage.
  • TwelveData is no longer used for candles. Its split-adjusted closes proved unreliable for the return math, so it's quote-fallback only now. Yahoo is the candle fallback.
  • Mutual-fund and dual-class coverage varies. Some symbols (ETFs, CUSIPs, a few dual-class shares like BRK.B) have no earnings on the free FMP tier and show "no earnings data" -- a documented limitation, not a bug. See the FAQ.

See also