Pfeil "naechste Kerze" gemessen: Effekt existiert, ist aber 50-100x zu klein
User: der Pfeil an der aktuellen Kerze zeigt die Abprall-Wahrscheinlichkeit des S/R -- er soll stattdessen die Richtung der naechsten Kerze schaetzen. Die Beobachtung stimmt und ist Absicht: live steht AR;L;81.815;81.983;62% Abprall -- der L-Pfeil, seit v1.32 bewusst als BEDINGTE, kalibrierte Groesse gebaut (haelt DIESES Level, AUC 0,65 oos) statt als freie Prognose. Trotzdem neu gemessen statt abgelehnt: die bisherigen Richtungs-Messungen liefen ueber 60-360 Minuten, die naechste M5-Kerze ist ein kuerzerer Horizont mit eigener Mikrostruktur. 80k M5-Bars, 2 Halbjahre, 5 Praediktoren: EMA-Trend 49,6 % / 49,6 % Momentum 3 Bars 48,3 % / 48,3 % letzte Kerze fort 48,6 % / 48,8 % letzte Kerze UMKEHR 51,4 % / 51,2 % <- beide KI ueber 50 langer Docht 49,5 % / 49,3 % Es GIBT einen Effekt, und zwar den umgekehrten: 1-Bar-Mean-Reversion trifft beidhaelftig ueber 50 %. Trendfolge und Momentum liegen darunter. ABER die oekonomische Bedingung faellt katastrophal durch: die Oe-Bewegung in Vorhersagerichtung ist +-0,0002 $, der halbe Spread 0,0100 $ -- der Effekt ist 50-100x zu klein. Eine M5-Kerze bewegt sich im Median 0,0400 $, der Spread ist 0,0200 $ = 50 % davon. URTEIL: der Pfeil bleibt. Ein "naechste Kerze"-Pfeil waere technisch wahr und praktisch wertlos -- und muesste nach der Messung GEGEN die letzte Kerze zeigen, was jeder Mensch als Fehler lesen wuerde. EIGENER MESSFEHLER, dokumentiert weil er eine Klasse ist: der erste Lauf zaehlte unveraenderte Schlusskurse als Fehltreffer, wodurch ein Praediktor UND sein Gegenteil beide unter 50 % lagen (43,4 + 45,8 = 89,2) -- arithmetisch unmoeglich und damit der Verraeter. Real sind ~11 % der M5-Kerzen unveraendert. Merksatz: wenn A und Nicht-A sich nicht zu 100 % addieren, ist die Messung kaputt, nicht der Markt. Nichts am Live-System geaendert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
792355e8f9
commit
eec28e3382
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Ist die Richtung der NAECHSTEN Kerze vorhersagbar? (User-Frage 2026-08-17)
|
||||
|
||||
Der Pfeil an der aktuellen Kerze zeigt heute die ABPRALL-Wahrscheinlichkeit des
|
||||
naechsten S/R-Levels (`AR;L;…`) — so ist er seit v1.32 (31.07.) entworfen. Der
|
||||
User moechte stattdessen die Richtung der naechsten Kerze.
|
||||
|
||||
⚠⚠ WARUM DAS NICHT EINFACH UMGEBAUT WIRD. Die freie Richtungsfrage ist im
|
||||
Projekt mehrfach als Muenzwurf gemessen (`analyze_reversal.py`: AUC 0,499-0,509
|
||||
out-of-sample und **in-sample nur 0,52** — die Merkmale enthalten keine
|
||||
Richtungsinformation; Live-Richtung 48-51 % ueber 1.071 Episoden). Genau deshalb
|
||||
zeigt der Pfeil eine BEDINGTE Groesse (haelt DIESES Level?), die out-of-sample
|
||||
kalibriert ist (AUC 0,65).
|
||||
|
||||
⚠ ABER: gemessen wurden bisher Horizonte von 60-360 Minuten. Die **naechste
|
||||
M5-Kerze** ist ein anderer, kuerzerer Horizont — auf Ein-Bar-Ebene gibt es
|
||||
Mikrostruktur-Effekte (Mean Reversion), die dort anders wirken koennen. Das ist
|
||||
offen und wird hier gemessen, statt aus Analogie abgelehnt.
|
||||
|
||||
VORAB FIXIERTE REGEL: ein Praediktor taugt, wenn er
|
||||
(1) in BEIDEN Haelften eine Trefferquote > 50 % hat,
|
||||
(2) deren 95-%-Intervall die 50 % ausschliesst, und
|
||||
(3) die mittlere Bewegung in Vorhersagerichtung den SPREAD schlaegt.
|
||||
Punkt (3) ist die haerteste Huerde: eine M5-Kerze bewegt sich im Median ~0,10 $,
|
||||
der Spread ist ~0,0225 $ — eine Trefferquote knapp ueber 50 % zahlt ihn nicht.
|
||||
|
||||
Aufruf: python backtest_naechste_kerze.py [bars]
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import sys
|
||||
|
||||
import MetaTrader5 as mt5
|
||||
|
||||
from core.squeeze_scan import atr_series
|
||||
|
||||
|
||||
def ema(v, p):
|
||||
k = 2 / (p + 1); o = [v[0]]
|
||||
for x in v[1:]:
|
||||
o.append(o[-1] + k * (x - o[-1]))
|
||||
return o
|
||||
|
||||
|
||||
def anteil_ci(tr, n, seed=5, w=2000):
|
||||
if n < 30:
|
||||
return None, None
|
||||
r = random.Random(seed); p = tr / n
|
||||
b = sorted(sum(1 if r.random() < p else 0 for _ in range(n)) / n for _ in range(w))
|
||||
return 100 * b[int(.025 * w)], 100 * b[int(.975 * w)]
|
||||
|
||||
|
||||
def main():
|
||||
n = int(sys.argv[1]) if len(sys.argv) > 1 else 80000
|
||||
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, n)
|
||||
point = mt5.symbol_info(sym).point
|
||||
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]; O = [float(b["open"]) for b in bars]
|
||||
SP = [float(b["spread"]) * point for b in bars]
|
||||
A = atr_series(H, L, C)
|
||||
ef, es = ema(C, 12), ema(C, 50)
|
||||
|
||||
beweg = sorted(abs(C[i + 1] - C[i]) for i in range(len(C) - 1))
|
||||
med_bew = beweg[len(beweg) // 2]
|
||||
med_sp = sorted(SP)[len(SP) // 2]
|
||||
print(f"\n {sym} · {len(C)} M5-Bars")
|
||||
print(f" Median-Bewegung einer M5-Kerze: {med_bew:.4f} $ · Median-Spread "
|
||||
f"{med_sp:.4f} $ = {100*med_sp/med_bew:.0f} % davon")
|
||||
print(f" ⚠ Eine Trefferquote muss diesen Anteil SCHLAGEN, nicht nur > 50 % sein.\n")
|
||||
|
||||
# Praediktoren: jeder gibt +1 / -1 / 0 fuer die Richtung der NAECHSTEN Kerze
|
||||
def p_ema(i): # Trendfolge (das Wellen-Signal)
|
||||
d = ef[i] - es[i]
|
||||
return 0 if not A[i] or abs(d) < 0.15 * A[i] else (1 if d > 0 else -1)
|
||||
|
||||
def p_mom3(i): # Momentum-Fortsetzung
|
||||
m = C[i] - C[i - 3]
|
||||
return 0 if not A[i] or abs(m) < 0.1 * A[i] else (1 if m > 0 else -1)
|
||||
|
||||
def p_kerze(i): # letzte Kerze setzt sich fort
|
||||
b = C[i] - O[i]
|
||||
return 0 if b == 0 else (1 if b > 0 else -1)
|
||||
|
||||
def p_kerze_geg(i): # letzte Kerze kehrt um (Mean Reversion auf 1 Bar)
|
||||
return -p_kerze(i)
|
||||
|
||||
def p_docht(i): # langer Docht oben -> abwaerts (Lehrbuch)
|
||||
sp = H[i] - L[i]
|
||||
if sp <= 0 or not A[i] or sp < 0.5 * A[i]:
|
||||
return 0
|
||||
ob = H[i] - max(O[i], C[i]); un = min(O[i], C[i]) - L[i]
|
||||
if ob > 2 * un and ob > 0.3 * sp:
|
||||
return -1
|
||||
if un > 2 * ob and un > 0.3 * sp:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
praed = (("EMA-Trend (Wellen-Signal)", p_ema),
|
||||
("Momentum 3 Bars", p_mom3),
|
||||
("letzte Kerze setzt fort", p_kerze),
|
||||
("letzte Kerze kehrt um", p_kerze_geg),
|
||||
("langer Docht (Lehrbuch)", p_docht))
|
||||
|
||||
mid = len(C) // 2
|
||||
print(f" {'Praediktor':<28}{'Haelfte':>8}{'n':>8}{'Treffer':>9}"
|
||||
f"{'95-%-KI':>16}{'Ø Bew. in Richtung':>20}")
|
||||
for name, fn in praed:
|
||||
for lbl, lo, hi in (("H1", 60, mid), ("H2", mid, len(C) - 2)):
|
||||
tr = ges = unentschieden = 0; summe = 0.0
|
||||
for i in range(lo, hi):
|
||||
if not A[i]:
|
||||
continue
|
||||
d = fn(i)
|
||||
if d == 0:
|
||||
continue
|
||||
bew = (C[i + 1] - C[i]) * d
|
||||
# ⚠⚠ UNVERAENDERTE Schlusskurse AUSSCHLIESSEN. Der erste Entwurf
|
||||
# zaehlte sie als Fehltreffer — dadurch lagen ein Praediktor UND
|
||||
# sein eigenes Gegenteil beide unter 50 % (43,4 + 45,8 = 89,2),
|
||||
# was arithmetisch unmoeglich ist und den Fehler verriet.
|
||||
# Real sind ~11 % der M5-Kerzen unveraendert.
|
||||
if bew == 0:
|
||||
unentschieden += 1
|
||||
continue
|
||||
ges += 1; summe += bew
|
||||
if bew > 0:
|
||||
tr += 1
|
||||
if ges < 100:
|
||||
continue
|
||||
u, o = anteil_ci(tr, ges)
|
||||
q = 100 * tr / ges
|
||||
flag = "" if u is None or (u <= 50 <= o) else (" ✅" if u > 50 else " ❌")
|
||||
print(f" {name:<28}{lbl:>8}{ges:>8}{q:>8.1f}%"
|
||||
f" [{u:>4.1f} … {o:>4.1f}]{summe/ges:>+17.4f} $" + flag)
|
||||
print()
|
||||
|
||||
print(" ── LESEHILFE ──────────────────────────────────────────────────")
|
||||
print(f" Die Spalte ganz rechts ist die Ø-Bewegung in Vorhersagerichtung.")
|
||||
print(f" Sie muss den halben Spread ({med_sp/2:.4f} $) schlagen, damit ein")
|
||||
print(f" Trade ueberhaupt kostendeckend waere — und den ganzen ({med_sp:.4f} $)")
|
||||
print(f" fuer Ein- UND Ausstieg.")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user