repos
/ finance-rust master

finance-rust

mirror archived upstream

Single-binary self-hosted market watcher for stocks, ETFs, indexes, and futures: live charts, key stats, fundamentals, SEC filings, and SSE streaming.

axumdockerfinancerustself-hostedsqlitestocksvite

5.7 KB · 103 lines · markdown Raw History
  1> **Archived.** This project is no longer in use and no longer maintained. Last updated July 2026.
  2
  3# Finance
  4
  5A self-hosted, real-timeish market watcher for stocks, ETFs, indexes, and futures: live charts, key stats, fundamentals, and SEC filings. One axum binary with sqlx + SQLite, minijinja templates, and a Vite frontend.
  6
  7Single-operator, no auth, no accounts. It is for *watching* the market, not tracking holdings: there is no portfolio, no cost basis, no money in it at all.
  8
  9## Features
 10
 11- Curated universe of ~150 stocks, ETFs, indexes, and commodity/index futures, extendable from the Search page
 12- Deep daily OHLCV history (decades) plus 15-minute intraday bars and live quotes
 13- Symbol pages with candlestick charts, SMA 50/200 + EMA 21 overlays, an RSI pane, a volume histogram, and a drag-to-measure tool
 14- Skimmable key stats: the day's range, the 52-week range, and volume vs average, all drawn as range meters rather than a flat card grid
 15- SEC fundamentals: nine graded ratios with plain-English readings, an annual/quarterly financials table, and a recent-filings list
 16- An opinionated home dashboard: index + commodity sparkline cards over the day's biggest movers
 17- Live prices over Server-Sent Events, polled only for the symbols actually being viewed, and only during market hours
 18- A `/health` page that lays the background machinery open: every job, every endpoint guard, and a tail of the fetch log
 19- A persistent per-endpoint guard (circuit breaker + hourly budget + request pacing) so an upstream rate limit can never be hit
 20- Single-binary deploy via `git push server master`
 21
 22## Data sources
 23
 24All free, no account, no key:
 25
 26| Source | Used for | Auth |
 27|---|---|---|
 28| Yahoo Finance | Deep daily history + live quotes + 15-minute intraday bars | None (a browser User-Agent) |
 29| SEC EDGAR | Fundamentals (XBRL) + filing history | None (a contact email, `SEC_CONTACT_EMAIL`, in the User-Agent) |
 30
 31Everything fetched is cached in SQLite; the network is touched only for increments. Yahoo's chart endpoint serves a symbol's entire daily history in one call, so the per-symbol backfill runs once; thereafter the daily-close snapshot appends each day's bar and intraday quotes are polled only for watched symbols during market hours. P/E and dividend yield are computed from SEC data plus the latest price, never stored.
 32
 33## System dependencies
 34
 35Local dev needs these on your `PATH`:
 36
 37| Tool | Why | Version |
 38|---|---|---|
 39| `rustc` / `cargo` | Build the axum binary | 2021 edition, current stable (1.70+) |
 40| `bun` | Frontend deps + Vite build | 1.x |
 41| `make` | Run the dev/build targets | any |
 42| A C toolchain + OpenSSL headers | Linked at build time on Linux | `build-essential pkg-config libssl-dev` (Debian/Ubuntu), `musl-dev pkgconfig openssl-dev` (Alpine) |
 43
 44The Docker build (see `Dockerfile`) reproduces this on `rust:alpine` + `alpine:3.23`. If you only care about Docker, you do not need any of the above on the host.
 45
 46## Quickstart
 47
 48```sh
 49cp samplefiles/env.sample .env
 50# edit .env: set SEC_CONTACT_EMAIL (and BASE_URL for prod)
 51make
 52```
 53
 54`make` (alias `make run`) installs frontend deps if needed, then runs Vite watch and `cargo run` concurrently on port 8000. Visit http://localhost:8000.
 55
 56On first boot the scheduler seeds the curated universe and backfills its deep daily history from Yahoo (resumable, paced, guarded). No API key is needed; Yahoo serves history, live quotes, and intraday bars from the same endpoint.
 57
 58## Configuration
 59
 60All config comes from `.env` (loaded via `dotenvy`). The full set:
 61
 62| Variable | Required | Purpose |
 63|---|---|---|
 64| `SEC_CONTACT_EMAIL` | for fundamentals | Appended to the User-Agent on SEC requests so SEC can identify the caller. Empty disables the SEC job |
 65| `BASE_URL` | yes for prod | Absolute origin used in the sitemap and og tags. No trailing slash |
 66| `PORT` | no (default `8000`) | HTTP listen port |
 67| `FINANCE_DATA_DIR` | no (default `./data`) | Where `db.sqlite3` lives. Production sets this to `/data` |
 68| `FINANCE_ROOT` | no (default `.`) | Override the project root (where `templates/`, `dist/`, `migrations/`, `universe/` are read from) |
 69| `FINANCE_USER_AGENT` | no | Browser-like User-Agent sent on every outbound data request |
 70| `FINANCE_QUOTE_PROVIDER` | no (default `yahoo`) | Which `QuoteProvider` impl to use for live data |
 71| `FINANCE_TITLE` | no (default `Finance`) | Title shown in the header and `<title>` |
 72
 73## Make targets
 74
 75| Target | What it does |
 76|---|---|
 77| `make run` (default) | Vite watch + `cargo run` on port 8000 |
 78| `make build` | Vite assets + release binary (`target/release/finance`) |
 79| `make start` | Run the release binary (after `make build`) |
 80| `make seed` | Re-run the universe seed (curated symbols + bulk daily history). Idempotent |
 81| `make push` | `git push` to every configured remote |
 82| `make clean` | Remove build output, frontend deps, and the local `data/` dir |
 83
 84There are no tests or linters configured.
 85
 86## Deploy
 87
 88Production runs on Docker. The standard flow is `git push server master` to a remote whose post-receive hook runs `docker compose up --build --detach`. Sample files in `samplefiles/`:
 89
 90- `env.sample`: the `.env` shown above
 91- `Caddyfile.sample`: reverse proxy with TLS
 92- `post-receive.sample`: the git hook
 93
 94Data persists to `/srv/data/finance/` on the host (mounted into the container at `/data`).
 95
 96## Stack
 97
 98- **Backend:** axum 0.8, sqlx 0.8 against SQLite (WAL), single binary
 99- **Templates:** minijinja 2 with a Jinja2-faithful HTML formatter
100- **Frontend:** Vite 6, SCSS, lightweight-charts; Source Serif 4 / Inter / JetBrains Mono, self-hosted via `@fontsource`
101- **Scheduler:** one long-lived tokio loop running market-hours-aware background jobs
102- **Real-time:** a `tokio::sync::broadcast` hub feeding a `/stream` SSE endpoint