Live-Backtest-Vergleich in die Pipeline: core/stichprobe.py + Abschnitt E
Konsequenz aus dem Messfehler vom 07.08.: der Vergleich lief nur, wenn jemand
daran dachte - und als er lief, war er falsch gebaut.
1) core/stichprobe.py - die Praevention ist KONSTRUKTIV, nicht ermahnend:
entkoppeln() / anteil_ci() / unterscheidbar() / schluessel_level_stunde().
Regel: vor jeder berichteten Rate entkoppeln, jede Aussage ueber einen
Unterschied mit Konfidenzintervall belegen. Die Zeilen in
pbreak_predictions und recommendations sind nicht unabhaengig.
8 Tests, darunter einer, der die reale Konstellation nachspielt
(roh 77 %, entkoppelt 33 %).
Fallstrick beim Bau, gefunden weil ich es laufen liess: ein sqlite3-Cursor
liefert Tupel, keine dicts - die Feldangabe akzeptiert jetzt Namen UND
Spaltennummern.
2) analyze_divergence.sec_d0 war selbst der Fehler. Es mittelte AVG(p_break)
ueber ALLE Rohzeilen und flaggte bei Delta > 8 Pp:
vorher 1058 rohe Zeilen, Delta +8,7 Pp -> ALARM
jetzt 110 entkoppelte, 37,6 % liegt in [37,3 ... 55,5] % -> OK
Der Waechter haette heute also einen Fehlalarm produziert - genau den, dem
ich elf Hypothesen lang nachgegangen bin.
3) NEU: Abschnitt E "GLEICHES FENSTER" (--backtest). Rechnet den Backtest ueber
genau den Live-Zeitraum und haelt ihn gegen das Intervall der entkoppelten
Live-Rate. Erster Lauf: live 46,4 % [37,3 ... 55,5] gegen Backtest 43,9 %
-> im Intervall, kein Befund.
4) Eingebaut in den Wochenreport (weekly_review._divergenz_section, montags
07:30 per Mail + Telegram), mit demselben Fail-safe wie der
Squeeze-Abschnitt. Bewusst NICHT in den pre-commit-Hook: der braucht MT5 und
Minuten, Stufe 1 muss bei ~5 s bleiben.
Ausserdem ein Rechenfehler in meinem ersten Entwurf behoben (p_break steht in
der DB bereits in Prozent, ich hatte zusaetzlich skaliert -> "3763,9 %") und
ein \n-Heredoc-Fall, der genau gegen die dokumentierte Regel verstiess.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1f58049049
commit
3f1f19087d
@@ -6,6 +6,7 @@ Aufruf: python weekly_review.py (letzte 6 Wochen + diese Woche im Detail
|
||||
Zeitspalten der DB sind LOKALE Epoch (Broker-Offset bereits korrigiert).
|
||||
"""
|
||||
import sqlite3, datetime as dt
|
||||
from pathlib import Path
|
||||
DB = "oil_widget_history.db"
|
||||
|
||||
# ── Backtest-Erwartung (R-basiert, exit-sim; s. CLAUDE.md / backtest_*.py) ──
|
||||
@@ -103,6 +104,58 @@ def _fetch_m5(days=30):
|
||||
return None
|
||||
|
||||
|
||||
def _divergenz_section() -> list:
|
||||
"""LIVE gegen BACKTEST auf DEMSELBEN Fenster — Pipeline-Einbau 2026-08-07.
|
||||
|
||||
⚠⚠ WARUM DAS HIER STEHT. Track B prüft, ob ein Edge existiert; der
|
||||
Wochenreport prüft, ob er live noch trägt. Was BEIDE nicht abdeckten: ob
|
||||
live überhaupt DASSELBE gemessen wird wie im Backtest. `analyze_divergence.py`
|
||||
gibt es dafür seit dem 31.07., aber es lief nur, wenn jemand daran dachte —
|
||||
und am 07.08. hat genau diese Lücke zugeschlagen: eine geclusterte
|
||||
6-Tage-Live-Stichprobe wurde gegen ein 208-Tage-Backtest-Mittel gehalten,
|
||||
Ergebnis eine „Lücke" von 14,1 Pp, die es nicht gab (34 % Zeitraum,
|
||||
53 % Clusterung, Rest Rauschen — elf Hypothesen umsonst geprüft).
|
||||
|
||||
Der Abschnitt beantwortet deshalb genau zwei Fragen, beide mit
|
||||
Konfidenzintervall statt Punktabstand:
|
||||
· sagt das Modell live das voraus, was eintritt? (entkoppelt!)
|
||||
· liefert der Backtest auf DEMSELBEN Zeitfenster dasselbe?
|
||||
|
||||
⚠ Fail-safe wie beim Squeeze-Abschnitt: schlägt der Aufruf fehl (kein MT5,
|
||||
keine DB), fehlt der Abschnitt — der Report darf daran nicht scheitern.
|
||||
"""
|
||||
import subprocess
|
||||
import sys
|
||||
out = ["", "=" * 92,
|
||||
"DIVERGENZ — läuft der Bot unter den Bedingungen, unter denen gemessen wurde?",
|
||||
"=" * 92]
|
||||
try:
|
||||
r = subprocess.run(
|
||||
[sys.executable, "-X", "utf8", "analyze_divergence.py", "7", "--backtest"],
|
||||
cwd=Path(__file__).resolve().parent, capture_output=True, text=True,
|
||||
timeout=900)
|
||||
txt = r.stdout or ""
|
||||
# Nur die beiden entscheidenden Abschnitte übernehmen — der Rest ist im
|
||||
# Wochenreport Rauschen und würde die Mail unlesbar machen.
|
||||
nimm = False
|
||||
for ln in txt.splitlines():
|
||||
if ln.strip().startswith(("D0)", "E)")):
|
||||
nimm = True
|
||||
elif ln.strip().startswith(("D)", "A)", "B)", "C)")):
|
||||
nimm = False
|
||||
if nimm and ln.strip() and not ln.startswith("==="):
|
||||
out.append(" " + ln.strip())
|
||||
if len(out) <= 4:
|
||||
out.append(" (keine auswertbaren Daten)")
|
||||
except Exception as e:
|
||||
out.append(f" Divergenz-Prüfung nicht möglich ({e})")
|
||||
out.append("")
|
||||
out.append(" ⚠ Gelesen wird gegen das KONFIDENZINTERVALL, nicht gegen den")
|
||||
out.append(" Punktabstand: „liegt der Backtest-Wert im Intervall der")
|
||||
out.append(" entkoppelten Live-Rate?" + '"' + " Nur ein NEIN ist ein Befund.")
|
||||
return out
|
||||
|
||||
|
||||
def build_report(db=DB, m5=None) -> str:
|
||||
"""Baut den B4-Wochenreport als reinen Text (für Konsole, Mail-<pre>, Telegram).
|
||||
m5 = vorab geholte M5-Bars für den Squeeze-Monitor (Server reicht sie unter
|
||||
@@ -166,6 +219,8 @@ def build_report(db=DB, m5=None) -> str:
|
||||
P("erst Ursache trennen (Regime vs. Disziplin vs. Sizing), nicht am Signal drehen.")
|
||||
for ln in _squeeze_section(m5):
|
||||
P(ln)
|
||||
for ln in _divergenz_section():
|
||||
P(ln)
|
||||
return "\n".join(out)
|
||||
|
||||
def main():
|
||||
|
||||
Reference in New Issue
Block a user