Document issuer, outpost, and header settings for Coolify, fail closed when AUTH_REQUIRED is true, and add harvester healthcheck per Coolify conventions.
97 lines
3.7 KiB
Markdown
97 lines
3.7 KiB
Markdown
# QuantTrade
|
|
|
|
Local-first quantitative backtesting on Coolify: Streamlit UI, VectorBT engine, Parquet market data, nightly Yahoo Finance sync, Authentik OIDC via reverse proxy, and SQLite strategy persistence.
|
|
|
|
## Architecture
|
|
|
|
| Layer | Technology |
|
|
|-------|------------|
|
|
| Auth | Authentik (`auth.aexoradao.com`) via reverse proxy headers |
|
|
| UI | Streamlit (`streamlit` service, port 8501) |
|
|
| Engine | VectorBT + NumPy |
|
|
| Market data | Parquet volume (`parquet-data`) |
|
|
| Ingestion | `harvester` cron @ 17:00 America/New_York (weekdays) |
|
|
| Strategies | SQLite on `strategy-data` volume, keyed by proxy username |
|
|
| Telemetry | Bugsink via `sentry-sdk` (`bugsink.aexoradao.com`) |
|
|
|
|
## Coolify deployment
|
|
|
|
1. Create a **Docker Compose** resource pointing at this repo.
|
|
2. Assign your public domain to the **`streamlit`** service on port **8501**.
|
|
3. Enable **Authentik forward auth** on that domain in Coolify (OIDC happens at the proxy; Streamlit never holds client secrets).
|
|
4. Set environment variables in Coolify (first deploy extracts defaults from compose):
|
|
- `BUGSINK_DSN` — DSN from your Bugsink project
|
|
- `AUTHENTIK_ISSUER`, `OIDC_ISSUER`, `AUTHENTIK_OUTPOST_URL`, `OIDC_CLIENT_ID` — match your Authentik application/outpost
|
|
- `AUTH_USERNAME_HEADER` — header Coolify/Traefik forwards after login (default `X-Forwarded-User`)
|
|
- `AUTH_REQUIRED` — keep `true` in production
|
|
- `CORE_TICKERS` — optional comma-separated tickers
|
|
- `DEV_USER` — only when `AUTH_REQUIRED=false` for local testing
|
|
|
|
**Coolify note:** if you change any default above after the first deploy, update the value manually in Coolify UI > Environment Variables. Coolify stores first-seen defaults and will not auto-refresh them from compose.
|
|
|
|
### Authentik / proxy headers
|
|
|
|
OIDC login is handled by Authentik + Coolify reverse proxy. The container does not run an OAuth code flow; it trusts identity headers injected after forward auth.
|
|
|
|
After login, the proxy must forward headers such as:
|
|
|
|
- `X-Forwarded-User` (default `AUTH_USERNAME_HEADER`)
|
|
- `X-Authentik-Uid` (`AUTH_UID_HEADER`)
|
|
- `X-Forwarded-Email` (`AUTH_EMAIL_HEADER`)
|
|
|
|
The app reads them via Streamlit websocket headers (`auth.get_current_user()`). With `AUTH_REQUIRED=true`, missing headers block the UI instead of falling back to anonymous.
|
|
|
|
Example Traefik middleware (adjust provider labels to your stack):
|
|
|
|
```yaml
|
|
# Forward auth endpoint on Authentik
|
|
http:
|
|
middlewares:
|
|
authentik:
|
|
forwardAuth:
|
|
address: https://auth.aexoradao.com/outpost.goauthentik.io/auth/traefik
|
|
trustForwardHeader: true
|
|
authResponseHeaders:
|
|
- X-authentik-username
|
|
- X-authentik-uid
|
|
- X-Forwarded-User
|
|
```
|
|
|
|
Map `X-authentik-username` → `X-Forwarded-User` in your proxy if Streamlit only sees the latter.
|
|
|
|
## Services
|
|
|
|
- **`data-seed`** — one-shot 5-year historical download into Parquet (idempotent).
|
|
- **`harvester`** — cron container; appends daily bars after US cash close.
|
|
- **`streamlit`** — dashboard, backtests, save/load strategies.
|
|
|
|
## Local development
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
python -m venv .venv && source .venv/bin/activate
|
|
pip install -r requirements.txt
|
|
python sync.py --seed
|
|
DEV_USER=you@example.com streamlit run app.py
|
|
```
|
|
|
|
## Manual sync
|
|
|
|
```bash
|
|
python sync.py --seed # full history
|
|
python sync.py --daily # append latest bars
|
|
```
|
|
|
|
## Strategy storage
|
|
|
|
SQLite path: `/data/strategies/strategies.db` (Docker volume `strategy-data`). Each row stores username, name, ticker, and JSON parameters (MA windows, cash, fees).
|
|
|
|
## Bugsink
|
|
|
|
Set `BUGSINK_DSN` to your project DSN, e.g.:
|
|
|
|
```text
|
|
http://<public-key>@bugsink.aexoradao.com/<project-id>
|
|
```
|
|
|
|
Both `app.py` and `sync.py` initialize the Sentry-compatible SDK with tracing disabled for Bugsink compatibility.
|