No description
Find a file
epistemophiliac 7f7133f535 Add Authentik/OIDC compose env vars and enforce proxy auth.
Document issuer, outpost, and header settings for Coolify, fail closed when AUTH_REQUIRED is true, and add harvester healthcheck per Coolify conventions.
2026-06-19 00:55:12 -04:00
.streamlit Initial QuantTrade stack for Coolify deployment. 2026-06-19 00:46:51 -04:00
scripts Initial QuantTrade stack for Coolify deployment. 2026-06-19 00:46:51 -04:00
.env.example Add Authentik/OIDC compose env vars and enforce proxy auth. 2026-06-19 00:55:12 -04:00
.gitignore Initial QuantTrade stack for Coolify deployment. 2026-06-19 00:46:51 -04:00
app.py Add Authentik/OIDC compose env vars and enforce proxy auth. 2026-06-19 00:55:12 -04:00
auth.py Add Authentik/OIDC compose env vars and enforce proxy auth. 2026-06-19 00:55:12 -04:00
backtest.py Initial QuantTrade stack for Coolify deployment. 2026-06-19 00:46:51 -04:00
docker-compose.yml Add Authentik/OIDC compose env vars and enforce proxy auth. 2026-06-19 00:55:12 -04:00
Dockerfile Initial QuantTrade stack for Coolify deployment. 2026-06-19 00:46:51 -04:00
Dockerfile.harvester Initial QuantTrade stack for Coolify deployment. 2026-06-19 00:46:51 -04:00
README.md Add Authentik/OIDC compose env vars and enforce proxy auth. 2026-06-19 00:55:12 -04:00
requirements.txt Initial QuantTrade stack for Coolify deployment. 2026-06-19 00:46:51 -04:00
strategy_db.py Initial QuantTrade stack for Coolify deployment. 2026-06-19 00:46:51 -04:00
sync.py Initial QuantTrade stack for Coolify deployment. 2026-06-19 00:46:51 -04:00
telemetry.py Initial QuantTrade stack for Coolify deployment. 2026-06-19 00:46:51 -04:00

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

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