analyze_slippage_holdtime.py: die offene Zahl gemessen — M1 ist entschieden

Der M1-Squeeze hing an der Exit-Slippage bei kurzer Haltedauer. Die bisher
zitierten "Median 0,017 / Ø 0,234" waren die Statistik NUR ueber die
Ausreisser — analyze_execution.py zaehlt ausschliesslich Faelle, die
schlechter als der Initial-SL endeten.

Sauber ist E[Slippage] >= P(gap>0) x Ø(gap|gap>0). Unkontaminiert, weil das
Trailing den gap nur negativer machen kann: ein positiver gap ist zwingend
Slippage. Ueber 317 SL-Closes, <30 min:
  alle Stunden   0,0370 $   (0-15 min allein 0,0470)
  nur 10-17 Uhr  0,0124 $   (0-15 min allein 0,0058)

Der Schwanz sitzt ausserhalb von 10-17 — bei kurzen Trades dort 8x kleiner.
Gleiche Ursache wie beim Spread (Buchtiefe), also Mechanismus statt Zufall.

Endvergleich mit dem gemessenen Wert je Fenster:
  M1 alle Stunden  -0,107/-0,161  PF 0,83/0,76   FAELLT HART DURCH
  M1 10-17         +0,354/+0,247  ΣR +150/+121
  M5 alle Stunden  +0,401/+0,261  ΣR +108/+71
  M5 10-17         +0,751/+0,444  ΣR  +68/+45

Der ΣR-Vorsprung von M1 ueber alle Stunden war reines Artefakt der Annahme
"keine Exit-Slippage". Auf demselben Fenster bleibt ein echter Zielkonflikt:
M5 doppelt so gut je Trade, M1 doppelt so gut in der Summe — bei EINEM Slot.

Urteil: nicht umstellen. Der entscheidende Parameter ist nur als Untergrenze
bekannt und M1 hat davon nur ~3x Luft bis zur Kippgrenze (M5 ~7x); die
Stichproben sind duenn; 80 Tage = ein Regime. Die Bedingung fuer ein spaeteres
Ja ist in CLAUDE.md benannt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-06 12:40:15 +02:00
co-authored by Claude Opus 5
parent 92187d7d32
commit 217981ccf5
3 changed files with 199 additions and 16 deletions
+44 -16
View File
@@ -364,22 +364,50 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
ATR-Verhältnis (0,198/0,079 = 2,5). Gemessen (`analyze_execution.py`):
**Median 0,017 $** (beide halten) · **Ø 0,234 $** (beide fallen, M1 weit
deutlicher) · Max 4,192 $.
**Was fehlt, ist genau die entscheidende Zahl:** die Slippage-Verteilung
**bedingt auf kurze Intraday-Haltedauern**. Ein M1-Trade lebt ≤24 min
(`LIVE.timestop`=24 Bars), hat also kaum Gap-Exposure — der Ø von 0,234 $ stammt
aus wenigen Ausreißern länger gehaltener Trades (4,192 nahe Marktschluss). Aber
**2 der 5 großen Fälle waren intraday** (30.07. 09:35 = 0,971 $ · 30.06. 15:36 =
0,751 $), und beide liegen im 1017-Fenster der Variante C. Überschlag: ~0,8 %
solcher Trades ergäben zusammen mit dem Median ~0,024 $ — **unter, aber nah an
der M1-Kippgrenze**. Das ist ein Überschlag, keine Messung.
**Urteil: NICHT umstellen.** Nicht weil M1 durchfällt, sondern weil (a) es je
Trade in **jeder** Variante unter M5 liegt, (b) beide um denselben EINEN
Positions-Slot konkurrieren, (c) der Vorteil ausschließlich aus der 4,3-fachen
Frequenz kommt — und genau diese Frequenz multipliziert die Slippage, deren wahre
Höhe ungemessen ist. **Der eine billige, entscheidende nächste Schritt** wäre, die
Exit-Slippage aus der echten Trade-Historie **nach Haltedauer** auszuwerten: liegt
sie für <30-min-Trades unter ~0,03 $, ist M1 ernsthaft ein Kandidat; darüber ist
es erledigt.
✅✅ **DIE FEHLENDE ZAHL IST NACHGEMESSEN (`analyze_slippage_holdtime.py`,
2026-08-06, 317 SL-Closes).** Die bisher zitierten „Median 0,017 · Ø 0,234"
waren die Statistik **nur über die Ausreißer**`analyze_execution.py` zählt
ausschließlich Fälle, die schlechter als der Initial-SL endeten (`if gap > 0`).
Sauber ist die Untergrenze **E[Slippage] ≥ P(gap>0) × Ø(gap | gap>0)**; sie ist
unkontaminiert, weil das **Trailing den gap nur negativer machen kann** (es zieht
den SL in Gewinnrichtung) — ein positiver gap ist damit zwingend Slippage.
| Haltedauer | alle Stunden | **nur 1017 Uhr** |
|---|---|---|
| 015 min | **0,0470 $** | **0,0058 $** |
| 1530 min | 0,0164 $ | 0,0238 $ |
| 60120 min | 0,0502 $ | 0,0449 $ |
| >120 min | **0,1691 $** | 0,0464 $ |
| **<30 min gewichtet** | **0,0370 $** | **0,0124 $** |
⚠⚠ **Der Schwanz sitzt AUSSERHALB von 1017** — bei kurzen Trades ist die
Slippage dort **8× kleiner** (0,0058 gegen 0,0470). Damit ist die
Stunden-Beschränkung nicht bloß eine Kosten-Optimierung: sie entfernt auch den
Slippage-Schwanz. Beides hat dieselbe Ursache (Buchtiefe), das ist ein
Mechanismus und kein Data-Mining.
**ENDVERGLEICH — jede Variante mit dem gemessenen Wert IHRES Fensters:**
| Variante | H1 ØR / ΣR | H2 ØR / ΣR | n (H1) |
|---|---|---|---|
| M1 A, alle Stunden · 0,0370 $ | **0,107 / 125 ❌** | **0,161 / 199 ❌** | 1168 |
| **M1 C, 1017 Uhr · 0,0124 $** | +0,354 / **+150** | +0,247 / **+121** | 424 |
| M5, alle Stunden · 0,0370 $ | **+0,401** / +108 | **+0,261** / +71 | 270 |
| M5, 1017 Uhr · 0,0124 $ | **+0,751** / +68 | **+0,444** / +45 | 90 |
**M1 über alle Stunden fällt jetzt HART durch** (PF 0,83/0,76) — die
Nachtstunden fressen es auf, exakt wie die Kosten-Arithmetik vorhergesagt hat.
Der ΣR-Vorsprung von Variante A war reines Artefakt der Annahme „keine
Exit-Slippage".
**Auf demselben Fenster (1017) bleibt es ein echter Zielkonflikt:** M5 liefert
je Trade **rund das Doppelte** (+0,751/+0,444 gegen +0,354/+0,247), M1 in der
Summe **rund das Doppelte** (+150/+121 gegen +68/+45) — weil es 4,7× so oft
handelt. Beide konkurrieren um denselben EINEN Positions-Slot.
**Urteil: NICHT umstellen.** Drei Gründe: (a) der entscheidende Parameter ist
nur als **Untergrenze** bekannt, und M1 C hat davon bis zur Kippgrenze nur
**~3× Luft** (0,0124 → ~0,04), M5 dagegen ~7×; (b) die Stichprobe hinter „M5 ist
je Trade doppelt so gut" ist mit n=90/101 dünn, die hinter der Slippage-Schätzung
im 1017-Fenster mit 17 Ereignissen ebenso; (c) 80 Tage = EIN Regime.
**Die Bedingung, unter der es kippen würde, ist benennbar** (für später): bleibt
die gemessene Exit-Slippage für <30-min-Trades im Fenster 1017 bei größerer
Stichprobe unter ~0,02 $, dann ist der **Hybrid** (M1 während 1017, M5 sonst)
rechnerisch ~1,9× der reinen M5-Variante (ΣR +190/+147 gegen +108/+71) und einen
kleinen Live-Test wert. Vorher nicht.
⚠ **Zwei Methodik-Lehren aus dem Lauf selbst:**
(1) **Der Härtetest lief zuerst auf der SCHWÄCHSTEN Variante.** `beste = "D" if …`
wählte nach Reihenfolge statt nach Ergebnis — D (+0,231/+0,130) statt C