Tag P/L war falsch: Fehlbuchungen beim Schliessen behoben + repariert

User-Frage "ueberpruefe ob Tag P/L richtig berechnet wird". Die Formel
(realisiert + offen) war bitgenau richtig - die Datenbasis nicht:
Anzeige +14,26 EUR gegen -74,08 EUR realisiert beim Broker.

Ursache, im Log im Sekundentakt (#49926460): 20:04:10 eroeffnet ->
20:04:10 "extern geschlossen" -> "kein OUT-Deal in 1 Deals" ->
Fallback bucht 0,00 -> 20:11:42 der echte Close lief ins Leere.
Drei Defekte: (1) positions_get sieht die frische Position einen Tick
lang nicht, (2) _log_external_close buchte TROTZ "kein OUT-Deal" einen
Close - dabei ist genau das der Beweis, dass sie noch offen ist,
(3) log_trade_close fasste nur exit_time IS NULL an, die Fehlbuchung
blockierte den echten Close dauerhaft. Bei #49852362 kostete das
+5,87 statt -95,38 EUR und den falschen Tag.

Behoben: (1) Abbruch statt Fallback bei "kein OUT-Deal"; (2) eine
erkennbare Fehlbuchung (closed_by='unknown') darf von einem echten
Close korrigiert werden - eng gefasst, gute Zeilen bleiben unberuehrt.
4 Tests inkl. Gegenprobe.

Altlast: tools/repair_closes.py (Trockenlauf Standard, Backup
automatisch). 18 Zeilen ueber 60 Tage korrigiert. Heute von +7,63 auf
-72,67 (Restfehler 1,41). Gesamt-P&L von -282,78 auf +169,98.

Zeitfalle zweimal getroffen: history_deals_get filtert nach
Broker-Wallclock, und fromtimestamp(d.time, BROKER) rendert 3 h zu
spaet. Aufgefallen nur, weil eine Deal-Zeit 23:11 lautete, das Log
aber 20:11:42 sagte.

Statistik-Modul separat geprueft: Arithmetik in allen drei Zeitraeumen
bitgenau korrekt (Abweichung 0,00). Der Netto-Defekt vom 05.08. besteht
weiter und ist groesser als damals: angezeigt -2.449,95 EUR, real
verblieben -17,06 (99 % der Steuer werden erstattet). Nicht gebaut -
die Loesung ist dokumentiert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-12 20:29:22 +02:00
co-authored by Claude Opus 5
parent 19ee379f20
commit d8839ef7c5
5 changed files with 369 additions and 2 deletions
+73
View File
@@ -6161,6 +6161,79 @@ Neumessung. Sie bleiben unverändert und reproduzierbar; wo ihre Schlussfolgerun
relevant wird, gehört sie live-treu **neu gerechnet** (Muster:
`backtest_auto_signal_norev.py`).
## ⚠⚠ TAG P/L WAR FALSCH — Fehlbuchungen beim Schliessen (2026-08-12)
User: „überprüfe ob Tag P/L richtig berechnet wird." **Die Formel war richtig, die
Datenbasis nicht.**
| | |
|---|---|
| Anzeige „TAG P/L" | **+14,26 €** |
| Broker, realisiert heute | **74,08 €** |
| **Abweichung** | **81,71 €, mit falschem Vorzeichen** |
`realisiert + offen` stimmt bitgenau gegen die DB (0,0000). Der Fehler lag
darunter: **die DB stimmte nicht mit dem Broker überein.**
⚠⚠ **URSACHE — eine Race Condition beim Eröffnen**, im Log im Sekundentakt
sichtbar (#49926460): `20:04:10 SELL eröffnet``20:04:10 „extern geschlossen"`
`20:04:12 „kein OUT-Deal in 1 Deals"` → Fallback bucht **0,00**
`20:11:42` der ECHTE Close **lief ins Leere**. Drei Defekte griffen ineinander:
**(1)** `positions_get` sieht die frische Position einen Tick lang nicht.
**(2)** `_log_external_close` buchte **trotz** „kein OUT-Deal" einen Close — dabei
ist genau das der Beweis, dass die Position NOCH OFFEN ist.
**(3)** `log_trade_close` fasste nur `exit_time IS NULL` an → die Fehlbuchung
blockierte den echten Close **dauerhaft**.
Bei #49852362 kostete das **+5,87 statt 95,38 €** und buchte den Trade auf den
**falschen Tag**.
**BEHOBEN:** (1) `_log_external_close` bricht bei „kein OUT-Deal" ab (der
Fallback bleibt nur für den wirklich blinden Fall, in dem gar keine Deals
abrufbar sind — dort ist `reconcile_open_trades` das Netz). (2) `log_trade_close`
darf eine **erkennbare Fehlbuchung** korrigieren — eng gefasst: nur wenn die
Zeile `closed_by='unknown'` trägt UND die neue Buchung echte Deal-Daten hat.
**4 Tests** (`tests/test_close_buchung.py`), inkl. der Gegenprobe „eine gute
Zeile wird NICHT überschrieben" — sonst wäre der Fix schlimmer als der Fehler.
⚠ Zwei Testfehlschläge waren **meine**: synthetische Zeitstempel (1000/2000) vor
der Eröffnungszeit lösten die Defensive „exit < entry → jetzt" aus.
**ALTLAST REPARIERT**`tools/repair_closes.py` (Trockenlauf ist Standard,
Schreiben nur mit `--schreiben`, Backup `…bak-2026-08-12-repair`). Korrigiert
werden **nur eindeutige Fälle**: `closed_by='unknown'` UND echter OUT-Deal beim
Broker. **18 Zeilen** über 60 Tage. Heute: von **+7,63 auf 72,67 €**, Restfehler
**1,41 €**. Gesamt-P&L (`all`): von **282,78 auf +169,98 €**.
⚠⚠ **ZEITFALLE dabei, zweimal:** `history_deals_get` filtert nach BROKER-Wallclock
`datetime`-Objekte verschieben das Fenster; und `fromtimestamp(d.time, BROKER)`
rendert **3 h zu spät**. Aufgefallen, weil eine Deal-Zeit „23:11" lautete, das Log
aber „20:11:42 CLOSE" sagte. ➜ **Epochs übergeben (lokal + Offset), beim Lesen
`d.time Offset`.**
**20 weitere Trades** weichen um ±14 € ab (DB nutzt den Schwebe-P&L im
Moment des Closes, der Broker den Fill). Die Summe hebt sich fast auf (+1,66 €
über 19 Trades) → nur berichtet, **nicht** automatisch korrigiert.
## ✅ STATISTIK-MODUL: ARITHMETIK KORREKT, NETTO-RECHNUNG WEITER DEFEKT (2026-08-12)
Gegen unabhängige SQL geprüft, alle drei Zeiträume: **Abweichung 0,00 in jeder
Zelle** (n · wins+losses+be = n · gross_win gross_loss = total_pnl).
| | today | week | all |
|---|---|---|---|
| n | 6 | 91 | 1.267 |
| total_pnl | 72,67 | 1.259,12 | **+169,98** |
✅ Das Modul rechnet also korrekt — es las nur eine fehlerhafte DB (jetzt repariert).
⚠⚠ **Der am 05.08. dokumentierte NETTO-Defekt besteht unverändert — und ist
grösser als damals gemessen:**
| | |
|---|---|
| Modell-Steuerlast (`gross_win × 26,375 %`) | **2.619,93 €** |
| **angezeigtes `net_pnl`** | **2.449,95 €** |
| ECHT einbehalten / erstattet (90 Tage) | 2.625,89 / **+2.608,83** |
| **tatsächlich verblieben** | **17,06 €** |
✅ Das Modell schätzt die *einbehaltene* Steuer fast perfekt (2.620 gegen 2.626).
Der Fehler ist die Annahme, sie sei **verloren** — real werden **99 %** erstattet
(am 05.08. waren es 79 %). Die Anzeige macht damit aus **+153 € rund 2.450 €**.
`_add_net`/`_add_net_setup` in `server.py:154/171` sind unverändert. Die Lösung
steht seit dem 05.08. fest: **die tatsächlichen `WHT #…`/`Tax settlement`-Deals
verwenden statt zu schätzen** (gecacht, unter `mt5_lock`). **Noch nicht gebaut.**
## ✅ AUTO-SIGNAL-ENTRY (🎯 SIG) KOMPLETT ENTFERNT (User-Entscheidung 2026-08-12)
User: „den Signal-Autotrader brauchen wir im Moment nicht mehr — sollten wir den