Gesamtpruefung: drei echte Fehler behoben, alle drei aus meinem eigenen Code
Dritter vollstaendiger Durchlauf nach docs/review-prompt.md (nach 02.08. und
11.08.). Bemerkenswert: alle drei Funde stammen aus Aenderungen der letzten zwei
Tage, und alle drei sind DIESELBE Klasse - ein vorhandenes Muster nicht kopiert,
sondern ein eigenes erfunden.
FUND 1 (kritisch) - DER CONFIG-WAECHTER WAR TOT.
Mein CONFIG_DEPS-Eintrag fuer auto_m15 vom 19.08. trug das Feld "soll", die
anderen 15 Eintraege tragen "validated". config_drift() lief in einen KeyError
und warf - damit meldeten ALLE 16 Anker nichts mehr, seit gestern. Der Waechter,
der die auto_m15-Abweichung haette melden sollen, war durch genau diesen
Eintrag erledigt.
Behoben: Feldname angeglichen UND config_drift gehaertet - ein defekter Eintrag
wird jetzt uebersprungen und als eigener Befund GEMELDET statt den ganzen
Waechter zu toeten. Ein Waechter, der still stirbt, ist schlimmer als keiner
(dieselbe Klasse wie der ruff-Exit-2-Fall vom 07.08.).
Der Waechter meldet seitdem wieder: margin_buffer_pct 40 gegen 95,
auto_m15 true gegen false, auto_squeeze true gegen false - alle drei sind
dokumentierte User-Entscheidungen, aber sie waren unsichtbar geworden.
FUND 2 (Geld) - DER EINSATZ JE PFAD WAR FUER BRK WIRKUNGSLOS.
engine._open setzt den Einsatz je Pfad - aber _manage_squeeze_pending legt
ruhende Stop-Orders ueber trader.place_stop -> calc_lots, also NICHT ueber
_open. Gemessen fuellen 7 von 8 BRK-Trades per ruhender Order (seit dem
Pending-Umbau 05.08.). Das Feld haette also genau an der Stelle nicht gegriffen,
fuer die es gebaut wurde - und das faellt im Betrieb nur auf, wenn jemand die
Lots nachrechnet.
FUND 3 (Geld, Race) - GLOBALE MUTATION UEBER EINE LOCK-GRENZE.
Der erste Entwurf setzte config.MARGIN_BUFFER temporaer. Der Global wirkt
prozessweit, und zwischen dem Setzen in _open und dem mt5_lock in trader._send
liegt ein Fenster von bis zu 15 s (Lock-Timeout). Eine gleichzeitige MANUELLE
Order haette darin mit dem Prozentsatz des AUTONOMEN Pfads gesized.
FUND 2 und 3 gemeinsam behoben: calc_lots bekommt einen EXPLIZITEN Parameter
buffer_pct (Default None = global), durchgereicht ueber _send/_send_locked/
open_long/open_short/place_stop. Keine Mutation mehr, und beide Bestellwege
tragen denselben Wert.
TESTS - und eine Luecke in meinem eigenen Test, die erst die Mutationsprobe zeigte:
tests/test_buffer_pct.py, 6 Tests. Die erste Fassung bildete die Regel NACH
(_buf) statt die echte Funktion zu pruefen - die Mutation "calc_lots ignoriert
den Parameter wieder" lief damit GRUEN durch. Das ist die dokumentierte
Nachbau-Falle, diesmal in einem TEST. Ergaenzt um eine AST-Pruefung, dass
calc_lots den Parameter im Rumpf wirklich benutzt. Beide Mutationen werden jetzt
gefangen (Parameter aus place_stop entfernt -> rot; calc_lots ignoriert ihn ->
rot).
OHNE BEFUND (geprueft, sauber): check_nfalle, ruff F821, 91 Tests, node --check;
100 JS-Zugriffe gegen 124 HTML-IDs -> 0 fehlend (die 4 gemeldeten waren
Falsch-Positive meiner Regex: zwei stehen in Kommentaren, raum-* wird dynamisch
als $("raum-" + st) gebaut, tb-dur ueber getElementById); 2 Config-Schluessel
ohne Leser (beide [zones], dokumentiert schlafend); 14 Snapshot-Felder ohne
app.js-Leser (dokumentiert als Diagnose-Oberflaeche, deploy.py --feld braucht
sie); Snapshot-Median 15,7 ms bei p90 25,7 ms - unveraendert zum 11.08. und weit
unter dem 1-s-Budget, keine Massnahme.
TELEMETRIE-PULS: alle 7 Logger schreiben. rec_outcomes steht bei 72 Zeilen -
beim Review am 11.08. stand es auf "hat NIE geschrieben", der Fix vom 12.08. hat
also gewirkt.
DIVERGENZ-WAECHTER: A) WARTEN +16,6 Pp ueber der Erwartung (bekannt, wird von
den Live-only-Gates getragen); D) mom3 -0,55 Sigma - knapp ueber der bewusst
tiefen 0,5-Sigma-Schwelle, beobachten.
⚠ NICHT ANGEFASST (User-Entscheidungen, nur berichtet): auto_m15 laeuft live
ueber runtime_state.json gegen die ini; Circuit Breaker aus (cb_limit_pct 0
gegen ini 8); BRK an trotz gefallener B5-Regel.
Deploy ueber tools/deploy.py --feld margin_brk, alle 5 Schritte gruen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
027267063d
commit
a07ad942c1
+11
-10
@@ -152,14 +152,14 @@ class TradeManager:
|
||||
src_str += f", auf min {INIT_SL_MIN_ATR}xATR={min_dist:.3f} aufgeweitet"
|
||||
return sl, tp, src_str
|
||||
|
||||
def _send(self, sym, otype, atr_tf=None):
|
||||
def _send(self, sym, otype, atr_tf=None, buffer_pct=None):
|
||||
with mt5_lock(timeout=15) as got:
|
||||
if not got:
|
||||
self.last_error = "MT5 belegt — bitte gleich nochmal"
|
||||
return None, 0.0
|
||||
return self._send_locked(sym, otype, atr_tf)
|
||||
return self._send_locked(sym, otype, atr_tf, buffer_pct)
|
||||
|
||||
def _send_locked(self, sym, otype, atr_tf=None):
|
||||
def _send_locked(self, sym, otype, atr_tf=None, buffer_pct=None):
|
||||
tick = get_tick(sym)
|
||||
if not tick:
|
||||
self.last_error = "Kein Tick"; return None, 0.0
|
||||
@@ -187,7 +187,7 @@ class TradeManager:
|
||||
"oder Daten fehlen) — Trade abgelehnt")
|
||||
return None, 0.0
|
||||
else:
|
||||
lots = calc_lots(sym, price, otype) # margin-basiert (risk_pct=0)
|
||||
lots = calc_lots(sym, price, otype, buffer_pct) # margin-basiert (risk_pct=0)
|
||||
if lots <= 0:
|
||||
self.last_error = "Lot-Fehler"; return None, 0.0
|
||||
|
||||
@@ -247,7 +247,7 @@ class TradeManager:
|
||||
|
||||
def place_stop(self, sym: str, otype: int, trigger: float,
|
||||
comment: str = "Widget-SQZ",
|
||||
atr_tf=None) -> tuple[int | None, str]:
|
||||
atr_tf=None, buffer_pct=None) -> tuple[int | None, str]:
|
||||
"""Pending BUY_STOP/SELL_STOP am Ausbruchs-Level. → (ticket, Fehlertext).
|
||||
|
||||
Größe und SL werden mit DERSELBEN Logik bestimmt wie bei der Market-Order
|
||||
@@ -278,7 +278,8 @@ class TradeManager:
|
||||
else mt5.ORDER_TYPE_SELL, trigger,
|
||||
atr_tf)
|
||||
lots = calc_lots(sym, trigger,
|
||||
mt5.ORDER_TYPE_BUY if ist_long else mt5.ORDER_TYPE_SELL)
|
||||
mt5.ORDER_TYPE_BUY if ist_long else mt5.ORDER_TYPE_SELL,
|
||||
buffer_pct)
|
||||
if lots <= 0:
|
||||
return None, "Lot-Fehler"
|
||||
req = {"action": mt5.TRADE_ACTION_PENDING, "symbol": sym,
|
||||
@@ -314,11 +315,11 @@ class TradeManager:
|
||||
return ""
|
||||
return _retcode_msg(res)
|
||||
|
||||
def open_long(self, sym, atr_tf=None):
|
||||
def open_long(self, sym, atr_tf=None, buffer_pct=None):
|
||||
with self._lock:
|
||||
if self.ticket:
|
||||
return "Position bereits offen!"
|
||||
t, e = self._send(sym, mt5.ORDER_TYPE_BUY, atr_tf)
|
||||
t, e = self._send(sym, mt5.ORDER_TYPE_BUY, atr_tf, buffer_pct)
|
||||
if not t:
|
||||
return self.last_error
|
||||
with self._lock:
|
||||
@@ -327,11 +328,11 @@ class TradeManager:
|
||||
self._log_open(t, sym, "BUY", e)
|
||||
return ""
|
||||
|
||||
def open_short(self, sym, atr_tf=None):
|
||||
def open_short(self, sym, atr_tf=None, buffer_pct=None):
|
||||
with self._lock:
|
||||
if self.ticket:
|
||||
return "Position bereits offen!"
|
||||
t, e = self._send(sym, mt5.ORDER_TYPE_SELL, atr_tf)
|
||||
t, e = self._send(sym, mt5.ORDER_TYPE_SELL, atr_tf, buffer_pct)
|
||||
if not t:
|
||||
return self.last_error
|
||||
with self._lock:
|
||||
|
||||
Reference in New Issue
Block a user