bugfixes
All checks were successful
Deployment / deploy-docker (push) Successful in 23s

This commit is contained in:
Melchior Reimers
2026-02-17 13:56:02 +01:00
parent 819b6c2232
commit ad890d23b0
2 changed files with 152 additions and 21 deletions

View File

@@ -7,4 +7,6 @@ RUN pip install --no-cache-dir -r requirements.txt
COPY . . COPY . .
ENV PYTHONPATH=/app
CMD ["python", "dashboard/server.py"] CMD ["python", "dashboard/server.py"]

171
README.md
View File

@@ -1,20 +1,140 @@
# Trading Data Daemon # Trading Data Daemon
Ein modularer Daemon zum Herunterladen und Speichern von Handelsdaten von verschiedenen Börsen in einer Time-Series-Datenbank. Ein modularer Daemon zum Herunterladen und Speichern von Handelsdaten von verschiedenen deutschen Börsen in QuestDB (Time-Series-Datenbank).
## Unterstützte Exchanges ## Unterstützte Exchanges
- **European Investor Exchange (EIX)**: Lädt tägliche Kursblatt-CSVs herunter.
- **Lang & Schwarz (LS)**: Fragt die heutigen Trades über deren JSON/CSV-RPC ab. - **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 ## Architektur
- `src/exchanges/base.py`: Basisklasse für neue Börsen (einfach erweiterbar).
- `src/database/questdb_client.py`: Speichert Daten in QuestDB via Influx Line Protocol (ILP). Fünf Microservices, orchestriert via Docker Compose:
- `daemon.py`: Der Orchestrator, der die Daten abruft und speichert.
```
┌─────────────────────────────────────────────────────────────────┐
│ 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 ## Installation und Setup
### 1. QuestDB (Timeseries DB) starten ### 1. QuestDB starten (via Docker Compose)
Am einfachsten via Docker Compose:
```bash ```bash
docker-compose up -d docker-compose up -d
``` ```
@@ -25,26 +145,35 @@ QuestDB ist dann unter `http://localhost:9000` erreichbar.
pip install -r requirements.txt pip install -r requirements.txt
``` ```
### 3. Systemd Service einrichten ### 3. Manuell starten
Kopiere die Dateien nach `/etc/systemd/system/`: ```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 ```bash
sudo cp systemd/trading-daemon.service /etc/systemd/system/ sudo cp systemd/trading-daemon.service /etc/systemd/system/
sudo cp systemd/trading-daemon.timer /etc/systemd/system/ sudo cp systemd/trading-daemon.timer /etc/systemd/system/
```
Pfade in `trading-daemon.service` müssen ggf. angepasst werden (aktuell auf `/Users/melchiorreimers/...` gesetzt).
Dienste aktivieren:
```bash
sudo systemctl daemon-reload sudo systemctl daemon-reload
sudo systemctl enable --now trading-daemon.timer sudo systemctl enable --now trading-daemon.timer
``` ```
### 4. Manuell testen ## Umgebungsvariablen
```bash
python3 daemon.py | Variable | Default | Beschreibung |
``` |----------|---------|-------------|
| `DB_USER` | `admin` | QuestDB Benutzername |
| `DB_PASSWORD` | `quest` | QuestDB Passwort |
| `DB_HOST` | `questdb` | QuestDB Hostname (Docker-intern) |
## Erweiterung ## Erweiterung
Um eine neue Börse hinzuzufügen, erstelle einfach eine neue Klasse in `src/exchanges/`, die von `BaseExchange` erbt und implementiere `fetch_latest_trades()`. Füge sie dann in `daemon.py` zur Liste hinzu.
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)