Sechs PDFs in ebooks/, zwei davon heute schon ausgewertet. Die vier neuen als Text extrahiert (346k Woerter) und gegen das Gemessene gescannt statt gelesen. - 'Day-Trading Attention' ist KEIN Trading-Buch: Vaynerchuks Social-Media- Marketing-Titel, ein Wortspiel. Null TA-Begriffe im ganzen Text. - 'Die Kunst des technischen und algorithmischen Tradings' (656 S.): RSI/MACD/ ADX 165x, Elliott 35x, Kerzen 37x, Fibonacci 18x, Bollinger 17x -- alles hier bereits gemessen und verworfen. Keine pruefbare Regel, kein CRV-Kapitel. - 'KDP968 4 in 1': ausdruecklich fuer Einsteiger, unter dem Projektstand. - 'Ein Fuchs namens Risiko': das einzige mit pruefbaren Aussagen, weil seine Kapitel ueber REIHENFOLGE und ABSTAND von Trades sprechen. Gemessen auf 1.318 eigenen Trades (analyze_verhalten.py, je Lot, Bootstrap-KI): keine der vier Behauptungen reproduziert. Revenge-Trading und Overtrading zeigen sogar in die Gegenrichtung (< 5 min nach Verlust -1,53 gegen > 2 h -16,16; 3.-5. Trade -7,23 gegen 11.+ +1,00). DER EIGENTLICHE BEFUND: die Projekt-eigene Checklisten-Regel 'nach 2 Losses Session beenden' (seit 30.07. Punkt 6) ist auf den eigenen Trades NICHT gestuetzt -- keine monotone Verschlechterung, der 3.-Verlust-Bucket ist wieder positiv, alle vier KI enthalten die Null. Uebernommen aus der Literatur, nie geprueft. Nicht ueberinterpretieren: ~20 Zellen getestet, ~1 Fehlalarm erwartbar, zwei schliessen die Null aus. Beobachtungsdaten, keine Zuweisung. Nichts gebaut. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
147 lines
6.0 KiB
Python
147 lines
6.0 KiB
Python
"""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()
|