Kegel mit Adaptive Conformal Inference nachkalibriert (v=158)

Der Kegel war seit dem 31.07. dokumentiert 3-5 Pp ZU ENG - 80 % nominal gegen
real 76,7 / 76,6 / 75,3 % - und blieb es, weil Nachfitten das Problem nur
verschiebt. ACI justiert stattdessen ONLINE nach jedem aufgeloesten Fenster und
konvergiert nachweislich gegen die Zielabdeckung, auch unter Drift.

EHRLICH ZUR BAUART: die Lehrbuch-Form justiert alpha und schlaegt das Quantil
nach. Hier liegt nur eine feste Quantil-Tabelle vor, kein Verteilungsobjekt -
umgesetzt ist die multiplikative Variante:
    s <- s * exp(gamma * (1{verfehlt} - alpha_ziel)),  gamma 0,02, Deckel 0,7-2,0
Dieselbe Regelungsidee, aber die Konvergenz-GARANTIE der Originalform ist damit
nicht woertlich uebertragen.

Verifiziert: bei exakt 20 % Verfehlern bleibt die Skala bei 1,0000 - der
Fixpunkt stimmt. Simulation aus der dokumentierten Lage (76,6 %): nach ~50
Checks um 80 %. Die Skala pendelt um das Ziel statt exakt zu treffen - das ist
das bekannte ACI-Verhalten (garantiert ist die Langfrist-Abdeckung).

NICHT-UEBERLAPPEND geloggt (neue Tabelle cone_checks): ein 120-min-Fenster alle
5 min waere 24-fach ueberlappend - genau die Cluster-Verzerrung, an der
analyze_hl_funding.py aufgelaufen ist und die die Faelligkeitsbedingung
pbreak_accuracy_v2 um das Zehnfache danebenliegen liess. Je Horizont startet ein
neuer Check erst, wenn der vorige ablief -> 48/24/12 Checks je Tag.

Neustart-fest ueber runtime_state.json. build() ohne skalen liefert bitgenau die
alten Werte (additiv geprueft).

ZWEI EIGENE PLATZIERUNGSFEHLER, beide gefangen: der Lade-Block landete zuerst
HINTER den except-Klauseln von _load_runtime_state, wo st nicht mehr existiert;
und beim M15-Setup landete ein Block mitten in einem mehrzeiligen Aufruf. Der
erste waere stillschweigend nie gelaufen - gefunden nur, weil ich die Funktion
danach gelesen habe statt dem gruenen py_compile zu trauen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-08 23:45:26 +02:00
co-authored by Claude Opus 5
parent 86c432f791
commit b8705e297f
6 changed files with 244 additions and 11 deletions
+49
View File
@@ -189,6 +189,26 @@ SCHEMA = [
)
""",
"""
-- KEGEL-ABDECKUNG fuer Adaptive Conformal Inference (2026-08-08).
-- ⚠ NICHT-UEBERLAPPEND je Horizont geloggt: ein 120-min-Fenster alle 5 min
-- waere 24-fach ueberlappend, und ueberlappende Beobachtungen haben genau
-- die Cluster-Verzerrung erzeugt, an der `analyze_hl_funding.py` (06.08.)
-- und die Faelligkeitsbedingung `pbreak_accuracy_v2` (07.08.) aufgelaufen
-- sind. Je Horizont startet ein neuer Check erst, wenn der vorige ablief.
CREATE TABLE IF NOT EXISTS cone_checks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ts INTEGER, -- lokale Epoch
bars INTEGER, -- Horizont in M5-Bars (6/12/24)
band INTEGER, -- Nennband in % (80)
price REAL,
lo REAL,
hi REAL,
skala REAL, -- ACI-Skala, mit der dieses Band gebaut wurde
drin INTEGER, -- 1 = Kurs lag im Band
done INTEGER
)
""",
"""
CREATE TABLE IF NOT EXISTS verdict_votes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ts INTEGER, -- lokale Epoch
@@ -486,6 +506,35 @@ class HistoryLogger:
conn.commit()
return cur.lastrowid
def log_cone_check(self, *, bars: int, band: int, price: float,
lo: float, hi: float, skala: float) -> int:
"""Legt EINEN Abdeckungs-Check des Kegels an (nicht-ueberlappend)."""
try:
with self._lock, self._connect() as conn:
cur = conn.execute("""
INSERT INTO cone_checks (ts,bars,band,price,lo,hi,skala)
VALUES (?,?,?,?,?,?,?)
""", (int(time.time()), int(bars), int(band), float(price),
float(lo), float(hi), float(skala)))
conn.commit()
return cur.lastrowid
except Exception:
return 0
def cone_coverage(self, bars: int, last_n: int = 100) -> dict:
"""Real gemessene Abdeckung der letzten `last_n` Checks eines Horizonts."""
try:
with self._lock, self._connect() as conn:
rows = conn.execute(
"SELECT drin FROM cone_checks WHERE bars=? AND done=1 "
"ORDER BY id DESC LIMIT ?", (int(bars), int(last_n))).fetchall()
except Exception:
return {"n": 0}
n = len(rows)
if not n:
return {"n": 0}
return {"n": n, "abdeckung": round(100 * sum(r[0] for r in rows) / n, 1)}
def log_m15_state(self, *, status: str, veto, kosten, level, gap_atr,
p_break, lesart, price, atr) -> int:
"""Loggt EINEN Zustandswechsel der M15-Karte.