zfin/docs/reference/cli/diagnose.md

4.3 KiB

zfin diagnose

Trace one symbol's candle data through every tier -- local cache, shared server, upstream provider -- and say where the chain breaks.

Usage: zfin diagnose SYMBOL

diagnose answers one question: is the provider behind for this symbol, or is it us? It is the counterpart to doctor, and deliberately its opposite on both axes -- doctor checks the whole setup and never touches the network, while diagnose checks a single symbol and queries every tier including the provider.

It is read-only: no cache writes, and the provider query does not populate the cache. Safe to run while investigating.

What it reports

Seven lines, in the order the data flows:

Line Says
local Newest cached bar, TTL state, which provider sourced it, consecutive failures, any Tiingo backoff
adj basis How current the cached adjusted closes are, against the newest dividend or split that has already gone ex
peers Newest bar held by other cached symbols of the same kind (equity vs mutual fund)
tracked Whether a normal run fetches this symbol, or it is only pulled on demand
server What ZFIN_SERVER offers, whether it is ahead or behind you, and whether it refreshes this symbol
provider What the upstream provider actually has right now
verdict Where the chain breaks, and what to do about it

Example

zfin diagnose SPY
local      newest 2026-08-19, TTL still in the future, tiingo
adj basis  2026-08-17 - current through the newest corporate action (2026-06-18)
peers      23 other equity cached, newest 2026-08-19
tracked    on demand - a projections benchmark symbol
server     offers 2026-08-19 - same as local, written 2026-08-19, tracked: yes
provider   tiingo newest 2026-08-19 (8 bars in the last 10 days)

verdict    up to date with everything available

Reading the adj basis line

This is the least obvious line, so it is worth spelling out. Cached price history grows by appending, which cannot retroactively correct the adjusted closes of bars already on disk. When a dividend or split goes ex, those earlier bars need marking down, and until they are, total returns spanning that ex-date read low by roughly the missed yield. See Incremental candle updates.

Three forms:

adj basis  2026-08-17 - current through the newest corporate action (2026-06-18)
adj basis  1970-01-01 - STALE, 2026-06-01 went ex behind it; total returns read low until restated
adj basis  2026-08-19 - no dividends or splits cached, nothing to restate

STALE is not something to act on -- the next refresh re-downloads that symbol's full history on its own. It explains a total return that looks slightly low in the meantime.

Two things the date is not: it is not when the restatement ran (it is the newest bar present at the time, which lags when a session's bar has not posted yet), and it is not an ex-date. 1970-01-01 means "never restated", which is what a cache predating the feature reads as.

The compared-against date is the newest ex-date that has already passed. A declared-but-not-yet-ex dividend is deliberately ignored: no provider has applied it either, so waiting on it would refetch forever.

Rate limit caveat

The provider query uses its own rate limiter, separate from the budget the rest of zfin accounts for -- so it is invisible to that budget. On a free tier close to its cap, diagnose can be the request that trips it. One request per invocation.

See also

  • doctor -- whole-setup health check, no network.
  • cache -- stale finds symbols behind their peers; refresh forces a local re-fetch.
  • server -- force a refresh in the shared server's cache instead.
  • Caching and data freshness -- the tiers and TTLs.

CLI command reference