S/R-Auto-Close komplett entfernt + Circuit-Breaker als runder CB-Knopf (v=210)
(1) S/R-AUTO-CLOSE RAUS (User-Vorgabe: "die brauche ich nicht mehr").
Der Schalter stand seit dem 19.08. ohnehin auf AUS - abgeschaltet, nachdem
analyze_pbreak_live.py das P(break)-Modell live als INVERTIERT gemessen hatte
(AUC 0,452, Klassen monoton rueckwaerts). Ohne funktionierendes Gate ist der
S/R-Close faktisch der PAUSCHALE, und der ist 2x gemessen und verworfen
(Gewinner-Kappen). Die Entfernung vollzieht den gemessenen Stand nach.
WEG: _check_sr_close, set_sr_autoclose, set_sr_close_min_gain, die
Konstruktor-Felder, die %-Armierung des Gewinn-Close, drei Snapshot-Felder,
beide runtime_state-Schluessel, die Reichweiten- und Systemstatus-Zeilen,
/api/srclose und /api/srclose_min, der Knopf S/R, das Gewinn-Close-Feld, der
Toast "Bot hat am Level geschlossen".
BLEIBT: `_sr_close_hint` (App-Hinweis, P(break)-Chartlinien, Copilot-Kontext,
pbreak_predictions-Tracking), `stop_approach`, das Modell selbst und die
closed_by=sr_close-Historie in der DB. Live gegengeprueft: die drei Felder sind
aus dem Snapshot verschwunden, sr_close_hint und stop_approach sind da, beide
Endpunkte antworten 405.
Sicherung: .removed_backup/sr_auto_close_2026-08-21.py
⚠ Der Close-Alarm gilt jetzt schlicht ab jedem Gewinn (`minGain = 0`) - die
Schwelle gab es nur fuer den Auto-Close. Das ist der Zustand von vor 2026-07.
⚠ Der Test test_automatik_zeile_nennt_alle_schalter war MITGEZAEHLT und faellt
korrekt - er ist angepasst, nicht entfernt: jetzt zwei Schalter statt drei, und
die Negativ-Pruefungen ("SIG"/"S/R-Close" duerfen NICHT auftauchen) sind der
eigentliche Wert, denn ein wieder auftauchender Pfad waere ein stiller Rueckbau.
(2) CIRCUIT BREAKER als runder Knopf "CB" rechts neben BALANCE.
⚠ Farb-Logik wie vorgegeben: GRUEN = inaktiv (aus), ROT = aktiv (scharf).
Bewusst NICHT die uebliche "gruen = geschuetzt"-Lesart - hier signalisiert Rot,
dass eine Automatik eingreifen kann. Im Code und im Markup steht das dran, damit
es niemand spaeter "korrigiert".
⚠ VERSCHOBEN, nicht kopiert: zwei Elemente mit derselben ID waeren ein stiller
Fehler, weil getElementById nur das erste findet.
⚠ Beim Entfernen zwei eigene Fehler: (a) ein Slice ueber `rindex("try:")`
schnitt durch fremde Konstruktor-Bloecke und riss Kommentar-Fragmente heraus -
zurueckgesetzt und zeilenbasiert von hinten neu gemacht; (b) beim Toast-Block
eine Klammer zu viel entfernt, von `node --check` sofort gefangen.
Pipeline A-G gruen, 97 Tests, 14 render*-Funktionen, deployt und am
ausgelieferten HTML/Snapshot verifiziert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ebf10da00e
commit
0dd2e524b7
+13
-121
@@ -444,14 +444,11 @@ class TradingEngine:
|
|||||||
self._close_alert_ts = 0.0 # letzter CLOSE-Telegram-Push (5-min-Cooldown)
|
self._close_alert_ts = 0.0 # letzter CLOSE-Telegram-Push (5-min-Cooldown)
|
||||||
self._close_alert_ticket = None # Ticket, auf das sich der Cooldown bezieht
|
self._close_alert_ticket = None # Ticket, auf das sich der Cooldown bezieht
|
||||||
self._close_alert_count = 0 # wie oft der Flip-Close-Alarm gefeuert hat
|
self._close_alert_count = 0 # wie oft der Flip-Close-Alarm gefeuert hat
|
||||||
self._auto_sr_close = self.cfg["trading"].get("auto_sr_close", "true").lower() == "true"
|
|
||||||
try:
|
try:
|
||||||
self._sr_close_pbreak = float(self.cfg["trading"].get("sr_close_pbreak", "0.60"))
|
self._sr_close_pbreak = float(self.cfg["trading"].get("sr_close_pbreak", "0.60"))
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
self._sr_close_pbreak = 0.60
|
self._sr_close_pbreak = 0.60
|
||||||
self._sr_close_pbreak = max(0.30, min(0.90, self._sr_close_pbreak)) # sinnvolles Band
|
self._sr_close_pbreak = max(0.30, min(0.90, self._sr_close_pbreak)) # sinnvolles Band
|
||||||
self._sr_close_count = 0 # wie oft der Bot am S/R automatisch schloss
|
|
||||||
self._sr_close_last_ticket = None # verhindert Doppel-Auslösung je Ticket
|
|
||||||
# Autonomer Entry auf den gemessen-validierten Squeeze-Ausbruch (nur FLAT).
|
# Autonomer Entry auf den gemessen-validierten Squeeze-Ausbruch (nur FLAT).
|
||||||
# ⚠ ECHTE Order — Default AUS (Autonomie nie stillschweigend an). `[trading]
|
# ⚠ ECHTE Order — Default AUS (Autonomie nie stillschweigend an). `[trading]
|
||||||
# auto_squeeze=true` aktiviert. Dedup über (dir, level) des Ausbruchs.
|
# auto_squeeze=true` aktiviert. Dedup über (dir, level) des Ausbruchs.
|
||||||
@@ -575,24 +572,6 @@ class TradingEngine:
|
|||||||
self._flip_close_count = 0
|
self._flip_close_count = 0
|
||||||
self._pos_close_dir = None # Art) → Squeeze-Wiedereinstiegs-Sperre (gegen die
|
self._pos_close_dir = None # Art) → Squeeze-Wiedereinstiegs-Sperre (gegen die
|
||||||
# Open→Instant-Close-Kaskade bei zu engem Notfall-Stop)
|
# Open→Instant-Close-Kaskade bei zu engem Notfall-Stop)
|
||||||
self._sr_close_min_gain_armed_ticket = None # Ticket, für das die %-Schwelle schon
|
|
||||||
# aus echter Margin berechnet wurde (Retry-Schutz,
|
|
||||||
# s. `_check_auto_close`)
|
|
||||||
try:
|
|
||||||
self._sr_close_min_gain = max(0.0, float(
|
|
||||||
self.cfg["trading"].get("sr_close_min_gain", "0")))
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
self._sr_close_min_gain = 0.0
|
|
||||||
# Gewinn-Close automatisch auf X% des Einsatzes (Margin) DIESER Position setzen,
|
|
||||||
# sobald sie eröffnet wird (User-Vorgabe 2026-07-23) — überschreibt den manuell
|
|
||||||
# gemerkten/persistierten Wert bei jeder ECHT NEUEN Position (nicht beim
|
|
||||||
# Wiedererkennen nach Neustart, s. `_check_auto_close`). 0 = aus (dann bleibt der
|
|
||||||
# manuell gesetzte/gemerkte Wert wie bisher maßgeblich).
|
|
||||||
try:
|
|
||||||
self._sr_close_min_gain_pct = max(0.0, float(
|
|
||||||
self.cfg["trading"].get("sr_close_min_gain_pct", "1.0")))
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
self._sr_close_min_gain_pct = 1.0
|
|
||||||
self._pb_state = None # geglättetes P(break) + Hysterese-Zone je Level
|
self._pb_state = None # geglättetes P(break) + Hysterese-Zone je Level
|
||||||
self._stop_pb_state = None # dito für die Gegen-/Stop-Seiten-Anzeige
|
self._stop_pb_state = None # dito für die Gegen-/Stop-Seiten-Anzeige
|
||||||
# (gemessen `analyze_pbreak_flicker.py`: mom3 der
|
# (gemessen `analyze_pbreak_flicker.py`: mom3 der
|
||||||
@@ -946,7 +925,6 @@ class TradingEngine:
|
|||||||
self._check_slot_reichweite() # meldet ungedeckte 2. Position
|
self._check_slot_reichweite() # meldet ungedeckte 2. Position
|
||||||
self._check_adverse15() # 15-Min-Regel (nur Bot-Trades)
|
self._check_adverse15() # 15-Min-Regel (nur Bot-Trades)
|
||||||
self._check_flip_close() # Empfehlung dreht → schließen
|
self._check_flip_close() # Empfehlung dreht → schließen
|
||||||
self._check_sr_close()
|
|
||||||
# ZUERST die ruhenden Stop-Orders pflegen (setzen/stornieren),
|
# ZUERST die ruhenden Stop-Orders pflegen (setzen/stornieren),
|
||||||
# DANN der Market-Fallback: so kann eine bereits liegende Order
|
# DANN der Market-Fallback: so kann eine bereits liegende Order
|
||||||
# den Ausbruch am Level abfangen, bevor nachgejagt würde.
|
# den Ausbruch am Level abfangen, bevor nachgejagt würde.
|
||||||
@@ -1202,8 +1180,6 @@ class TradingEngine:
|
|||||||
or (getattr(self, "_emergency_pct", 0) or 0) > 0
|
or (getattr(self, "_emergency_pct", 0) or 0) > 0
|
||||||
or (getattr(self, "_emergency_remember", 0) or 0) > 0):
|
or (getattr(self, "_emergency_remember", 0) or 0) > 0):
|
||||||
offen.append("Notfall-Stop")
|
offen.append("Notfall-Stop")
|
||||||
if getattr(self, "_auto_sr_close", False):
|
|
||||||
offen.append("S/R-Close")
|
|
||||||
if (getattr(self, "_adverse15_atr", 0) or 0) > 0:
|
if (getattr(self, "_adverse15_atr", 0) or 0) > 0:
|
||||||
offen.append("15-Min-Regel")
|
offen.append("15-Min-Regel")
|
||||||
if getattr(self, "_flip_close", False):
|
if getattr(self, "_flip_close", False):
|
||||||
@@ -1321,7 +1297,6 @@ class TradingEngine:
|
|||||||
# bei offenem Trade kappte sonst die von Hand gesetzten −25 € auf −19,42).
|
# bei offenem Trade kappte sonst die von Hand gesetzten −25 € auf −19,42).
|
||||||
self._emergency_loss = self._emergency_state_loss
|
self._emergency_loss = self._emergency_state_loss
|
||||||
self._takeprofit = self._emergency_state_tp
|
self._takeprofit = self._emergency_state_tp
|
||||||
self._sr_close_min_gain_armed_ticket = ticket # wiederhergestellter Wert
|
|
||||||
# gilt als final — NICHT auf 1% zurücksetzen
|
# gilt als final — NICHT auf 1% zurücksetzen
|
||||||
self._emergency_margin_armed_ticket = ticket # dito für den margin-%-Stop
|
self._emergency_margin_armed_ticket = ticket # dito für den margin-%-Stop
|
||||||
log.info(f"Auto-Close wiederhergestellt (Pos {ticket}): Stop "
|
log.info(f"Auto-Close wiederhergestellt (Pos {ticket}): Stop "
|
||||||
@@ -1359,16 +1334,8 @@ class TradingEngine:
|
|||||||
# umgesetzt, der Ticket-Wechsel-Zweig feuert nur 1×) — konnte den Trade zu
|
# umgesetzt, der Ticket-Wechsel-Zweig feuert nur 1×) — konnte den Trade zu
|
||||||
# früh (falscher, zu niedriger Alt-Wert) ODER dauerhaft mit falscher Schwelle
|
# früh (falscher, zu niedriger Alt-Wert) ODER dauerhaft mit falscher Schwelle
|
||||||
# laufen lassen.
|
# laufen lassen.
|
||||||
if (self._sr_close_min_gain_pct > 0
|
# ⚠ Die automatische %-Armierung des Gewinn-Close ist am 2026-08-21
|
||||||
and self._sr_close_min_gain_armed_ticket != ticket):
|
# mit dem S/R-Auto-Close entfallen — sie diente ausschliesslich ihm.
|
||||||
margin = ps.get("margin") or 0.0
|
|
||||||
if margin > 0:
|
|
||||||
self._sr_close_min_gain = round(
|
|
||||||
self._sr_close_min_gain_pct / 100.0 * margin, 2)
|
|
||||||
self._sr_close_min_gain_armed_ticket = ticket
|
|
||||||
self._save_runtime_state()
|
|
||||||
log.info(f"Gewinn-Close armiert (Pos {ticket}): "
|
|
||||||
f"+{self._sr_close_min_gain:.2f} ({self._sr_close_min_gain_pct:.0f}% Margin {margin:.2f})")
|
|
||||||
# Notfall-Stop als % der Margin — gleiches Retry-Muster (margin-Wert kann im
|
# Notfall-Stop als % der Margin — gleiches Retry-Muster (margin-Wert kann im
|
||||||
# ersten Tick nach dem Öffnen noch 0 sein). Hat Vorrang vor Balance-%/Fixwert
|
# ersten Tick nach dem Öffnen noch 0 sein). Hat Vorrang vor Balance-%/Fixwert
|
||||||
# (die im "echt neue Position"-Zweig oben bewusst übersprungen wurden, wenn
|
# (die im "echt neue Position"-Zweig oben bewusst übersprungen wurden, wenn
|
||||||
@@ -1430,62 +1397,17 @@ class TradingEngine:
|
|||||||
self._takeprofit = None
|
self._takeprofit = None
|
||||||
return
|
return
|
||||||
|
|
||||||
def _check_sr_close(self):
|
# ⚠⚠ `_check_sr_close` ENTFERNT am 2026-08-21 (User-Vorgabe). Der Schalter
|
||||||
"""Automatischer S/R-Close (User-Vorgabe): schließt eine Position **im Plus**
|
# stand seit dem 19.08. auf AUS — abgeschaltet, nachdem
|
||||||
selbstständig, wenn die gemessene Bedingung greift (Kurs klebt am gegenüber-
|
# `analyze_pbreak_live.py` das P(break)-Modell live als INVERTIERT gemessen
|
||||||
liegenden Level + schwacher Anlauf → Durchbruch ~26 %, Close schlägt Laufen-
|
# hatte (AUC 0,452, Klassen monoton rueckwaerts). Ohne funktionierendes
|
||||||
lassen; `backtest_srbreak.py`). Nur bei `auto_sr_close=true`, genau 1×/Ticket,
|
# Gate ist der S/R-Close faktisch der PAUSCHALE, und der ist 2x gemessen
|
||||||
wirkt auch bei gesperrtem Handy. Fail-safe."""
|
# und verworfen (Gewinner-Kappen). Die Entfernung vollzieht den gemessenen
|
||||||
if not self._auto_sr_close:
|
# Stand nach; sie schaltet nichts ab, was noch lief.
|
||||||
return
|
# ⚠ BLEIBT: `_sr_close_hint` (App-Hinweis, P(break)-Chartlinien,
|
||||||
if self._in_startup_grace(): # Startup-Schonfrist: kein Sofort-Close nach Neustart
|
# Copilot-Kontext, `pbreak_predictions`-Tracking), `stop_approach`, das
|
||||||
return
|
# Modell selbst und die `closed_by=sr_close`-Historie in der DB.
|
||||||
ps = self.trader.snapshot()
|
# Sicherung: `.removed_backup/sr_auto_close_2026-08-21.py`.
|
||||||
ticket = ps.get("ticket")
|
|
||||||
if not ticket:
|
|
||||||
self._sr_close_last_ticket = None
|
|
||||||
return
|
|
||||||
if ticket == self._sr_close_last_ticket: # bereits ausgelöst → nicht erneut
|
|
||||||
return
|
|
||||||
pnl = ps.get("pnl")
|
|
||||||
if pnl is None or pnl <= 0: # NUR bei Trade im Plus (User-Vorgabe)
|
|
||||||
return
|
|
||||||
# Optionaler Mindestgewinn (User-Vorgabe; Default 0=aus — gemessen ist ohne
|
|
||||||
# besser): unter der Schwelle wird am Level NICHT geschlossen, Trade läuft.
|
|
||||||
if self._sr_close_min_gain > 0 and pnl < self._sr_close_min_gain:
|
|
||||||
return
|
|
||||||
hint = self._sr_close_hint(self.data.snapshot(), ps, self.wave.snapshot())
|
|
||||||
if not hint or not hint.get("close"): # am Level, aber P(break) ≥ Schwelle → laufen lassen
|
|
||||||
return
|
|
||||||
self._sr_close_last_ticket = ticket # vor dem Close markieren (kein Doppel)
|
|
||||||
sym = self.data.symbol or ""
|
|
||||||
_confirm = hint.get("confirm")
|
|
||||||
log.info(f"🎯 S/R-AUTO-CLOSE: {sym} P&L {pnl:+.2f} — am Level {hint['level']}, "
|
|
||||||
f"Durchbruch nur ~{hint['p_break']}% (< {self._sr_close_pbreak:.0%})"
|
|
||||||
+ (f" — Bestätigung erst ab {_confirm}" if _confirm else "")
|
|
||||||
+ " → Gewinn sichern")
|
|
||||||
err = self.trader.close(reason="sr_close")
|
|
||||||
tg = self.cfg["telegram"]
|
|
||||||
tg_on = (tg.get("enabled", "false").lower() == "true" and tg.get("bot_token"))
|
|
||||||
if err:
|
|
||||||
log.error(f"S/R-Auto-Close fehlgeschlagen: {err}")
|
|
||||||
self._sr_close_last_ticket = None # Fehlschlag → nächster Tick erneut
|
|
||||||
if tg_on:
|
|
||||||
try: send_telegram(f"⚠ <b>S/R-Close FEHLGESCHLAGEN</b>\n{sym} P&L {pnl:+.2f} "
|
|
||||||
f"— bitte MANUELL schließen! ({err})",
|
|
||||||
tg["bot_token"], tg["chat_id"])
|
|
||||||
except Exception as e: log.warning(f"S/R-Close-Telegram (Fehler): {e}")
|
|
||||||
return
|
|
||||||
# Richtung + Zeit merken → Auto-Squeeze-Cooldown gegen Gleichrichtungs-Roundtrip
|
|
||||||
self._sr_close_dir = "LONG" if ps.get("order_type") == 0 else "SHORT"
|
|
||||||
self._sr_close_ts = time.time()
|
|
||||||
self._sr_close_count += 1
|
|
||||||
if tg_on:
|
|
||||||
try: send_telegram(f"🎯 <b>S/R-Auto-Close</b>\n{sym} bei P&L {pnl:+.2f} geschlossen "
|
|
||||||
f"— Kurs klebte am Level {hint['level']} mit schwachem Anlauf "
|
|
||||||
f"(Durchbruch ~{hint['p_break']}% unwahrscheinlich).",
|
|
||||||
tg["bot_token"], tg["chat_id"])
|
|
||||||
except Exception as e: log.warning(f"S/R-Close-Telegram: {e}")
|
|
||||||
|
|
||||||
def _auto_guard(self, pfad: str) -> str | None:
|
def _auto_guard(self, pfad: str) -> str | None:
|
||||||
"""Die NICHT richtungsabhängigen Gates für autonome Entries.
|
"""Die NICHT richtungsabhängigen Gates für autonome Entries.
|
||||||
@@ -2174,24 +2096,6 @@ class TradingEngine:
|
|||||||
tg["bot_token"], tg["chat_id"])
|
tg["bot_token"], tg["chat_id"])
|
||||||
except Exception as e: log.warning(f"Adverse15-Telegram: {e}")
|
except Exception as e: log.warning(f"Adverse15-Telegram: {e}")
|
||||||
|
|
||||||
def set_sr_autoclose(self, on: bool) -> bool:
|
|
||||||
"""Automatischen S/R-Close an/aus (UI/Config). Rückgabe = neuer Zustand."""
|
|
||||||
self._auto_sr_close = bool(on)
|
|
||||||
log.info(f"Auto-S/R-Close {'AN' if self._auto_sr_close else 'AUS'}")
|
|
||||||
self._save_runtime_state()
|
|
||||||
return self._auto_sr_close
|
|
||||||
|
|
||||||
def set_sr_close_min_gain(self, value) -> float:
|
|
||||||
"""Mindestgewinn (EUR) für den S/R-Auto-Close. 0/leer = aus."""
|
|
||||||
try:
|
|
||||||
v = max(0.0, float(value)) if value not in (None, "") else 0.0
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
v = 0.0
|
|
||||||
self._sr_close_min_gain = v
|
|
||||||
log.info(f"S/R-Close-Mindestgewinn {('+' + format(v, '.2f')) if v > 0 else 'aus'}")
|
|
||||||
self._save_runtime_state() # neustart-fest (Fix 2026-07-22 — war vergessen)
|
|
||||||
return self._sr_close_min_gain
|
|
||||||
|
|
||||||
def set_sltp(self, sl=None, tp=None) -> dict:
|
def set_sltp(self, sl=None, tp=None) -> dict:
|
||||||
"""Manuelles SL/TP der offenen Position setzen. **Deaktiviert das Trailing**
|
"""Manuelles SL/TP der offenen Position setzen. **Deaktiviert das Trailing**
|
||||||
(User-Vorgabe) — sonst zöge es SL/TP beim nächsten Tick wieder um. Rückgabe
|
(User-Vorgabe) — sonst zöge es SL/TP beim nächsten Tick wieder um. Rückgabe
|
||||||
@@ -2731,10 +2635,6 @@ class TradingEngine:
|
|||||||
# ⚠ `auto_signal` wird seit 2026-08-12 NICHT mehr gelesen (Pfad
|
# ⚠ `auto_signal` wird seit 2026-08-12 NICHT mehr gelesen (Pfad
|
||||||
# entfernt). Ein Altbestand in der Datei schadet nicht — er wird
|
# entfernt). Ein Altbestand in der Datei schadet nicht — er wird
|
||||||
# beim naechsten Schreiben ohnehin nicht mehr mitgeschrieben.
|
# beim naechsten Schreiben ohnehin nicht mehr mitgeschrieben.
|
||||||
if "auto_sr_close" in st:
|
|
||||||
self._auto_sr_close = bool(st["auto_sr_close"])
|
|
||||||
if "sr_close_min_gain" in st:
|
|
||||||
self._sr_close_min_gain = max(0.0, float(st["sr_close_min_gain"] or 0))
|
|
||||||
if "manual_margin" in st:
|
if "manual_margin" in st:
|
||||||
from core.config import set_manual_margin as _set
|
from core.config import set_manual_margin as _set
|
||||||
self._manual_margin = _set(st["manual_margin"] or 0)
|
self._manual_margin = _set(st["manual_margin"] or 0)
|
||||||
@@ -2783,8 +2683,6 @@ class TradingEngine:
|
|||||||
self._cone_skalen = {int(k): float(v)
|
self._cone_skalen = {int(k): float(v)
|
||||||
for k, v in (st["cone_skalen"] or {}).items()}
|
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"MinGewinn={self._sr_close_min_gain:+.2f} · "
|
|
||||||
f"Einsatz={'auto' if not getattr(self, '_manual_margin', 0) else f'{self._manual_margin:.2f}'}"
|
f"Einsatz={'auto' if not getattr(self, '_manual_margin', 0) else f'{self._manual_margin:.2f}'}"
|
||||||
f" · Einsatz-%={getattr(self, '_margin_pct', 0):.0f}")
|
f" · Einsatz-%={getattr(self, '_margin_pct', 0):.0f}")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
@@ -2798,8 +2696,6 @@ class TradingEngine:
|
|||||||
tmp = self._runtime_state_path + ".tmp"
|
tmp = self._runtime_state_path + ".tmp"
|
||||||
with open(tmp, "w", encoding="utf-8") as f:
|
with open(tmp, "w", encoding="utf-8") as f:
|
||||||
json.dump({"auto_squeeze": self._auto_squeeze,
|
json.dump({"auto_squeeze": self._auto_squeeze,
|
||||||
"auto_sr_close": self._auto_sr_close,
|
|
||||||
"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),
|
"margin_pct": getattr(self, "_margin_pct", 0.0),
|
||||||
# Circuit-Breaker als PROZENTZAHL (nicht bool):
|
# Circuit-Breaker als PROZENTZAHL (nicht bool):
|
||||||
@@ -5258,10 +5154,7 @@ class TradingEngine:
|
|||||||
"entry_gap": self._entry_gap_cached(),
|
"entry_gap": self._entry_gap_cached(),
|
||||||
"sr_close_hint": sr_close_hint,
|
"sr_close_hint": sr_close_hint,
|
||||||
"stop_approach": stop_approach,
|
"stop_approach": stop_approach,
|
||||||
"auto_sr_close": self._auto_sr_close,
|
|
||||||
"sr_close_min_gain": self._sr_close_min_gain,
|
|
||||||
"sr_close_pbreak": self._sr_close_pbreak,
|
"sr_close_pbreak": self._sr_close_pbreak,
|
||||||
"sr_close_count": self._sr_close_count,
|
|
||||||
# Schwelle der Close-Benachrichtigung — sichtbar, damit belegbar ist,
|
# Schwelle der Close-Benachrichtigung — sichtbar, damit belegbar ist,
|
||||||
# dass sie im LAUFENDEN Prozess angekommen ist. „Erfolg melden, wo
|
# dass sie im LAUFENDEN Prozess angekommen ist. „Erfolg melden, wo
|
||||||
# nichts geprueft wurde" ist im Projekt bereits viermal passiert.
|
# nichts geprueft wurde" ist im Projekt bereits viermal passiert.
|
||||||
@@ -5488,7 +5381,6 @@ class TradingEngine:
|
|||||||
try:
|
try:
|
||||||
an = lambda b: "AN" if b else "aus" # noqa: E731
|
an = lambda b: "AN" if b else "aus" # noqa: E731
|
||||||
z.append(f"Automatik: BRK {an(self._auto_squeeze)} · "
|
z.append(f"Automatik: BRK {an(self._auto_squeeze)} · "
|
||||||
f"S/R-Close {an(self._auto_sr_close)} · "
|
|
||||||
f"Flip {an(getattr(self, '_flip_close', False))}")
|
f"Flip {an(getattr(self, '_flip_close', False))}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
z.append(f"Automatik: nicht lesbar ({e})")
|
z.append(f"Automatik: nicht lesbar ({e})")
|
||||||
|
|||||||
@@ -346,15 +346,6 @@ async def set_sltp(payload: dict = Body(...),
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/srclose")
|
|
||||||
async def toggle_srclose(x_auth_token: str | None = Header(default=None)):
|
|
||||||
"""Automatischen S/R-Close (P(break)-Regel) an/aus."""
|
|
||||||
_require_auth(x_auth_token)
|
|
||||||
eng = app.state.engine
|
|
||||||
state = eng.set_sr_autoclose(not eng._auto_sr_close)
|
|
||||||
return {"ok": True, "enabled": state}
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/autom15")
|
@app.post("/api/autom15")
|
||||||
async def toggle_autom15(x_auth_token: str | None = Header(default=None)):
|
async def toggle_autom15(x_auth_token: str | None = Header(default=None)):
|
||||||
"""M15-Karten-Auto-Entry an/aus (User-Test 2026-08-19, gemessen negativ)."""
|
"""M15-Karten-Auto-Entry an/aus (User-Test 2026-08-19, gemessen negativ)."""
|
||||||
@@ -464,16 +455,6 @@ async def set_margin_pct(body: dict,
|
|||||||
# Sicherung: `.removed_backup/auto_signal_2026-08-12.py` + Git-Historie.
|
# Sicherung: `.removed_backup/auto_signal_2026-08-12.py` + Git-Historie.
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/srclose_min")
|
|
||||||
async def srclose_min(payload: dict = Body(...),
|
|
||||||
x_auth_token: str | None = Header(default=None)):
|
|
||||||
"""Mindestgewinn (EUR) für den S/R-Auto-Close setzen. 0/leer = aus."""
|
|
||||||
_require_auth(x_auth_token)
|
|
||||||
get_logger("server").info(f"[WEB] Mindestgewinn angefordert: {payload.get('value')!r}")
|
|
||||||
cur = app.state.engine.set_sr_close_min_gain(payload.get("value"))
|
|
||||||
return {"ok": True, "min_gain": cur}
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/trail")
|
@app.post("/api/trail")
|
||||||
async def toggle_trail(x_auth_token: str | None = Header(default=None)):
|
async def toggle_trail(x_auth_token: str | None = Header(default=None)):
|
||||||
_require_auth(x_auth_token)
|
_require_auth(x_auth_token)
|
||||||
|
|||||||
@@ -46,14 +46,18 @@ def _text(z):
|
|||||||
|
|
||||||
|
|
||||||
def test_automatik_zeile_nennt_alle_schalter():
|
def test_automatik_zeile_nennt_alle_schalter():
|
||||||
"""⚠ Seit dem 2026-08-12 sind es DREI — der Auto-Signal-Pfad (SIG) ist
|
"""⚠ Seit dem 2026-08-21 sind es ZWEI. Entfernt wurden der Auto-Signal-Pfad
|
||||||
entfernt. Der Test zaehlt sie bewusst einzeln auf: verschwindet einer
|
(SIG, am 12.08.) und der S/R-Auto-Close (am 21.08., User-Vorgabe — er stand
|
||||||
stillschweigend aus der Zeile, faellt es hier auf und nicht erst, wenn
|
seit dem 19.08. ohnehin aus, weil das P(break)-Modell live INVERTIERT misst).
|
||||||
monatelang niemand merkt, dass ein Schalter aus ist (real geschehen:
|
Der Test zaehlt sie bewusst einzeln auf: verschwindet einer stillschweigend
|
||||||
`auto_sr_close` stand 5 Tage aus, gemessener Wert +350,81 EUR)."""
|
aus der Zeile, faellt es hier auf und nicht erst, wenn monatelang niemand
|
||||||
|
merkt, dass ein Schalter aus ist.
|
||||||
|
⚠ Die beiden Negativ-Pruefungen sind der eigentliche Wert: ein entfernter
|
||||||
|
Pfad, der wieder auftaucht, waere ein stiller Rueckbau."""
|
||||||
z = _text(_Stub(brk=True, src=True, flip=False)._system_status())
|
z = _text(_Stub(brk=True, src=True, flip=False)._system_status())
|
||||||
assert "BRK AN" in z and "S/R-Close AN" in z and "Flip aus" in z
|
assert "BRK AN" in z and "Flip aus" in z
|
||||||
assert "SIG" not in z, "der entfernte Pfad darf nicht wieder auftauchen"
|
assert "SIG" not in z, "der entfernte Pfad darf nicht wieder auftauchen"
|
||||||
|
assert "S/R-Close" not in z, "der S/R-Auto-Close ist entfernt (21.08.)"
|
||||||
|
|
||||||
|
|
||||||
def test_toter_logger_wird_gemeldet():
|
def test_toter_logger_wird_gemeldet():
|
||||||
|
|||||||
+18
-56
@@ -94,7 +94,7 @@ function beepCloseAlert() {
|
|||||||
// unterscheidbar). Sofort beim Signal-Wechsel + WIEDERHOLUNG alle 30 s, solange
|
// unterscheidbar). Sofort beim Signal-Wechsel + WIEDERHOLUNG alle 30 s, solange
|
||||||
// der Button blinkt (Empfehlung aktiv & flat) — einmaliger Piep war überhörbar.
|
// der Button blinkt (Empfehlung aktiv & flat) — einmaliger Piep war überhörbar.
|
||||||
const _REC_REBEEP_MS = 30000;
|
const _REC_REBEEP_MS = 30000;
|
||||||
let _lastRecBeep = 0, _lastRecSignal = null, _audioHintShown = false, _lastSrCloseCount = null;
|
let _lastRecBeep = 0, _lastRecSignal = null, _audioHintShown = false;
|
||||||
|
|
||||||
// ── Laufzeit-Uhr des offenen Trades ───────────────────────────────────────────
|
// ── Laufzeit-Uhr des offenen Trades ───────────────────────────────────────────
|
||||||
// Öffnungszeit kommt als echte Epoch (Broker-Offset serverseitig korrigiert) im
|
// Öffnungszeit kommt als echte Epoch (Broker-Offset serverseitig korrigiert) im
|
||||||
@@ -1519,16 +1519,13 @@ function render(d) {
|
|||||||
+ " Entries). ACHTUNG: gemessen negativ -- reiner Test."
|
+ " Entries). ACHTUNG: gemessen negativ -- reiner Test."
|
||||||
: "Auto-Entry auf die gruene M15-Karte AUS (gemessen negativ).";
|
: "Auto-Entry auf die gruene M15-Karte AUS (gemessen negativ).";
|
||||||
}
|
}
|
||||||
const srb = $streng("btn-sr");
|
|
||||||
if (srb) {
|
|
||||||
srb.classList.toggle("on", !!d.auto_sr_close);
|
|
||||||
srb.title = d.auto_sr_close
|
|
||||||
? "S/R-Auto-Close AN: schliesst am Level, wenn P(break) unter der Schwelle liegt."
|
|
||||||
: "S/R-Auto-Close AUS -- der Bot schliesst nicht mehr selbst am Level.";
|
|
||||||
}
|
|
||||||
const cbb = $streng("btn-cb");
|
const cbb = $streng("btn-cb");
|
||||||
if (cbb) {
|
if (cbb) {
|
||||||
cbb.classList.toggle("on", !!cb.enabled);
|
// ⚠ Vorgabe des Nutzers: GRUEN = inaktiv (aus), ROT = aktiv (scharf).
|
||||||
|
// Bewusst nicht die uebliche "gruen = geschuetzt"-Lesart — Rot
|
||||||
|
// signalisiert hier, dass eine Automatik eingreifen kann.
|
||||||
|
cbb.classList.toggle("aktiv", !!cb.enabled);
|
||||||
|
cbb.classList.toggle("inaktiv", !cb.enabled);
|
||||||
cbb.title = cb.enabled
|
cbb.title = cb.enabled
|
||||||
? "Circuit Breaker AN: schliesst bei " + fmt(cb.limit_eur, 2) + " € ("
|
? "Circuit Breaker AN: schliesst bei " + fmt(cb.limit_eur, 2) + " € ("
|
||||||
+ cb.limit_pct + " % der Balance). Heute: " + fmt(cb.day_total, 2) + " €."
|
+ cb.limit_pct + " % der Balance). Heute: " + fmt(cb.day_total, 2) + " €."
|
||||||
@@ -1559,7 +1556,9 @@ function render(d) {
|
|||||||
// Deckt sich mit dem Auto-Close-Gate im Backend (unter der Schwelle schließt der
|
// Deckt sich mit dem Auto-Close-Gate im Backend (unter der Schwelle schließt der
|
||||||
// Bot ohnehin nicht → dann auch kein Alarm/Ton).
|
// Bot ohnehin nicht → dann auch kein Alarm/Ton).
|
||||||
const posLong = p.order_type === 0;
|
const posLong = p.order_type === 0;
|
||||||
const minGain = d.sr_close_min_gain || 0;
|
// ⚠ Der Mindestgewinn ist mit dem S/R-Auto-Close entfallen; der
|
||||||
|
// Close-Alarm gilt jetzt schlicht ab jedem Gewinn (wie vor 2026-07).
|
||||||
|
const minGain = 0;
|
||||||
const gainOK = hasPos && (p.pnl || 0) > minGain;
|
const gainOK = hasPos && (p.pnl || 0) > minGain;
|
||||||
const flipClose = gainOK &&
|
const flipClose = gainOK &&
|
||||||
((posLong && w.signal === "SHORT") || (!posLong && w.signal === "LONG"));
|
((posLong && w.signal === "SHORT") || (!posLong && w.signal === "LONG"));
|
||||||
@@ -1567,7 +1566,8 @@ function render(d) {
|
|||||||
// schwacher Anlauf → Level hält ~74 % → Close schlägt Laufenlassen. Text-Hinweis
|
// schwacher Anlauf → Level hält ~74 % → Close schlägt Laufenlassen. Text-Hinweis
|
||||||
// in der Position-Kachel immer; Blink/Ton nur über dem Mindestgewinn.
|
// in der Position-Kachel immer; Blink/Ton nur über dem Mindestgewinn.
|
||||||
const srHint = d.sr_close_hint || null; // vorhanden = Kurs am Level
|
const srHint = d.sr_close_hint || null; // vorhanden = Kurs am Level
|
||||||
const srAuto = !!d.auto_sr_close;
|
// ⚠ Der Bot schliesst seit dem 2026-08-21 NICHT mehr selbst am Level.
|
||||||
|
const srAuto = false;
|
||||||
const srClose = !!(srHint && srHint.close); // P(break) < Schwelle → schließen
|
const srClose = !!(srHint && srHint.close); // P(break) < Schwelle → schließen
|
||||||
const closeAlert = flipClose || (gainOK && srClose);
|
const closeAlert = flipClose || (gainOK && srClose);
|
||||||
// ⚠ Der Alarm gilt der Position in Slot 1 (dort entsteht `sr_close_hint` und
|
// ⚠ Der Alarm gilt der Position in Slot 1 (dort entsteht `sr_close_hint` und
|
||||||
@@ -1686,23 +1686,9 @@ function render(d) {
|
|||||||
flipEl.className = "news-conflict hidden"; flipEl.textContent = "";
|
flipEl.className = "news-conflict hidden"; flipEl.textContent = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ⚠ Der Auto-Close-Schalter der Trade-Leiste ist am 2026-08-20 entfernt
|
// ⚠ Am 2026-08-21 entfernt: der Auto-Close-Schalter der Trade-Leiste, das
|
||||||
// (User-Wunsch) — er war doppelt: der Knopf S/R in der Aktionsleiste
|
// Mindestgewinn-Feld und die Toast-Meldung "Bot hat am Level
|
||||||
// schaltet dasselbe und ist auch sichtbar, wenn KEINE Position offen ist.
|
// geschlossen" — es gibt keinen Auto-Close am Level mehr.
|
||||||
// `srAuto` wird weiter gebraucht (Knopf `btn-sr`, Hinweistexte).
|
|
||||||
const srMin = d.sr_close_min_gain || 0;
|
|
||||||
const smi = $("srmin-input");
|
|
||||||
if (smi && document.activeElement !== smi) {
|
|
||||||
smi.value = srMin > 0 ? String(srMin) : "";
|
|
||||||
}
|
|
||||||
// Einblendung: der Bot hat am S/R automatisch geschlossen (Zähler stieg)
|
|
||||||
const src = d.sr_close_count;
|
|
||||||
if (src != null) {
|
|
||||||
if (_lastSrCloseCount != null && src > _lastSrCloseCount) {
|
|
||||||
toast("🎯 Bot hat am Level geschlossen (schwacher Anlauf, Gewinn gesichert)", true);
|
|
||||||
}
|
|
||||||
_lastSrCloseCount = src;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Letzte Trades ───────────────────────
|
// ── Letzte Trades ───────────────────────
|
||||||
// 5 → 10 (User-Wunsch 2026-08-04). Das Backend liefert bereits 10
|
// 5 → 10 (User-Wunsch 2026-08-04). Das Backend liefert bereits 10
|
||||||
@@ -2116,37 +2102,13 @@ _updateMuteBtn();
|
|||||||
|
|
||||||
// Toggle-Buttons (AUTO/TRAIL/S-R-Close) — ohne Bestätigung
|
// Toggle-Buttons (AUTO/TRAIL/S-R-Close) — ohne Bestätigung
|
||||||
$("btn-cb").onclick = () => toggle("api/circuit", "Circuit Breaker");
|
$("btn-cb").onclick = () => toggle("api/circuit", "Circuit Breaker");
|
||||||
$("btn-sr").onclick = () => toggle("api/srclose", "S/R-Auto-Close");
|
|
||||||
$("btn-m15").onclick = () => toggle("api/autom15", "M15-Auto-Entry (gemessen negativ!)");
|
$("btn-m15").onclick = () => toggle("api/autom15", "M15-Auto-Entry (gemessen negativ!)");
|
||||||
// (🎯 SIG entfernt 2026-08-12 — s. renderOrderButtons oben)
|
// (🎯 SIG entfernt 2026-08-12 — s. renderOrderButtons oben)
|
||||||
$("btn-trail").onclick = () => toggle("api/trail", "Trailing");
|
$("btn-trail").onclick = () => toggle("api/trail", "Trailing");
|
||||||
|
|
||||||
// Mindestgewinn für den S/R-Auto-Close (0/leer = aus)
|
// ⚠ Der Mindestgewinn-Sender ist am 2026-08-21 mit dem S/R-Auto-Close
|
||||||
async function setSrMin() {
|
// entfallen — die Schwelle gab es nur fuer ihn (Endpoint, Feld und
|
||||||
const raw = $("srmin-input").value;
|
// Backend-Zustand sind ebenfalls weg).
|
||||||
const v = raw === "" ? 0 : parseFloat(raw);
|
|
||||||
if (isNaN(v) || v < 0) { toast("Bitte Betrag ≥ 0 eingeben (0 = aus)", false); return; }
|
|
||||||
const tok = await ensureToken();
|
|
||||||
if (tok === null) return;
|
|
||||||
$("srmin-input").blur();
|
|
||||||
try {
|
|
||||||
const r = await fetch("api/srclose_min", { method: "POST",
|
|
||||||
headers: { "X-Auth-Token": tok, "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({ value: v }) });
|
|
||||||
if (r.status === 401) { clearToken(); throw new Error("401"); }
|
|
||||||
toast(v > 0 ? `Mindestgewinn +${v} gesetzt` : "Mindestgewinn aus", true);
|
|
||||||
} catch (e) {
|
|
||||||
toast(e.message === "401" ? "Token abgelaufen — neu eingeben" : "Netzwerkfehler", false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Feld sitzt in der Button-Zeile: setzt beim Verlassen/Enter automatisch
|
|
||||||
$("srmin-input").addEventListener("change", setSrMin);
|
|
||||||
// Enter NUR blurren → das change-Event feuert setSrMin genau EINMAL (und nur, wenn
|
|
||||||
// der Wert wirklich geändert wurde). Vorher: keydown + change = doppelter Send,
|
|
||||||
// und Enter auf leerem Feld schickte ungewollt 0 (Fix 2026-07-22).
|
|
||||||
$("srmin-input").addEventListener("keydown", e => {
|
|
||||||
if (e.key === "Enter") { e.preventDefault(); e.target.blur(); }
|
|
||||||
});
|
|
||||||
|
|
||||||
// Einsatz-Felder ENTFERNT (User 2026-08-19). Das BACKEND bleibt vollstaendig:
|
// Einsatz-Felder ENTFERNT (User 2026-08-19). Das BACKEND bleibt vollstaendig:
|
||||||
// beide Endpunkte sind weiter erreichbar, die Werte leben in
|
// beide Endpunkte sind weiter erreichbar, die Werte leben in
|
||||||
@@ -2519,7 +2481,7 @@ async function closeSlot(slot, label, pnl) {
|
|||||||
// und der Browser zeigte Altes. Statt das jedes Mal von Hand zu diagnostizieren,
|
// und der Browser zeigte Altes. Statt das jedes Mal von Hand zu diagnostizieren,
|
||||||
// sagt die Seite es jetzt selbst.
|
// sagt die Seite es jetzt selbst.
|
||||||
// ⚠ Bewusst SICHTBAR statt nur Konsole: die Konsole sieht am Handy niemand.
|
// ⚠ Bewusst SICHTBAR statt nur Konsole: die Konsole sieht am Handy niemand.
|
||||||
const _JS_V = "208";
|
const _JS_V = "210";
|
||||||
{
|
{
|
||||||
const htmlV = document.body && document.body.dataset
|
const htmlV = document.body && document.body.dataset
|
||||||
? document.body.dataset.htmlV : null;
|
? document.body.dataset.htmlV : null;
|
||||||
|
|||||||
+19
-7
@@ -12,9 +12,9 @@
|
|||||||
⚠ LOKAL eingebunden, kein CDN: die PWA laeuft ueber WireGuard
|
⚠ LOKAL eingebunden, kein CDN: die PWA laeuft ueber WireGuard
|
||||||
und muss offline funktionieren. -->
|
und muss offline funktionieren. -->
|
||||||
<link rel="stylesheet" href="pico.min.css?v=1">
|
<link rel="stylesheet" href="pico.min.css?v=1">
|
||||||
<link rel="stylesheet" href="style.css?v=208">
|
<link rel="stylesheet" href="style.css?v=210">
|
||||||
</head>
|
</head>
|
||||||
<body data-html-v="208">
|
<body data-html-v="210">
|
||||||
<!-- Modul-Menü (ganz oben) -->
|
<!-- Modul-Menü (ganz oben) -->
|
||||||
<nav id="tabs">
|
<nav id="tabs">
|
||||||
<button class="tab active" data-view="dash">Dashboard</button>
|
<button class="tab active" data-view="dash">Dashboard</button>
|
||||||
@@ -43,6 +43,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="price-row">
|
<div class="price-row">
|
||||||
<div class="px"><label title="Kontostand ohne die offene Position.">BALANCE</label><span id="balance">—</span></div>
|
<div class="px"><label title="Kontostand ohne die offene Position.">BALANCE</label><span id="balance">—</span></div>
|
||||||
|
<!-- ⚠⚠ Farb-Logik wie vom Nutzer vorgegeben: GRUEN = Breaker AUS
|
||||||
|
(inaktiv, nichts begrenzt), ROT = Breaker AN (aktiv, ein
|
||||||
|
Tagesverlust-Limit ist scharf). Das ist bewusst NICHT die
|
||||||
|
uebliche "gruen = geschuetzt"-Lesart — hier signalisiert Rot,
|
||||||
|
dass eine Automatik eingreifen kann. -->
|
||||||
|
<button class="cb-dot" id="btn-cb" title="Circuit Breaker (Tagesverlust-Stopp) an/aus">CB</button>
|
||||||
<div class="px"><label title="Realisiertes Ergebnis von heute. Brutto — die Quellensteuer wird größtenteils erstattet und ist hier nicht abgezogen.">TAG P/L</label><span id="day-pl">—</span></div>
|
<div class="px"><label title="Realisiertes Ergebnis von heute. Brutto — die Quellensteuer wird größtenteils erstattet und ist hier nicht abgezogen.">TAG P/L</label><span id="day-pl">—</span></div>
|
||||||
<div class="px"><label title="Kontostand einschließlich der offenen Position.">EQUITY</label><span id="equity">—</span></div>
|
<div class="px"><label title="Kontostand einschließlich der offenen Position.">EQUITY</label><span id="equity">—</span></div>
|
||||||
<div class="px"><label id="hdr-price-lbl" title="Der Kurs, zu dem tatsächlich gehandelt wird. Steht er länger als 3 Minuten still, gilt der Markt als geschlossen und das Label zeigt ZU.">PEPPERSTONE KURS</label><span id="hdr-price">—</span></div>
|
<div class="px"><label id="hdr-price-lbl" title="Der Kurs, zu dem tatsächlich gehandelt wird. Steht er länger als 3 Minuten still, gilt der Markt als geschlossen und das Label zeigt ZU.">PEPPERSTONE KURS</label><span id="hdr-price">—</span></div>
|
||||||
@@ -98,8 +104,8 @@
|
|||||||
Broker-TP NICHT kennt. -->
|
Broker-TP NICHT kennt. -->
|
||||||
<span class="tb-field gain"><label title="TP3 — die Obergrenze des 80-%-Kegels auf 120 Minuten (core/cone.py). Out-of-sample geprüft: die 80-%-Bänder treffen real 77 %. ⚠ Das ist eine Aussage über die REICHWEITE, nicht über die Richtung — weiter kommt der Kurs in dieser Zeit selten, nicht: er kommt dorthin.">TP3 · Kegel 120′</label>
|
<span class="tb-field gain"><label title="TP3 — die Obergrenze des 80-%-Kegels auf 120 Minuten (core/cone.py). Out-of-sample geprüft: die 80-%-Bänder treffen real 77 %. ⚠ Das ist eine Aussage über die REICHWEITE, nicht über die Richtung — weiter kommt der Kurs in dieser Zeit selten, nicht: er kommt dorthin.">TP3 · Kegel 120′</label>
|
||||||
<span class="tb-val" id="tb-tp3">—</span></span>
|
<span class="tb-val" id="tb-tp3">—</span></span>
|
||||||
<span class="tb-field gain"><label title="Mindestgewinn in Euro, unter dem der Auto-Close am Level NICHT schließt. Leer oder 0 = aus.">Gewinn-Close</label>
|
<!-- ⚠ "Gewinn-Close" entfernt am 2026-08-21 mit dem S/R-Auto-Close:
|
||||||
<input id="srmin-input" type="number" inputmode="decimal" step="1" placeholder="€"></span>
|
die Schwelle gab es NUR fuer ihn. -->
|
||||||
<span class="tb-field stop"><label title="Harte Verlustgrenze in Euro — der Server schließt sofort, wenn sie erreicht ist. Wirkt auch bei gesperrtem Handy. ⚠ Ein gesetzter Wert wird auf den nächsten Trade übernommen, bis er gelöscht wird.">Notfall-Close</label>
|
<span class="tb-field stop"><label title="Harte Verlustgrenze in Euro — der Server schließt sofort, wenn sie erreicht ist. Wirkt auch bei gesperrtem Handy. ⚠ Ein gesetzter Wert wird auf den nächsten Trade übernommen, bis er gelöscht wird.">Notfall-Close</label>
|
||||||
<input id="emg-input" type="number" inputmode="decimal" step="1" placeholder="€"></span>
|
<input id="emg-input" type="number" inputmode="decimal" step="1" placeholder="€"></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -421,14 +427,20 @@
|
|||||||
Close-Alarm (nur Slot 1, dort entsteht der Anlass). -->
|
Close-Alarm (nur Slot 1, dort entsteht der Anlass). -->
|
||||||
<!-- BRK-Schalter ENTFERNT, dafuer der Circuit-Breaker (User 2026-08-19).
|
<!-- BRK-Schalter ENTFERNT, dafuer der Circuit-Breaker (User 2026-08-19).
|
||||||
Der Auto-Squeeze-Zustand bleibt in der Breakout-Karte sichtbar. -->
|
Der Auto-Squeeze-Zustand bleibt in der Breakout-Karte sichtbar. -->
|
||||||
<button class="btn tog" id="btn-cb" title="Circuit Breaker (Tagesverlust-Stopp) an/aus">🛑 CIRCUIT BREAKER</button>
|
<!-- ⚠ Der CIRCUIT-BREAKER-Knopf sitzt seit dem 2026-08-21 als runder
|
||||||
|
"CB" rechts neben BALANCE (User-Wunsch). VERSCHOBEN, nicht kopiert:
|
||||||
|
zwei Elemente mit derselben ID waeren ein stiller Fehler, weil
|
||||||
|
`getElementById` nur das erste findet. -->
|
||||||
<!-- S/R-Auto-Close auch in der Aktionsleiste (User 2026-08-19). Den
|
<!-- S/R-Auto-Close auch in der Aktionsleiste (User 2026-08-19). Den
|
||||||
Schalter gab es nur in der Trade-Leiste -- die ist aber NUR bei
|
Schalter gab es nur in der Trade-Leiste -- die ist aber NUR bei
|
||||||
offener Position sichtbar, also genau dann nicht, wenn man ihn vor
|
offener Position sichtbar, also genau dann nicht, wenn man ihn vor
|
||||||
einem Trade setzen will. Der alte Knopf bleibt; beide lesen
|
einem Trade setzen will. Der alte Knopf bleibt; beide lesen
|
||||||
`auto_sr_close` aus demselben Snapshot und koennen nicht
|
`auto_sr_close` aus demselben Snapshot und koennen nicht
|
||||||
auseinanderlaufen. -->
|
auseinanderlaufen. -->
|
||||||
<button class="btn tog" id="btn-sr" title="Auto-Close am S/R-Level an/aus (P(break)-gegatet: schliesst nur, wenn das Level wahrscheinlich haelt)">S/R</button>
|
<!-- ⚠ Knopf S/R entfernt am 2026-08-21 (User-Vorgabe). Der Auto-Close am
|
||||||
|
Level ist samt Endpoint und Backend-Logik weg; der HINWEIS in der
|
||||||
|
Meldungen-Karte, die P(break)-Chartlinien und das
|
||||||
|
`pbreak_predictions`-Tracking bleiben. -->
|
||||||
<!-- M15-Karten-Auto-Entry (User-Test 2026-08-19). ⚠ GEGEN DIE MESSUNG:
|
<!-- M15-Karten-Auto-Entry (User-Test 2026-08-19). ⚠ GEGEN DIE MESSUNG:
|
||||||
backtest_m15_auto.py -> Lesart beidhaelftig negativ (OeR -0,162/
|
backtest_m15_auto.py -> Lesart beidhaelftig negativ (OeR -0,162/
|
||||||
-0,094, PF 0,72/0,84), KI ohne Null, schlechter als die
|
-0,094, PF 0,72/0,84), KI ohne Null, schlechter als die
|
||||||
@@ -473,6 +485,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="toast" class="toast hidden"></div>
|
<div id="toast" class="toast hidden"></div>
|
||||||
|
|
||||||
<script src="app.js?v=208"></script>
|
<script src="app.js?v=210"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -757,3 +757,18 @@ main{padding-bottom:4.1111rem} /* Platz für die fixe Leiste */
|
|||||||
border-radius:var(--r-sm); color:var(--bright); cursor:pointer;
|
border-radius:var(--r-sm); color:var(--bright); cursor:pointer;
|
||||||
font-size:1.1111rem; line-height:1; padding:0.3333rem 0.5556rem}
|
font-size:1.1111rem; line-height:1; padding:0.3333rem 0.5556rem}
|
||||||
.pt-img[data-bild]{cursor:zoom-in}
|
.pt-img[data-bild]{cursor:zoom-in}
|
||||||
|
|
||||||
|
/* ── Runder Circuit-Breaker-Knopf neben BALANCE (User 2026-08-21) ──────────
|
||||||
|
⚠ Farb-Logik ist die VORGABE des Nutzers: gruen = Breaker AUS (inaktiv),
|
||||||
|
rot = Breaker AN (aktiv/scharf). Bewusst nicht die uebliche
|
||||||
|
"gruen = geschuetzt"-Lesart — hier heisst Rot: eine Automatik kann eingreifen. */
|
||||||
|
.cb-dot{
|
||||||
|
width:2.0556rem; height:2.0556rem; border-radius:50%; flex:0 0 auto;
|
||||||
|
border:1px solid var(--border); cursor:pointer; align-self:center;
|
||||||
|
font:700 0.6667rem/1 var(--mono); letter-spacing:.5px;
|
||||||
|
display:flex; align-items:center; justify-content:center;
|
||||||
|
background:var(--surface-2); color:var(--dim); transition:filter .15s;
|
||||||
|
}
|
||||||
|
.cb-dot:active{filter:brightness(1.3)}
|
||||||
|
.cb-dot.inaktiv{background:#0d2a16; border-color:#1a4731; color:#3fb950}
|
||||||
|
.cb-dot.aktiv{background:#2d0d0d; border-color:#5c1a1a; color:#f85149}
|
||||||
|
|||||||
Reference in New Issue
Block a user