# zfin A financial data library, CLI, and terminal UI written in Zig. Tracks portfolios, analyzes trailing returns, displays options chains, earnings history, and more -- all from the terminal. ## Quick start ### macOS (Apple Silicon) -- pre-built binary ```bash # Download the latest aarch64-macos binary, make it executable, drop on $PATH curl -L -o zfin \ https://git.lerch.org/api/packages/lobo/generic/zfin-aarch64-macos/latest/zfin-aarch64-macos chmod +x zfin sudo mv zfin /usr/local/bin/ # or anywhere on $PATH ``` ### Linux / building from source ```bash # Requires Zig 0.16.0. With mise installed, `mise install` will pick the right # version from .mise.toml. Otherwise grab Zig 0.16.0 manually. zig build # Binary lands at zig-out/bin/zfin ``` ### Configure ```bash # Set at least one API key plus your contact email (see "API keys" below). # The email is required for ETF profiles + `enrich` because SEC EDGAR mandates # a User-Agent contact. export TIINGO_API_KEY=your_key export ZFIN_USER_EMAIL=you@example.com ``` ### Use it ```bash zfin perf VTI # trailing returns zfin quote AAPL # real-time quote zfin options AAPL # options chains zfin earnings MSFT # earnings history zfin portfolio # portfolio summary (reads portfolio.srf) zfin analysis # portfolio analysis (reads portfolio.srf + metadata.srf) # Interactive TUI zfin i # auto-loads portfolio.srf from cwd zfin i -p portfolio.srf -w watchlist.srf zfin i -s AAPL # start with a symbol, no portfolio ``` Building from source requires Zig 0.16.0. ## Documentation Full user documentation lives in [`docs/`](docs/README.md) and is built around the runnable example portfolios in [`examples/`](examples/). - **New here?** [Getting started](docs/getting-started.md) -- install, configure, and run your first commands. - **Learn the model:** [Core concepts](docs/explanation/concepts.md). - **Do a task (the user manual):** - [Build your portfolio](docs/guides/set-up-your-portfolio.md) - [Classify your holdings](docs/guides/classify-holdings.md) and [map your accounts](docs/guides/set-up-accounts.md) - [Read your portfolio](docs/guides/read-your-portfolio.md) - [Plan for retirement](docs/guides/plan-retirement.md) - [Snapshots and history](docs/guides/snapshots-and-history.md), [track contributions](docs/guides/track-contributions.md) - [Audit against your brokerage](docs/guides/audit-against-brokerage.md) - [Customize the TUI](docs/guides/customize-the-tui.md), [offline use and refreshing data](docs/guides/offline-and-refresh.md) - **Look something up (reference):** - [CLI commands](docs/reference/cli/index.md) - Config files: [`portfolio.srf`](docs/reference/config/portfolio-srf.md), [`accounts.srf`](docs/reference/config/accounts-srf.md), [`metadata.srf`](docs/reference/config/metadata-srf.md), [`projections.srf`](docs/reference/config/projections-srf.md), and [more](docs/reference/config/environment.md) - [The interactive TUI](docs/reference/tui.md) - [Data providers and API keys](docs/reference/providers.md) - **Understand the why (explanation):** [caching](docs/explanation/caching.md), [data providers](docs/explanation/data-providers.md), [returns](docs/explanation/returns-and-performance.md), [the projection model](docs/explanation/projections-model.md), [FAQ](docs/explanation/faq-troubleshooting.md). ## Data providers zfin aggregates data from multiple free-tier APIs, using each for what it does best, with aggressive caching to stay within free-tier limits. | Data type | Provider | Auth | Free-tier limit | Cache TTL | |-----------------------|------------------|----------------------|----------------------------|--------------| | Daily candles (OHLCV) | Tiingo | `TIINGO_API_KEY` | 1,000 req/day, 50 req/hour | 23h45m | | Real-time quotes | Yahoo Finance | None required | Unofficial | Never cached | | Quote fallback | TwelveData | `TWELVEDATA_API_KEY` | 8 req/min, 800/day | Never cached | | Dividends | Polygon | `POLYGON_API_KEY` | 5 req/min | 14 days | | Splits | Polygon | `POLYGON_API_KEY` | 5 req/min | 14 days | | Options chains | CBOE | None required | ~30 req/min (self-imposed) | 1 hour | | Earnings | FMP | `FMP_API_KEY` | 250 req/day | 30 days* | | ETF profiles | SEC EDGAR | `ZFIN_USER_EMAIL` | 10 req/sec | ~90 days | | Classification | Wikidata + EDGAR | `ZFIN_USER_EMAIL` | No per-day quota | Long-lived | Not all keys are required; without a given key, that data type is simply unavailable. For per-provider notes, signup links, the full caching/TTL model, and the complete environment-variable list, see [Data providers and API keys](docs/reference/providers.md), [Caching and data freshness](docs/explanation/caching.md), and [Environment variables](docs/reference/config/environment.md). ## Architecture ``` src/ root.zig Library root, exports all public types format.zig Shared formatters, braille engine, ANSI helpers config.zig Configuration from env vars / .env files service.zig DataService: cache-check -> fetch -> cache -> return models/ candle.zig OHLCV price bars date.zig Date type with arithmetic, snapping, formatting dividend.zig Dividend records with type classification split.zig Stock splits option.zig Option contracts and chains earnings.zig Earnings events with surprise calculation etf_profile.zig ETF profiles with holdings and sectors portfolio.zig Lots, positions, and portfolio aggregation classification.zig Classification metadata parser quote.zig Real-time quote data providers/ tiingo.zig Tiingo: daily candles (primary), supplementary div/split merge twelvedata.zig TwelveData: quote fallback polygon.zig Polygon: dividends, splits (primary, with forward-looking entries) fmp.zig FMP: earnings (actuals + estimates) cboe.zig CBOE: options chains (no API key) Edgar.zig SEC EDGAR: ETF profiles (NPORT-P), mutual-fund ticker map, XBRL company facts Wikidata.zig Wikidata SPARQL: classification metadata for `enrich` yahoo.zig Yahoo Finance: quotes (primary), candles (Tiingo fallback) openfigi.zig OpenFIGI: CUSIP to ticker lookup xml.zig Vendored XML parser used by Edgar.zig (see "Vendored code") analytics/ indicators.zig SMA, Bollinger Bands, RSI performance.zig Trailing returns (as-of-date + month-end) risk.zig Volatility, Sharpe, drawdown valuation.zig Portfolio summary, allocations, covered call adjustments analysis.zig Portfolio analysis engine (breakdowns by class/sector/geo/account/tax) cache/ store.zig SRF file cache with TTL freshness checks net/ http.zig HTTP client with retries and server error retry rate_limiter.zig Token-bucket rate limiter commands/ common.zig Shared CLI helpers (progress, formatting) perf.zig Trailing returns command quote.zig Quote command ... (14 command files) tui.zig Interactive TUI application tui/ chart.zig z2d pixel chart renderer (Kitty graphics) keybinds.zig Configurable keybinding system theme.zig Configurable color theme ``` Data files (user-managed, in project root): ``` portfolio.srf Portfolio lots metadata.srf Classification metadata for analysis accounts.srf Account to tax type mapping for analysis ``` ### Dependencies | Dependency | Source | Purpose | |----------------------------------------------------|---------------|---------------------------------------------------| | [SRF](https://git.lerch.org/lobo/srf) | Git | Cache file format and portfolio/watchlist parsing | | [libvaxis](https://github.com/rockorager/libvaxis) | Git (v0.6.0) | Terminal UI rendering | | [z2d](https://github.com/vancluever/z2d) | Git (v0.11.0) | Pixel chart rendering (Kitty graphics protocol) | ## Building Requires Zig 0.16.0. The canonical version is pinned in `.mise.toml`: ```bash # Recommended: use mise to install the right Zig and ZLS automatically mise install # Or, with Zig 0.16.0 already on PATH: zig build # build the zfin binary zig build test # run all tests zig build run -- # build and run ``` The compiled binary is at `zig-out/bin/zfin`. ## Vendored code A small amount of third-party source is vendored directly into the tree (rather than added as a Zig package dependency) where the upstream is small, stable, and not packaged for `build.zig.zon`: | File | Source | Purpose | |-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------| | `src/providers/xml.zig` | [Snektron/vulkan-zig](https://github.com/Snektron/vulkan-zig/blob/797ae8af88e84753af9640266de61a985b76b580/generator/xml.zig), via [aws-zig](https://github.com/elerch/aws-sdk-for-zig) | XML DOM parser used by the EDGAR provider for NPORT-P primary documents. | Each vendored file carries a `// VENDORED - see README.md` header identifying its upstream source. When updating, copy the new upstream verbatim and re-add the header. ## License MIT