trading-system-docs/notes/trading/system-docs/modul-04-market-regime.md

7.6 KiB
Raw Blame History

type _organized
Trading-Modul-System true

Modul-04-Market-Regime — Betriebsdokumentation

Erstellt: 20.08.2026 (Rain Ocampo) · Status: Freigegeben (E2E bestanden)

Zweck

Erster Consumer der Market-Data-Events von Modul-03. Pipeline: MARKET_DATA_READY / MARKET_CANDLE_CLOSED (Modul-03) → Regime-Berechnung → PostgreSQL (market_regime) → MARKET_REGIME_READY Deterministische, regelbasierte Engine — bewusst OHNE KI/ML.

Container

Attribut Wert
Name Modul-04-Market-Regime
Image market-regime:1.0.0 (lokal gebaut)
Port 55004NUR intern (expose, nicht öffentlich)
Netzwerk trading-modules (bridge)
Build-Context /opt/trading-modules/modul04-market-regime/
Restart unless-stopped
Healthcheck healthy

Deployment

cd /opt/trading-modules
docker compose build modul-04-market-regime
docker compose up -d --no-deps --force-recreate modul-04-market-regime

Environment Variables (Compose)

Variable Wert (Default) Zweck
PG_HOST Modul-01-PostgreSQL Docker-interner Servicename
PG_PORT 5432 intern (Host: 55432)
PG_USER/PASSWORD/DB trading aus .env-Defaults
RABBITMQ_HOST Modul-02-RabbitMQ Docker-interner Servicename
RABBITMQ_PORT 5672 intern (Host: 55672)
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-03 ──market.data.ready / market.data.candle.closed──▶ RegimeConsumer
                                                            │  (bindet beide Routing-Keys)
                                                            ▼
                                              RegimeEngine (deterministisch)
                                              EMA / ADX / ATR / Slope / Preisstruktur
                                                            │
                                                ┌───────────┴───────────┐
                                                ▼                       ▼
                                       market_regime (PG)      MARKET_REGIME_READY
                                       (16 Spalten)            → market.regime.ready
  • Consumer (app/consumer/consumer.py): bindet market.data.ready + market.data.candle.closed; durable Queue market-regime.input; manuelles Ack; Reconnect mit Backoff; schließt alte Verbindung beim Reconnect (verhindert Consumer-Leak/Nachrichtenverlust).
  • Engine (app/regime/engine.py): deterministisch, ohne KI.
  • Storage (app/storage/storage.py): idempotent via partiellen Unique-Index.
  • Publisher (app/publisher/publisher.py): publiziert MARKET_REGIME_READY auf market.regime (Routing market.regime.ready).
  • History-Client (app/marketdata/client.py): liest OHLCV über interne FastAPI Modul-03 (http://Modul-03-Market-Data:55003/history/{symbol}).

Regime-Engine (app/regime/engine.py)

Deterministische Regel-Engine (Version 1.0.0), 7 Regime: TREND_UP, TREND_DOWN, RANGE, HIGH_VOLATILITY, LOW_VOLATILITY, TRANSITION, UNKNOWN

Indikatoren & Metriken:

Indikator Fenster/Param Zweck
EMA fast/slow 10 / 30 Trendrichtung (EMA-Flanken-Differenz)
ADX 14 Trendstärke (≥20 = echter Trend)
ATR 14 Volatilität (absolut + Ratio + Perzentil)
Slope 20 normierte Steigung der Close-Linie
Preisstruktur higher_highs / lower_lows / range

Zentrale Schwellenwerte (app/config.py, env-overridable):

Parameter Default Bedeutung
min_candles_required 30 UNKNOWN, wenn weniger Daten
regime_lookback 60 max. Kerzen für Berechnung
trend_min_ema_gap 0.02
adx_trend_threshold 20.0 ADX ≥ → echter Trend
slope_up/down_threshold 0.05 / -0.05 normierte Steigung
range_atr_ratio 0.02 ATR/close darunter = Range
atr_high_vol_multiplier 1.5 ATR jetzt > hist_mean × → HIGH_VOL
atr_low_vol_multiplier 0.6 ATR jetzt < hist_mean × → LOW_VOL
high_vol_atr_ratio 0.03 ATR/close ≥ → starke Vol
low_vol_atr_ratio 0.008 ATR/close ≤ → geringe Vol
slope_threshold 0.01
transition_min_events 3 Events für TRANSITION

Datenbank (Modul-01-PostgreSQL)

Tabelle public.market_regime (16 Spalten, eigene Tabelle — bestehende unangetastet):

symbol TEXT, asset_class TEXT, timeframe TEXT, provider TEXT,
regime TEXT, confidence INTEGER (0-100),
trend_strength DOUBLE PRECISION, volatility_state TEXT,
timestamp TIMESTAMPTZ, indicators_json JSONB,
candles_used INTEGER, version TEXT,
source_event_id TEXT, correlation_id TEXT,
data_ts TIMESTAMPTZ, data_ts_end TIMESTAMPTZ
  • Unique (partiell): uq_market_regime_src auf (symbol, timeframe, source_event_id) WHERE source_event_id IS NOT NULL → Idempotenz.
  • Migration: migrations/001_market_regime.sql (idempotent, löscht nichts).

RabbitMQ (Modul-02)

Exchange Typ Routing Event
market.data topic market.data.ready (eingang) MARKET_DATA_READY
market.data topic market.data.candle.closed (eingang) MARKET_CANDLE_CLOSED
market.regime topic market.regime.ready (ausgang) MARKET_REGIME_READY

Interne API

Endpoint Zweck
GET /health Liveness (200 immer) + Komponentenstatus im Body
GET /health/ready Readiness (503 wenn PG/RabbitMQ/Modul-03 down)
GET /regime/{symbol} Regime-Einträge abfragen
GET /regime/latest/{symbol} Letztes Regime eines Symbols

End-to-End-Test (20.08.2026, final, nach Rebuild)

Kette verifiziert: Modul-03 Ingest → market.data.ready → Modul-04 Consumer → RegimeEngine → market_regimeMARKET_REGIME_READY auf market.regime.ready.

Fall Regime Conf candles version Event DB
M4TREND_UP (40) TREND_UP 100 40 1.0.0 genau 1
M4TREND_DN (40) TREND_DOWN 100 40 1.0.0 genau 1
M4RANGE (40) LOW_VOLATILITY (Range) 60 40 1.0.0 genau 1
M4HIGHVOL (40) HIGH_VOLATILITY 75 40 1.0.0 genau 1
M4UNKNOWN (5) UNKNOWN 20 5 1.0.0 genau 1
M4IDEMPOT (40) TREND_UP 100 40 1.0.0 genau 1

Idempotenz: dasselbe Quell-Event (source_event_id) erneut → kein zweiter Datensatz, kein Doppel-Event. Logs: keine Errors/Tracebacks. Health {postgresql:true, rabbitmq:true, market_data_ready:true}.

Bugs behoben während E2E (20.08.2026)

Bug Fix
can't adapt type 'dict' (JSONB) json.dumps(ind.model_dump(mode="json"))
tuple index out of range (16/15) version in INSERT-VALUES ergänzt
ON CONFLICT + partieller Index Fehler WHERE source_event_id IS NOT NULL in Klausel
model_dump(default=...) TypeError default-Kwarg entfernt (model_dump(mode="json"))
Consumer-Verbindungs-Leak conn.close() bei Reconnect → kein Message-Leak

Offene Punkte

  • Consumer-Downstream für market.regime.ready (Modul-05+)
  • Bestätigte TRANSITION-Detektion mit echten Folgedaten

Geändert von: Rain Ocampo
Datum: 20.08.2026
Grund: Modul-04-Dokumentation angelegt (Regime-Engine, market_regime-Schema, Events, E2E freigegeben).