7.5 KiB
Trading Data Daemon
Ein modularer Daemon zum Herunterladen und Speichern von Handelsdaten von verschiedenen deutschen Börsen in QuestDB (Time-Series-Datenbank).
Unterstützte Exchanges
- European Investor Exchange (EIX) — Streaming-Verarbeitung (große CSV-Dateien)
- Lang & Schwarz (LS) — JSON/CSV-RPC API
- Deutsche Börse — Xetra, Frankfurt, Quotrix
- Gettex — Bayerische Börse (MUNC/MUND)
- Stuttgart — MiFIR II Delayed Data
- Börsenag — Düsseldorf (DUSA/DUSB/DUSC/DUSD), Hamburg (HAMA/HAMB), Hannover (HANA/HANB)
Architektur
Fünf Microservices, orchestriert via Docker Compose:
┌─────────────────────────────────────────────────────────────────┐
│ QuestDB │
│ (9000=HTTP, 8812=PostgreSQL, 9009=ILP) │
└──────────┬──────────────┬──────────────┬──────────────┬─────────┘
│ │ │ │
┌──────┴──────┐ ┌─────┴─────┐ ┌──────┴──────┐ ┌─────┴─────┐
│ fetcher │ │ analytics │ │ metadata │ │ dashboard │
│ daemon.py │ │ worker │ │ fetcher │ │ :8080 │
└─────────────┘ └───────────┘ └─────────────┘ └───────────┘
- Fetcher (
daemon.py): Orchestrator. Holt Trades von allen Börsen täglich um 23:00. Streaming für EIX, Batch für alle anderen. Deduplizierung via Hash-Cache. - Analytics Worker (
src/analytics/worker.py): Berechnet aggregierte Tabellen für Zeiträume: 7, 30, 42, 69, 180, 365 Tage. - Metadata Fetcher (
src/metadata/fetcher.py): Reichert ISINs mit Firmen-/Sektordaten an (OpenFIGI API, yfinance). - Dashboard (
dashboard/server.py): FastAPI-Server mit REST-Endpunkten und statischem UI ausdashboard/public/.
Datenbank-Schema
QuestDB speichert alle Daten via Influx Line Protocol (ILP) mit Nanosekunden-Präzision.
trades
Rohe Handelsdaten aller Börsen. Geschrieben vom Fetcher.
| Spalte | Typ | Beschreibung |
|---|---|---|
timestamp |
timestamp | Zeitpunkt des Trades |
exchange |
symbol (tag) | Börsenname (z.B. XETRA, LS, GETTEX) |
symbol |
symbol (tag) | Wertpapiername |
isin |
symbol (tag) | ISIN-Kennung (z.B. DE000BAY0017) |
price |
double | Handelspreis |
quantity |
double | Handelsvolumen (Stückzahl) |
analytics_exchange_daily
Tägliche Aggregationen pro Börse mit Moving Averages. Geschrieben vom Analytics Worker.
| Spalte | Typ | Beschreibung |
|---|---|---|
timestamp |
timestamp | Tag der Aggregation |
exchange |
symbol (tag) | Börsenname |
trade_count |
long | Anzahl Trades am Tag |
volume |
double | Gesamtvolumen (Summe von Preis × Menge) |
ma{N}_count |
double | N-Tage Moving Average der Trade-Anzahl |
ma{N}_volume |
double | N-Tage Moving Average des Volumens |
N = 7, 30, 42, 69, 180, 365
analytics_daily_summary
Tagesübergreifende Zusammenfassung aller Börsen. Geschrieben vom Analytics Worker.
| Spalte | Typ | Beschreibung |
|---|---|---|
timestamp |
timestamp | Tag der Zusammenfassung |
total_trades |
long | Gesamtanzahl Trades über alle Börsen |
total_volume |
double | Gesamtvolumen über alle Börsen |
unique_assets |
long | Anzahl verschiedener gehandelter ISINs |
analytics_stock_trends
Trendanalyse pro ISIN mit prozentualen Veränderungen. Geschrieben vom Analytics Worker.
| Spalte | Typ | Beschreibung |
|---|---|---|
timestamp |
timestamp | Analysedatum |
isin |
symbol (tag) | ISIN-Kennung |
trade_count |
long | Gesamtanzahl Trades im Zeitraum |
volume |
double | Gesamtvolumen im Zeitraum |
count_change_pct |
double | Prozentuale Änderung der Trade-Anzahl (1. vs. 2. Hälfte) |
volume_change_pct |
double | Prozentuale Änderung des Volumens |
period_days |
long | Zeitraum in Tagen (7/30/42/69/180/365) |
analytics_volume_changes
Volumen- und Anzahländerungen pro Börse mit Trendklassifizierung. Geschrieben vom Analytics Worker.
| Spalte | Typ | Beschreibung |
|---|---|---|
timestamp |
timestamp | Analysedatum |
exchange |
symbol (tag) | Börsenname |
trend |
symbol (tag) | Trendklasse (s.u.) |
trade_count |
long | Gesamtanzahl Trades im Zeitraum |
volume |
double | Gesamtvolumen im Zeitraum |
count_change_pct |
double | Prozentuale Änderung der Trade-Anzahl |
volume_change_pct |
double | Prozentuale Änderung des Volumens |
period_days |
long | Zeitraum in Tagen |
Trendklassen: mehr_trades_mehr_volumen, mehr_trades_weniger_volumen, weniger_trades_mehr_volumen, weniger_trades_weniger_volumen, stabil
analytics_custom
Vorberechnete Custom-Analytics für den Dashboard-Graphen-Builder. Geschrieben vom Analytics Worker.
| Spalte | Typ | Beschreibung |
|---|---|---|
timestamp |
timestamp | Tag der Berechnung |
y_axis |
symbol (tag) | Metrik-Typ (volume, trade_count, avg_price) |
group_by |
symbol (tag) | Gruppierung (exchange, isin, date) |
exchange_filter |
symbol (tag) | Exchange-Filter (Börsenname oder all) |
group_value |
string | Wert der Gruppierung (z.B. Börsenname, ISIN) |
y_value |
double | Berechneter Metrik-Wert |
metadata
ISIN-Stammdaten (Firmenname, Land, Sektor). Geschrieben vom Metadata Fetcher.
| Spalte | Typ | Beschreibung |
|---|---|---|
timestamp |
timestamp | Zeitpunkt der letzten Aktualisierung |
isin |
symbol (tag) | ISIN-Kennung |
name |
string | Firmen-/Wertpapiername |
country |
string | Ländercode oder -name |
continent |
string | Kontinent |
sector |
string | Branchenklassifizierung |
Installation und Setup
1. QuestDB starten (via Docker Compose)
docker-compose up -d
QuestDB ist dann unter http://localhost:9000 erreichbar.
2. Python Abhängigkeiten installieren
pip install -r requirements.txt
3. Manuell starten
python3 daemon.py # Fetcher
python -m src.analytics.worker # Analytics Worker
python src/metadata/fetcher.py # Metadata Fetcher
python dashboard/server.py # Dashboard (Port 8000)
4. Systemd Service (optional)
sudo cp systemd/trading-daemon.service /etc/systemd/system/
sudo cp systemd/trading-daemon.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now trading-daemon.timer
Umgebungsvariablen
| Variable | Default | Beschreibung |
|---|---|---|
DB_USER |
admin |
QuestDB Benutzername |
DB_PASSWORD |
quest |
QuestDB Passwort |
DB_HOST |
questdb |
QuestDB Hostname (Docker-intern) |
Erweiterung
Um eine neue Börse hinzuzufügen:
- Erstelle eine neue Klasse in
src/exchanges/, die vonBaseExchangeerbt - Implementiere
fetch_latest_trades()(gibtList[Trade]zurück) - Implementiere die
name-Property - Registriere in
daemon.pyunterSTREAMING_EXCHANGES(große Daten) oderSTANDARD_EXCHANGES(Batch)