diff --git a/CLAUDE.md b/CLAUDE.md index df24be2..e50405d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7434,6 +7434,59 @@ vollständig. ⚠ **Verifikation der Zustellung steht aus** — sie erfolgt mit dem Report am nächsten Morgen um 07:30. Die Bausteine sind einzeln live gegengeprüft. +## ⚠⚠ VIER WEITERE BÜCHER (`ebooks/`) — drei ohne Ertrag, das vierte +## widerlegt eine Regel, die IM PROJEKT steht (2026-08-19) + +User: „nutze alle Bücher im Verzeichnis ebooks als Ideenquelle“. Sechs PDFs, +zwei davon am selben Tag schon ausgewertet. Die vier neuen als Text extrahiert +(346k Wörter, `pypdf`) und gegen das Gemessene gescannt statt gelesen. + +| Buch | Umfang | Befund | +|---|---|---| +| **Day-Trading Attention** (Vaynerchuk) | 333 S. | ❌ **kein Trading-Buch** — Social-Media-Marketing („build brand and sales in the new Social Media World“). Der Titel ist ein Wortspiel. **Null** TA-Begriffe im ganzen Text. | +| **Die Kunst des techn. u. algo. Tradings** (Fatih AK) | 656 S. | ⚠ breites Lehrbuch, FX-/Makro-lastig. RSI/MACD/ADX **165×**, Elliott 35×, Kerzen 37×, Fibonacci 18×, Bollinger 17× — **alles hier bereits gemessen und verworfen**. Kein CRV-Kapitel, keine Risiko-Zahlen, keine prüfbare Regel. | +| **KDP968 4 in 1** (Lakefield) | 401 S. | ❌ ausdrücklich „für Einsteiger“ (ETF/Aktien/Dividenden). Unter dem Projektstand. | +| **Ein Fuchs namens Risiko** | 62 S. | ✅ **das einzige mit prüfbaren Aussagen** — s. u. | + +✅ **Warum das vierte:** seine Kapitel sind Aussagen über **Reihenfolge und +Abstand** von Trades („Revenge Trading“, „Overtrading fühlt sich an wie +Kontrolle“, „warum Langeweile profitabel ist“) — und genau das steht in +`trades`. **Gemessen auf 1.318 eigenen Trades** (`analyze_verhalten.py`), +je Lot normiert, 95-%-Bootstrap je Zelle. + +| Behauptung | Gemessen | +|---|---| +| „Revenge: gleich nach einem Verlust wieder rein ist teuer“ | ❌ **umgekehrt**: < 5 min −1,53 [−5,22 … +2,18] · **> 2 h −16,16 [−36,08 … −0,33]** | +| „Overtrading“ — späte Trades des Tages sind schlechter | ❌ **umgekehrt**: 1.–2. −1,04 · **3.–5. −7,23 [−12,77 … −2,36]** · 6.–10. +0,52 · 11.+ **+1,00** | +| „Langeweile ist profitabel“ — ruhige Tage besser | ❌ 1–3 Trades +1,83 (n=11) · **4–8 −36,52** · 16+ −0,63 | +| *(Projekt-eigene Regel)* „nach 2 Losses Session beenden“ | ❌ **nicht gestützt**: 0 Verl. +1,12 · 1 −4,31 · 2 −4,98 · **3+ wieder +1,87** — alle vier KI enthalten die Null | + +⚠⚠ **DER EIGENTLICHE BEFUND ist die letzte Zeile.** „Nach 2 Losses Session +beenden“ steht seit dem 30.07. als Punkt 6 in der Entry-Checkliste +(`_entry_checklist`, „Mental-Check: Verlust-Serie heute“) — **übernommen aus +der Handbuch-Literatur, nie auf den eigenen Trades geprüft.** Auf 1.318 Trades +gibt es keine monotone Verschlechterung; der 3.-Verlust-Bucket ist wieder +positiv. Damit ist es dieselbe Klasse wie die 28 verworfenen Signal-Eingriffe: +plausibel klingend, gemessen ohne Inhalt. + +⚠⚠ **NICHT ÜBERINTERPRETIEREN — Mehrfachvergleich.** Getestet wurden ~20 +Zellen; bei 5 % ist **etwa eine** falsch-positive zu erwarten. **Zwei** +schliessen die Null aus („> 2 h nach Verlust“ und „3.–5. Trade“). Dass beide +in dieselbe, dem Buch **entgegengesetzte** Richtung zeigen, ist ein **Hinweis, +kein Beleg**. Als Befund taugt allein: **keine der vier Behauptungen +reproduziert.** + +⚠ **Zwei Grenzen, ehrlich:** (a) Beobachtungsdaten, keine Zuweisung — wer nach +einem Verlust weiterhandelt, wählt das selbst; ein Unterschied kann auch +„andere Marktlage“ heissen. (b) Der Block „Langeweile“ vergleicht **Tages- +SUMMEN** über Gruppen mit verschieden vielen Trades — mehr Trades = grössere +Summe, die Buckets sind damit nicht sauber vergleichbar. Die Richtung deckt +sich mit Block (3), der das sauber je Trade rechnet. + +✅ **Nichts gebaut.** Die Checklisten-Zeile bleibt stehen (sie **blockiert +nichts**, seit dem 11.08. gibt es ohnehin keinen Dialog mehr) — sie ist jetzt +aber als **unbelegt** gekennzeichnet statt als Regel. + ## ✅ RAUM JE RICHTUNG AUF DEN ORDER-KNÖPFEN (2026-08-19, v=175) Die einzige umgesetzte Empfehlung aus der Ideen-Runde — und sie stammt nicht diff --git a/analyze_verhalten.py b/analyze_verhalten.py new file mode 100644 index 0000000..6890f3d --- /dev/null +++ b/analyze_verhalten.py @@ -0,0 +1,146 @@ +"""Die Verhaltens-Behauptungen aus „Ein Fuchs namens Risiko“ auf den EIGENEN +Trades gemessen (User-Auftrag 2026-08-19: "nutze alle Buecher als Ideenquelle"). + +WARUM AUSGERECHNET DIESES BUCH. Von den sechs Buechern im Verzeichnis ist es das +einzige, dessen Kernaussagen auf der vorhandenen Datenlage **pruefbar** sind: + Kap. 9 "Der Drang, Verluste zurueckzuholen" -> Revenge-Trading + Kap. 11 "Overtrading fuehlt sich an wie Kontrolle" + Kap. 12 "Revenge Trading und der rote Nebel" + Kap. 14 "Warum Langeweile profitabel ist" + Kap. 10 "Warum kleine Verluste gesund sind" +Alle vier sind Aussagen ueber die REIHENFOLGE und den ABSTAND von Trades -- und +genau das steht in `trades` (entry_time, exit_time, pnl, lots). + +⚠⚠ WARUM DAS NICHT NUR EIN BUCH-TEST IST. Die Projekt-Zahlen zeigen seit +Wochen in dieselbe Richtung: der MENSCH schlaegt den Bot (+3,20 gegen +-5,85 EUR/Lot), 28 Signal-Eingriffe sind gescheitert, und die einzige +beidhaelftig robuste Aussage ist ein VETO (gegen das Signal -6,60 EUR/Lot). +Der Hebel liegt gemessen im Verhalten -- nur ist das Verhalten selbst hier nie +gemessen worden. Die Entry-Checkliste nennt "nach 2 Losses Session beenden" als +Regel, ohne sie je auf den eigenen Trades geprueft zu haben. + +⚠ JE LOT NORMIERT. Absolute Euro sind bei schwankender Positionsgroesse +ungueltig (Lehre 04.08.: der 04.08. sah nur wegen groesserer Lots wie ein +Ausreisser aus). Gerechnet wird `pnl / lots`. + +⚠ 95-%-BOOTSTRAP je Zelle. Ein Punktschaetzer ist auf so kleinen Gruppen keine +Aussage. Zellen mit n < 15 werden als zu duenn markiert statt interpretiert. + +⚠ GRENZE, vorab benannt: das sind BEOBACHTUNGSdaten, keine Zuweisung. Wer nach +einem Verlust weiterhandelt, waehlt das selbst -- ein Unterschied kann also auch +heissen "in solchen Marktlagen handelt er anders", nicht "der Zeitabstand ist +die Ursache". Die Richtung ist trotzdem verwertbar, weil sie handlungsnah ist. + +Aufruf: python analyze_verhalten.py [tage] +""" +import sqlite3 +import sys + +from backtest_cost_gate import ci95 + +DB = "oil_widget_history.db" +MIN_N = 15 + + +def lade(tage): + c = sqlite3.connect(DB) + c.row_factory = sqlite3.Row + q = ("SELECT entry_time, exit_time, pnl, lots FROM trades " + " WHERE exit_time IS NOT NULL AND pnl IS NOT NULL AND lots > 0 ") + if tage: + q += " AND entry_time > strftime('%s','now','-{} days') ".format(int(tage)) + q += " ORDER BY entry_time" + rows = [dict(r) for r in c.execute(q)] + c.close() + for r in rows: + r["pl"] = r["pnl"] / r["lots"] + return rows + + +def zeig(lbl, werte): + if not werte: + print(" {:<34} --".format(lbl)); return + n = len(werte); m = sum(werte) / n + ci = ci95(werte) if n >= 20 else None + s = "n={:>4} {:>5.0f}% Gew. {:+8.2f} EUR/Lot".format( + n, 100.0 * sum(1 for x in werte if x > 0) / n, m) + if ci: + s += " [{:+7.2f} .. {:+7.2f}]".format(ci[0], ci[1]) + s += "" if ci[0] * ci[1] > 0 else " ~0" + if n < MIN_N: + s += " ⚠ zu duenn" + print(" {:<34} {}".format(lbl, s)) + + +def main(): + tage = int(sys.argv[1]) if len(sys.argv) > 1 else 0 + tr = lade(tage) + if len(tr) < 50: + print("zu wenige Trades:", len(tr)); return + + print("=" * 100) + print(" VERHALTENS-MESSUNG auf {} eigenen Trades{}".format( + len(tr), " (letzte {} Tage)".format(tage) if tage else " (gesamt)")) + print(" je Lot normiert · 95-%-Bootstrap · Zellen < {} als zu duenn markiert".format(MIN_N)) + print("=" * 100) + + # ---- (1) REVENGE: Abstand zum vorigen EXIT, getrennt nach dessen Ausgang -- + print("\n (1) REVENGE-TRADING — wie schnell nach dem letzten Ausstieg?") + print(" " + "-" * 96) + for nach_verlust in (True, False): + gr = {"< 5 min": [], "5–30 min": [], "30–120 min": [], "> 2 h": []} + for a, b in zip(tr, tr[1:]): + if (a["pnl"] < 0) != nach_verlust: + continue + dt = (b["entry_time"] - a["exit_time"]) / 60.0 + if dt < 0: + continue + k = ("< 5 min" if dt < 5 else "5–30 min" if dt < 30 + else "30–120 min" if dt < 120 else "> 2 h") + gr[k].append(b["pl"]) + print(" nach einem {}:".format("VERLUST" if nach_verlust else "Gewinn")) + for k, v in gr.items(): + zeig(" " + k, v) + + # ---- (2) VERLUST-SERIE --------------------------------------------------- + print("\n (2) VERLUST-SERIE — der wievielte Trade nach wie vielen Verlusten?") + print(" (Projekt-Regel der Entry-Checkliste: 'nach 2 Losses Session beenden')") + print(" " + "-" * 96) + serie = 0 + gr = {0: [], 1: [], 2: [], 3: []} + for t in tr: + gr[min(serie, 3)].append(t["pl"]) + serie = serie + 1 if t["pnl"] < 0 else 0 + for k in sorted(gr): + zeig(" nach {} Verlust{} in Folge".format(k, "" if k == 1 else "en"), gr[k]) + + # ---- (3) OVERTRADING / "Langeweile" ------------------------------------- + print("\n (3) OVERTRADING — der wievielte Trade des Tages?") + print(" " + "-" * 96) + tage_d = {} + for t in tr: + d = int(t["entry_time"]) // 86400 + tage_d.setdefault(d, []).append(t) + gr = {"1.–2.": [], "3.–5.": [], "6.–10.": [], "11.+": []} + tagesbilanz = {"1–3 Trades": [], "4–8": [], "9–15": [], "16+": []} + for d, ts in tage_d.items(): + for i, t in enumerate(ts, 1): + k = ("1.–2." if i <= 2 else "3.–5." if i <= 5 + else "6.–10." if i <= 10 else "11.+") + gr[k].append(t["pl"]) + n = len(ts) + kk = ("1–3 Trades" if n <= 3 else "4–8" if n <= 8 + else "9–15" if n <= 15 else "16+") + tagesbilanz[kk].append(sum(x["pl"] for x in ts)) + for k, v in gr.items(): + zeig(" " + k + " Trade des Tages", v) + print("\n (4) „LANGEWEILE IST PROFITABEL“ — TAGESbilanz je Lot nach Handelsmenge") + print(" (Einheit: Summe EUR/Lot des Tages, n = Anzahl Tage)") + print(" " + "-" * 96) + for k, v in tagesbilanz.items(): + zeig(" " + k, v) + print("=" * 100) + + +if __name__ == "__main__": + main()