# 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 aus `dashboard/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) ```bash docker-compose up -d ``` QuestDB ist dann unter `http://localhost:9000` erreichbar. ### 2. Python Abhängigkeiten installieren ```bash pip install -r requirements.txt ``` ### 3. Manuell starten ```bash 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) ```bash 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: 1. Erstelle eine neue Klasse in `src/exchanges/`, die von `BaseExchange` erbt 2. Implementiere `fetch_latest_trades()` (gibt `List[Trade]` zurück) 3. Implementiere die `name`-Property 4. Registriere in `daemon.py` unter `STREAMING_EXCHANGES` (große Daten) oder `STANDARD_EXCHANGES` (Batch)