Kegel mit Adaptive Conformal Inference nachkalibriert (v=158)
Der Kegel war seit dem 31.07. dokumentiert 3-5 Pp ZU ENG - 80 % nominal gegen
real 76,7 / 76,6 / 75,3 % - und blieb es, weil Nachfitten das Problem nur
verschiebt. ACI justiert stattdessen ONLINE nach jedem aufgeloesten Fenster und
konvergiert nachweislich gegen die Zielabdeckung, auch unter Drift.
EHRLICH ZUR BAUART: die Lehrbuch-Form justiert alpha und schlaegt das Quantil
nach. Hier liegt nur eine feste Quantil-Tabelle vor, kein Verteilungsobjekt -
umgesetzt ist die multiplikative Variante:
s <- s * exp(gamma * (1{verfehlt} - alpha_ziel)), gamma 0,02, Deckel 0,7-2,0
Dieselbe Regelungsidee, aber die Konvergenz-GARANTIE der Originalform ist damit
nicht woertlich uebertragen.
Verifiziert: bei exakt 20 % Verfehlern bleibt die Skala bei 1,0000 - der
Fixpunkt stimmt. Simulation aus der dokumentierten Lage (76,6 %): nach ~50
Checks um 80 %. Die Skala pendelt um das Ziel statt exakt zu treffen - das ist
das bekannte ACI-Verhalten (garantiert ist die Langfrist-Abdeckung).
NICHT-UEBERLAPPEND geloggt (neue Tabelle cone_checks): ein 120-min-Fenster alle
5 min waere 24-fach ueberlappend - genau die Cluster-Verzerrung, an der
analyze_hl_funding.py aufgelaufen ist und die die Faelligkeitsbedingung
pbreak_accuracy_v2 um das Zehnfache danebenliegen liess. Je Horizont startet ein
neuer Check erst, wenn der vorige ablief -> 48/24/12 Checks je Tag.
Neustart-fest ueber runtime_state.json. build() ohne skalen liefert bitgenau die
alten Werte (additiv geprueft).
ZWEI EIGENE PLATZIERUNGSFEHLER, beide gefangen: der Lade-Block landete zuerst
HINTER den except-Klauseln von _load_runtime_state, wo st nicht mehr existiert;
und beim M15-Setup landete ein Block mitten in einem mehrzeiligen Aufruf. Der
erste waere stillschweigend nie gelaufen - gefunden nur, weil ich die Funktion
danach gelesen habe statt dem gruenen py_compile zu trauen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
86c432f791
commit
b8705e297f
@@ -4182,7 +4182,7 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
|
|||||||
(„⚠ die Welle (steuert die Order) schweigt").
|
(„⚠ die Welle (steuert die Order) schweigt").
|
||||||
Live gegengerechnet, beide Zeilen erscheinen wie beabsichtigt.
|
Live gegengerechnet, beide Zeilen erscheinen wie beabsichtigt.
|
||||||
⚠ Reine Anzeige — an Gewichten, Gates und Order-Logik ist nichts geändert.
|
⚠ Reine Anzeige — an Gewichten, Gates und Order-Logik ist nichts geändert.
|
||||||
- Asset-Version aktuell **v=157** (in `web/index.html` hochzählen, siehe Workflows).
|
- Asset-Version aktuell **v=158** (in `web/index.html` hochzählen, siehe Workflows).
|
||||||
Schriftgrößen 2026-07-24 global **+4px** (2× je +2px auf User-Wunsch; Body-Basis
|
Schriftgrößen 2026-07-24 global **+4px** (2× je +2px auf User-Wunsch; Body-Basis
|
||||||
14→18px). ⚠ Betrifft in `style.css` sowohl `font-size:Npx` (71×) ALS AUCH die
|
14→18px). ⚠ Betrifft in `style.css` sowohl `font-size:Npx` (71×) ALS AUCH die
|
||||||
`font:<weight> Npx/…`-**Shorthand** (3×: `.ms-chip`/`.ms-bos-lbl`/`.sqm-badge` —
|
`font:<weight> Npx/…`-**Shorthand** (3×: `.ms-chip`/`.ms-bos-lbl`/`.sqm-badge` —
|
||||||
@@ -4942,6 +4942,48 @@ Modell schliesst keine Trades.
|
|||||||
„die Rangfolge ist kaputt" ist **nicht** belegt; belegt ist nur die
|
„die Rangfolge ist kaputt" ist **nicht** belegt; belegt ist nur die
|
||||||
Basisraten-/Kalibrierungslücke.
|
Basisraten-/Kalibrierungslücke.
|
||||||
|
|
||||||
|
## ✅ KEGEL MIT ADAPTIVE CONFORMAL INFERENCE (2026-08-08, v=158)
|
||||||
|
|
||||||
|
Der Kegel war seit dem 31.07. dokumentiert **3–5 Pp ZU ENG** — 80 % nominal
|
||||||
|
gegen real **76,7 / 76,6 / 75,3 %** — und blieb es, weil Nachfitten das Problem
|
||||||
|
nur verschiebt: die nächste Periode hat wieder eine andere Vola. **ACI** ist die
|
||||||
|
Standardmethode dafür (Web-Recherche 08.08.): sie justiert das Niveau **online**
|
||||||
|
nach jedem aufgelösten Fenster und konvergiert nachweislich gegen die
|
||||||
|
Zielabdeckung, **auch unter Verteilungsdrift**.
|
||||||
|
|
||||||
|
⚠ **EHRLICH ZUR BAUART:** die Lehrbuch-Form justiert `α` und schlägt das
|
||||||
|
zugehörige Quantil nach. Hier liegt nur eine feste **Quantil-Tabelle** vor, kein
|
||||||
|
Verteilungsobjekt — umgesetzt ist deshalb die **multiplikative Variante**:
|
||||||
|
```
|
||||||
|
s ← s · exp(γ · (1{verfehlt} − α_ziel)) γ = 0,02 · Deckel [0,7 … 2,0]
|
||||||
|
```
|
||||||
|
Dieselbe Regelungsidee, aber **die Konvergenz-Garantie der Originalform ist
|
||||||
|
damit NICHT wörtlich übertragen** — es ist ACI im Geiste.
|
||||||
|
|
||||||
|
✅ **Verifiziert:** bei **exakt 20 % Verfehlern bleibt die Skala bei 1,0000** —
|
||||||
|
das ist der Fixpunkt, und er stimmt. Simulation aus der dokumentierten Lage
|
||||||
|
(76,6 % Abdeckung): nach ~50 Checks um 80 %.
|
||||||
|
⚠ Die Skala **pendelt** um das Ziel statt exakt zu treffen. Das ist das bekannte
|
||||||
|
ACI-Verhalten: garantiert ist die **Langfrist**-Abdeckung, nicht der Einzelwert.
|
||||||
|
|
||||||
|
⚠⚠ **NICHT-ÜBERLAPPEND geloggt** (`cone_checks`): ein 120-min-Fenster alle 5 min
|
||||||
|
wäre **24-fach überlappend** — genau die Cluster-Verzerrung, an der
|
||||||
|
`analyze_hl_funding.py` (06.08.) aufgelaufen ist und die die
|
||||||
|
Fälligkeitsbedingung `pbreak_accuracy_v2` um das Zehnfache danebenliegen liess
|
||||||
|
(07.08.). Je Horizont startet ein neuer Check erst, wenn der vorige abgelaufen
|
||||||
|
ist → 48/24/12 Checks je Tag.
|
||||||
|
✅ **Neustart-fest** über `runtime_state.json` — ohne Persistenz liefe die
|
||||||
|
erlernte Kalibrierung nach jedem Neustart wieder bei 1,0 los.
|
||||||
|
⚠ `build(price, atr)` OHNE `skalen` liefert **bitgenau** die alten Werte
|
||||||
|
(additiv geprüft).
|
||||||
|
|
||||||
|
⚠⚠ **ZWEI EIGENE PLATZIERUNGSFEHLER beim Bau, beide gefangen:** der Lade-Block
|
||||||
|
landete zuerst **hinter** den `except`-Klauseln von `_load_runtime_state`, wo
|
||||||
|
`st` gar nicht mehr existiert; und beim M15-Setup landete ein Block **mitten in
|
||||||
|
einem mehrzeiligen Aufruf**. Der erste wäre stillschweigend nie gelaufen
|
||||||
|
(`except Exception` hätte ihn geschluckt) — gefunden nur, weil ich die Funktion
|
||||||
|
danach gelesen habe statt dem grünen `py_compile` zu trauen.
|
||||||
|
|
||||||
## ✅ DIE M15-KARTE MISST SICH JETZT SELBST + AUSFÜHRUNGSQUALITÄT SICHTBAR (2026-08-08, v=157)
|
## ✅ DIE M15-KARTE MISST SICH JETZT SELBST + AUSFÜHRUNGSQUALITÄT SICHTBAR (2026-08-08, v=157)
|
||||||
|
|
||||||
Nach Web-Recherche umgesetzt (User-Wahl aus drei Vorschlägen). ⚠ Der dritte
|
Nach Web-Recherche umgesetzt (User-Wahl aus drei Vorschlägen). ⚠ Der dritte
|
||||||
@@ -5927,7 +5969,7 @@ besser) · Teil-Exit bei 1:1 (`_PARTIAL_TP_FRAC=0`, User-Vorgabe).
|
|||||||
(Beobachtungen/Feedback) ergänzt diese Datei.
|
(Beobachtungen/Feedback) ergänzt diese Datei.
|
||||||
- `oil_widget_config.ini` enthält **Live-Secrets** (Keys/Token) — nicht ins
|
- `oil_widget_config.ini` enthält **Live-Secrets** (Keys/Token) — nicht ins
|
||||||
Repo/Logs leaken.
|
Repo/Logs leaken.
|
||||||
- **DB** `oil_widget_history.db` (trades · intended_trades · recommendations · **m15_states** · **candles_m1** · **pbreak_predictions** · **verdict_votes**).
|
- **DB** `oil_widget_history.db` (trades · intended_trades · recommendations · **m15_states** · **cone_checks** · **candles_m1** · **pbreak_predictions** · **verdict_votes**).
|
||||||
Vor jedem Eingriff Backup (`*.bak-<datum>`); Zeitspalten sind lokale Epoch
|
Vor jedem Eingriff Backup (`*.bak-<datum>`); Zeitspalten sind lokale Epoch
|
||||||
(Broker-Offset bereits korrigiert) — **AUSNAHME `candles_m1.time` = ROHE Broker-Zeit
|
(Broker-Offset bereits korrigiert) — **AUSNAHME `candles_m1.time` = ROHE Broker-Zeit
|
||||||
(UTC+3)**, deckungsgleich mit `copy_rates`.
|
(UTC+3)**, deckungsgleich mit `copy_rates`.
|
||||||
|
|||||||
+40
-4
@@ -45,24 +45,60 @@ _ATRMIN = 0.06
|
|||||||
MINUTES = {6: 30, 12: 60, 24: 120}
|
MINUTES = {6: 30, 12: 60, 24: 120}
|
||||||
|
|
||||||
|
|
||||||
def build(price: float, atr: float, bands=(50, 80)) -> dict | None:
|
# ── ADAPTIVE CONFORMAL INFERENCE (2026-08-08) ────────────────────────────────
|
||||||
"""→ {'atr':…, 'levels':[{minutes, bars, band, lo, hi, coverage}, …]}
|
# ⚠⚠ WOZU: die Baender sind oben dokumentiert **3–5 Pp ZU ENG** (80 % nominal →
|
||||||
|
# real 76,7 / 76,6 / 75,3 %). Das stand seit dem 31.07. so da und wurde NICHT
|
||||||
|
# behoben, weil ein Nachfitten das Problem nur verschiebt: die naechste Periode
|
||||||
|
# hat wieder eine andere Vola.
|
||||||
|
# ACI loest genau das — es justiert das Niveau ONLINE nach jedem aufgeloesten
|
||||||
|
# Fenster und konvergiert nachweislich gegen die Zielabdeckung, AUCH unter
|
||||||
|
# Verteilungsdrift (Gibbs & Candes; DtACI schaetzt zusaetzlich gamma selbst).
|
||||||
|
#
|
||||||
|
# ⚠ EHRLICH ZUR BAUART: die Lehrbuch-Form justiert `alpha` und schlaegt das
|
||||||
|
# zugehoerige Quantil nach. Hier liegt nur eine feste Quantil-TABELLE vor, kein
|
||||||
|
# vollstaendiges Verteilungsobjekt — deshalb die **multiplikative Variante**:
|
||||||
|
# ein Skalenfaktor je Horizont, aktualisiert als
|
||||||
|
# s <- s * exp(gamma * (1{verfehlt} - alpha_ziel))
|
||||||
|
# Verfehlt das Fenster oefter als alpha_ziel, waechst s (Band wird breiter),
|
||||||
|
# sonst schrumpft es. Dieselbe Regelungsidee, aber die Konvergenz-GARANTIE der
|
||||||
|
# Originalform ist damit NICHT woertlich uebertragen — es ist ACI im Geiste.
|
||||||
|
_ACI_GAMMA = 0.02 # Schrittweite (Literatur ~0,005–0,05)
|
||||||
|
_ACI_MIN, _ACI_MAX = 0.7, 2.0 # Skalen-Deckel gegen Ausreisser/Endlos-Drift
|
||||||
|
|
||||||
|
|
||||||
|
def aci_update(skala: float, verfehlt: bool, band: int = 80,
|
||||||
|
gamma: float = _ACI_GAMMA) -> float:
|
||||||
|
"""Ein ACI-Schritt. `verfehlt` = der Kurs lag AUSSERHALB des Bandes."""
|
||||||
|
ziel = 1.0 - band / 100.0 # z. B. 0,20 bei 80 %
|
||||||
|
import math
|
||||||
|
s = skala * math.exp(gamma * ((1.0 if verfehlt else 0.0) - ziel))
|
||||||
|
return max(_ACI_MIN, min(_ACI_MAX, s))
|
||||||
|
|
||||||
|
|
||||||
|
def build(price: float, atr: float, bands=(50, 80),
|
||||||
|
skalen: dict | None = None) -> dict | None:
|
||||||
|
"""→ {'atr':…, 'levels':[{minutes, bars, band, lo, hi, coverage, skala}, …]}
|
||||||
|
|
||||||
`price` = aktueller Kurs (Bid), `atr` = ATR der M5-Basis.
|
`price` = aktueller Kurs (Bid), `atr` = ATR der M5-Basis.
|
||||||
|
`skalen` = {bars: Faktor} aus ACI; ohne Angabe bleibt alles wie bisher
|
||||||
|
(⚠ ADDITIV — ein Aufruf ohne `skalen` liefert bitgenau die alten Werte).
|
||||||
"""
|
"""
|
||||||
if not price or not atr or atr <= 0:
|
if not price or not atr or atr <= 0:
|
||||||
return None
|
return None
|
||||||
a = max(float(atr), _ATRMIN)
|
a = max(float(atr), _ATRMIN)
|
||||||
|
sk = skalen or {}
|
||||||
out = []
|
out = []
|
||||||
for bars in sorted(_CONE):
|
for bars in sorted(_CONE):
|
||||||
for band in bands:
|
for band in bands:
|
||||||
q = _CONE[bars].get(band)
|
q = _CONE[bars].get(band)
|
||||||
if not q:
|
if not q:
|
||||||
continue
|
continue
|
||||||
|
s = float(sk.get(bars) or sk.get(str(bars)) or 1.0)
|
||||||
out.append({
|
out.append({
|
||||||
"minutes": MINUTES[bars], "bars": bars, "band": band,
|
"minutes": MINUTES[bars], "bars": bars, "band": band,
|
||||||
"lo": round(price + q[0] * a, 3),
|
"lo": round(price + q[0] * a * s, 3),
|
||||||
"hi": round(price + q[1] * a, 3),
|
"hi": round(price + q[1] * a * s, 3),
|
||||||
"coverage": _COVERAGE.get(bars, {}).get(band),
|
"coverage": _COVERAGE.get(bars, {}).get(band),
|
||||||
|
"skala": round(s, 3),
|
||||||
})
|
})
|
||||||
return {"atr": round(a, 4), "price": round(float(price), 3), "levels": out}
|
return {"atr": round(a, 4), "price": round(float(price), 3), "levels": out}
|
||||||
|
|||||||
+101
-2
@@ -698,6 +698,9 @@ class TradingEngine:
|
|||||||
# geschlossen hat.
|
# geschlossen hat.
|
||||||
try: self._evaluate_m15_states() # ~alle 5 min, self-throttled
|
try: self._evaluate_m15_states() # ~alle 5 min, self-throttled
|
||||||
except Exception as me: log.warning(f"m15_states: {me}")
|
except Exception as me: log.warning(f"m15_states: {me}")
|
||||||
|
# Kegel-Abdeckung + ACI-Nachjustierung (2026-08-08)
|
||||||
|
try: self._evaluate_cone_checks()
|
||||||
|
except Exception as ce: log.warning(f"cone_checks: {ce}")
|
||||||
# Wirtschaftskalender (self-throttled ~1 h, außerhalb des mt5_lock
|
# Wirtschaftskalender (self-throttled ~1 h, außerhalb des mt5_lock
|
||||||
# unkritisch — reiner HTTP-Fetch mit Timeout)
|
# unkritisch — reiner HTTP-Fetch mit Timeout)
|
||||||
# HL-Kontext (Funding/OI/Premium) — reine Anzeige.
|
# HL-Kontext (Funding/OI/Premium) — reine Anzeige.
|
||||||
@@ -2101,6 +2104,13 @@ class TradingEngine:
|
|||||||
from core.config import set_margin_buffer as _setp, get_margin_buffer
|
from core.config import set_margin_buffer as _setp, get_margin_buffer
|
||||||
_setp(float(st["margin_pct"] or 0) or 95.0)
|
_setp(float(st["margin_pct"] or 0) or 95.0)
|
||||||
self._margin_pct = round(get_margin_buffer() * 100.0, 1)
|
self._margin_pct = round(get_margin_buffer() * 100.0, 1)
|
||||||
|
if "cone_skalen" in st:
|
||||||
|
# ⚠ JSON liefert String-Schluessel → auf int zurueckholen, sonst
|
||||||
|
# findet `cone.build` sie nicht (es sucht nach `bars` als int).
|
||||||
|
# ⚠ Der Block MUSS im `try` stehen: der erste Entwurf landete
|
||||||
|
# hinter den except-Klauseln, wo `st` gar nicht mehr existiert.
|
||||||
|
self._cone_skalen = {int(k): float(v)
|
||||||
|
for k, v in (st["cone_skalen"] or {}).items()}
|
||||||
log.info(f"Runtime-State geladen: BRK={'AN' if self._auto_squeeze else 'aus'} · "
|
log.info(f"Runtime-State geladen: BRK={'AN' if self._auto_squeeze else 'aus'} · "
|
||||||
f"S/R-Close={'AN' if self._auto_sr_close else 'aus'} · "
|
f"S/R-Close={'AN' if self._auto_sr_close else 'aus'} · "
|
||||||
f"MinGewinn={self._sr_close_min_gain:+.2f} · "
|
f"MinGewinn={self._sr_close_min_gain:+.2f} · "
|
||||||
@@ -2121,7 +2131,15 @@ class TradingEngine:
|
|||||||
"auto_sr_close": self._auto_sr_close,
|
"auto_sr_close": self._auto_sr_close,
|
||||||
"sr_close_min_gain": self._sr_close_min_gain,
|
"sr_close_min_gain": self._sr_close_min_gain,
|
||||||
"manual_margin": getattr(self, "_manual_margin", 0.0),
|
"manual_margin": getattr(self, "_manual_margin", 0.0),
|
||||||
"margin_pct": getattr(self, "_margin_pct", 0.0)}, f)
|
"margin_pct": getattr(self, "_margin_pct", 0.0),
|
||||||
|
# Kegel-ACI-Skalen (2026-08-08): ohne Persistenz waere
|
||||||
|
# die muehsam erlernte Kalibrierung nach jedem Neustart
|
||||||
|
# weg und liefe von 1,0 neu an. ⚠ JSON-Schluessel sind
|
||||||
|
# Strings — `cone.build` und der ACI-Schritt lesen
|
||||||
|
# deshalb beide Formen (int UND str).
|
||||||
|
"cone_skalen": {str(k): v for k, v in
|
||||||
|
(getattr(self, "_cone_skalen", None)
|
||||||
|
or {}).items()}}, f)
|
||||||
os.replace(tmp, self._runtime_state_path)
|
os.replace(tmp, self._runtime_state_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.warning(f"runtime_state speichern: {e}")
|
log.warning(f"runtime_state speichern: {e}")
|
||||||
@@ -3503,6 +3521,85 @@ class TradingEngine:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug(f"m15_state log: {e}")
|
log.debug(f"m15_state log: {e}")
|
||||||
|
|
||||||
|
def _log_cone_check(self, cone: dict | None):
|
||||||
|
"""Legt je Horizont EINEN nicht-ueberlappenden Abdeckungs-Check an.
|
||||||
|
|
||||||
|
⚠⚠ NICHT-UEBERLAPPEND ist hier kein Detail: ein 120-min-Fenster alle
|
||||||
|
5 min waere 24-fach ueberlappend. Genau daran ist `analyze_hl_funding.py`
|
||||||
|
(06.08.) aufgelaufen, und die Faelligkeitsbedingung `pbreak_accuracy_v2`
|
||||||
|
ueberschaetzte damit die Beweismenge um das Zehnfache (07.08.). Ein neuer
|
||||||
|
Check startet je Horizont erst, wenn der vorige abgelaufen ist."""
|
||||||
|
try:
|
||||||
|
if not cone or not self.history:
|
||||||
|
return
|
||||||
|
now = time.time()
|
||||||
|
letzte = getattr(self, "_cone_check_ts", None)
|
||||||
|
if letzte is None:
|
||||||
|
letzte = self._cone_check_ts = {}
|
||||||
|
for lv in cone.get("levels") or []:
|
||||||
|
if lv.get("band") != 80:
|
||||||
|
continue
|
||||||
|
b = lv.get("bars")
|
||||||
|
fenster = (lv.get("minutes") or 0) * 60
|
||||||
|
if not b or not fenster:
|
||||||
|
continue
|
||||||
|
if now - letzte.get(b, 0.0) < fenster:
|
||||||
|
continue # voriger Check laeuft noch
|
||||||
|
letzte[b] = now
|
||||||
|
self.history.log_cone_check(
|
||||||
|
bars=b, band=80, price=cone.get("price") or 0.0,
|
||||||
|
lo=lv["lo"], hi=lv["hi"], skala=lv.get("skala") or 1.0)
|
||||||
|
except Exception as e:
|
||||||
|
log.debug(f"cone_check log: {e}")
|
||||||
|
|
||||||
|
def _evaluate_cone_checks(self):
|
||||||
|
"""Loest faellige Kegel-Checks auf und fuehrt den ACI-Schritt aus.
|
||||||
|
|
||||||
|
⚠ Der Kegel war dokumentiert **3–5 Pp zu eng** (80 % nominal → real
|
||||||
|
76,7 / 76,6 / 75,3 %) und blieb es seit dem 31.07., weil Nachfitten das
|
||||||
|
Problem nur verschiebt. ACI justiert stattdessen laufend nach.
|
||||||
|
⚠ `candles_m1.time` ist ROHE Broker-Zeit — Offset noetig."""
|
||||||
|
now = time.time()
|
||||||
|
if now - getattr(self, "_cone_eval_ts", 0.0) < 300:
|
||||||
|
return
|
||||||
|
self._cone_eval_ts = now
|
||||||
|
try:
|
||||||
|
import sqlite3
|
||||||
|
from core.cone import MINUTES, aci_update
|
||||||
|
off = self.trader._broker_offset_s()
|
||||||
|
con = sqlite3.connect(HISTORY_DB_FILE, timeout=5.0)
|
||||||
|
con.row_factory = sqlite3.Row
|
||||||
|
offen = con.execute(
|
||||||
|
"SELECT id, ts, bars, band, lo, hi, skala FROM cone_checks "
|
||||||
|
"WHERE done IS NULL OR done = 0").fetchall()
|
||||||
|
skalen = dict(getattr(self, "_cone_skalen", {}) or {})
|
||||||
|
for r in offen:
|
||||||
|
ziel = r["ts"] + MINUTES.get(r["bars"], 30) * 60
|
||||||
|
if now < ziel:
|
||||||
|
continue
|
||||||
|
row = con.execute(
|
||||||
|
"SELECT c FROM candles_m1 WHERE time <= ? AND time > ? "
|
||||||
|
"ORDER BY time DESC LIMIT 1",
|
||||||
|
(ziel + off, ziel + off - 900)).fetchone()
|
||||||
|
if not row:
|
||||||
|
if now >= r["ts"] + 6 * 3600: # keine Bars mehr zu erwarten
|
||||||
|
con.execute("UPDATE cone_checks SET done=1 WHERE id=?", (r["id"],))
|
||||||
|
continue
|
||||||
|
drin = 1 if r["lo"] <= row["c"] <= r["hi"] else 0
|
||||||
|
con.execute("UPDATE cone_checks SET drin=?, done=1 WHERE id=?",
|
||||||
|
(drin, r["id"]))
|
||||||
|
s = float(skalen.get(r["bars"]) or 1.0)
|
||||||
|
skalen[r["bars"]] = aci_update(s, verfehlt=(drin == 0),
|
||||||
|
band=r["band"] or 80)
|
||||||
|
con.commit(); con.close()
|
||||||
|
if skalen != getattr(self, "_cone_skalen", None):
|
||||||
|
self._cone_skalen = skalen
|
||||||
|
self._save_runtime_state() # Neustart-fest
|
||||||
|
log.info("Kegel-ACI: Skalen " + ", ".join(
|
||||||
|
f"{k}→{v:.3f}" for k, v in sorted(skalen.items())))
|
||||||
|
except Exception as e:
|
||||||
|
log.debug(f"cone_checks auswerten: {e}")
|
||||||
|
|
||||||
def _evaluate_m15_states(self):
|
def _evaluate_m15_states(self):
|
||||||
"""Traegt den Forward-Return offener M15-Zustaende nach.
|
"""Traegt den Forward-Return offener M15-Zustaende nach.
|
||||||
|
|
||||||
@@ -3771,7 +3868,8 @@ class TradingEngine:
|
|||||||
stop_approach = self._stop_approach_hint(market, position, wave_snap)
|
stop_approach = self._stop_approach_hint(market, position, wave_snap)
|
||||||
_cone = _cone_build(
|
_cone = _cone_build(
|
||||||
(market or {}).get("bid"),
|
(market or {}).get("bid"),
|
||||||
float(((wave_snap or {}).get("pb_feats") or {}).get("atr") or 0.0))
|
float(((wave_snap or {}).get("pb_feats") or {}).get("atr") or 0.0),
|
||||||
|
skalen=getattr(self, "_cone_skalen", None))
|
||||||
# M15-Setup EINMAL rechnen (nicht im Dict), damit die Selbstmessung
|
# M15-Setup EINMAL rechnen (nicht im Dict), damit die Selbstmessung
|
||||||
# daran haengen kann — ein zweiter Aufruf waere Arbeit fuer dieselben
|
# daran haengen kann — ein zweiter Aufruf waere Arbeit fuer dieselben
|
||||||
# Zahlen (der Konsens-Pfeil-Fehler).
|
# Zahlen (der Konsens-Pfeil-Fehler).
|
||||||
@@ -3783,6 +3881,7 @@ class TradingEngine:
|
|||||||
_m15 = self._m15_setup(market, wave_snap, _cone,
|
_m15 = self._m15_setup(market, wave_snap, _cone,
|
||||||
self._alignment_cached())
|
self._alignment_cached())
|
||||||
self._log_m15_state(_m15, market)
|
self._log_m15_state(_m15, market)
|
||||||
|
self._log_cone_check(_cone)
|
||||||
# Für den KI-Copiloten festhalten (2026-08-02) — er bekam bis dahin nur
|
# Für den KI-Copiloten festhalten (2026-08-02) — er bekam bis dahin nur
|
||||||
# das Wellen-Signal und sah ausgerechnet die beiden kalibrierten Größen
|
# das Wellen-Signal und sah ausgerechnet die beiden kalibrierten Größen
|
||||||
# des Projekts nicht. Hier nur ZUWEISEN, nicht neu rechnen.
|
# des Projekts nicht. Hier nur ZUWEISEN, nicht neu rechnen.
|
||||||
|
|||||||
@@ -189,6 +189,26 @@ SCHEMA = [
|
|||||||
)
|
)
|
||||||
""",
|
""",
|
||||||
"""
|
"""
|
||||||
|
-- KEGEL-ABDECKUNG fuer Adaptive Conformal Inference (2026-08-08).
|
||||||
|
-- ⚠ NICHT-UEBERLAPPEND je Horizont geloggt: ein 120-min-Fenster alle 5 min
|
||||||
|
-- waere 24-fach ueberlappend, und ueberlappende Beobachtungen haben genau
|
||||||
|
-- die Cluster-Verzerrung erzeugt, an der `analyze_hl_funding.py` (06.08.)
|
||||||
|
-- und die Faelligkeitsbedingung `pbreak_accuracy_v2` (07.08.) aufgelaufen
|
||||||
|
-- sind. Je Horizont startet ein neuer Check erst, wenn der vorige ablief.
|
||||||
|
CREATE TABLE IF NOT EXISTS cone_checks (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
ts INTEGER, -- lokale Epoch
|
||||||
|
bars INTEGER, -- Horizont in M5-Bars (6/12/24)
|
||||||
|
band INTEGER, -- Nennband in % (80)
|
||||||
|
price REAL,
|
||||||
|
lo REAL,
|
||||||
|
hi REAL,
|
||||||
|
skala REAL, -- ACI-Skala, mit der dieses Band gebaut wurde
|
||||||
|
drin INTEGER, -- 1 = Kurs lag im Band
|
||||||
|
done INTEGER
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS verdict_votes (
|
CREATE TABLE IF NOT EXISTS verdict_votes (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
ts INTEGER, -- lokale Epoch
|
ts INTEGER, -- lokale Epoch
|
||||||
@@ -486,6 +506,35 @@ class HistoryLogger:
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
return cur.lastrowid
|
return cur.lastrowid
|
||||||
|
|
||||||
|
def log_cone_check(self, *, bars: int, band: int, price: float,
|
||||||
|
lo: float, hi: float, skala: float) -> int:
|
||||||
|
"""Legt EINEN Abdeckungs-Check des Kegels an (nicht-ueberlappend)."""
|
||||||
|
try:
|
||||||
|
with self._lock, self._connect() as conn:
|
||||||
|
cur = conn.execute("""
|
||||||
|
INSERT INTO cone_checks (ts,bars,band,price,lo,hi,skala)
|
||||||
|
VALUES (?,?,?,?,?,?,?)
|
||||||
|
""", (int(time.time()), int(bars), int(band), float(price),
|
||||||
|
float(lo), float(hi), float(skala)))
|
||||||
|
conn.commit()
|
||||||
|
return cur.lastrowid
|
||||||
|
except Exception:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def cone_coverage(self, bars: int, last_n: int = 100) -> dict:
|
||||||
|
"""Real gemessene Abdeckung der letzten `last_n` Checks eines Horizonts."""
|
||||||
|
try:
|
||||||
|
with self._lock, self._connect() as conn:
|
||||||
|
rows = conn.execute(
|
||||||
|
"SELECT drin FROM cone_checks WHERE bars=? AND done=1 "
|
||||||
|
"ORDER BY id DESC LIMIT ?", (int(bars), int(last_n))).fetchall()
|
||||||
|
except Exception:
|
||||||
|
return {"n": 0}
|
||||||
|
n = len(rows)
|
||||||
|
if not n:
|
||||||
|
return {"n": 0}
|
||||||
|
return {"n": n, "abdeckung": round(100 * sum(r[0] for r in rows) / n, 1)}
|
||||||
|
|
||||||
def log_m15_state(self, *, status: str, veto, kosten, level, gap_atr,
|
def log_m15_state(self, *, status: str, veto, kosten, level, gap_atr,
|
||||||
p_break, lesart, price, atr) -> int:
|
p_break, lesart, price, atr) -> int:
|
||||||
"""Loggt EINEN Zustandswechsel der M15-Karte.
|
"""Loggt EINEN Zustandswechsel der M15-Karte.
|
||||||
|
|||||||
+8
-1
@@ -572,10 +572,17 @@ function renderCone(cn) {
|
|||||||
.sort((a, b) => a.minutes - b.minutes);
|
.sort((a, b) => a.minutes - b.minutes);
|
||||||
if (!b80.length) { el.innerHTML = ""; return; }
|
if (!b80.length) { el.innerHTML = ""; return; }
|
||||||
const cov = b80[0].coverage != null ? `${fmt(b80[0].coverage, 0)} %` : "~";
|
const cov = b80[0].coverage != null ? `${fmt(b80[0].coverage, 0)} %` : "~";
|
||||||
|
// ⚠ ACI (2026-08-08): die Bänder waren dokumentiert 3–5 Pp ZU ENG (80 %
|
||||||
|
// nominal → real 76,7/76,6/75,3). Adaptive Conformal Inference justiert das
|
||||||
|
// jetzt online nach; die Skala zeigt, wie stark. 1,00 = noch unverändert.
|
||||||
|
const sk = b80.map(x => x.skala).filter(v => v != null);
|
||||||
|
const skTxt = (sk.length && sk.some(v => Math.abs(v - 1) > 0.005))
|
||||||
|
? `<span class="kx-cone-cov">ACI ×${fmt(sk.reduce((a, b) => a + b, 0) / sk.length, 2)}</span>`
|
||||||
|
: "";
|
||||||
el.innerHTML = `<span class="kx-cone-lbl">📐 erwartete Spanne</span>`
|
el.innerHTML = `<span class="kx-cone-lbl">📐 erwartete Spanne</span>`
|
||||||
+ b80.map(x => `<span class="kx-cone-item"><i>${x.minutes}′</i>`
|
+ b80.map(x => `<span class="kx-cone-item"><i>${x.minutes}′</i>`
|
||||||
+ `${fmt(x.lo, 2)}–${fmt(x.hi, 2)}</span>`).join("")
|
+ `${fmt(x.lo, 2)}–${fmt(x.hi, 2)}</span>`).join("")
|
||||||
+ `<span class="kx-cone-cov">trifft ${cov}</span>`;
|
+ `<span class="kx-cone-cov">trifft ${cov}</span>` + skTxt;
|
||||||
// Die Einordnung gehört an die Zahl, nicht in einen Absatz darunter — sonst
|
// Die Einordnung gehört an die Zahl, nicht in einen Absatz darunter — sonst
|
||||||
// liest jemand die Spanne als Richtungsprognose.
|
// liest jemand die Spanne als Richtungsprognose.
|
||||||
el.title = "STREUUNG, nicht Richtung: wie WEIT der Kurs plausibel läuft, nicht "
|
el.title = "STREUUNG, nicht Richtung: wie WEIT der Kurs plausibel läuft, nicht "
|
||||||
|
|||||||
+2
-2
@@ -6,7 +6,7 @@
|
|||||||
<meta name="theme-color" content="#0d1117">
|
<meta name="theme-color" content="#0d1117">
|
||||||
<title>Oil · MT5</title>
|
<title>Oil · MT5</title>
|
||||||
<link rel="manifest" href="manifest.json">
|
<link rel="manifest" href="manifest.json">
|
||||||
<link rel="stylesheet" href="style.css?v=157">
|
<link rel="stylesheet" href="style.css?v=158">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Modul-Menü (ganz oben) -->
|
<!-- Modul-Menü (ganz oben) -->
|
||||||
@@ -347,6 +347,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="toast" class="toast hidden"></div>
|
<div id="toast" class="toast hidden"></div>
|
||||||
|
|
||||||
<script src="app.js?v=157"></script>
|
<script src="app.js?v=158"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user