Systemzustand in den Tagesreport - der fehlende letzte Meter

Selbstaendige Empfehlung nach der Gesamtpruefung, vom User beauftragt.

Befund: die Erkennung funktioniert, die Zustellung nicht. Sieben
Waechter, jeder nach einem eigenen Vorfall gebaut, jeder funktioniert -
und trotzdem blieben diese Woche sechs Zustaende tagelang unbemerkt,
vier davon waren bereits erkannt.

Belegt an den Marker-Dateien: cfg_auto_sr_close traegt 06.08. 18:10,
cfg_auto_squeeze sogar 02.08. Der Config-Waechter meldet je Schluessel
genau einmal und schweigt danach fuer immer. auto_sr_close war damit
fuenf Tage aus - gemessen +350,81 EUR ueber 43 Trades. Ursache ist ein
Kategorienfehler: die Marker-Logik behandelt einen Dauerzustand wie ein
Einmal-Ereignis.

Gebaut: engine._system_status() als Block im Tagesreport (07:30,
Telegram + E-Mail) - der einzige Kanal, der nachweislich jeden Tag
ankommt. Saubere Trennung: Popup = "etwas Neues", Report = "so steht
es gerade". Reine Anzeige.

- telemetrie_puls() liegt in core/history.py, beide Nutzer rufen
  dieselbe Funktion (Skripte importieren core, nie umgekehrt)
- measurement_reminder wird lazy und gekapselt importiert; ein
  Fehlschlag wird sichtbar gemeldet statt still verschluckt
- tests/test_system_status.py: 7 Tests, Schwerpunkt Ausfallpfade -
  der Report darf an dieser Zeile nie scheitern

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-11 22:43:24 +02:00
co-authored by Claude Opus 5
parent dca3c11bbd
commit b18b594639
5 changed files with 297 additions and 38 deletions
+14 -37
View File
@@ -427,44 +427,20 @@ CONFIG_DEPS = [
# ⚠ Die Toleranz ist grosszügig (Faktor 20 der erwarteten Kadenz), damit ein
# ruhiger Markt keinen Fehlalarm auslöst — ein Wächter, der oft warnt, wird
# ignoriert (Lehre vom 02.08.).
_PULS = [
# (Tabelle, Zeitspalte, erwartete Kadenz in Minuten, wozu)
("recommendations", "timestamp", 1, "Empfehlungs-Log"),
("candles_m1", "time", 1, "M1-Kerzen-Sammlung"),
("verdict_votes", "ts", 1, "Modul-Stimmen"),
("m15_states", "ts", 60, "M15-Karte Selbstmessung"),
("cone_checks", "ts", 60, "Kegel-Kalibrierung (ACI)"),
("pbreak_predictions", "ts", 60, "P(break)-Prognose-Tracking"),
("rec_outcomes", "ts", 180, "Selbst-Kalibrierung Empfehlung"),
]
# ⚠ Die Implementierung liegt in `core/history.py` (DB-Schicht) — BEIDE Nutzer
# (dieses Popup und der Tagesreport in `engine._send_daily_report`) rufen
# dieselbe Funktion. Zwei Kopien waeren die Divergenz-Falle, die im Projekt
# dreimal zugeschlagen hat. Richtungsregel: Skripte importieren `core`.
def telemetrie_puls() -> list:
"""Welche Telemetrie-Tabelle schreibt nicht mehr? → Liste von Klartext-Zeilen."""
import sqlite3
import time as _t
out = []
"""Welche Telemetrie-Tabelle schreibt nicht mehr? → Klartext-Zeilen."""
try:
db = sqlite3.connect(DB)
except Exception:
return out
jetzt = _t.time()
for tab, sp, kadenz, wozu in _PULS:
try:
n = db.execute(f"SELECT COUNT(*) FROM {tab}").fetchone()[0]
letzt = db.execute(f"SELECT MAX({sp}) FROM {tab}").fetchone()[0]
except Exception:
continue # Tabelle gibt es (noch) nicht
if not n:
out.append(f"{tab}: 0 Zeilen — der Logger hat NIE geschrieben ({wozu})")
continue
# ⚠ candles_m1.time ist ROHE Brokerzeit (UTC+3) — sonst 3 h Fehlalarm.
alter_min = (jetzt - (letzt - 10800 if tab == "candles_m1" else letzt)) / 60.0
if alter_min > kadenz * 20:
out.append(f"{tab}: letzte Zeile vor {alter_min/60:.1f} h "
f"(erwartet ~alle {kadenz} min) — {wozu}")
db.close()
return out
from core.history import HistoryLogger
return HistoryLogger(DB).telemetrie_puls()
except Exception as e:
return [f"Puls-Pruefung nicht moeglich: {e}"]
_PULS = () # Rueckwaerts-Kompatibilitaet fuer die Zaehl-Ausgabe unten
def _cfg_now() -> dict:
@@ -591,7 +567,8 @@ def main() -> None:
print("=" * 78)
puls = telemetrie_puls()
if not puls:
print(f"\n ✅ alle {len(_PULS)} Telemetrie-Tabellen schreiben")
from core.history import HistoryLogger as _HL
print(f"\n ✅ alle {len(_HL.PULS)} Telemetrie-Tabellen schreiben")
for x in puls:
print(f"\n{x}")
return