zfin-server/README.md
Emil Lerch 2503f6bc2a
Some checks failed
Generic zig build / build (push) Failing after 28s
Generic zig build / deploy (push) Has been skipped
mutual fund logic in zfin proper now
2026-03-11 11:47:29 -07:00

101 lines
3.2 KiB
Markdown

# zfin-server
HTTP data service backed by [zfin](https://git.lerch.org/lobo/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
```sh
# 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 |
## LibreCalc usage
```
=FILTERXML(WEBSERVICE("http://localhost:8080/AAPL/returns?fmt=xml"), "//trailing1YearReturn")
```
XML response format:
```xml
<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:
```sh
# 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.15.2](https://ziglang.org/download/).
```sh
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 |
| `ALPHAVANTAGE_API_KEY` | No | Alpha Vantage API key |
| `ZFIN_PORTFOLIO` | No | Path to portfolio SRF (default: `portfolio.srf`) |
| `ZFIN_CACHE_DIR` | No | Cache directory (default: `~/.cache/zfin`) |
## License
MIT