Auto-Squeeze-Nachtsperre von 0-7 auf 3-6 Uhr verkuerzt (User-Vorgabe)

Gemessen (backtest_cost_gate.py, Teil 2): es gibt KEINE toten Stunden - alle
24 Stunden sind in beiden Halbjahren positiv, keine ist beidhaelftig negativ.
Std 0 ist sogar die staerkste des Tages (OeR +1,48/+1,51) und lag im alten
Gate. Jedes Fenster kostet also Ertrag; die Sperre kauft ausschliesslich
Beaufsichtigungs-Ruhe.

Gewaehlt wurde deshalb nach PREIS, nicht nach Edge: 3-6 ist das guenstigste
Fenster mit noch >=4 h Schutz (SigmaR -12,5/-62,9 gegen -42,4/-242,6 bei 0-7
= ~27 %). Freigegeben: 0, 1, 2, 7 Uhr. Die 4-h-Untergrenze ist gesetzt, nicht
gemessen.

Umsetzung: neues [trading] auto_squeeze_night_hours (Default 3,4,5,6, leer =
aus), genutzt von _check_auto_squeeze und _check_auto_signal. _SQUEEZE_NIGHT
bleibt als STATISTISCHE Nacht-Definition fuer Entry-Checkliste und B4-Monitor
- dort gilt die Kostenfalle weiter und der Altdaten-Vergleich bleibt stabil.

7 Parse-Faelle getestet (Default, fehlender Schluessel, leer, Muell,
Rueckwaerts-Kompatibilitaet). Live verifiziert am NEUEN Snapshot-Feld
squeeze_night_hours = 3,4,5,6 und am Startup-Log; genau eine Instanz auf 8000.

Offen und als Reminder hinterlegt: der Backtest modelliert keine Slippage,
und die freigegebenen Stunden liegen in der duennsten Liquiditaet. Nach 15
Squeeze-Trades aus 0/1/2/7 Uhr gegen die Erwartung pruefen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-05 08:25:48 +02:00
co-authored by Claude Opus 5
parent cdee6eced7
commit 1c9bb34095
4 changed files with 197 additions and 15 deletions
+86
View File
@@ -346,6 +346,92 @@ def main():
print(" waehrend ich schlafe\") ist eine Praeferenz und wird hier NICHT beruehrt.")
print()
# ── TEIL 2: welche Nachtstunden sind WIRKLICH tot? ─────────────────────
print("=" * 100)
print(" TEIL 2 — WELCHE Nachtstunden tragen den Block? (je Stunde, sequentiell)")
print("=" * 100)
print(f" {'Std':>3} {'Kosten':>7} | {'n H1':>5} {'OeR H1':>8} {'SigmaR H1':>10}"
f" | {'n H2':>5} {'OeR H2':>8} {'SigmaR H2':>10} Urteil")
print(" " + "-" * 92)
beide_neg = []
for s in range(24):
k1 = kennzahlen(sequentiell(K, H, L, C, lambda e, s=s: e["stunde"] == s, 0, mid))
k2 = kennzahlen(sequentiell(K, H, L, C, lambda e, s=s: e["stunde"] == s, mid, N))
ks_ = [e["kosten"] for e in E if e["stunde"] == s]
kmed = sorted(ks_)[len(ks_) // 2] if ks_ else float("nan")
if not k1 or not k2:
continue
neg = k1["sr"] < 0 and k2["sr"] < 0
if neg:
beide_neg.append(s)
print(f" {s:>3} {kmed:>7.3f} | {k1['n']:>5} {k1['oer']:>+8.3f} {k1['sr']:>+10.1f}"
f" | {k2['n']:>5} {k2['oer']:>+8.3f} {k2['sr']:>+10.1f} "
f"{'beide NEGATIV' if neg else ''}")
print()
print(f" In BEIDEN Haelften negativ: {beide_neg or 'keine'}")
print(" ⚠ Diese Liste NICHT direkt als Gate verwenden — 24 Stunden = 24 Tests,")
print(" das waere in-sample-zirkulaer (dokumentierter Fehler, backtest_realcosts).")
print(" Deshalb unten nur ZUSAMMENHAENGENDE Fenster: ein Fenster hat 1 Freiheits-")
print(" grad statt 24 und laesst sich nicht auf das Rauschen zurechtlegen.")
print()
# ── Fenster-Sweep, Regel vorab fixiert ────────────────────────────────
print(" ZUSAMMENHAENGENDE NACHT-FENSTER (sequentiell, EIN Slot)")
print(" REGEL (vor dem Lauf fixiert): das Fenster muss das heutige 0-7 im SigmaR")
print(" in BEIDEN Haelften schlagen. Bei mehreren Treffern gewinnt das LAENGSTE")
print(" — der Beaufsichtigungs-Grund hat Wert, der in keiner Zahl steht.")
print(f" {'Fenster':<18}{'H1 n WR OeR PF SigmaR':>32}"
f" |{'H2 n WR OeR PF SigmaR':>32}")
print(" " + "-" * 96)
fenster = [("kein Gate", ())]
for a in range(0, 8):
for b in range(a, 8):
fenster.append((f"{a}-{b} Uhr", tuple(range(a, b + 1))))
b1, b2 = ergebnis["ohne Gate (Basis)"]
zeilen = []
for lbl, hh in fenster:
if not hh:
continue
k1 = kennzahlen(sequentiell(K, H, L, C,
lambda e, hh=hh: e["stunde"] not in hh, 0, mid))
k2 = kennzahlen(sequentiell(K, H, L, C,
lambda e, hh=hh: e["stunde"] not in hh, mid, N))
if not k1 or not k2:
continue
p1 = k1["sr"] - b1["sr"]; p2 = k2["sr"] - b2["sr"] # Preis (negativ)
nblk = sum(1 for e in E if e["stunde"] in hh)
zeilen.append({"lbl": lbl, "hh": hh, "h": len(hh), "p1": p1, "p2": p2,
"n": nblk, "je": (p1 + p2) / len(hh)})
print(" PREIS DER BEAUFSICHTIGUNG — was kostet ein Fenster gegenueber KEINEM Gate?")
print(" ⚠ Keine Stunde ist in beiden Haelften negativ. Es gibt also keine")
print(" 'toten Stunden' zu streichen — jedes Fenster KOSTET. Die Frage ist")
print(" nur, wieviel Schlaf-Schutz man wie teuer einkauft. Das ist eine")
print(" PREIS-Minimierung fuer eine Praeferenz, KEINE Edge-Behauptung —")
print(" deshalb ist die Auswahl hier auch nicht overfitting-gefaehrdet.")
print(f" {'Fenster':<12}{'Std':>4}{'geblockt':>10}{'Preis H1':>10}{'Preis H2':>10}"
f"{'SigmaR/Std':>12}")
print(" " + "-" * 60)
for z in sorted(zeilen, key=lambda z: -z["je"])[:12]:
print(f" {z['lbl']:<12}{z['h']:>4}{z['n']:>10}{z['p1']:>+10.1f}"
f"{z['p2']:>+10.1f}{z['je']:>+12.1f}")
heute = next(z for z in zeilen if z["lbl"] == "0-7 Uhr")
print(f" {'... heute:':<12}{heute['h']:>4}{heute['n']:>10}{heute['p1']:>+10.1f}"
f"{heute['p2']:>+10.1f}{heute['je']:>+12.1f} <- 0-7 Uhr")
print()
# Auswahl: guenstigstes Fenster, das noch >=4 Stunden Schlaf-Schutz gibt.
# 4 h ist gesetzt, nicht gemessen — darunter waere der Schutzzweck hinfaellig.
kand = [z for z in zeilen if z["h"] >= 4]
best = max(kand, key=lambda z: z["je"])
print(f" => EMPFEHLUNG (>=4 h Schutz, guenstigstes Fenster): **{best['lbl']}**")
print(f" Preis H1 {best['p1']:+.1f} / H2 {best['p2']:+.1f} R "
f"gegen heute {heute['p1']:+.1f} / {heute['p2']:+.1f}")
print(f" = {100*abs(best['p1'])/abs(heute['p1']):.0f} % / "
f"{100*abs(best['p2'])/abs(heute['p2']):.0f} % der heutigen Kosten,"
f" bei {best['h']} statt 8 Stunden")
print(f" freigegeben: {[s for s in range(8) if s not in best['hh']]} Uhr")
print()
if __name__ == "__main__":
main()