Elliott entmachtet (v=144)
Vier Verbesserungen, alle aus dem Gemessenen abgeleitet — kein neues Signal.
Ausgangspunkt: die Karte hat genau eine belegte Funktion, das Veto; als Prognose
ist sie ein Muenzwurf (48-51 % ueber 1.071 Episoden).
(1) SELBST-KALIBRIERUNG. Neue Tabelle rec_outcomes: eine Zeile je EPISODE
(Richtungswechsel, nicht je Minute), Auswertung ~alle 5 min gegen candles_m1
nach 30/60 min, Snapshot rec_track, Zeile #vd-selfcal. Gegen 50 % zu lesen.
Warum der groesste Hebel: die Qualitaet war bis heute unsichtbar und musste
auf Nachfrage rueckwirkend gemessen werden. Dasselbe Muster
(pbreak_predictions) hat den Ausfall des P(break)-Modells LIVE aufgedeckt.
Mit 4 Szenarien getestet (tests_rec_outcomes.py). Zwei Fehlschlaege dabei
waren Testfehler, keine Code-Fehler — dokumentiert.
(2) alignment_stats auf die VOLLE Historie (1.216 statt 40 Trades) und
zusaetzlich je Lot. Absolute Euro-Vergleiche sind bei wechselnder
Positionsgroesse ungueltig (Lehre 04.08.). Damit steht die einzige
beidhaelftig robuste Aussage der Karte auf ihrer vollen Stichprobe.
(3) Block-Gruende sichtbar (block_mix -> #vd-blocks): "heute X % ohne Block ·
entry_room … · min_conf …". Bisher nur per DB-Abfrage zu beantworten.
(4) ELLIOTT: Verdict-Gewicht 1,0 -> 0. Gemessen ueber 15.544 Zeilen hatte es mit
1.384 Episoden die groesste Stichprobe der Tabelle und ist darin flach
(-0,075/+0,032, 50 % Treffer) — bei 25,9 % Einfluss auf die Nadel, weil es
in nur 1 % der Zeilen schweigt. Chip bleibt, Stimme entfaellt.
⚠ Folge: die Nadel schlaegt staerker aus (real +0,33 -> +1,00).
⚠ Namenskollision beim Bau gefunden und behoben: die neue Klasse hiess zuerst
.vd-track — so heisst bereits die Schiene der Bias-Nadel; sie waere
ueberschrieben worden. Jetzt .vd-selfcal.
Live verifiziert: alignment je Lot, block_mix (93 von 1381 ohne Block),
rec_outcomes angelegt, Elliott weight=0 bei erhaltenem Chip, v=144 ausgeliefert,
eine Instanz auf Port 8000.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
118 lines
5.1 KiB
Python
118 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
||
"""Haelt der SIG-Pending-Pfad auch mit realistischem Fill? — die offene Zahl.
|
||
|
||
ANLASS (2026-08-06): `signal_pending_entry` laeuft seit dem 05.08. mit ECHTEM
|
||
Geld. Die Erwartung dahinter (ØR +0,39/+0,36) stammt aus
|
||
`backtest_auto_signal_v3.py` und unterstellt: Einstieg zum Level-Preis, aber
|
||
**nur dort, wo der Bar-CLOSE das Level gebrochen hat**. Eine liegende Stop-Order
|
||
weiss das nicht — sie fuellt bei der ERSTEN BERUEHRUNG, auch bei jeder, die
|
||
wieder zurueckfaellt.
|
||
|
||
Wie teuer dieser Unterschied ist, wurde heute zweimal gemessen:
|
||
Momentum +0,40 → −0,06 (0,45 R Aufschlag) — Level WANDERT
|
||
Squeeze +0,46 → +0,13 (0,32 R Aufschlag) — Level STEHT
|
||
Der Squeeze haelt, das Momentum nicht. **Und `_pend` gehoert zur wandernden
|
||
Sorte:** der Anker wird bei jeder k×ATR-Gegenbewegung, nach Timeout und bei
|
||
Richtungswechsel neu gesetzt. Es ist also mit dem schlechteren Fall zu rechnen.
|
||
|
||
Benutzt dieselbe `lauf()` wie v3, nur mit `fill="touch"` — nichts nachgebaut,
|
||
damit die Zahlen vergleichbar bleiben. Der Default `fill="close"` reproduziert
|
||
v3 bitgenau (verifiziert).
|
||
|
||
VORAB FIXIERTE ENTSCHEIDUNGSREGEL:
|
||
`signal_pending_entry` bleibt nur gerechtfertigt, wenn der Pfad mit
|
||
`fill="touch"` in BEIDEN Haelften ØR > 0 UND PF > 1 haelt UND besser ist als
|
||
der Markt-Einstieg. Sonst gehoert er abgeschaltet.
|
||
|
||
Aufruf: python backtest_signal_touchfill.py [bars]
|
||
"""
|
||
import sys
|
||
|
||
import MetaTrader5 as mt5
|
||
|
||
import backtest_auto_signal_v3 as V
|
||
from core.wave_rec import WaveRecommender, calc_trend_angle
|
||
|
||
|
||
def main():
|
||
n_bars = 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_bars)
|
||
point = mt5.symbol_info(sym).point
|
||
mt5.shutdown()
|
||
# ⚠ Aufbau 1:1 wie in v3.main() — aber ueber die IMPORTIERTEN Helfer, nicht
|
||
# ueber Kopien. Waere hier ein eigener EMA/ATR drin, waere der Vergleich
|
||
# zwischen den beiden Fill-Annahmen nicht mehr sauber.
|
||
H = [float(b["high"]) for b in bars]; L = [float(b["low"]) for b in bars]
|
||
C = [float(b["close"]) for b in bars]; T = [int(b["time"]) for b in bars]
|
||
SP = [float(b["spread"]) * point for b in bars]
|
||
EF = V._ema_series(C, V._EMA_FAST); ES = V._ema_series(C, V._EMA_SLOW)
|
||
A = V._atr_series(H, L, C)
|
||
AD = [0.0] * len(C)
|
||
for i in range(V._N_BARS, len(C)):
|
||
AD[i] = calc_trend_angle(C[i - V._N_BARS:i + 1], V._ANGLE_LR) - 90.0
|
||
if abs(AD[i]) < V._ANGLE_DEAD:
|
||
AD[i] = 0.0
|
||
HTF = [V._htf_sign(C, i, 6, A[i] or 0.1) for i in range(len(C))]
|
||
H1S = [V._htf_sign(C, i, 12, A[i] or 0.1) for i in range(len(C))]
|
||
PH = [j for j in range(V._PIV_K, len(C) - V._PIV_K)
|
||
if H[j] == max(H[j - V._PIV_K:j + V._PIV_K + 1])]
|
||
PL = [j for j in range(V._PIV_K, len(C) - V._PIV_K)
|
||
if L[j] == min(L[j - V._PIV_K:j + V._PIV_K + 1])]
|
||
|
||
w = WaveRecommender(lambda: None)
|
||
w.set_reversal_enabled(False)
|
||
w.set_entry_room(0.6) # ⚠ ohne das ist das Raum-Gate ein No-op
|
||
w.set_dead_hours("")
|
||
mid = len(C) // 2
|
||
|
||
print("=" * 104)
|
||
print(f" SIG-PENDING — Fill bei BAR-CLOSE gegen Fill bei BERUEHRUNG "
|
||
f"({sym}, {len(C)} M5-Bars)")
|
||
print("=" * 104)
|
||
print(f" {V._berlin(T[0]):%d.%m.%Y} bis {V._berlin(T[-1]):%d.%m.%Y} · "
|
||
f"voller Live-Gate-Stack · kanonischer Exit · Echtkosten · EIN Slot")
|
||
print()
|
||
|
||
def paar(mc, am_level, fill):
|
||
r1, _ = V.lauf(w, H, L, C, T, A, SP, EF, ES, AD, HTF, H1S, PH, PL,
|
||
0, mid, mc, V._NACHT_LIVE, am_level, 0.0, fill)
|
||
r2, _ = V.lauf(w, H, L, C, T, A, SP, EF, ES, AD, HTF, H1S, PH, PL,
|
||
mid, len(C), mc, V._NACHT_LIVE, am_level, 0.0, fill)
|
||
return V.kenn(r1), V.kenn(r2)
|
||
|
||
print(f" {'Variante':<38}{'H1 n WR OeR PF SigmaR':>33}"
|
||
f" |{'H2 n WR OeR PF SigmaR':>33}")
|
||
print(" " + "-" * 102)
|
||
print(" A) MARKT am Bar-Close (der Ist-Zustand vor dem 05.08.)")
|
||
for mc in (55, 65, 75):
|
||
V.zeile(f" Konf>={mc}", *paar(mc, False, "close"))
|
||
print(" " + "-" * 102)
|
||
print(" B) am Level, Fill nur bei CLOSE-Bruch (die Zahl, auf der live steht)")
|
||
for mc in (55, 65, 75):
|
||
V.zeile(f" Konf>={mc}", *paar(mc, True, "close"))
|
||
print(" " + "-" * 102)
|
||
print(" C) am Level, Fill bei BERUEHRUNG (was live wirklich passiert)")
|
||
haelt = []
|
||
for mc in (55, 65, 75):
|
||
k1, k2 = paar(mc, True, "touch")
|
||
if V.zeile(f" Konf>={mc}", k1, k2):
|
||
haelt.append(mc)
|
||
print()
|
||
print("=" * 104)
|
||
if haelt:
|
||
print(f" → Variante C haelt bei Konf {haelt} — `signal_pending_entry` ist gedeckt.")
|
||
else:
|
||
print(" → Variante C haelt in KEINER Konfidenz-Stufe.")
|
||
print(" Damit steht `signal_pending_entry=true` auf einer Zahl, die die")
|
||
print(" realistische Fill-Annahme nicht ueberlebt → abschalten.")
|
||
print(" ⚠ B gegen C gelesen = der Look-ahead-Aufschlag (Squeeze 0,32 R,")
|
||
print(" Momentum 0,45 R).")
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|