M15-Karte misst sich selbst + Ausfuehrungsqualitaet sichtbar (v=157)
Nach Web-Recherche umgesetzt, Punkte 2 und 3 der Wahl. SELBSTMESSUNG (neue Tabelle m15_states): die Karte hatte KEINE Rueckkopplung - geprueft, es gab kein Logging. Das war die auffaelligste Luecke: jeder Ausfall, der in diesem Projekt je aufgedeckt wurde, kam aus einer Rueckkopplung (pbreak_predictions entlarvte den Modellausfall LIVE, was kein Backtest konnte; der B4-Monitor die Squeeze-Drift). Die Karte haette monatelang falsch stehen koennen. Neu: eine Zeile je ZUSTANDSWECHSEL, nach 30/60 min gegen candles_m1 ausgewertet, Ergebnis als Zeile 6 in der Karte. Gewertet wird die LESART, nicht der Status, und nur die gerichtete (45-55 % zaehlt nicht mit). Gegen 50 % lesen. Nur bei Wechsel, nie je Tick - sonst dieselbe Cluster-Verzerrung, die am 07.08. elf widerlegte Hypothesen ausgeloest hat. Live verifiziert: 1 Zeile trotz laufendem Sekundentakt. AUSFUEHRUNGSQUALITAET (Zeile 7): analyze_squeeze_entry_gap.py existiert seit dem 05.08. und misst die TCA-Kennzahl (Arrival-Price-Slippage) - niemand hat je hineingesehen. Dabei war das der einzige Erfolgsmassstab des Stop-Order-Umbaus und zugleich der groesste je gemessene Hebel (+0,32 R). Jetzt steht der Zaehlstand in der Karte: 3 von 12 Bot-Trades seit dem Umbau. NICHT gebaut: der Kegel mit Adaptive Conformal Inference. Er ist mit 76,7/76,6/75,3 % gegen 80 % Nennwert dokumentiert zu eng, und ACI waere die Standardmethode (adjustiert online, garantiert Konvergenz auch unter Drift). Bleibt offen. BEIM BAU EIN NAMEERROR IM 1-SEKUNDEN-PFAD, VOM LINTER GEFANGEN: der erste Entwurf berechnete _m15 in _run_analysis und benutzte es in snapshot(); dort gibt es weder market noch wave_snap. py_compile sieht das NICHT, ruff F821 meldete 4 Befunde. Genau die Fehlerklasse, fuer die der Linter am 07.08. eingebaut wurde - und der erste echte Fang. Zweiter Fehler beim Verschieben: der Block landete mitten in einem mehrzeiligen Aufruf. Beide behoben. DB-Backup: oil_widget_history.db.bak-2026-08-08-m15states Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
5ddbe07066
commit
86c432f791
@@ -161,6 +161,34 @@ SCHEMA = [
|
||||
)
|
||||
""",
|
||||
"""
|
||||
-- M15-KARTE misst sich SELBST (2026-08-08).
|
||||
-- ⚠ WARUM: jeder Ausfall, der in diesem Projekt je aufgedeckt wurde, kam aus
|
||||
-- einer Rueckkopplung — `pbreak_predictions` entlarvte den Modellausfall LIVE
|
||||
-- (was kein Backtest konnte), der B4-Monitor die Squeeze-Drift. Die Karte
|
||||
-- hatte nichts davon und koennte monatelang falsch stehen, ohne dass es
|
||||
-- auffaellt. Geloggt wird EINE Zeile je STATUSWECHSEL (nicht je Tick — sonst
|
||||
-- zaehlt man dieselbe Marktlage dutzendfach; die Lehre aus rec_outcomes und
|
||||
-- der Clusterung bei pbreak_predictions).
|
||||
CREATE TABLE IF NOT EXISTS m15_states (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
ts INTEGER, -- lokale Epoch, Beginn des Zustands
|
||||
status TEXT, -- 'gruen' | 'gelb' | 'rot'
|
||||
veto TEXT, -- verbotene Richtung ('LONG'/'SHORT'/NULL)
|
||||
kosten REAL, -- Spread/ATR_M15
|
||||
level REAL, -- naechstes stehendes Level
|
||||
gap_atr REAL, -- Abstand Kurs<->Level in ATR_M15
|
||||
p_break INTEGER, -- Durchbruchwahrscheinlichkeit in %
|
||||
lesart TEXT, -- 'auf' | 'ab' | 'unklar' (die Richtungs-Lesart)
|
||||
price REAL,
|
||||
atr REAL, -- ATR_M15 zur Normierung
|
||||
ret30 REAL, -- (Kurs[+30min]-price) x Lesart-Richtung / atr
|
||||
ret60 REAL,
|
||||
hit30 INTEGER, -- 1 = Kurs lief in Richtung der Lesart
|
||||
hit60 INTEGER,
|
||||
done INTEGER
|
||||
)
|
||||
""",
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS verdict_votes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
ts INTEGER, -- lokale Epoch
|
||||
@@ -458,6 +486,63 @@ class HistoryLogger:
|
||||
conn.commit()
|
||||
return cur.lastrowid
|
||||
|
||||
def log_m15_state(self, *, status: str, veto, kosten, level, gap_atr,
|
||||
p_break, lesart, price, atr) -> int:
|
||||
"""Loggt EINEN Zustandswechsel der M15-Karte.
|
||||
|
||||
⚠ Nur bei WECHSEL aufrufen, nicht je Tick — sonst entsteht dieselbe
|
||||
Cluster-Verzerrung, die am 07.08. eine Untersuchung mit elf widerlegten
|
||||
Hypothesen ausgeloest hat (roh 922 Zeilen mit 52,6 %, entkoppelt 93 mit
|
||||
45,2 %). Ausgewertet wird separat gegen `candles_m1`.
|
||||
⚠ Fail-open wie der Rest dieser Klasse: ein Logging-Fehler darf den
|
||||
Handelspfad nie stoeren."""
|
||||
try:
|
||||
with self._lock, self._connect() as conn:
|
||||
cur = conn.execute("""
|
||||
INSERT INTO m15_states
|
||||
(ts,status,veto,kosten,level,gap_atr,p_break,lesart,price,atr)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?)
|
||||
""", (int(time.time()), status or "", veto,
|
||||
None if kosten is None else float(kosten),
|
||||
None if level is None else float(level),
|
||||
None if gap_atr is None else float(gap_atr),
|
||||
None if p_break is None else int(p_break),
|
||||
lesart, float(price or 0.0), float(atr or 0.0)))
|
||||
conn.commit()
|
||||
return cur.lastrowid
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
def m15_accuracy(self, last_n: int = 200) -> dict:
|
||||
"""Trefferquote der LESART (nicht des Status) ueber die letzten
|
||||
ausgewerteten Zustaende mit gerichteter Lesart.
|
||||
|
||||
⚠ 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."""
|
||||
try:
|
||||
with self._lock, self._connect() as conn:
|
||||
rows = conn.execute("""
|
||||
SELECT hit30, hit60, ret30 FROM m15_states
|
||||
WHERE done=1 AND lesart IN ('auf','ab')
|
||||
ORDER BY id DESC LIMIT ?
|
||||
""", (int(last_n),)).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}
|
||||
n = len(rows)
|
||||
if not n:
|
||||
return {"n": 0, "offen": offen}
|
||||
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,
|
||||
"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}
|
||||
|
||||
def rec_accuracy(self, last_n: int = 200) -> dict:
|
||||
"""Trefferquote der letzten `last_n` ausgewerteten Empfehlungs-Episoden.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user