9.4 KiB
| type | _organized |
|---|---|
| Modul | true |
Modul-06-Signal-Ranking — Betriebsdokumentation
Erstellt: 20.08.2026 (Rain Ocampo) · Status: ✅ Freigegeben (E2E+Idempotenz+Reconnect+Doku grün)
Zweck
Signal-Ranking — konsumiert SIGNAL_DETECTED (Modul-05) + OHLCV (Modul-03), bewertet die Signalqualität deterministisch (Score 0–100, vollständig nachvollziehbar und konfigurierbar), persistiert das Ergebnis und publiziert SIGNAL_RANKED.
Pipeline: SIGNAL_DETECTED (Modul-05) → Signal-Ranking (signal_quality_v1) → PostgreSQL (signal_ranking) → SIGNAL_RANKED
Deterministische, regelbasierte Ranking-Engine — bewusst OHNE KI/ML. Keine Positionsgröße, kein Risk Management, keine Broker-/Order-Ausführung (Trade-Freigabe macht später der Risk Manager). Modular aufgebaut, damit später eine ML/KI-Engine als ZUSÄTZLICHE Ranking-Engine registriert werden kann.
Container
| Attribut | Wert |
|---|---|
| Name | Modul-06-Signal-Ranking |
| Image | signal-ranking:0.1.0 (lokal gebaut) |
| Port | 55006 — NUR intern (expose, nicht öffentlich) |
| Netzwerk | trading-modules (bridge) |
| Build-Context | /opt/trading-modules/modul06-signal-ranking/ |
| Restart | unless-stopped |
| Healthcheck | ✅ healthy |
Deployment
cd /opt/trading-modules
docker compose build modul-06-signal-ranking
docker compose up -d --no-deps --force-recreate modul-06-signal-ranking
Environment Variables (Compose)
| Variable | Wert (Default) | Zweck |
|---|---|---|
PG_HOST |
Modul-01-PostgreSQL |
Docker-interner Servicename |
PG_PORT |
5432 |
intern |
PG_USER/PASSWORD/DB |
trading |
aus .env-Defaults |
RABBITMQ_HOST |
Modul-02-RabbitMQ |
Docker-interner Servicename |
RABBITMQ_PORT |
5672 |
intern |
RABBITMQ_USER/PASSWORD/VHOST |
trading |
vhost trading |
LOG_LEVEL |
INFO |
Strukturiertes Logging |
Keine festen IPs — nur Docker-interne Hostnamen. Creds via Compose env + Defaults.
Architektur
Modul-05 ──signal.detected──▶ RankingConsumer (ranking.input)
│
▼
OHLCV (Modul-03, intern 55003/history/{symbol})
│
▼
RankingEngine (deterministisch, Registry)
signal_quality_v1 (9 Komponenten, Score 0–100)
│
┌───────────┴───────────┐
▼ ▼
signal_ranking (PG) SIGNAL_RANKED
(eigene Tabelle) → market.rankings / signal.ranked
- Consumer (
app/consumer/consumer.py): bindet Exchangemarket.signals, Routingstrategy.signal.detected; durable Queueranking.input; manuelles Ack erst nach erfolgreicher Verarbeitung; Reconnect mit Backoff +conn.close();queue_deletebeim Start (entfernt verwaiste/Zombie-Consumer). - MarketData-Client (
app/marketdata/client.py): liest OHLCV über interne FastAPI Modul-03 (http://Modul-03-Market-Data:55003/history/{symbol}); hoher Lookback, damit die letzten geschlossenen Kerzen enthalten sind. - Engine/Register (
app/ranking/engine.py): modular — Ranking-Engines via.name/.version/rank()registriert; KI/ML später ergänzbar. - Storage (
app/storage/storage.py): idempotent via partiellen Unique-Index aufsource_signal_id. - Publisher (
app/publisher/publisher.py): frische Verbindung je Publish +conn.close()im finally (verhindertConnectionResetErrordurch RabbitMQ-Closed-Verbindungen). - Service (
app/core/service.py): Pipeline Event → OHLCV → Ranking → speichern + publizieren; robuste Payload-Extraktion; setztsource_signal_idaus dem Event-Top-Level, falls die Engine es nicht aus dem inneren payload ziehen konnte.
Ranking-Engine V1 — signal_quality_v1 (app/ranking/signal_quality_v1.py)
Deterministische Qualitätsbewertung. 9 Komponenten, Score 0–100, vollständig nachvollziehbar und konfigurierbar. Jede Komponente liefert 0..max; Summe = total_score. Komponenten werden einzeln in der DB gespeichert (comp_*).
| Komponente | Max | Bewertet |
|---|---|---|
regime |
20 | Market-Regime-Qualität / Confidence |
trend |
15 | Trendstärke |
pullback |
15 | Pullback-Qualität |
trigger |
10 | Entry-Bestätigung |
rr |
10 | Chance/Risiko-Verhältnis |
volatility |
10 | Volatilitätszustand |
distance |
10 | Distanz Entry→Stop |
data_quality |
5 | Datenqualität / Candle-Anzahl |
consistency |
5 | Setup-Konsistenz |
Klassifizierung: total_score >= eligible_threshold → eligible; darunter weak (wird trotzdem gespeichert).
Zentrale Schwellenwerte (app/config.py, env-overridable):
| Parameter | Default | Bedeutung |
|---|---|---|
max_score |
100 | Score-Obergrenze |
eligible_threshold |
70 | Score ≥ 70 → eligible |
ranking_lookback |
500 | max. Kerzen für Trend/Volatilität (Modul-03 liefert die N ältesten, daher hoch) |
min_candles_required |
60 | unter dieser Zahl → Datenqualität-Punktabzug |
full_candles_target |
250 | ab dieser Zahl → volle Datenqualität |
pullback_depth_min/max |
0.5 / 4.0 | Abstand Entry zu Trend-Referenz in ATR |
vol_ideal_lo/hi |
0.005 / 0.030 | ATR %-Fenster für "ideale" Volatilität |
Keine Trade-Freigabe — nur Qualitätsbewertung.
Datenbank (Modul-01-PostgreSQL)
Eigene Tabelle public.signal_ranking (bestehende unangetastet):
ranking_id UUID, source_signal_id TEXT, source_event_id TEXT, correlation_id TEXT,
timestamp TIMESTAMPTZ, symbol TEXT, asset_class TEXT, provider TEXT, timeframe TEXT,
ranking_name TEXT, ranking_version TEXT, ranking_class TEXT (eligible/weak),
total_score DOUBLE PRECISION, comp_regime/comp_trend/comp_pullback/comp_trigger/comp_rr/
comp_volatility/comp_distance/comp_data_quality/comp_consistency DOUBLE PRECISION,
details JSONB, reasons JSONB
- Unique (partiell):
uq_signal_ranking_srcauf(symbol, timeframe, source_signal_id)WHERE source_signal_id IS NOT NULL → Idempotenz (source_signal_idnie doppelt). - Migration:
migrations/001_signal_ranking.sql(idempotent, löscht nichts).
RabbitMQ (Modul-02)
| Exchange | Typ | Routing | Event |
|---|---|---|---|
market.signals |
topic | strategy.signal.detected (eingang) |
SIGNAL_DETECTED |
market.rankings |
topic | signal.ranked (ausgang) |
SIGNAL_RANKED |
Interne API
| Endpoint | Zweck |
|---|---|
GET /health |
Liveness (200) + Komponentenstatus im Body |
GET /health/ready |
Readiness (503 wenn PG/RabbitMQ/Modul-03 down) |
GET /rankings/{symbol} |
Rankings eines Symbols |
GET /rankings/latest/{symbol} |
Neuestes Ranking eines Symbols |
GET /ranking-engines |
Registrierte Ranking-Engines |
End-to-End-Test (20.08.2026, final) ✅
Kette verifiziert: Modul-03 Ingest → market.data.ready → Modul-04 → market.regime.ready → Modul-05 → SIGNAL_DETECTED → Modul-06 Consumer → signal_quality_v1 → signal_ranking → SIGNAL_RANKED.
| Fall | Ranking | Score | Class | DB | SIGNAL_RANKED |
|---|---|---|---|---|---|
| M5LONG (TREND_UP) | eligible | 72.2 | eligible | ✅ 1 | ✅ 1 |
| M5SHORT (TREND_DOWN) | eligible | 73.6 | eligible | ✅ 1 | ✅ 1 |
| M5NOPULL (kein Pullback) | — | — | — | ✅ 0 | ✅ 0 |
| M5RANGE (Range) | — | — | — | ✅ 0 | ✅ 0 |
Verifizierte Eigenschaften:
- Gültiger LONG/SHORT → genau 1
SIGNAL_RANKED; NOPULL/RANGE → 0 Ranking + 0 Event. ✅ - DB-Eintrag je gültigem Signal vorhanden;
source_signal_idkorrekt übernommen (z.B.effd782c...,42dd2042...). ✅ total_scoreimmer 0–100; Summe aller Komponenten == total_score. ✅eligible/weakkorrekt gemäß Threshold (72.2/73.6 ≥ 70 → eligible). ✅- Idempotenz: identisches
SIGNAL_DETECTEDerneut → kein zweiter DB-Eintrag, kein zweites SIGNAL_RANKED (count=1). ✅ - RabbitMQ-Reconnect: kontrollierter Neustart → Modul-04/05/06 verbinden automatisch (Backoff 1s→2s→4s→8s), je exakt 1 Consumer, keine Zombies, keine verlorenen Events. ✅
- Logs: keine unbehandelten Tracebacks nach Reconnect. Health/Readiness
{postgresql:true, rabbitmq:true, market_data:true, consumer_ready:true}. ✅
Bugs behoben während E2E (20.08.2026)
| Bug | Fix |
|---|---|
source_signal_id leer |
Service setzt source_signal_id aus dem Event-Top-Level, falls die Engine es nicht aus dem inner-Payload ziehen konnte |
| OHLCV-Lookback zu klein (120) | ranking_lookback auf 500 erhöht — Modul-03 /history?limit=N liefert die N ältesten Kerzen; zu kleiner Lookback → Engine bewertete auf veralteten Kerzen (Konsistenz/Trend/Pullback schief) |
direction-Spalte existierte nicht |
E2E-Query auf details/Modell angepasst |
Offene Punkte
- Downstream-Consumer für
signal.ranked(Modul-07+ — noch NICHT begonnen) - KI/ML-Ranking-Engine über Registry ergänzbar
- Trade-Freigabe später durch Risk Manager (noch nicht gebaut)
Geändert von: Rain Ocampo
Datum: 20.08.2026
Grund: Modul-06-Dokumentation angelegt (Signal-Ranking signal_quality_v1, signal_ranking-Schema, Events, E2E final grün).