finance web server
Find a file
Emil Lerch 297c1c8bb8
All checks were successful
Generic zig build / build (push) Successful in 1m24s
Generic zig build / deploy (push) Successful in 16s
log slow requests
2026-06-01 12:58:52 -07:00
.forgejo/workflows ai: yolo the CI and docker image create/push 2026-03-10 17:48:07 -07:00
docker mutual fund logic in zfin proper now 2026-03-11 11:47:29 -07:00
src log slow requests 2026-06-01 12:58:52 -07:00
.gitignore upgrade to zig 0.16.0 and latest zfin lib, add /splits 2026-05-20 16:34:16 -07:00
.mise.toml upgrade to zig 0.16.0 and latest zfin lib, add /splits 2026-05-20 16:34:16 -07:00
.pre-commit-config.yaml add basic structure 2026-03-10 17:29:14 -07:00
build.zig main.zig cleanup / add version and rate limiting output 2026-03-11 10:45:48 -07:00
build.zig.zon update printRateLimitWait/bump zfin for cache improvements 2026-06-01 12:41:35 -07:00
GitVersion.zig upgrade to zig 0.16.0 and latest zfin lib, add /splits 2026-05-20 16:34:16 -07:00
LICENSE add basic structure 2026-03-10 17:29:14 -07:00
README.md add edgar/wikidata endpoints/refresh, zfin upgrade 2026-06-01 08:12:51 -07:00

zfin-server

HTTP data service backed by zfin's financial data providers. Serves cached market data over HTTP for two consumers:

  1. LibreCalc spreadsheets — trailing returns via WEBSERVICE/FILTERXML
  2. zfin CLI/TUI — raw SRF cache files as an L1 data cache

Quick start

# Set API keys (same as zfin)
export TWELVEDATA_API_KEY=...
export POLYGON_API_KEY=...

# Start the server
zig build run -- serve --port=8080

# In another terminal
curl http://localhost:8080/AAPL/returns
curl http://localhost:8080/AAPL/returns?fmt=xml

Endpoints

Route Content-Type Description
GET / text/html Landing page
GET /help text/plain Endpoint documentation
GET /symbols application/json List of tracked symbols
GET /:symbol/returns application/json Trailing 1/3/5/10yr returns + volatility
GET /:symbol/returns?fmt=xml application/xml Same, XML for LibreCalc
GET /:symbol/quote application/json Latest quote
GET /:symbol/candles application/x-srf Raw SRF cache file
GET /:symbol/dividends application/x-srf Raw SRF cache file
GET /:symbol/earnings application/x-srf Raw SRF cache file
GET /:symbol/options application/x-srf Raw SRF cache file
GET /:symbol/classification application/x-srf Wikidata classification (SRF)
GET /:symbol/etf_metrics application/x-srf EDGAR NPORT-P fund metrics; 404 for non-funds
GET /:cik/entity_facts application/x-srf EDGAR XBRL entity facts (CIK-keyed)
GET /_edgar/tickers_funds application/x-srf EDGAR mutual-fund ticker map (~3 MB)
GET /_edgar/tickers_companies application/x-srf EDGAR company ticker map (~5 MB)

LibreCalc usage

=FILTERXML(WEBSERVICE("http://localhost:8080/AAPL/returns?fmt=xml"), "//trailing1YearReturn")

XML response format:

<returns>
  <ticker>AAPL</ticker>
  <returnDate>2026-03-07</returnDate>
  <trailing1YearReturn>12.34000</trailing1YearReturn>
  <trailing3YearReturn>8.56000</trailing3YearReturn>
  <trailing5YearReturn>15.78000</trailing5YearReturn>
  <trailing10YearReturn>22.10000</trailing10YearReturn>
  <volatility>18.50000</volatility>
</returns>

Cache refresh

Use cron to keep the cache warm for all symbols in your portfolio:

# Refresh all portfolio symbols daily at 5pm ET (after market close)
0 17 * * 1-5 cd /path/to/workdir && ZFIN_PORTFOLIO=portfolio.srf zfin-server refresh

The candle cache TTL is 23h45m (not a full 24h), providing a 15-minute jitter buffer so daily cron runs at the same time always see stale data and trigger a fresh fetch. Dividend and earnings TTLs are 14 and 30 days respectively.

The refresh command reads the portfolio SRF file (defaults to portfolio.srf in the current directory if ZFIN_PORTFOLIO is not set), extracts all stock and watch symbols, and fetches candles, dividends, and earnings for each.

Building

Requires Zig 0.16.0.

zig build        # build
zig build test   # run tests
zig build run -- serve --port=8080

Configuration

All configuration is via environment variables:

Variable Required Description
TWELVEDATA_API_KEY Yes TwelveData API key
POLYGON_API_KEY No Polygon API key
FINNHUB_API_KEY No Finnhub API key
ZFIN_USER_EMAIL Yes Contact email for SEC EDGAR User-Agent header
ZFIN_PORTFOLIO No Path to portfolio SRF (default: portfolio.srf)
ZFIN_CACHE_DIR No Cache directory (default: ~/.cache/zfin)

License

MIT