Erfolgskontrolle fuer den Stop-Order-Umbau: Skript + Reminder
analyze_squeeze_entry_gap.py fuehrt die zwei noetigen Quellen zusammen - das Ausbruchs-Level steht NUR im Log, der tatsaechliche Fill NUR in trades - und splittet am Umbau-Stichtag. Die Erfolgsmeldung ist paradox: eine per Pending gefuellte Order erzeugt KEINE AUTO-SQUEEZE-ENTRY-Logzeile (die entsteht nur im Market-Fallback), Squeeze-Trades ohne Log-Treffer sind also der Erfolg. Das Skript weist sie deshalb getrennt aus. Als Messung squeeze_entry_gap im measurement_reminder.py hinterlegt (>=12 Squeeze-Trades ab dem Umbau). Stichtag exakt 05.08. 08:55 statt Mitternacht - der 08:33-Trade lief noch ueber die Market-Order und haette die Zaehlung verfaelscht (0/12 statt faelschlich 1/12). Zahlen-Korrektur: die zuerst dokumentierten +0,306 / +0,741 xATR stammten aus einer Scratchpad-Auswertung mit FESTEM Stundenversatz. DST-korrekt ueber zoneinfo sind es +0,275 / +0,686 (n=34 unveraendert). In CLAUDE.md, engine.py, trader.py und der ini nachgezogen; die Schlussfolgerung aendert sich nicht. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
5e0e8b00ca
commit
5f70980e59
@@ -1466,8 +1466,8 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
|
|||||||
**`backtest_breakout_squeeze.py` steigt AM LEVEL ein** (`sim(lvl, …)`). Live schickt
|
**`backtest_breakout_squeeze.py` steigt AM LEVEL ein** (`sim(lvl, …)`). Live schickt
|
||||||
`_check_auto_squeeze` eine **MARKET**-Order, sobald `state=='active'` — der Kurs ist
|
`_check_auto_squeeze` eine **MARKET**-Order, sobald `state=='active'` — der Kurs ist
|
||||||
dann schon ein Stück weiter. **Aus 34 echten Live-Entries (Logs 16.07.–05.08.,
|
dann schon ein Stück weiter. **Aus 34 echten Live-Entries (Logs 16.07.–05.08.,
|
||||||
Level aus der Log-Zeile × Einstiegspreis aus der DB): Median +0,306×ATR über dem
|
Level aus der Log-Zeile × Einstiegspreis aus der DB): Median +0,275×ATR über dem
|
||||||
Level**, Mittel +0,741 · 75 % +0,863 · Max +4,339; nur **18 %** liegen innerhalb
|
Level**, Mittel +0,686 · 75 % +0,744 · Max +4,339; nur **18 %** liegen innerhalb
|
||||||
0,10×ATR, **53 % über 0,30×ATR**.
|
0,10×ATR, **53 % über 0,30×ATR**.
|
||||||
**Was dieser Preisunterschied kostet** (80k M5, 2 Halbjahre, sequentiell EIN Slot,
|
**Was dieser Preisunterschied kostet** (80k M5, 2 Halbjahre, sequentiell EIN Slot,
|
||||||
kanonischer Exit, Echtkosten):
|
kanonischer Exit, Echtkosten):
|
||||||
@@ -1477,7 +1477,7 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
|
|||||||
| **B Einstieg am Bar-Close** (≈ live) | **−0,158 / −125,9** | **−0,006 / −7,6** | 37/42 % |
|
| **B Einstieg am Bar-Close** (≈ live) | **−0,158 / −125,9** | **−0,006 / −7,6** | 37/42 % |
|
||||||
**Allein der Einstiegspreis dreht das Setup — −0,61 ØR in BEIDEN Hälften, WR bricht
|
**Allein der Einstiegspreis dreht das Setup — −0,61 ØR in BEIDEN Hälften, WR bricht
|
||||||
von 56 auf 37 %.** Modell B ist dabei **nicht pessimistisch**: sein Median-Abstand
|
von 56 auf 37 %.** Modell B ist dabei **nicht pessimistisch**: sein Median-Abstand
|
||||||
(0,38×ATR) liegt nah am LIVE gemessenen (0,31×ATR); der Live-Betrieb liegt also
|
(0,38×ATR) liegt nah am LIVE gemessenen (0,28×ATR); der Live-Betrieb liegt also
|
||||||
~80 % des Weges von A nach B, also grob bei **breakeven bis leicht negativ** —
|
~80 % des Weges von A nach B, also grob bei **breakeven bis leicht negativ** —
|
||||||
nicht bei den dokumentierten +0,14…+0,23.
|
nicht bei den dokumentierten +0,14…+0,23.
|
||||||
⚠⚠ **Das ordnet den B4-Befund vom 01.08. NEU ein.** Dort stand: „Mechanik +0,102 vs.
|
⚠⚠ **Das ordnet den B4-Befund vom 01.08. NEU ein.** Dort stand: „Mechanik +0,102 vs.
|
||||||
@@ -1520,7 +1520,7 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
|
|||||||
**Selbst mit 0,20×ATR unterstellter Fill-Slippage — dem ~9-fachen des Median-Spreads
|
**Selbst mit 0,20×ATR unterstellter Fill-Slippage — dem ~9-fachen des Median-Spreads
|
||||||
— bleibt es in BEIDEN Hälften klar positiv.**
|
— bleibt es in BEIDEN Hälften klar positiv.**
|
||||||
⚠⚠ **Der Schlüssel ist nicht der Median, sondern der SCHWANZ.** Live ist der
|
⚠⚠ **Der Schlüssel ist nicht der Median, sondern der SCHWANZ.** Live ist der
|
||||||
Median-Abstand +0,306×ATR, der **Mittelwert aber +0,741** (Max +4,339). Eine
|
Median-Abstand +0,275×ATR, der **Mittelwert aber +0,686** (Max +4,339). Eine
|
||||||
Stop-Order **deckelt den Einstiegspreis konstruktiv**; die Market-Order auf dem
|
Stop-Order **deckelt den Einstiegspreis konstruktiv**; die Market-Order auf dem
|
||||||
5-s-Poll tut das nicht. Die Extremfälle (+3,5 / +4,3×ATR) stammen erkennbar aus
|
5-s-Poll tut das nicht. Die Extremfälle (+3,5 / +4,3×ATR) stammen erkennbar aus
|
||||||
**blockiert-dann-freigegebenen** Ausbrüchen: feuert der Squeeze, während eine
|
**blockiert-dann-freigegebenen** Ausbrüchen: feuert der Squeeze, während eine
|
||||||
@@ -1560,9 +1560,23 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
|
|||||||
Live verifiziert am Snapshot: `squeeze_pending=true`, `squeeze_max_chase_atr=0.2`,
|
Live verifiziert am Snapshot: `squeeze_pending=true`, `squeeze_max_chase_atr=0.2`,
|
||||||
`squeeze_pending_levels` (leer, weil eine Position offen war = korrektes Verhalten).
|
`squeeze_pending_levels` (leer, weil eine Position offen war = korrektes Verhalten).
|
||||||
**Zurück zum alten Verhalten: `squeeze_pending_entry=false`.**
|
**Zurück zum alten Verhalten: `squeeze_pending_entry=false`.**
|
||||||
⚠ **B4-Pflicht:** der Live-Abstand Einstieg↔Level muss jetzt gegen ~0 gehen
|
⚠ **B4-Pflicht + Werkzeug:** der Live-Abstand Einstieg↔Level muss jetzt gegen ~0
|
||||||
(vorher Median +0,306×ATR). Das ist die Erfolgskontrolle — nachrechnen wie in
|
gehen (vorher Median +0,275×ATR). Dafür gibt es jetzt
|
||||||
diesem Abschnitt (Log-Zeile „Ausbruch <level>" × `trades.entry_price`).
|
**`analyze_squeeze_entry_gap.py`** (führt die zwei nötigen Quellen zusammen: das
|
||||||
|
Level steht NUR im Log, der Fill NUR in `trades`) — mit Vorher/Nachher-Split am
|
||||||
|
Umbau-Stichtag. ⚠ **Die Erfolgsmeldung ist paradox:** eine per Pending gefüllte
|
||||||
|
Order erzeugt **keine** `AUTO-SQUEEZE-ENTRY`-Logzeile (die entsteht nur im
|
||||||
|
Market-Fallback). Squeeze-Trades **ohne** Log-Treffer sind also der Erfolg, nicht
|
||||||
|
ein Fehler — das Skript weist sie deshalb getrennt aus. Überwacht als Messung
|
||||||
|
`squeeze_entry_gap` im `measurement_reminder.py` (≥12 Squeeze-Trades ab dem
|
||||||
|
Umbau; Stichtag exakt 05.08. 08:55, nicht Mitternacht — der 08:33-Trade lief noch
|
||||||
|
über Market). Bleibt der Abstand bei ~0,3×ATR, füllt die Pending nicht → Broker-
|
||||||
|
Mindestabstand und die Logzeile „Squeeze-Pending nicht platzierbar" prüfen.
|
||||||
|
⚠ **Zahlen-Korrektur (05.08.):** zuerst standen hier Median +0,306 / Ø +0,741 —
|
||||||
|
das war eine Scratchpad-Auswertung mit FESTEM Stundenversatz. `analyze_squeeze_
|
||||||
|
entry_gap.py` rechnet DST-korrekt über `zoneinfo` und liefert **+0,275 / +0,686**
|
||||||
|
(n=34 unverändert). Gültig sind die zweiten Werte; die Schlussfolgerung ändert
|
||||||
|
sich nicht.
|
||||||
- **Auto-Squeeze-Entry = LIVE AUTONOM (User-Vorgabe 2026-07-16, `[trading]
|
- **Auto-Squeeze-Entry = LIVE AUTONOM (User-Vorgabe 2026-07-16, `[trading]
|
||||||
auto_squeeze=true`, Default FALSE):** der Bot eröffnet **selbständig eine echte
|
auto_squeeze=true`, Default FALSE):** der Bot eröffnet **selbständig eine echte
|
||||||
Order**, sobald der **gemessen-validierte** Squeeze-Ausbruch feuert (`wave.squeeze.
|
Order**, sobald der **gemessen-validierte** Squeeze-Ausbruch feuert (`wave.squeeze.
|
||||||
@@ -3019,7 +3033,7 @@ Bedingungen BETRIEBEN als VALIDIERT. An EINEM Tag wurden drei Fälle gefunden:
|
|||||||
| 2 | `breakout_k=0,3` | **feste** Zeitebene | TF wechselt 33×/Tag, löscht den Anker | 43 % → **93 % WARTEN** |
|
| 2 | `breakout_k=0,3` | **feste** Zeitebene | TF wechselt 33×/Tag, löscht den Anker | 43 % → **93 % WARTEN** |
|
||||||
| 3 | Trailing `mult` | **1,5** | **1,5–3,0** je nach TF | H1 ΣR −249 → **−1367**, Worst −1,50 → −2,50 |
|
| 3 | Trailing `mult` | **1,5** | **1,5–3,0** je nach TF | H1 ΣR −249 → **−1367**, Worst −1,50 → −2,50 |
|
||||||
| 4 | `_broker_offset_s()` | **frischem** Tick | Tick beliebig alt (Wochenende) | Offset **−9,5 h statt +3 h** → `open_time` 12,5 h in der Zukunft, **Time-Stop-Alter negativ** |
|
| 4 | `_broker_offset_s()` | **frischem** Tick | Tick beliebig alt (Wochenende) | Offset **−9,5 h statt +3 h** → `open_time` 12,5 h in der Zukunft, **Time-Stop-Alter negativ** |
|
||||||
| 7 | Auto-Squeeze-**Einstiegspreis** | Fill **AM Ausbruchs-Level** (`backtest_breakout_squeeze.py`) | **MARKET**-Order, live median **+0,306×ATR** über dem Level (34 echte Entries) | ØR **+0,456 → −0,158** (H1) bzw. **+0,611 → −0,006** (H2); WR 56 → 37 % |
|
| 7 | Auto-Squeeze-**Einstiegspreis** | Fill **AM Ausbruchs-Level** (`backtest_breakout_squeeze.py`) | **MARKET**-Order, live median **+0,275×ATR** über dem Level (34 echte Entries) | ØR **+0,456 → −0,158** (H1) bzw. **+0,611 → −0,006** (H2); WR 56 → 37 % |
|
||||||
| 6 | `auto_squeeze_skip_night` | Nacht-Kostenfalle am **Wellensignal** (alle Nacht-Bars: 0,333×ATR) | **Squeeze**-Ausbrüche, die nur bei anziehendem ATR feuern (0,183×ATR = Tag-Niveau) | Gate kostet ΣR **−42 (H1) / −243 (H2)**; geblockte Ausbrüche sind in beiden Hälften positiv |
|
| 6 | `auto_squeeze_skip_night` | Nacht-Kostenfalle am **Wellensignal** (alle Nacht-Bars: 0,333×ATR) | **Squeeze**-Ausbrüche, die nur bei anziehendem ATR feuern (0,183×ATR = Tag-Niveau) | Gate kostet ΣR **−42 (H1) / −243 (H2)**; geblockte Ausbrüche sind in beiden Hälften positiv |
|
||||||
| 5 | `backtest_auto_signal.py` | **ohne Winkel** (`_build` ohne `angle=` → Default 90 → `ad=0`) | Winkel steuert einen **Signalzweig** (Reversal) UND **±15 Konfidenzpunkte** | Urteil vom 30.07. beschrieb weder das alte noch das neue System; der Winkelterm allein hebt H1 bei conf 75 von **−0,123 auf −0,047** |
|
| 5 | `backtest_auto_signal.py` | **ohne Winkel** (`_build` ohne `angle=` → Default 90 → `ad=0`) | Winkel steuert einen **Signalzweig** (Reversal) UND **±15 Konfidenzpunkte** | Urteil vom 30.07. beschrieb weder das alte noch das neue System; der Winkelterm allein hebt H1 bei conf 75 von **−0,123 auf −0,047** |
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Wie weit über dem Ausbruchs-Level steigt der Auto-Squeeze LIVE wirklich ein?
|
||||||
|
|
||||||
|
WOZU — das ist die Erfolgskontrolle für den Umbau vom 2026-08-05 (Market-Order →
|
||||||
|
ruhende Stop-Order, `squeeze_pending_entry`). Der gemessene Zusammenhang
|
||||||
|
(`backtest_squeeze_entry.py`): der Squeeze hat seinen gesamten Edge im
|
||||||
|
EINSTIEGSPREIS — am Level ØR **+0,456/+0,611**, hinterhergelaufen **−0,158/−0,006**.
|
||||||
|
Vor dem Umbau lag der Live-Abstand im **Median +0,306×ATR** (Mittel +0,741, Max
|
||||||
|
+4,339). **Er muss jetzt gegen 0 gehen.** Tut er das nicht, greift die Pending-Order
|
||||||
|
nicht wie gedacht — dann ist der Umbau wirkungslos, ohne dass es sonst auffiele.
|
||||||
|
|
||||||
|
QUELLE (bewusst zwei unabhängige): das Ausbruchs-Level steht NUR im Log
|
||||||
|
(„AUTO-SQUEEZE-ENTRY: <dir> @ Ausbruch <level>"), der tatsächliche Fill NUR in der
|
||||||
|
`trades`-Tabelle. Zusammengeführt über die Zeit (±90 s).
|
||||||
|
⚠ Seit dem Umbau füllt eine Pending-Order OHNE diese Log-Zeile (sie entsteht im
|
||||||
|
Market-Fallback-Pfad). Deshalb werden Squeeze-Trades ohne Log-Treffer separat
|
||||||
|
ausgewiesen — **genau die sind der Erfolg**, nicht ein Fehler.
|
||||||
|
|
||||||
|
Aufruf: python analyze_squeeze_entry_gap.py [tage]
|
||||||
|
"""
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sqlite3
|
||||||
|
import sys
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
|
import MetaTrader5 as mt5
|
||||||
|
|
||||||
|
_HIER = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
_BERLIN = ZoneInfo("Europe/Berlin")
|
||||||
|
_BROKER = timezone(timedelta(hours=3))
|
||||||
|
_UTC = timezone.utc
|
||||||
|
_UMBAU = datetime(2026, 8, 5, 8, 55, tzinfo=_BERLIN) # Pending-Entry ging live
|
||||||
|
_RX = re.compile(r"^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d).*AUTO-SQUEEZE-ENTRY: (\w+) "
|
||||||
|
r"@ Ausbruch ([\d.]+)")
|
||||||
|
|
||||||
|
|
||||||
|
def _berlin(ts):
|
||||||
|
"""MT5-Bar-Zeitstempel → echte Berliner Zeit (s. CLAUDE.md, Fix 2026-08-05)."""
|
||||||
|
return (datetime.fromtimestamp(int(ts), _UTC)
|
||||||
|
.replace(tzinfo=_BROKER).astimezone(_BERLIN))
|
||||||
|
|
||||||
|
|
||||||
|
def _stat(v, lbl):
|
||||||
|
if not v:
|
||||||
|
print(f" {lbl:<22} —")
|
||||||
|
return
|
||||||
|
s = sorted(v)
|
||||||
|
print(f" {lbl:<22} n={len(s):<4} Median {s[len(s)//2]:+.3f} · "
|
||||||
|
f"Ø {sum(s)/len(s):+.3f} · 75 % {s[3*len(s)//4]:+.3f} · Max {s[-1]:+.3f}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
tage = int(sys.argv[1]) if len(sys.argv) > 1 else 60
|
||||||
|
seit = datetime.now(_BERLIN) - timedelta(days=tage)
|
||||||
|
|
||||||
|
# ── 1) Log: Ausbruchs-Level je Market-Entry ──────────────────────────
|
||||||
|
log_eintraege = []
|
||||||
|
for f in sorted(glob.glob(os.path.join(_HIER, "oil_widget.log*"))):
|
||||||
|
try:
|
||||||
|
with open(f, encoding="utf-8", errors="replace") as fh:
|
||||||
|
for z in fh:
|
||||||
|
m = _RX.match(z)
|
||||||
|
if m:
|
||||||
|
ts = datetime.strptime(m.group(1), "%Y-%m-%d %H:%M:%S") \
|
||||||
|
.replace(tzinfo=_BERLIN)
|
||||||
|
if ts >= seit:
|
||||||
|
log_eintraege.append((ts, m.group(2), float(m.group(3))))
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
log_eintraege.sort()
|
||||||
|
|
||||||
|
# ── 2) ATR-Reihe für die Normierung ──────────────────────────────────
|
||||||
|
mt5.initialize()
|
||||||
|
sym = next((c for c in ("SpotCrude", "USOIL", "WTI", "XTIUSD")
|
||||||
|
if mt5.symbol_info(c)), None)
|
||||||
|
bars = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M5, 0, 30000)
|
||||||
|
mt5.shutdown()
|
||||||
|
H = [float(b["high"]) for b in bars]; L = [float(b["low"]) for b in bars]
|
||||||
|
C = [float(b["close"]) for b in bars]
|
||||||
|
# Bar-Zeit → lokale Epoch, DST-korrekt (kein fester Versatz!)
|
||||||
|
EP = [_berlin(b["time"]).timestamp() for b in bars]
|
||||||
|
tr = [0.0] + [max(H[i] - L[i], abs(H[i] - C[i - 1]), abs(L[i] - C[i - 1]))
|
||||||
|
for i in range(1, len(C))]
|
||||||
|
|
||||||
|
def atr_bei(ep):
|
||||||
|
j = min(range(len(EP)), key=lambda i: abs(EP[i] - ep))
|
||||||
|
seg = tr[max(1, j - 13):j + 1]
|
||||||
|
return (sum(seg) / len(seg)) if seg else 0.0
|
||||||
|
|
||||||
|
# ── 3) Trades dazu ───────────────────────────────────────────────────
|
||||||
|
db = sqlite3.connect(os.path.join(_HIER, "oil_widget_history.db"))
|
||||||
|
db.row_factory = sqlite3.Row
|
||||||
|
trades = db.execute(
|
||||||
|
"SELECT ticket, entry_time, entry_price, direction, pnl, closed_by "
|
||||||
|
"FROM trades WHERE entry_time >= ? ORDER BY entry_time",
|
||||||
|
(seit.timestamp(),)).fetchall()
|
||||||
|
|
||||||
|
vorher, nachher, ohne_log = [], [], []
|
||||||
|
getroffen = set()
|
||||||
|
for ts, richtung, lvl in log_eintraege:
|
||||||
|
ep = ts.timestamp()
|
||||||
|
kand = [t for t in trades if abs(t["entry_time"] - ep) <= 90
|
||||||
|
and t["entry_price"]]
|
||||||
|
if not kand:
|
||||||
|
continue
|
||||||
|
t = min(kand, key=lambda r: abs(r["entry_time"] - ep))
|
||||||
|
getroffen.add(t["ticket"])
|
||||||
|
a = atr_bei(ep)
|
||||||
|
if a <= 0:
|
||||||
|
continue
|
||||||
|
d = 1 if richtung == "LONG" else -1
|
||||||
|
weg = (float(t["entry_price"]) - lvl) * d / a
|
||||||
|
(nachher if ts >= _UMBAU else vorher).append(weg)
|
||||||
|
|
||||||
|
print("=" * 82)
|
||||||
|
print(f" AUTO-SQUEEZE — Abstand Einstieg ↔ Ausbruchs-Level (×ATR), {tage} Tage")
|
||||||
|
print(f" Umbau auf ruhende Stop-Orders: {_UMBAU:%d.%m.%Y %H:%M}")
|
||||||
|
print("=" * 82)
|
||||||
|
print(" Market-Entries (haben eine Log-Zeile mit dem Level):")
|
||||||
|
_stat(vorher, "VOR dem Umbau")
|
||||||
|
_stat(nachher, "NACH dem Umbau")
|
||||||
|
print()
|
||||||
|
print(" Erwartung: NACH dem Umbau sollten hier kaum noch Entries auftauchen —")
|
||||||
|
print(" die Market-Order ist nur noch Fallback, und die Nachjagd-Bremse")
|
||||||
|
print(" (squeeze_max_chase_atr) deckelt sie bei 0,20×ATR.")
|
||||||
|
print()
|
||||||
|
print(" ⚠ Die eigentliche Erfolgsmeldung: Squeeze-Trades OHNE Log-Zeile —")
|
||||||
|
print(" das sind die per Pending-Order gefüllten.")
|
||||||
|
n_sq = 0
|
||||||
|
for t in trades:
|
||||||
|
if t["entry_time"] < _UMBAU.timestamp():
|
||||||
|
continue
|
||||||
|
n_sq += 1
|
||||||
|
if t["ticket"] not in getroffen:
|
||||||
|
ohne_log.append(t)
|
||||||
|
print(f" Trades seit dem Umbau: {n_sq} · davon ohne Market-Log-Zeile: "
|
||||||
|
f"{len(ohne_log)}")
|
||||||
|
for t in ohne_log[-10:]:
|
||||||
|
print(f" {datetime.fromtimestamp(t['entry_time'], _BERLIN):%d.%m %H:%M} "
|
||||||
|
f"{t['direction']:<5} @ {t['entry_price']:.3f} "
|
||||||
|
f"P&L {(t['pnl'] if t['pnl'] is not None else 0):+.2f} {t['closed_by']}")
|
||||||
|
print()
|
||||||
|
print(" MASSSTAB (backtest_squeeze_entry.py): am Level ØR +0,456/+0,611 ·")
|
||||||
|
print(" bei 0,20×ATR noch +0,244/+0,426 · hinterhergelaufen −0,158/−0,006.")
|
||||||
|
print(" Vor dem Umbau war der Live-Median +0,306×ATR.")
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
+1
-1
@@ -1104,7 +1104,7 @@ class TradingEngine:
|
|||||||
|
|
||||||
WARUM (gemessen `backtest_squeeze_entry.py`, 2026-08-05): der Squeeze hat
|
WARUM (gemessen `backtest_squeeze_entry.py`, 2026-08-05): der Squeeze hat
|
||||||
seinen gesamten Edge im EINSTIEGSPREIS. Die Market-Order auf dem 5-s-Poll
|
seinen gesamten Edge im EINSTIEGSPREIS. Die Market-Order auf dem 5-s-Poll
|
||||||
füllt live im Median 0,306×ATR hinter dem Level (Mittel 0,741, Max 4,3) →
|
füllt live im Median 0,275×ATR hinter dem Level (Mittel 0,686, Max 4,3) →
|
||||||
ØR kippt von +0,456 auf −0,158. Eine ruhende Stop-Order deckelt den Preis
|
ØR kippt von +0,456 auf −0,158. Eine ruhende Stop-Order deckelt den Preis
|
||||||
konstruktiv: selbst mit 0,20×ATR Fill-Slippage bleibt ØR +0,244/+0,426.
|
konstruktiv: selbst mit 0,20×ATR Fill-Slippage bleibt ØR +0,244/+0,426.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -199,7 +199,7 @@ class TradeManager:
|
|||||||
# ══════════════════════════════════════════════════════════════════════
|
# ══════════════════════════════════════════════════════════════════════
|
||||||
# WARUM: `backtest_squeeze_entry.py` hat gemessen, dass der Squeeze seinen
|
# WARUM: `backtest_squeeze_entry.py` hat gemessen, dass der Squeeze seinen
|
||||||
# gesamten Edge im EINSTIEGSPREIS hat. Die Market-Order auf dem 5-s-Poll füllt
|
# gesamten Edge im EINSTIEGSPREIS hat. Die Market-Order auf dem 5-s-Poll füllt
|
||||||
# live im Median 0,306×ATR hinter dem Level (Mittel 0,741, Max 4,3) — damit
|
# live im Median 0,275×ATR hinter dem Level (Mittel 0,686, Max 4,3) — damit
|
||||||
# dreht ØR von +0,456 auf −0,158. Eine ruhende Stop-Order deckelt den Preis
|
# dreht ØR von +0,456 auf −0,158. Eine ruhende Stop-Order deckelt den Preis
|
||||||
# konstruktiv: selbst mit 0,20×ATR unterstellter Fill-Slippage bleibt ØR
|
# konstruktiv: selbst mit 0,20×ATR unterstellter Fill-Slippage bleibt ØR
|
||||||
# +0,244/+0,426 in beiden Halbjahren.
|
# +0,244/+0,426 in beiden Halbjahren.
|
||||||
|
|||||||
@@ -145,6 +145,30 @@ CHECKS = [
|
|||||||
"→ `auto_squeeze=false` (B5-Rückbau, kein Ego). Sonst weiterlaufen "
|
"→ `auto_squeeze=false` (B5-Rückbau, kein Ego). Sonst weiterlaufen "
|
||||||
"lassen. Zahlen: /api/squeeze_monitor bzw. Statistik-Tab.",
|
"lassen. Zahlen: /api/squeeze_monitor bzw. Statistik-Tab.",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "squeeze_entry_gap",
|
||||||
|
"title": "Stop-Order-Umbau: kommt der Einstieg jetzt AM Level an?",
|
||||||
|
"why": "Am 05.08. wurde der Auto-Squeeze von der Market-Order auf ruhende "
|
||||||
|
"Stop-Orders am Ausbruchs-Level umgestellt. Grund: der Squeeze hat "
|
||||||
|
"seinen GESAMTEN Edge im Einstiegspreis — am Level ØR +0,456/+0,611, "
|
||||||
|
"hinterhergelaufen −0,158/−0,006 (`backtest_squeeze_entry.py`). Live "
|
||||||
|
"lag der Abstand vorher im Median +0,275×ATR (Mittel +0,686, Max "
|
||||||
|
"+4,339). Greift die Pending-Order nicht wie gedacht, ist der ganze "
|
||||||
|
"Umbau wirkungslos — und das fiele sonst NICHT auf, weil der Bot "
|
||||||
|
"weiterhin Trades macht.",
|
||||||
|
# ⚠ Stichtag exakt auf den Umbau (05.08. 08:55 Berlin = 06:55 UTC), NICHT auf
|
||||||
|
# Mitternacht: der Squeeze-Trade von 08:33 lief noch über die Market-Order und
|
||||||
|
# würde die Zählung verfälschen. `strftime('%s', …)` liest UTC, `entry_time`
|
||||||
|
# ist lokale Epoch — deshalb 07:00 UTC als sicherer Schnitt.
|
||||||
|
"have": lambda: _q("SELECT COUNT(*) FROM trades WHERE setup LIKE 'SQUEEZE%' "
|
||||||
|
"AND entry_time >= strftime('%s','2026-08-05 07:00:00')"),
|
||||||
|
"need": 12, "unit": "Squeeze-Trades seit dem Umbau (05.08. 08:55)",
|
||||||
|
"cmd": "python analyze_squeeze_entry_gap.py 60 → Der Median-Abstand muss "
|
||||||
|
"gegen 0 gehen und die Market-Log-Zeilen ('AUTO-SQUEEZE-ENTRY') "
|
||||||
|
"sollten weitgehend verschwinden. Bleibt der Abstand bei ~0,3×ATR, "
|
||||||
|
"füllt die Pending-Order nicht — dann Broker-Mindestabstand und die "
|
||||||
|
"Log-Zeile 'Squeeze-Pending nicht platzierbar' prüfen.",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "night_window_0127",
|
"key": "night_window_0127",
|
||||||
"title": "Nacht-Fenster 3–6: tragen die freigegebenen Stunden 0/1/2/7?",
|
"title": "Nacht-Fenster 3–6: tragen die freigegebenen Stunden 0/1/2/7?",
|
||||||
|
|||||||
Reference in New Issue
Block a user