Konfidenz-Schwelle und M15-Selektivitaet gemessen: keine Aenderung
(2) conf_pct trennt im Markt-Modus NICHT: der Bandverlauf ist nicht gleichgerichtet (H1 bestes Band 0-44, schlechtestes 55-64), und die Schwelle bewegt nichts -- >=0 liefert H1 -0,189, >=55 liefert -0,197. 11,4 % Signalmenge fuer 0,017 R. Mit ruhender Order trennt die obere Haelfte: >=75 schlaegt die Live-Schwelle im OeR beidhaelftig (-0,001/+0,147 gegen -0,070/+0,081), aber die Summe faellt (+82,8 gegen +146,1). Regel verlangte beides -> nicht geaendert, Regel NICHT nachtraeglich gelockert. 27. verworfener Signal-Eingriff. Dritte unabhaengige Bestaetigung des Ausfuehrungs-Hebels am selben Tag: Level gegen Markt +0,127/+0,096 R, groessengleich zu backtest_entryroom_level. (3) M15-Karte steht 37,8 % der ZEIT gruen (in Wechseln gerechnet waeren es 49 % -- gruene Phasen sind kuerzer). Handlungsrelevanter Zustand entkoppelt 54,1 % / 51,5 %, beide KI enthalten die 50 %. 205 von 350 unabhaengigen Faellen, also in gut zwei Wochen entscheidbar. Die Hysterese vom 12.08. wirkt (53 -> 54,1 %). Gate 3b ins Banner zu ziehen ist durch den Entry-Raum-Lauf schon beantwortet: diese Dimension trennt nicht. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
be9f444507
commit
f15a36138f
@@ -7434,6 +7434,83 @@ vollständig.
|
|||||||
⚠ **Verifikation der Zustellung steht aus** — sie erfolgt mit dem Report am
|
⚠ **Verifikation der Zustellung steht aus** — sie erfolgt mit dem Report am
|
||||||
nächsten Morgen um 07:30. Die Bausteine sind einzeln live gegengeprüft.
|
nächsten Morgen um 07:30. Die Bausteine sind einzeln live gegengeprüft.
|
||||||
|
|
||||||
|
## ⚠⚠ KONFIDENZ-SCHWELLE 55 GEMESSEN: SIE TRENNT NICHTS — keine Änderung
|
||||||
|
## (`backtest_conf_gated.py`, 2026-08-19)
|
||||||
|
|
||||||
|
Punkt (2) der Verbesserungsliste. `min_conf` blockt live **11,4 %**. Die 55
|
||||||
|
stammen aus `backtest_conf.py` — gemessen an `_build` **allein**, ohne
|
||||||
|
Breakout-Bestätigung und Raum-Gate (also eine andere Population, 77,9 % gegen
|
||||||
|
19,5 % gerichtet) und mit älterem Exit. Neu: voller Gate-Stack, `_MIN_CONF`
|
||||||
|
für die Messung auf 0, kanonischer Exit, Echtkosten, 2 Halbjahre, 95-%-KI,
|
||||||
|
**beide Ausführungs-Achsen**.
|
||||||
|
|
||||||
|
**A) Markt — der Verlauf ist NICHT gleichgerichtet, also Rauschen:**
|
||||||
|
|
||||||
|
| Band | H1 ØR | H2 ØR |
|
||||||
|
|---|---|---|
|
||||||
|
| 0–44 | **−0,014** (bestes H1!) | −0,072 |
|
||||||
|
| 45–54 | −0,141 | −0,082 |
|
||||||
|
| **55–64** | **−0,259** (schlechtestes) | −0,046 |
|
||||||
|
| 65–74 | −0,196 | −0,017 |
|
||||||
|
| 75–100 | −0,180 | +0,018 |
|
||||||
|
|
||||||
|
⚠⚠ **Die Schwelle bewegt gar nichts:** ≥ 0 liefert H1 −0,189, ≥ 55 liefert
|
||||||
|
**−0,197** — also minimal SCHLECHTER. Über alle fünf Schwellen liegt der ØR in
|
||||||
|
H1 zwischen −0,180 und −0,197. **11,4 % der Signalmenge werden für eine
|
||||||
|
Wirkung von 0,017 R weggeworfen.**
|
||||||
|
|
||||||
|
**B) ruhende Order am Level — hier trennt die OBERE Hälfte, aber:**
|
||||||
|
|
||||||
|
| Schwelle | H1 ØR / ΣR | H2 ØR / ΣR |
|
||||||
|
|---|---|---|
|
||||||
|
| ≥ 0 | −0,062 / −83,6 | +0,078 / **+165,6** |
|
||||||
|
| **≥ 55 (live)** | **−0,070 / −82,1** | **+0,081 / +146,1** |
|
||||||
|
| ≥ 65 | −0,074 / −77,8 | +0,103 / +133,0 |
|
||||||
|
| **≥ 75** | **−0,001 / −0,5** | **+0,147 / +82,8** |
|
||||||
|
|
||||||
|
✅ **≥ 75 schlägt die Live-Schwelle im ØR in BEIDEN Hälften** (−0,001 gegen
|
||||||
|
−0,070 · +0,147 gegen +0,081) und ist die einzige Zelle, in der H1 den
|
||||||
|
Breakeven erreicht. ❌ **Aber ΣR fällt** (+82,8 gegen +146,1) — die vorab
|
||||||
|
fixierte Regel verlangte **beides**. **Nicht geändert.**
|
||||||
|
⚠ Das ist wieder der dokumentierte Spezifikations-Konflikt aus
|
||||||
|
`backtest_cost_gate.py`: ØR und ΣR laufen mechanisch gegeneinander, wenn die
|
||||||
|
Varianten verschieden viele Trades handeln (416 gegen 1.175). Die Regel wurde
|
||||||
|
**nicht nachträglich gelockert**; beide Spalten stehen deshalb oben.
|
||||||
|
|
||||||
|
✅ **Dritte unabhängige Bestätigung des Ausführungs-Hebels am selben Tag:** bei
|
||||||
|
≥ 55 liefert der Level-Einstieg −0,070/+0,081 gegen −0,197/−0,015 am Markt =
|
||||||
|
**+0,127 / +0,096 R**, größengleich zu `backtest_entryroom_level.py`
|
||||||
|
(+0,109/+0,088). **Die Achse trägt reproduzierbar, das Signal darunter nicht.**
|
||||||
|
**27. verworfener Signal-Eingriff.**
|
||||||
|
|
||||||
|
## ⚠ M15-KARTE: SELEKTIVITÄT GEMESSEN — weiter kein Urteil möglich (2026-08-19)
|
||||||
|
|
||||||
|
Punkt (3). Ausgewertet ab dem Hysterese-Stichtag 12.08. (5.979 Wechsel).
|
||||||
|
⚠ **In ZEIT statt in Wechseln gerechnet** — die Wechsel-Zahl (49 % grün)
|
||||||
|
überschätzt, weil grüne Phasen kürzer sind:
|
||||||
|
|
||||||
|
| Zustand | Anteil der Zeit |
|
||||||
|
|---|---|
|
||||||
|
| gelb | **62,2 %** (104,0 h) |
|
||||||
|
| **grün** | **37,8 %** (63,1 h) |
|
||||||
|
| rot | 0,0 % (0,1 h) |
|
||||||
|
|
||||||
|
| handlungsrelevant (grün + gerichtet) | Treffer | n | 95-%-KI |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 30 min roh | 51,2 % | 2.869 | [49,3 … 53,0] |
|
||||||
|
| **30 min entkoppelt** | **54,1 %** | **205** | **[47,3 … 60,5]** ⚠ |
|
||||||
|
| 60 min entkoppelt | 51,5 % | 204 | [44,1 … 58,3] ⚠ |
|
||||||
|
|
||||||
|
**Beide Intervalle enthalten die 50 %** — unverändert **nicht belegt**, aber
|
||||||
|
auch nicht widerlegt. Aus 2.869 rohen Zeilen bleiben **205** unabhängige; die
|
||||||
|
Latte von 350 (wie bei `pbreak_accuracy_v2`) ist zu **59 %** erreicht, also in
|
||||||
|
gut zwei Wochen entscheidbar. ✅ Die Hysterese vom 12.08. wirkt: der
|
||||||
|
entkoppelte Wert stieg von 53 auf 54,1 %.
|
||||||
|
⚠⚠ **Die naheliegende Schärfung ist damit schon beantwortet:** Gate ③b
|
||||||
|
(Entry-Raum) ins Banner zu ziehen würde auf einer Dimension filtern, die am
|
||||||
|
selben Tag als **nicht trennend** gemessen wurde — was `entry_room`
|
||||||
|
durchlässt, ist selbst beidhälftig negativ. **Nichts geändert.**
|
||||||
|
|
||||||
## ⚠⚠ ENTRY-RAUM-GATE GEGEN AUSFÜHRUNG = NICHT GEBAUT — aber der Lauf
|
## ⚠⚠ ENTRY-RAUM-GATE GEGEN AUSFÜHRUNG = NICHT GEBAUT — aber der Lauf
|
||||||
## zeigt etwas Wichtigeres (`backtest_entryroom_level.py`, 2026-08-19)
|
## zeigt etwas Wichtigeres (`backtest_entryroom_level.py`, 2026-08-19)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
"""Trennt `conf_pct` ueberhaupt? Und ist 55 die richtige Schwelle? (2026-08-19)
|
||||||
|
|
||||||
|
FRAGE (User, Punkt (2) der Verbesserungsliste). `min_conf` blockt live **11,4 %**
|
||||||
|
aller Empfehlungen. Die Schwelle 55 stammt aus `backtest_conf.py`: Band 40-54 %
|
||||||
|
gemessen negativ (-0,025), >= 55 % positiv (+0,058).
|
||||||
|
|
||||||
|
WARUM DAS NEU ZU MESSEN IST -- drei Gruende, jeder fuer sich hinreichend:
|
||||||
|
1. `backtest_conf.py` misst `_build` ALLEIN, ohne Breakout-Bestaetigung und
|
||||||
|
ohne Entry-Raum-Gate. Genau die beiden sind live die groessten Blocker
|
||||||
|
(dokumentiert 2026-08-05: 77,9 % gerichtet allein vs. 19,5 % im vollen
|
||||||
|
Stack). Es ist also eine andere Population.
|
||||||
|
2. Es nutzt ein aelteres Exit-Modell, nicht `exit_model.LIVE`.
|
||||||
|
3. `analyze_verdict_calibration.py` hat `conf_pct` als **nicht kalibriert**
|
||||||
|
ausgewiesen und in H2 sogar INVERTIERT (85-100 % -> 40 % Trefferquote).
|
||||||
|
Ob es wenigstens im ERTRAG trennt, ist damit offen.
|
||||||
|
|
||||||
|
AUFBAU. Voller Live-Gate-Stack, aber `_MIN_CONF` auf 0 gesetzt, damit auch die
|
||||||
|
heute geblockten Signale sichtbar werden; danach nach Konfidenz-Baendern
|
||||||
|
aufgeteilt. Kanonischer Exit, Echtkosten, 2 Halbjahre, 95-%-KI je Zelle.
|
||||||
|
Zusaetzlich beide Ausfuehrungs-Achsen (Markt / ruhende Order am Level), weil
|
||||||
|
`backtest_entryroom_level.py` am selben Tag gezeigt hat, dass die Achse
|
||||||
|
beidhaelftig +0,09 bis +0,11 R traegt.
|
||||||
|
|
||||||
|
REGEL VORAB FIXIERT:
|
||||||
|
- Die Schwelle wird nur verschoben, wenn ein anderer Schnitt in BEIDEN
|
||||||
|
Haelften mehr OeR UND mehr Summe liefert und die Nachbarbaender mithalten.
|
||||||
|
- Zusaetzliche Aussage: trennt conf ueberhaupt? Das verlangt einen in beiden
|
||||||
|
Haelften GLEICHGERICHTETEN Verlauf ueber die Baender -- ein Band, das in H1
|
||||||
|
steigt und in H2 faellt, ist Rauschen.
|
||||||
|
|
||||||
|
GRENZE: kein sequentieller Ein-Slot-Lauf (verglichen werden Populationen).
|
||||||
|
Exit-Slippage ist nicht modelliert.
|
||||||
|
|
||||||
|
Aufruf: python backtest_conf_gated.py [bars]
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import MetaTrader5 as mt5
|
||||||
|
|
||||||
|
import core.wave_rec as WR
|
||||||
|
from backtest_breakout_gated import _PIV_K, _TU, _atr_series, _htf_sign
|
||||||
|
from backtest_cost_gate import kennzahlen
|
||||||
|
from backtest_entryroom_level import _GATE, _K, handeln, sammle
|
||||||
|
from core.analysis import calc_trend_angle
|
||||||
|
from core.exit_model import LIVE
|
||||||
|
from core.wave_rec import (WaveRecommender, _ANGLE_LR, _EMA_FAST, _EMA_SLOW,
|
||||||
|
_ema_series)
|
||||||
|
|
||||||
|
BAENDER = [(0, 45), (45, 55), (55, 65), (65, 75), (75, 101)]
|
||||||
|
|
||||||
|
|
||||||
|
def zeig(lbl, k1, k2):
|
||||||
|
def f(k):
|
||||||
|
if not k:
|
||||||
|
return " --"
|
||||||
|
ci = k.get("ci")
|
||||||
|
m = ""
|
||||||
|
if ci:
|
||||||
|
m = (" [{:+.3f} .. {:+.3f}]".format(ci[0], ci[1])
|
||||||
|
+ ("" if ci[0] * ci[1] > 0 else " ~0"))
|
||||||
|
return ("n={:>4} WR={:>3.0f}% OeR={:+.3f} SR={:+8.1f} PF={:.2f}{}"
|
||||||
|
.format(k["n"], k["wr"], k["oer"], k["sr"], k["pf"], m))
|
||||||
|
print(" {:<16} H1 {}".format(lbl, f(k1)))
|
||||||
|
print(" {:<16} H2 {}".format("", f(k2)))
|
||||||
|
|
||||||
|
|
||||||
|
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]
|
||||||
|
SP = [float(b["spread"]) * point for b in bars]
|
||||||
|
A = _atr_series(H, L, C)
|
||||||
|
EF = _ema_series(C, _EMA_FAST); ES = _ema_series(C, _EMA_SLOW)
|
||||||
|
N = len(C); mid = N // 2; ende = N - LIVE.max_hold - 1
|
||||||
|
|
||||||
|
print("Vorberechnung ...", flush=True)
|
||||||
|
AD = [90.0] * N
|
||||||
|
for i in range(_ANGLE_LR + 2, N):
|
||||||
|
AD[i] = calc_trend_angle(C[i - (_ANGLE_LR + 1):i + 1], _ANGLE_LR)
|
||||||
|
HTF = [0] * N; H1 = [0] * N
|
||||||
|
for i in range(N):
|
||||||
|
if A[i]:
|
||||||
|
HTF[i] = _htf_sign(C, i, 6, A[i])
|
||||||
|
H1[i] = _htf_sign(C, i, 12, A[i])
|
||||||
|
PH = [j for j in range(_PIV_K, N - _PIV_K)
|
||||||
|
if H[j] == max(H[j - _PIV_K:j + _PIV_K + 1])]
|
||||||
|
PL = [j for j in range(_PIV_K, N - _PIV_K)
|
||||||
|
if L[j] == min(L[j - _PIV_K:j + _PIV_K + 1])]
|
||||||
|
|
||||||
|
w = WaveRecommender(_TU(), mt5.TIMEFRAME_M5)
|
||||||
|
w.set_reversal_enabled(False)
|
||||||
|
w.set_entry_room(_GATE)
|
||||||
|
w.set_dead_hours([])
|
||||||
|
w.set_breakout_k(_K)
|
||||||
|
|
||||||
|
# Gate oeffnen, damit die heute geblockten Baender ueberhaupt entstehen.
|
||||||
|
# ⚠ Modul-Konstante, wirkt prozessweit -- deshalb hier und nirgends sonst.
|
||||||
|
alt = WR._MIN_CONF
|
||||||
|
WR._MIN_CONF = 0
|
||||||
|
print("=" * 100)
|
||||||
|
print(" KONFIDENZ-SCHWELLE im vollen Gate-Stack -- {} M5 ({} Bars)".format(sym, N))
|
||||||
|
print(" _MIN_CONF {} -> 0 fuer die Messung ({} Bars pro Haelfte)".format(alt, mid))
|
||||||
|
print("=" * 100)
|
||||||
|
try:
|
||||||
|
s1 = sammle(w, H, L, C, A, EF, ES, AD, HTF, H1, PH, PL, 0, mid)
|
||||||
|
s2 = sammle(w, H, L, C, A, EF, ES, AD, HTF, H1, PH, PL, mid, ende)
|
||||||
|
finally:
|
||||||
|
WR._MIN_CONF = alt
|
||||||
|
print(" Signale ohne Konfidenz-Gate: H1 {} H2 {}".format(len(s1), len(s2)))
|
||||||
|
|
||||||
|
for modus, titel in (("markt", "A) MARKT am Bar-Close (= wie die Sim von 2026-07-16)"),
|
||||||
|
("level", "B) ruhende Order AM Level, Fill bei BERUEHRUNG")):
|
||||||
|
print("")
|
||||||
|
print(" " + titel)
|
||||||
|
print(" " + "-" * 96)
|
||||||
|
for lo, hi in BAENDER:
|
||||||
|
def rs(sigs):
|
||||||
|
out = []
|
||||||
|
for s in sigs:
|
||||||
|
c = s.get("conf")
|
||||||
|
if c is None or not (lo <= c < hi):
|
||||||
|
continue
|
||||||
|
r = handeln(s, H, L, C, SP, ende, modus, 0.0, 12)
|
||||||
|
if r is not None:
|
||||||
|
out.append(r)
|
||||||
|
return out
|
||||||
|
zeig("conf {}-{}".format(lo, hi - 1), kennzahlen(rs(s1)), kennzahlen(rs(s2)))
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# Kumulativ: was liefert die Schwelle X, wenn man alles >= X handelt?
|
||||||
|
print(" Schwellen-Vergleich (alles >= X gehandelt)")
|
||||||
|
for x in (0, 45, 55, 65, 75):
|
||||||
|
def rs2(sigs):
|
||||||
|
out = []
|
||||||
|
for s in sigs:
|
||||||
|
c = s.get("conf")
|
||||||
|
if c is None or c < x:
|
||||||
|
continue
|
||||||
|
r = handeln(s, H, L, C, SP, ende, modus, 0.0, 12)
|
||||||
|
if r is not None:
|
||||||
|
out.append(r)
|
||||||
|
return out
|
||||||
|
tag = " <- LIVE" if x == alt else ""
|
||||||
|
zeig(">= {}{}".format(x, tag), kennzahlen(rs2(s1)), kennzahlen(rs2(s2)))
|
||||||
|
print("")
|
||||||
|
print("=" * 100)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -114,6 +114,7 @@ def sammle(w, H, L, C, A, EF, ES, AD, HTF, H1, PH, PL, lo, hi):
|
|||||||
# ECHTE Methode, nicht nachgebaut -- dieselbe Zahl, die das Gate benutzt.
|
# ECHTE Methode, nicht nachgebaut -- dieselbe Zahl, die das Gate benutzt.
|
||||||
ri = w.room_info(C[i])[("long" if d > 0 else "short")] or {}
|
ri = w.room_info(C[i])[("long" if d > 0 else "short")] or {}
|
||||||
out.append({"i": i, "d": d, "atr": max(atr, _ATRMIN), "px": C[i],
|
out.append({"i": i, "d": d, "atr": max(atr, _ATRMIN), "px": C[i],
|
||||||
|
"conf": rec.get("conf_pct"), # additiv, s. backtest_conf_gated.py
|
||||||
"lvl": ri.get("level"), "dist": ri.get("dist_atr"),
|
"lvl": ri.get("level"), "dist": ri.get("dist_atr"),
|
||||||
"frei": bool(ri.get("frei"))})
|
"frei": bool(ri.get("frei"))})
|
||||||
pend = None
|
pend = None
|
||||||
|
|||||||
Reference in New Issue
Block a user