Trade-Leiste: TP1/TP2/TP3 + Setup-Block "Entry Zone / SL / TP1-3" in der M15-Karte

User-Wunsch, mit einer Vorlage im Format "USOIL BUY SETUP: Entry Zone / Stop
Loss / Take Profit 1-3".

(1) TRADE-LEISTE — drei Anzeige-Boxen fuer die LAUFENDE Position:
    TP1 · Level     naechstes STEHENDES M30-Level in Trade-Richtung + P(haelt)
    TP2 · Trailing  der Broker-TP, den `core/trailing.py` dynamisch fuehrt
    TP3 · Kegel     Obergrenze des 80-%-Bandes auf 120 min (core/cone.py)
    Live gegengerechnet: 85.745 (67 % haelt) / 86.634 / 86.153 (trifft 75 %).

(2) M15-KARTE — Setup-Block im Format der Vorlage, direkt unter dem Banner:
    Richtung · Entry Zone (Level ± 0,15xATR) · Stop Loss (2,0xATR_M15) ·
    TP1 (Gegenlevel) · TP2 (3,5xATR) · TP3 (Kegel 120').
    Blendet sich aus, wenn kein Veto, keine Zone oder kein ATR vorliegt -
    aktuell ist genau das der Fall (M30 flach -> kein Veto -> keine erlaubte
    Richtung), und das ist korrektes Verhalten, kein Fehler.

⚠⚠ DREI LEITPLANKEN, damit daraus keine Prognose wird:
  - Die RICHTUNG kommt ausschliesslich aus dem VETO (erlaubte Richtung). Die
    Karte gibt weiterhin KEINE Richtungsprognose ab - die ist ueber 1.071
    Live-Episoden als Muenzwurf gemessen (48-51 %). Ohne Veto: kein Block.
  - Die drei TP sind ANZEIGE, nichts davon geht an den Broker. Ein FESTER TP am
    Gegenlevel ist der staerkste Gewinner-Kappen-Beleg des Projekts: er drehte
    den Squeeze von +0,102/+0,108 auf -0,066/-0,004 (backtest_trailing_sr.py).
    Deshalb steht an TP2 ausdruecklich, dass das Trailing ihn nachfuehrt.
  - NICHTS wird neu gerechnet - Zonen, ATR und Kegel stehen im Snapshot. Ein
    zweiter Rechenweg waere die Divergenz-Falle (dreimal zugeschlagen).
  - Neutral gerahmt, nicht gruen/rot: der Block sagt WO, nicht OB.

Die 0,15xATR der Entry Zone sind die im Projekt gemessene "Beruehrung"
(dieselbe Schwelle wie `at_level` im S/R-Hinweis), nicht geraten.

Reine Frontend-Aenderung (v=195), kein Neustart. node --check, Render-Probe und
die volle Pipeline gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-20 09:00:01 +02:00
co-authored by Claude Opus 5
parent 5e476025d7
commit 5925d9a527
3 changed files with 93 additions and 2 deletions
+66
View File
@@ -416,6 +416,45 @@ function renderM15(s, snap) {
+ "gedeckelt, der Verlust laeuft bis zum Stop. Reine Anzeige.";
}
// --- SETUP-BLOCK: Entry Zone · SL · TP1-3 (User-Wunsch 2026-08-20) ------
// ⚠⚠ Die RICHTUNG kommt aus dem VETO (erlaubte Richtung), NICHT aus einer
// Prognose — die Karte gibt keine ab, und das ist gemessen richtig so
// (1.071 Live-Episoden, 4851 % Treffer). Der Block beantwortet nur:
// WENN gehandelt wird, zu welchen Preisen.
// ⚠ Nichts wird neu gerechnet — Zonen, ATR und Kegel stehen im Snapshot.
// ⚠ TP1 ist ein LEVEL, kein Auftrag: ein fester TP am Gegenlevel ist der
// staerkste Gewinner-Kappen-Beleg des Projekts (Squeeze +0,102/+0,108 →
// 0,066/0,004). Deshalb steht bei TP2, dass das Trailing fuehrt.
{
const sb = $streng("m15-setupblock");
const verb = ((s.bias || {}).verboten || "").toUpperCase();
const erl = verb === "SHORT" ? "LONG" : verb === "LONG" ? "SHORT" : null;
const zonen = s.zonen || [];
const nah = zonen.slice().sort((a, b) => (a.gap_atr15 ?? 9) - (b.gap_atr15 ?? 9))[0];
const atr = s.atr_m15 || 0;
if (sb && erl && nah && atr > 0) {
const lg = erl === "LONG";
const e = nah.level, tol = 0.15 * atr;
const sl = lg ? e - 2.0 * atr : e + 2.0 * atr;
const geg = zonen.find(z => lg ? z.level > e : z.level < e);
const lv = ((snap || {}).cone || {}).levels || [];
const k120 = lv.find(x => x.band === 80 && x.minutes === 120);
const zl2 = [`<b>${lg ? "▲" : "▼"} ${erl}</b> <span class="dim">— nur wenn die Kette gruen ist</span>`,
`Entry Zone: <b>${f(e - tol, 3)} ${f(e + tol, 3)}</b>`,
`Stop Loss: <b>${f(sl, 3)}</b> <span class="dim">(2,0×ATR_M15)</span>`];
if (geg) zl2.push(`TP1: <b>${f(geg.level, 3)}</b> <span class="dim">(Level · ` +
`${100 - (geg.p_break ?? 50)} % haelt)</span>`);
zl2.push(`TP2: <b>${f(lg ? e + 3.5 * atr : e - 3.5 * atr, 3)}</b> ` +
`<span class="dim">(3,5×ATR — das Trailing fuehrt ihn nach)</span>`);
if (k120) zl2.push(`TP3: <b>${f(lg ? k120.hi : k120.lo, 3)}</b> ` +
`<span class="dim">(Kegel 120, trifft ${Math.round(k120.coverage || 0)} %)</span>`);
sb.innerHTML = zl2.join("<br>");
sb.hidden = false;
} else if (sb) {
sb.hidden = true;
}
}
// --- M5-Kontext: reine ZUSTANDS-Zeile, keine Richtung, kein Banner ------
// Bewusst KEINE eigene M5-Karte (User-Entscheidung 19.08.): die entkoppelte
// Selbstmessung dieser Karte steht bei n=342 auf 53,5 % [48,2 .. 58,8] und
@@ -1158,6 +1197,33 @@ function render(d) {
// Enter darauf schickt den GERUNDETEN Wert an den Broker — der Stop
// verschiebt sich also still um bis zu 0,5 Cent. Bei einem Trail von
// 11 Cent (ATR_M5 0,11 in dieser Nacht) sind das 5 % der Distanz.
// --- TP1/TP2/TP3: voraussichtliche Ziele (User-Wunsch 2026-08-20) -----
// ⚠⚠ REINE ANZEIGE — keines davon wird an den Broker geschickt. Ein FESTER
// TP am Gegenlevel ist im Projekt der staerkste Gewinner-Kappen-Beleg:
// er drehte den Squeeze von +0,102/+0,108 auf 0,066/0,004
// (backtest_trailing_sr.py). Die drei Zahlen sind Orientierung, kein
// Auftrag — deshalb Anzeige-Boxen und keine Eingabefelder.
// ⚠ NICHTS wird neu gerechnet: Zonen und Kegel stehen ohnehin im Snapshot.
// Ein zweiter Rechenweg waere die Divergenz-Falle (dreimal zugeschlagen).
{
const lg = p.order_type === 0;
const ep = Number(p.entry_price) || 0;
// TP1 — naechstes STEHENDES Level in Trade-Richtung
const zn = ((d.m15_setup || {}).zonen) || [];
const ziel = zn.find(z => lg ? (z.seite === "res" && z.level > ep)
: (z.seite === "sup" && z.level < ep));
$("tb-tp1").textContent = ziel
? `${fmt(ziel.level, 3)} (${100 - (ziel.p_break ?? 50)}% hält)`
: "—";
// TP2 — der Broker-TP, den das Trailing fuehrt
$("tb-tp2").textContent = p.tp ? fmt(p.tp, 3) : "—";
// TP3 — Obergrenze des 80-%-Kegels auf 120 min
const lv = ((d.cone || {}).levels) || [];
const k = lv.find(x => x.band === 80 && x.minutes === 120);
$("tb-tp3").textContent = k
? fmt(lg ? k.hi : k.lo, 3) + (k.coverage ? ` (trifft ${Math.round(k.coverage)}%)` : "")
: "—";
}
if (document.activeElement !== slEl) slEl.value = p.sl ? fmt(p.sl, 3) : "";
if (document.activeElement !== tpEl) tpEl.value = p.tp ? fmt(p.tp, 3) : "";
} else {