C: Wahrscheinlichkeits-Kegel (kalibriert) + Config-Waechter im Reminder
C - core/cone.py + Kachel #card-cone + MT5 v1.31 (CN;<min>;<lo>;<hi>): "Erwartete Spanne" statt "Kursvorhersage". Der User wollte eingezeichnete Verlaufspfade; bewusst NICHT gebaut - sie suggerieren eine Praezision, die es nicht gibt (Lehre aus analyze_verdict_calibration.py). Der Kegel sagt wie WEIT der Kurs in 30/60/120 min plausibel laeuft, nicht wohin. analyze_cone.py: r(h)=(C[i+h]-C[i])/ATR[i], Fit auf H1, Abdeckung gemessen auf H2 (echtes out-of-sample): 80%-Band -> 76,7 / 76,6 / 75,3 % 90%-Band -> 87,5 / 87,2 / 86,5 % Konsistent ~3-5 Pp ZU ENG. Das wird NICHT weggefittet - Kachel und Tooltip nennen die REAL gemessene Abdeckung, nicht den Nennwert. Damit nach dem P(break)-Modell die zweite kalibriert geprueft Komponente im Projekt. Zentriert auf den aktuellen Kurs, KEINE Drift addiert (Median +-0,0..0,16 xATR = klein gegen die Bandbreite; eine Drift-Korrektur waere eine Richtungsaussage und die ist nicht belegt). Farbe neutral grau, kein gruen/rot. Kein Signal, kein Verdict-Gewicht. MQL5 v1.31: zwei sich oeffnende gepunktete Pfade, verkettet 30->60->120. Startpunkt aus der PX-Zeile - die setzt g_conePx jetzt auch, wenn InpShowPrice aus ist (sonst verliert der Faecher seinen Anker). Config-Waechter in measurement_reminder.py (Antwort auf "sollten wir alle verworfenen Backtests woechentlich neu rechnen?"): NEIN - eine Woche sind ~2000 Bars, und 18 Ideen x 52 Wochen = 936 Tests/Jahr erzeugen bei 5 % Fehlalarmquote ~47 falsche "funktioniert jetzt!" pro Jahr. Stattdessen EREIGNIS-gesteuert: CONFIG_DEPS verankert 8 config-abhaengige Messungen an den Wert, gegen den sie validiert wurden (entry_room_atr 0,6 / sr_close_pbreak 0,55 / breakout_k 0,3 / risk_pct 0 / margin_buffer_pct 95 / adverse_15min_atr 0,5 / auto_signal_min_conf 75 / dead_hours leer). Weicht einer ab, meldet der Timer welche Messung veraltet ist. Numerischer Vergleich, damit 0.60 == 0.6. Mit 5 synthetischen Szenarien getestet. Erledigt ausgetragen: Chartmuster-Kontrolltest (30.07., Muster schlagen die Kontrolle in beiden Haelften +0,022/+0,108). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
03be3b8f5f
commit
d9cb54a52c
@@ -0,0 +1,68 @@
|
||||
"""core/cone.py — Wahrscheinlichkeits-Kegel (Streuung, NICHT Richtung).
|
||||
|
||||
User-Wunsch 2026-07-31: „ein Kursvorhersagemodul, das mögliche Verläufe in MT5
|
||||
einzeichnet". Eingezeichnete PFADE würden eine Präzision suggerieren, die es nicht
|
||||
gibt — das Projekt hat mit `analyze_verdict_calibration.py` teuer gelernt, dass eine
|
||||
Zahl ohne Kalibrierungsprüfung in die Irre führt (conf_pct war in H2 invertiert).
|
||||
|
||||
Deshalb bewusst WENIGER, dafür belegt: der Kegel sagt nicht, WOHIN der Kurs geht,
|
||||
sondern WIE WEIT er in 30/60/120 min plausibel gelaufen sein kann.
|
||||
|
||||
GEMESSEN & OUT-OF-SAMPLE VALIDIERT (`analyze_cone.py`, 80k M5-Bars, Fit auf H1,
|
||||
Abdeckung gemessen auf H2):
|
||||
|
||||
Band 30 min 60 min 120 min
|
||||
80 % nom. 76,7 % 76,6 % 75,3 %
|
||||
90 % nom. 87,5 % 87,2 % 86,5 %
|
||||
|
||||
⚠ Die Bänder sind konsistent ~3–5 Prozentpunkte ZU ENG (H2 war relativ zum ATR
|
||||
etwas volatiler als H1). Das wird NICHT weggefittet — die Anzeige nennt die real
|
||||
gemessene Abdeckung, nicht den Nennwert. Damit ist der Kegel nach dem P(break)-
|
||||
Modell die zweite kalibriert geprüfte Komponente im Projekt.
|
||||
|
||||
Quantile final auf allen 80k Bars gefittet (dasselbe Vorgehen wie beim P(break)-
|
||||
Modell: erst out-of-sample validieren, dann für den Live-Einsatz auf der vollen
|
||||
History fitten). ATR-normiert → über Vola-Regime hinweg gültig.
|
||||
|
||||
⚠ KEIN Signal, kein Verdict-Gewicht, kein Trade-Trigger. Der Kegel ist um den
|
||||
AKTUELLEN Kurs zentriert (keine Drift addiert — der Median lag bei ±0,0…0,16×ATR,
|
||||
also klein gegen die Bandbreite; eine Drift-Korrektur wäre eine Richtungsaussage
|
||||
und genau die ist hier nicht belegt).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
# Horizont (M5-Bars) → {Nennband: (unteres, oberes Quantil in ×ATR)}
|
||||
_CONE = {
|
||||
6: {50: (-0.915, +0.940), 80: (-2.000, +1.962), 90: (-2.800, +2.713)},
|
||||
12: {50: (-1.333, +1.346), 80: (-2.854, +2.833), 90: (-4.064, +4.000)},
|
||||
24: {50: (-1.949, +2.000), 80: (-4.183, +4.177), 90: (-5.955, +5.938)},
|
||||
}
|
||||
# real gemessene Abdeckung (H2, out-of-sample) — das steht in der UI, nicht der Nennwert
|
||||
_COVERAGE = {6: {50: 44.4, 80: 76.7, 90: 87.5},
|
||||
12: {50: 45.1, 80: 76.6, 90: 87.2},
|
||||
24: {50: 45.5, 80: 75.3, 90: 86.5}}
|
||||
_ATRMIN = 0.06
|
||||
MINUTES = {6: 30, 12: 60, 24: 120}
|
||||
|
||||
|
||||
def build(price: float, atr: float, bands=(50, 80)) -> dict | None:
|
||||
"""→ {'atr':…, 'levels':[{minutes, bars, band, lo, hi, coverage}, …]}
|
||||
|
||||
`price` = aktueller Kurs (Bid), `atr` = ATR der M5-Basis.
|
||||
"""
|
||||
if not price or not atr or atr <= 0:
|
||||
return None
|
||||
a = max(float(atr), _ATRMIN)
|
||||
out = []
|
||||
for bars in sorted(_CONE):
|
||||
for band in bands:
|
||||
q = _CONE[bars].get(band)
|
||||
if not q:
|
||||
continue
|
||||
out.append({
|
||||
"minutes": MINUTES[bars], "bars": bars, "band": band,
|
||||
"lo": round(price + q[0] * a, 3),
|
||||
"hi": round(price + q[1] * a, 3),
|
||||
"coverage": _COVERAGE.get(bars, {}).get(band),
|
||||
})
|
||||
return {"atr": round(a, 4), "price": round(float(price), 3), "levels": out}
|
||||
@@ -43,6 +43,7 @@ from core.gaps import GapAnalyzer
|
||||
from core.structure import MarketStructure
|
||||
from core.patterns import PatternDetector
|
||||
from core.candles import CandleAnatomy
|
||||
from core.cone import build as _cone_build
|
||||
from core.candle_logger import CandleLogger
|
||||
from core.wave_rec import (_atr as _wr_atr, _ema_last,
|
||||
_EMA_FAST, _EMA_SLOW, _TREND_DEADBAND, _STRETCH_MAX)
|
||||
@@ -2093,6 +2094,19 @@ class TradingEngine:
|
||||
lines.append(f"PX;{_bid}")
|
||||
except Exception:
|
||||
pass
|
||||
# WAHRSCHEINLICHKEITS-KEGEL: CN;<minuten>;<lo>;<hi> je Horizont (30/60/120),
|
||||
# aufsteigend — der Indikator verbindet sie vom aktuellen Bar aus zu zwei
|
||||
# sich öffnenden Pfaden. ⚠ Streuung, NICHT Richtung: der Kegel ist um den
|
||||
# aktuellen Kurs zentriert und sagt nur, wie weit der Kurs plausibel läuft.
|
||||
# Out-of-sample kalibriert (`analyze_cone.py`), 80 %-Band trifft real ~76 %.
|
||||
try:
|
||||
_atr5 = float(((self.wave.snapshot() or {}).get("pb_feats") or {})
|
||||
.get("atr") or 0.0)
|
||||
_cn = _cone_build(_bid, _atr5, bands=(80,))
|
||||
for lv in (_cn or {}).get("levels", []):
|
||||
lines.append(f"CN;{lv['minutes']};{lv['lo']};{lv['hi']}")
|
||||
except Exception:
|
||||
pass
|
||||
# G/V der offenen Position, direkt unter dem Kurs (User-Wunsch 2026-07-30):
|
||||
# PL;wert;waehrung. **NETTO** wie im Dashboard — bei Gewinn abzüglich der
|
||||
# WHT-Quellensteuer, die der Broker einbehält (`[trading] wht_pct`); bei
|
||||
@@ -2714,6 +2728,11 @@ class TradingEngine:
|
||||
# Kerzen-Anatomie (M5) — reine Anzeige, KEIN Verdict-Gewicht (gemessen:
|
||||
# Lehrbuch-Deutung invertiert, Handelssignal durchgefallen).
|
||||
"candle_anat": self.candle_anat.snapshot(),
|
||||
# Wahrscheinlichkeits-Kegel (Streuung, NICHT Richtung) — out-of-sample
|
||||
# kalibriert (`analyze_cone.py`). Reine Anzeige.
|
||||
"cone": _cone_build(
|
||||
(market or {}).get("bid"),
|
||||
float(((wave_snap or {}).get("pb_feats") or {}).get("atr") or 0.0)),
|
||||
"stats_compact": {"week": self._compact_stats("week"),
|
||||
"all": self._compact_stats("all")},
|
||||
"close_alert_count": self._close_alert_count,
|
||||
|
||||
Reference in New Issue
Block a user