quant-web/README.md
epistemophiliac b5db15d6ab Initial QuantTrade stack for Coolify deployment.
Streamlit + VectorBT dashboard, Parquet harvester with nightly cron, Authentik header auth, SQLite strategy persistence, and Bugsink telemetry.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-19 00:46:51 -04:00

2.9 KiB

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. Set environment variables in Coolify (first deploy extracts defaults from compose):
    • BUGSINK_DSN — DSN from your Bugsink project
    • CORE_TICKERS — optional comma-separated tickers
    • DEV_USER — only for unauthenticated local testing
  4. Protect the domain in your reverse proxy with Authentik forward auth.

Authentik / proxy headers

After login, the proxy must forward one of these headers to Streamlit:

  • X-Forwarded-User (recommended)
  • X-Authentik-Username
  • Remote-User

The app reads them via Streamlit websocket headers (auth.get_current_user()). Saved strategies are scoped to that username.

Example Traefik middleware (adjust provider labels to your stack):

# 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-usernameX-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

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

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.:

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.