M15-Karte: Pruefkette als Akkordeon in drei Abschnitten

User-Wunsch. Die Karte war auf zehn Zeilen gewachsen und dominierte das
Dashboard; jetzt sind sie in drei aufklappbare Gruppen sortiert:

  ① - ④  Pruefkette                        (offen)   Bias · Kosten · Zone · Reichweite
  ⑤      Kontext - Motor · M5 · RSI        (zu)      Motor/Raum · M5-Zustand · RSI
  ⑥ - ⑦  Selbstmessung · Ausfuehrung · Veto (zu)      Track · Exec · Veto

Das Status-Banner bleibt IMMER sichtbar - es ist die eine Zeile, die eine
Handlungsaussage traegt, und es bestaetigt ausdruecklich auch das Nicht-Handeln.

⚠⚠ NATIVES <details>/<summary>, kein JS fuer das Klappen. Entscheidend ist, dass
die Elemente IM DOM bleiben: der Render schreibt weiter in alle zehn IDs, auch
wenn ein Abschnitt zugeklappt ist. Ein Container, der die Elemente ENTFERNT,
haette den Render abbrechen lassen - genau der Ausfall von gestern Abend, als
ein ReferenceError in renderM15 das halbe Dashboard auf "—" stehen liess.

JS macht nur EINES: den Auf-/Zu-Zustand in localStorage merken. Ohne das waere
jeder Reload ein Rueckschritt - und die Seite wird bei jedem ?v=-Bump neu
geladen. Faellt localStorage aus (privater Modus), greift der Default.

Verifiziert: 10 m15-Items unveraendert vorhanden, keine doppelten IDs,
div 86/86 und details 3/3 ausgeglichen, node --check gruen, Render-Probe
(Stufe B2) gruen. Reine Frontend-Aenderung (v=190), kein Neustart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-20 00:11:17 +02:00
co-authored by Claude Opus 5
parent 5684589878
commit d3d613068c
3 changed files with 62 additions and 24 deletions
+23
View File
@@ -2183,3 +2183,26 @@ async function setMgGlobal() {
if (e.key === "Enter") { e.preventDefault(); e.target.blur(); } if (e.key === "Enter") { e.preventDefault(); e.target.blur(); }
}); });
}); });
// --- M15-Akkordeon: Auf-/Zuklappen merken -------------------------------
// ⚠ Das Auf- und Zuklappen macht natives <details> selbst - hier wird NUR der
// Zustand gemerkt, damit die Karte nach jedem Reload so aussieht, wie der
// Nutzer sie zuletzt hatte. Ohne das waere jede Seitenaktualisierung ein
// Rueckschritt, und die Seite wird bei jedem `?v=`-Bump neu geladen.
// ⚠ KEIN Eingriff in den Render: die Elemente bleiben im DOM, auch zugeklappt.
// Ein zugeklapptes <details> ist nur nicht sichtbar - `textContent` wird
// weiter gesetzt, und die naechste Oeffnung zeigt den aktuellen Stand.
{
const KEY = "oil_m15_akk";
let stand = {};
try { stand = JSON.parse(localStorage.getItem(KEY) || "{}"); } catch (e) { stand = {}; }
document.querySelectorAll("details.m15-akk").forEach(el => {
const k = el.dataset.akk;
if (k && Object.prototype.hasOwnProperty.call(stand, k)) el.open = !!stand[k];
el.addEventListener("toggle", () => {
stand[k] = el.open;
try { localStorage.setItem(KEY, JSON.stringify(stand)); } catch (e) { /* privater Modus */ }
});
});
}
+11 -13
View File
@@ -12,7 +12,7 @@
⚠ LOKAL eingebunden, kein CDN: die PWA laeuft ueber WireGuard ⚠ LOKAL eingebunden, kein CDN: die PWA laeuft ueber WireGuard
und muss offline funktionieren. --> und muss offline funktionieren. -->
<link rel="stylesheet" href="pico.min.css?v=1"> <link rel="stylesheet" href="pico.min.css?v=1">
<link rel="stylesheet" href="style.css?v=189"> <link rel="stylesheet" href="style.css?v=190">
</head> </head>
<body> <body>
<!-- Modul-Menü (ganz oben) --> <!-- Modul-Menü (ganz oben) -->
@@ -111,27 +111,25 @@
gemessen 68 % WR. Sichtbar machen, nicht bevormunden. --> gemessen 68 % WR. Sichtbar machen, nicht bevormunden. -->
<div class="m15-status" id="m15-status"></div> <div class="m15-status" id="m15-status"></div>
<div class="m15-grid"> <div class="m15-grid">
<details class="m15-akk" data-akk="prüfkette" open>
<summary> ④ Prüfkette</summary>
<div class="m15-item" id="m15-bias" title="Uebergeordneter Trend M30 + H1. Der EINZIGE belegte Filter: gegen den HTF zu handeln halbiert den Edge (gemessen ×2)."></div> <div class="m15-item" id="m15-bias" title="Uebergeordneter Trend M30 + H1. Der EINZIGE belegte Filter: gegen den HTF zu handeln halbiert den Edge (gemessen ×2)."></div>
<div class="m15-item" id="m15-kosten" title="Spread geteilt durch ATR_M15. Auf M15 gemessen 0,104 gegen 0,193 auf M5 - hier ist die groebere Zeitebene echt im Vorteil. Schwellen 0,20 / 0,32 aus backtest_realcosts.py."></div> <div class="m15-item" id="m15-kosten" title="Spread geteilt durch ATR_M15. Auf M15 gemessen 0,104 gegen 0,193 auf M5 - hier ist die groebere Zeitebene echt im Vorteil. Schwellen 0,20 / 0,32 aus backtest_realcosts.py."></div>
<div class="m15-item" id="m15-zone" title="Naechstes STEHENDES Level (M30-Pivots, dieselbe Quelle wie Chart und S/R-Close) mit Abstand und Durchbruchwahrscheinlichkeit. ⚠ P(break) ist live derzeit rund 7 Pp zu niedrig kalibriert."></div> <div class="m15-item" id="m15-zone" title="Naechstes STEHENDES Level (M30-Pivots, dieselbe Quelle wie Chart und S/R-Close) mit Abstand und Durchbruchwahrscheinlichkeit. ⚠ P(break) ist live derzeit rund 7 Pp zu niedrig kalibriert."></div>
<div class="m15-item" id="m15-reich" title="Erwartete Spanne aus core/cone.py - out-of-sample geprueft, die 80-%-Baender treffen real 77 %. Sagt WIE WEIT, nicht wohin."></div> <div class="m15-item" id="m15-reich" title="Erwartete Spanne aus core/cone.py - out-of-sample geprueft, die 80-%-Baender treffen real 77 %. Sagt WIE WEIT, nicht wohin."></div>
<!-- ③b RAUM + MOTOR-ZUSTAND (2026-08-10, nach Trade #49671601 / -87 EUR). </details>
Die Karte zeigte GRUEN, waehrend der Signal-Motor zu 76 % mit <details class="m15-akk" data-akk="kontext">
entry_room blockte: dieselbe Tatsache ("ein Level ist nah") wird von <summary>⑤ Kontext — Motor · M5 · RSI</summary>
Gate ③ als GUT und von entry_room als SCHLECHT gelesen - beide
gemessen, aber ueber verschiedene Trades. Diese Zeile schliesst die
Luecke. REINE ANZEIGE, blockt nichts. -->
<div class="m15-item" id="m15-motor" title="Was der Signal-Motor GERADE blockt, plus der Raum zum naechsten Gegenlevel je Richtung (M5, dieselbe Rechnung wie das Gate selbst). Unter 0,6xATR ist der Ertrag am Level gedeckelt - gemessen ØR -0,119/-0,067 bei PF 0,42/0,66, also Trefferquote hoch und trotzdem Verlust. ⚠ Gate ③ liest dieselbe Naehe als GUT (ruhende Order AM Level), entry_room als SCHLECHT (Markt-Einstieg mit dem Level als Hindernis). Beides stimmt - fuer verschiedene Trades."></div> <div class="m15-item" id="m15-motor" title="Was der Signal-Motor GERADE blockt, plus der Raum zum naechsten Gegenlevel je Richtung (M5, dieselbe Rechnung wie das Gate selbst). Unter 0,6xATR ist der Ertrag am Level gedeckelt - gemessen ØR -0,119/-0,067 bei PF 0,42/0,66, also Trefferquote hoch und trotzdem Verlust. ⚠ Gate ③ liest dieselbe Naehe als GUT (ruhende Order AM Level), entry_room als SCHLECHT (Markt-Einstieg mit dem Level als Hindernis). Beides stimmt - fuer verschiedene Trades."></div>
<div class="m15-item" id="m15-m5" title="M5-ZUSTAND, reine Anzeige - KEINE Richtung und KEIN Banner. Bewusst KEINE eigene M5-Setup-Karte (User-Entscheidung 2026-08-19): die entkoppelte Selbstmessung dieser Karte steht bei n=342 auf 53,5 % [48,2 .. 58,8] auf 30 min und 49,3 % auf 60 min - die vorab fixierte Bedingung (>=350 Faelle, KI ohne die 50) ist bei vorhandener Stichprobe NICHT erfuellt. Als Handelsregel faellt die Karte durch (backtest_m15_auto.py: OeR -0,162/-0,094, beide KI ohne Null). Kosten-Schwellen aus backtest_realcosts.py: Median 0,193, ab 0,32 Kostenfalle. Der M5-Raum steht bereits in Zeile 3b."></div> <div class="m15-item" id="m15-m5" title="M5-ZUSTAND, reine Anzeige - KEINE Richtung und KEIN Banner. Bewusst KEINE eigene M5-Setup-Karte (User-Entscheidung 2026-08-19): die entkoppelte Selbstmessung dieser Karte steht bei n=342 auf 53,5 % [48,2 .. 58,8] auf 30 min und 49,3 % auf 60 min - die vorab fixierte Bedingung (>=350 Faelle, KI ohne die 50) ist bei vorhandener Stichprobe NICHT erfuellt. Als Handelsregel faellt die Karte durch (backtest_m15_auto.py: OeR -0,162/-0,094, beide KI ohne Null). Kosten-Schwellen aus backtest_realcosts.py: Median 0,193, ab 0,32 Kostenfalle. Der M5-Raum steht bereits in Zeile 3b."></div>
<div class="m15-item" id="m15-rsi" title="RSI(14) auf M15 - REINE ANZEIGE, kein Signal und kein Verdict-Gewicht. WICHTIG: die Lehrbuch-Lesart (>70 ueberkauft -> short, <30 ueberverkauft -> long) ist hier GEMESSEN und faellt durch: 24 Zellen ueber 80k M5-Bars und 2 Halbjahre, keine besteht, vier sind sogar signifikant negativ (backtest_rsi_v2.py, 19.08.). Auch die Umkehrung traegt standalone nicht. Was WIRKT, ist der Pullback-Effekt - und der laeuft im Bot bereits ueber die EMA-Distanz (Konfidenz-Bonus 'tiefer Pullback' +15) und ueber die Ueberdehnung. Lesen Sie den Wert als Kontext, nicht als Handlungsanweisung."></div> <div class="m15-item" id="m15-rsi" title="RSI(14) auf M15 - REINE ANZEIGE, kein Signal und kein Verdict-Gewicht. WICHTIG: die Lehrbuch-Lesart (>70 ueberkauft -> short, <30 ueberverkauft -> long) ist hier GEMESSEN und faellt durch: 24 Zellen ueber 80k M5-Bars und 2 Halbjahre, keine besteht, vier sind sogar signifikant negativ (backtest_rsi_v2.py, 19.08.). Auch die Umkehrung traegt standalone nicht. Was WIRKT, ist der Pullback-Effekt - und der laeuft im Bot bereits ueber die EMA-Distanz (Konfidenz-Bonus 'tiefer Pullback' +15) und ueber die Ueberdehnung. Lesen Sie den Wert als Kontext, nicht als Handlungsanweisung."></div>
<!-- ⑥ SELBSTMESSUNG: die Karte zeigt die Trefferquote ihrer EIGENEN </details>
Lesart. ⚠ Jeder Ausfall, der in diesem Projekt je aufgedeckt wurde, <details class="m15-akk" data-akk="kontrolle">
kam aus einer Rueckkopplung — pbreak_predictions entlarvte den <summary> ⑦ Selbstmessung · Ausführung · Veto</summary>
Modellausfall LIVE, was kein Backtest konnte. -->
<div class="m15-item" id="m15-track" title="Trefferquote der Lesart dieser Karte, nach 30/60 Minuten gegen den echten Kurs ausgewertet. Gegen 50 % zu lesen, nicht gegen 0. Geloggt wird EIN Zustand je Wechsel, nicht je Tick - sonst zaehlt man dieselbe Marktlage dutzendfach."></div> <div class="m15-item" id="m15-track" title="Trefferquote der Lesart dieser Karte, nach 30/60 Minuten gegen den echten Kurs ausgewertet. Gegen 50 % zu lesen, nicht gegen 0. Geloggt wird EIN Zustand je Wechsel, nicht je Tick - sonst zaehlt man dieselbe Marktlage dutzendfach."></div>
<!-- ⑦ AUSFUEHRUNGSQUALITAET: der einzige gemessen grosse Hebel (+0,32 R). -->
<div class="m15-item" id="m15-exec" title="Der Umbau auf ruhende Stop-Orders (05.08.) hatte als Erfolgskriterium: der Abstand Einstieg zum Level muss gegen 0 gehen (vorher Median +0,275xATR). Das ist der groesste je gemessene Hebel des Projekts - und war bis heute unbeobachtet."></div> <div class="m15-item" id="m15-exec" title="Der Umbau auf ruhende Stop-Orders (05.08.) hatte als Erfolgskriterium: der Abstand Einstieg zum Level muss gegen 0 gehen (vorher Median +0,275xATR). Das ist der groesste je gemessene Hebel des Projekts - und war bis heute unbeobachtet."></div>
<div class="m15-item" id="m15-veto" title="Deine eigene Bilanz mit/ohne/gegen Signal, je Lot gerechnet. Gegen das Signal zu handeln kostet gemessen 6,60 EUR je Lot - beidhaelftig robust."></div> <div class="m15-item" id="m15-veto" title="Deine eigene Bilanz mit/ohne/gegen Signal, je Lot gerechnet. Gegen das Signal zu handeln kostet gemessen 6,60 EUR je Lot - beidhaelftig robust."></div>
</details>
</div> </div>
</section> </section>
@@ -392,6 +390,6 @@
</div> </div>
<div id="toast" class="toast hidden"></div> <div id="toast" class="toast hidden"></div>
<script src="app.js?v=189"></script> <script src="app.js?v=190"></script>
</body> </body>
</html> </html>
+17
View File
@@ -630,3 +630,20 @@ main{padding-bottom:4.1111rem} /* Platz für die fixe Leiste */
nicht bedienbar (User: „Einsatz je Pfad kann ich nichts eingeben"). */ nicht bedienbar (User: „Einsatz je Pfad kann ich nichts eingeben"). */
.mg-row{margin-top:0.4444rem;padding-top:0.4444rem;border-top:1px solid var(--line)} .mg-row{margin-top:0.4444rem;padding-top:0.4444rem;border-top:1px solid var(--line)}
.mg-row .tb-field input{width:7ch} .mg-row .tb-field input{width:7ch}
/* ── M15-Prüfkette als Akkordeon (User-Wunsch 2026-08-20) ─────────────────
⚠ Natives <details>/<summary>: kein JS für das Auf- und Zuklappen, und —
entscheidend — die Elemente bleiben IM DOM, auch wenn zugeklappt. Ein
`display:none`-Container würde den Render NICHT stören (die IDs existieren
weiter), ein Entfernen dagegen schon. */
.m15-akk{border:1px solid var(--line);border-radius:var(--r-sm);
margin-bottom:0.3333rem;background:var(--surface-2)}
.m15-akk > summary{cursor:pointer;padding:0.3889rem 0.5556rem;
font-size:0.8333rem;color:var(--dim);letter-spacing:.3px;
list-style:none;user-select:none}
.m15-akk > summary::-webkit-details-marker{display:none}
.m15-akk > summary::before{content:"▸ ";color:var(--dim)}
.m15-akk[open] > summary::before{content:"▾ "}
.m15-akk > summary:hover{color:var(--bright)}
.m15-akk[open] > summary{border-bottom:1px solid var(--line)}
.m15-akk .m15-item{margin:0.2222rem 0.3333rem}