KI-Copilot: zwei Prompt-Fehler behoben + kalibrierte Groessen ergaenzt
Diagnose zur Frage "Bias fast immer neutral": es ist NICHT der Prompt, es ist
der Provider. Bruch exakt am 20.07. (DeepSeek-Wechsel) - bis 19.07. war der
Copilot zu 42-90 % gerichtet, ab 21.07. nur noch zu 1,5-9,3 %. Der Prompt war
unveraendert. Und er hedged aus KORREKTER Schlussfolgerung: ~90 % WARTEN-Signal,
negativer Track-Record, plus die Prompt-Anweisung, genau dann NEUTRAL zu sagen.
Gemessen, ob mehr Meinung ueberhaupt Wert haette: KI-LONG n=286 +0,29 $ / 76 %
Treffer, KI-SHORT n=93 -0,02 $ / 55 %. ABER die 286 sind 20 Episoden an 5 Tagen
(Minutentakt-Logger), die 93 sind 16 Episoden -> effektiv n~20 gegen n~16, ein
Regime. Kein Beleg. Deshalb BEWUSST nicht am Prompt gedreht, um Meinung zu
erzwingen; Verdict-Gewicht unveraendert.
Zwei echte Prompt-Fehler behoben (Korrektheit, keine Meinungsmache):
- _SYS beschrieb das Wellen-Signal als "ATR-ZigZag" - es ist EMA12 vs EMA50
- _SYS nannte "TradersUnion-Tachos" als Input - TU ist seit 19.07. raus
Kalibrierte Groessen ergaenzt: _tool_market gab dem Copiloten NUR Wellen-Signal
und Session. Neu: p_break_target / p_break_stop (AUC 0,65 bzw. 0,68-0,72) und
cone (80%-Baender mit der REAL gemessenen Abdeckung 77 %), plus Lese-Anleitung
im Prompt (45-55 % explizit als Muenzwurf markiert).
Zwei Fallen an Live-Daten korrigiert: p_break steht bereits in PROZENT (die
zuerst gebaute x100-Umrechnung haette 300 erzeugt), und die Engine-Felder plus
die engine-Referenz im Agent existierten gar nicht - der Fail-safe haette still
nichts geliefert. Snapshot weist die Werte jetzt nur zu, rechnet sie nicht neu.
DeepSeek max_tokens 4000 -> 8000: das JSON brach regelmaessig mitten im Text ab
("Unterminated string"), real 2x in ~14 Zyklen = ~14 % stille Ausfaelle.
Kerzen/Muster bewusst NICHT eingespeist - die Lehrbuch-Lesart ist hier gemessen
invertiert (langer Koerper im Trend -0,132/-0,042; 2x Volumen -0,117/-0,204;
Muster-Kursziel trifft nur 13-38 %). Roh eingespeist wuerden sie schaden.
Verifiziert: Stub-Test von _tool_market (Werte unveraendert durchgereicht, nur
80%-Baender, ohne Engine kein Absturz); Prozess juenger als beide Dateien.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
20cd04caa7
commit
00c78201fa
+83
-7
@@ -50,8 +50,16 @@ _OPENAI_URL = "https://api.openai.com/v1/chat/completions"
|
||||
_SYS = (
|
||||
"Du bist ein nüchterner Trading-Copilot für WTI-Rohöl (Intraday-Scalping). "
|
||||
"Du bekommst den aktuellen Systemzustand eines automatischen Handels-Bots "
|
||||
"(Wellen-Signal als ATR-ZigZag, TradersUnion-Tachos, offene Position, "
|
||||
"Konto, Track-Record, News). Beurteile die Lage knapp und ehrlich — keine "
|
||||
# ⚠ KORRIGIERT 2026-08-02: hier stand „Wellen-Signal als ATR-ZigZag,
|
||||
# TradersUnion-Tachos". BEIDES war falsch und hat das Modell in die Irre
|
||||
# geführt: (a) die Richtung kommt seit Langem aus EMA12 vs. EMA50 — ZigZag
|
||||
# wurde verworfen, weil es ~0 Edge hatte; (b) TradersUnion ist seit
|
||||
# 2026-07-19 gar nicht mehr im Copilot-Kontext. Das Modell wurde also auf
|
||||
# Daten hingewiesen, die es nie sieht, und hat die Natur des Hauptsignals
|
||||
# missverstanden.
|
||||
"(Wellen-Signal aus EMA12 gegen EMA50 mit Totband, Durchbruch-"
|
||||
"Wahrscheinlichkeit am nächsten S/R-Level, erwartete Kursspanne, offene "
|
||||
"Position, Konto, Track-Record, News). Beurteile die Lage knapp und ehrlich — keine "
|
||||
"Garantien, keine Hype-Sprache. Wenn die Signale widersprüchlich oder dünn "
|
||||
"sind, sag das klar und empfiehl NEUTRAL/abwarten.\n\n"
|
||||
"WICHTIG — nutze den Track-Record zur Kalibrierung: 'current_setup_history' "
|
||||
@@ -62,6 +70,28 @@ _SYS = (
|
||||
"Live-Signal stark wirkt. Hat es sich bewährt, darf das deine Konfidenz "
|
||||
"stützen. Folge dem Signal nicht blind gegen eine klar negative Historie; "
|
||||
"nenne den Bezug in 'reasoning' kurz (z.B. Setup-Trefferquote).\n\n"
|
||||
# ── Die zwei EINZIGEN kalibriert geprüften Größen des Projekts ────────────
|
||||
# ⚠ Ergänzt 2026-08-02. Der Copilot sah bis dahin NUR das Wellen-Signal und
|
||||
# die Session — er war damit das schlechtest informierte Modul im System und
|
||||
# bekam ausgerechnet die beiden Komponenten nicht, deren Treffsicherheit
|
||||
# out-of-sample nachgewiesen ist. Die Lese-Anleitung ist Pflicht: ohne sie
|
||||
# deutet ein LLM „P(break) 30 %" als schwaches Signal statt als klare
|
||||
# Aussage „das Level hält mit 70 %".
|
||||
"ZWEI KALIBRIERTE GRÖSSEN — nutze sie bevorzugt, sie sind die einzigen "
|
||||
"Zahlen hier mit nachgewiesener Treffsicherheit:\n"
|
||||
"1) 'p_break_target' / 'p_break_stop' = Wahrscheinlichkeit in PROZENT, dass "
|
||||
"der Kurs das jeweilige S/R-Level DURCHBRICHT (Ziel-Level in Trade-Richtung, "
|
||||
"Stop-Level dagegen). Out-of-sample geprüft (AUC 0,65 bzw. 0,68–0,72). "
|
||||
"Lies sie richtig: 30 % Durchbruch heißt 70 % ABPRALL — das ist eine starke "
|
||||
"Aussage, kein schwaches Signal. Ein Abprall am Ziel-Level deckelt den "
|
||||
"Ertrag (spricht gegen einen Einstieg dorthin); ein Durchbruch am "
|
||||
"Stop-Level ist eine Warnung für eine offene Position. Werte zwischen 45 "
|
||||
"und 55 % sind ein Münzwurf — dann NICHT darauf argumentieren.\n"
|
||||
"2) 'cone' = erwartete Kursspanne in 30/60/120 Minuten (80 %-Band). "
|
||||
"Gemessene Abdeckung real 77 %, nicht 80 % — das Band ist eher etwas ZU "
|
||||
"ENG. Es sagt NICHTS über die Richtung, nur über die plausible Weite. "
|
||||
"Nutze es, um Ziele/Stops auf Realismus zu prüfen: liegt ein Kursziel "
|
||||
"außerhalb des 120-min-Bands, ist es für einen Intraday-Trade unrealistisch.\n\n"
|
||||
"Wähle außerdem den Analyse-Timeframe 'timeframe' für die Wellen-Erkennung "
|
||||
"(M1|M5|M15|M30|H1): M1/M5 bei enger Range und ruhigem Markt (Scalping, "
|
||||
"kleine Wellen); höhere TF (M15/M30/H1) bei klarem Trend, hoher Volatilität "
|
||||
@@ -136,7 +166,11 @@ _SCHEMA = {
|
||||
|
||||
class TradingAgent:
|
||||
def __init__(self, cfg, *, data, trader, trail, tu, wave, history,
|
||||
news, elliott=None):
|
||||
news, elliott=None, engine=None):
|
||||
# `engine` (optional, 2026-08-02): Zugriff auf die kalibrierten Größen
|
||||
# P(break) und Kegel, die die Engine ohnehin je Snapshot berechnet.
|
||||
# Optional gehalten, damit Tests/Standalone-Nutzung ohne Engine laufen.
|
||||
self.engine = engine
|
||||
self.cfg = cfg
|
||||
self.data = data
|
||||
self.trader = trader
|
||||
@@ -221,7 +255,7 @@ class TradingAgent:
|
||||
# TU entfernt (2026-07-08): war nach der TU-Entfernung aus Empfehlung/Verdict
|
||||
# die letzte Hintertür — der Copilot ist eine Verdict-Stimme, TU floss so
|
||||
# indirekt wieder ein (lagging, nicht backtestbar).
|
||||
return {
|
||||
out = {
|
||||
"wave_signal": wsig.get("signal"),
|
||||
"wave_confidence": wsig.get("conf_pct"),
|
||||
"wave_setup": wsig.get("setup"),
|
||||
@@ -231,6 +265,42 @@ class TradingAgent:
|
||||
"wave_reasons": wsig.get("reasons", [])[:4],
|
||||
"session": _agent_session(),
|
||||
}
|
||||
# ── Die kalibrierten Größen dazugeben (2026-08-02) ────────────────────
|
||||
# ⚠ Bis hierher sah der Copilot NUR Wellen-Signal + Session. Er war damit
|
||||
# das schlechtest informierte Modul im System — und ihm fehlten
|
||||
# ausgerechnet die beiden Komponenten, deren Kalibrierung out-of-sample
|
||||
# nachgewiesen ist (P(break) AUC 0,65 / Kegel 77 % reale Abdeckung).
|
||||
# Fail-safe: fehlt die Engine oder wirft ein Teil, bleibt das Feld weg —
|
||||
# ein fehlender Kontext darf die Analyse nie verhindern.
|
||||
eng = getattr(self, "engine", None)
|
||||
if eng is not None:
|
||||
try:
|
||||
# ⚠ `p_break` steht im Snapshot BEREITS in Prozent (3 = 3 %,
|
||||
# deckungsgleich mit der Chart-Zeile „97 % Abprall") — NICHT
|
||||
# nochmal ×100 rechnen. Beim Bau zuerst falsch angenommen und
|
||||
# an den Live-Daten korrigiert.
|
||||
hint = getattr(eng, "_last_sr_close_hint", None) or {}
|
||||
if hint.get("p_break") is not None:
|
||||
out["p_break_target"] = round(float(hint["p_break"]))
|
||||
out["p_break_target_level"] = hint.get("level")
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
stop = getattr(eng, "_last_stop_approach", None) or {}
|
||||
if stop.get("p_break") is not None:
|
||||
out["p_break_stop"] = round(float(stop["p_break"]))
|
||||
out["p_break_stop_level"] = stop.get("level")
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
cone = getattr(eng, "_last_cone", None) or {}
|
||||
lv = [l for l in (cone.get("levels") or []) if l.get("band") == 80]
|
||||
if lv:
|
||||
out["cone"] = [{"minutes": l["minutes"], "lo": l["lo"], "hi": l["hi"],
|
||||
"abdeckung_real_pct": l.get("coverage")} for l in lv]
|
||||
except Exception:
|
||||
pass
|
||||
return out
|
||||
|
||||
def _tool_position(self) -> dict:
|
||||
ps = self.trader.snapshot()
|
||||
@@ -461,8 +531,14 @@ class TradingAgent:
|
||||
|
||||
def _call_deepseek(self, prompt: str) -> str:
|
||||
# DeepSeek (OpenAI-kompatibel, api.deepseek.com). deepseek-v4-flash ist ein
|
||||
# Reasoning-Modell (content nach reasoning_content) → max_tokens großzügig
|
||||
# (4000), sonst content leer. temperature 0.3 ok. CJK-Drift-Schutz im Aufrufer.
|
||||
# Reasoning-Modell (content nach reasoning_content) → max_tokens großzügig,
|
||||
# sonst content leer. temperature 0.3 ok. CJK-Drift-Schutz im Aufrufer.
|
||||
# ⚠ 4000 → 8000 (2026-08-02): bei 4000 brach das JSON regelmäßig MITTEN im
|
||||
# Text ab („Unterminated string …"), real 2× in ~14 Zyklen ≈ 14 % stille
|
||||
# Ausfälle — das Reasoning frisst das Budget, bevor der content fertig ist.
|
||||
# Ein Fehlschlag verwirft die Analyse und lässt die ALTE Empfehlung stehen,
|
||||
# ist also von außen kaum sichtbar. Mit dem ergänzten P(break)/Kegel-Kontext
|
||||
# wird die Antwort eher länger, nicht kürzer.
|
||||
import requests
|
||||
dc = self.cfg["deepseek"] if self.cfg.has_section("deepseek") else {}
|
||||
base = (dc.get("base_url") or "https://api.deepseek.com").rstrip("/")
|
||||
@@ -474,7 +550,7 @@ class TradingAgent:
|
||||
json={"model": model,
|
||||
"messages": [{"role": "system", "content": _SYS},
|
||||
{"role": "user", "content": prompt}],
|
||||
"temperature": 0.3, "max_tokens": 4000},
|
||||
"temperature": 0.3, "max_tokens": 8000},
|
||||
timeout=120)
|
||||
resp.raise_for_status()
|
||||
return (resp.json()["choices"][0]["message"].get("content") or "").strip()
|
||||
|
||||
Reference in New Issue
Block a user