Streamlit + VectorBT dashboard, Parquet harvester with nightly cron, Authentik header auth, SQLite strategy persistence, and Bugsink telemetry. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|---|---|---|
| .streamlit | ||
| scripts | ||
| .env.example | ||
| .gitignore | ||
| app.py | ||
| auth.py | ||
| backtest.py | ||
| docker-compose.yml | ||
| Dockerfile | ||
| Dockerfile.harvester | ||
| README.md | ||
| requirements.txt | ||
| strategy_db.py | ||
| sync.py | ||
| telemetry.py | ||
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
- Create a Docker Compose resource pointing at this repo.
- Assign your public domain to the
streamlitservice on port 8501. - Set environment variables in Coolify (first deploy extracts defaults from compose):
BUGSINK_DSN— DSN from your Bugsink projectCORE_TICKERS— optional comma-separated tickersDEV_USER— only for unauthenticated local testing
- 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-UsernameRemote-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-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
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.