M15-Karte: Selbstmessung entkoppelt - 60 % waren 53 %

User fragte nach einer zweiten Karte auf M5. Die Antwort haengt daran,
ob die bestehende traegt - und sie misst sich seit 08.08. selbst.

Befund: die Karte zeigte 60 % Trefferquote. Zwei Gruende, warum das
nichts belegt. (1) Geclustert: m15_accuracy nahm die letzten 200
Zeilen ohne Entkopplung, bei ~990 Zustandswechseln/Tag sind das fuenf
Stunden derselben Marktlage. Aus 2.302 rohen bleiben 114 unabhaengige.
(2) Regime: das Fenster lief +4,93 $, und roh liest die Karte "auf" zu
62 % richtig und "ab" zu 46 % - das ist der Trend.

Entkoppelt: 53-54 %, KI [46 ... 63] - enthaelt die 50. Der
handlungsrelevante Zustand (gruen + gerichtet) liegt bei 45,5 %.

Behoben: m15_accuracy entkoppelt (Schluessel Level+Stunde) und meldet
beide Zahlen. Anzeige jetzt 53 % statt 60 %.

Antwort auf die M5-Frage: nein, jetzt nicht - die erste Karte hat kein
Urteil, M5 waere teurer (0,193 gegen 0,104), die M5-Information ist
grossenteils schon da (Gate 3b rechnet bereits auf M5), und eine
zweite Karte verdoppelt die Drift-Flaeche.

Offen benannt: die Karte flackert (~990 Wechsel/Tag).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-12 09:31:42 +02:00
co-authored by Claude Opus 5
parent b2a1e35f5e
commit e882d795a6
4 changed files with 88 additions and 9 deletions
+31 -6
View File
@@ -636,26 +636,51 @@ class HistoryLogger:
⚠ Gegen 50 % zu lesen, nicht gegen 0. Und ⚠ die Karte behauptet KEINE
freie Richtung — gemessen wird nur, ob die BEDINGTE Lesart am Level
(„Abprall -> eher abwaerts") getroffen hat."""
(„Abprall -> eher abwaerts") getroffen hat.
⚠⚠ ENTKOPPELT seit 2026-08-12. Vorher nahm die Abfrage schlicht die
letzten N Zeilen (`ORDER BY id DESC LIMIT ?`). Die sind NICHT unabhaengig:
der Zustand wechselt ~990x/Tag, 200 Zeilen sind also rund fuenf Stunden
DERSELBEN Marktlage, vielfach gezaehlt. Die Karte zeigte dadurch **60 %**,
entkoppelt sind es **54,4 %** mit dem Intervall [46 … 63] — also nicht von
der Muenze zu unterscheiden.
⚠ Dieselbe Cluster-Falle hat im Projekt schon die Faelligkeitsbedingung
`pbreak_accuracy_v2` um das ZEHNFACHE danebenliegen lassen (07.08.) und
elf Hypothesen ausgeloest (07.08.). Sie ist hier dieselbe.
⚠ Schluessel = (Level auf 2 Stellen, Stunde) — identisch zu
`core.stichprobe.schluessel_level_stunde`, damit beide Auswertungen
dieselbe Definition benutzen.
"""
try:
with self._lock, self._connect() as conn:
rows = conn.execute("""
SELECT hit30, hit60, ret30 FROM m15_states
# ⚠ Grosszuegig lesen und DANACH entkoppeln — sonst waeren nach der
# Entkopplung nur noch eine Handvoll Faelle uebrig.
raw = conn.execute("""
SELECT hit30, hit60, ret30, level, ts FROM m15_states
WHERE done=1 AND lesart IN ('auf','ab')
ORDER BY id DESC LIMIT ?
""", (int(last_n),)).fetchall()
""", (int(last_n) * 40,)).fetchall()
offen = conn.execute(
"SELECT COUNT(*) FROM m15_states WHERE done IS NULL "
"AND lesart IN ('auf','ab')").fetchone()[0]
except Exception:
return {"n": 0}
seen, rows = set(), []
for r in raw:
k = (round(r[3] or 0.0, 2), int((r[4] or 0) // 3600))
if k in seen:
continue
seen.add(k)
rows.append(r)
if len(rows) >= int(last_n):
break
n = len(rows)
if not n:
return {"n": 0, "offen": offen}
return {"n": 0, "offen": offen, "roh": len(raw)}
h30 = [r[0] for r in rows if r[0] is not None]
h60 = [r[1] for r in rows if r[1] is not None]
r30 = [r[2] for r in rows if r[2] is not None]
return {"n": n, "offen": offen,
return {"n": n, "offen": offen, "roh": len(raw),
"wr30": round(100 * sum(h30) / len(h30)) if h30 else None,
"wr60": round(100 * sum(h60) / len(h60)) if h60 else None,
"avg30": round(sum(r30) / len(r30), 3) if r30 else None}