Neues Modul: Visuelle Chartmuster-Erkennung (core/patterns.py) — reine Anzeige

Erkennt aus M30-Swing-Pivots: Doppeltop/-boden, Kopf-Schulter/inverse SKS,
Tasse+Henkel/invers, auf-/absteigendes+symmetrisches Dreieck. Je Muster Richtung,
Trigger/Nackenlinie, Measured-Move-Ziel, Status (bildet sich/bestätigt/ungültig),
Güte. Dashboard-Karte #card-patterns + Disclaimer (v=116). KEIN Signal, kein
Verdict-Gewicht — Signal-Einfluss erst nach Backtest (Muster-Klasse 2x verworfen,
hohe Beweislast). Live getestet: findet bestätigten Doppeltop.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-07-27 18:49:40 +02:00
co-authored by Claude Opus 4.8
parent cd8ee5b01b
commit e5589da08b
6 changed files with 310 additions and 3 deletions
+32
View File
@@ -224,6 +224,37 @@ function renderCircuitBreaker(cb) {
}
}
// Chartmuster (visuell) — reine Anzeige. Status: bildet sich / bestätigt / (ungültig raus).
function renderPatterns(pt) {
const el = $("pt-list");
if (!el) return;
const items = (pt && pt.patterns) || [];
if (!items.length) {
el.innerHTML = `<span class="dim">Aktuell kein klares Muster erkannt.</span>`;
return;
}
el.innerHTML = items.map(m => {
const dirCls = m.dir === "bull" ? "up" : m.dir === "bear" ? "down" : "dim";
const arr = m.dir === "bull" ? "▲" : m.dir === "bear" ? "▼" : "◆";
const st = m.status === "confirmed"
? `<span class="pt-badge conf">bestätigt</span>`
: `<span class="pt-badge form">bildet sich</span>`;
const tgt = m.target != null
? `Ziel <b>${fmt(m.target, 2)}</b>` : `Ausbruch offen`;
const q = Math.round((m.quality || 0) * 100);
return `<div class="pt-item ${dirCls}">
<div class="pt-head"><span class="pt-name">${arr} ${m.name}</span>${st}
<span class="pt-q">Güte ${q}%</span></div>
<div class="pt-det">Trigger <b>${fmt(m.trigger, 2)}</b> · ${tgt}
· Höhe ${m.height_atr}×ATR · vor ${m.bars_ago} Bars</div>
<div class="pt-note">${m.note || ""}</div>
</div>`;
}).join("") +
`<div class="pt-disclaimer">📊 Reine Anzeige (mechanisch aus M30-Pivots) — KEIN Signal,
kein Einfluss auf die Empfehlung. Muster-Klasse im Projekt als Signal noch unbelegt;
Einfluss erst nach Backtest.</div>`;
}
function render(d) {
// ── Header ──────────────────────────────
$("conn").className = "dot " + (d.connected ? "on" : "off");
@@ -314,6 +345,7 @@ function render(d) {
// ── Gesamtempfehlung (aggregiert) ───────
renderVerdict(d.verdict || {}, d);
renderCircuitBreaker(d.circuit_breaker);
renderPatterns(d.patterns);
renderStructure(d.structure);
renderStatsCompact(d.stats_compact, d.market);
renderGaps(d.gaps, d.market);
+8 -2
View File
@@ -6,7 +6,7 @@
<meta name="theme-color" content="#0d1117">
<title>Oil · MT5</title>
<link rel="manifest" href="manifest.json">
<link rel="stylesheet" href="style.css?v=115">
<link rel="stylesheet" href="style.css?v=116">
</head>
<body>
<!-- Modul-Menü (ganz oben) -->
@@ -116,6 +116,12 @@
</div>
</section>
<!-- Chartmuster (visuell) — reine Anzeige, kein Signal (noch nicht backtestet) -->
<section class="card wide" id="card-patterns">
<h2>Chartmuster <span class="pt-tf">M30 · visuell</span></h2>
<div class="pt-list" id="pt-list"><span class="dim"></span></div>
</section>
<!-- KI-Agent -->
<section class="card wide" id="card-agent">
<h2>KI-Copilot</h2>
@@ -220,6 +226,6 @@
<div id="toast" class="toast hidden"></div>
<script src="lightweight-charts.standalone.production.js?v=114"></script>
<script src="app.js?v=115"></script>
<script src="app.js?v=116"></script>
</body>
</html>
+15
View File
@@ -141,6 +141,21 @@ main{display:grid;grid-template-columns:1fr 1fr;gap:11px;padding:11px}
.circuit.tripped{background:#3d1a1a;color:#ff6b6b;border:1px solid var(--down);
box-shadow:0 0 0 1px var(--down)}
.circuit.near{background:#2a1f00;color:var(--accent);border:1px solid #4a3600}
/* Chartmuster-Karte (visuell, reine Anzeige) */
#card-patterns .pt-tf{font-size:11px;color:var(--dim);font-weight:600;margin-left:6px}
.pt-item{background:var(--surface-2);border:1px solid var(--border);border-left:3px solid var(--line);
border-radius:var(--r-sm);padding:9px 12px;margin-bottom:8px}
.pt-item.up{border-left-color:var(--up)} .pt-item.down{border-left-color:var(--down)}
.pt-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.pt-name{font-weight:700;font-size:15px}
.pt-item.up .pt-name{color:var(--up)} .pt-item.down .pt-name{color:var(--down)}
.pt-badge{font-size:11px;font-weight:700;border-radius:4px;padding:1px 7px}
.pt-badge.conf{background:#0d2a16;color:var(--up);border:1px solid #1a4731}
.pt-badge.form{background:#2a1f00;color:var(--accent);border:1px solid #4a3600}
.pt-q{margin-left:auto;font-size:12px;color:var(--dim);font-family:var(--mono)}
.pt-det{font-size:13px;margin-top:4px;font-family:var(--mono);color:var(--bright)}
.pt-note{font-size:12px;color:var(--dim);margin-top:3px}
.pt-disclaimer{font-size:12px;color:var(--dim);margin-top:6px;line-height:1.4}
#card-verdict{border-color:var(--accent)}
.vd-head{display:flex;align-items:center;gap:14px;margin-bottom:10px}
.vd-ring{width:60px;height:60px;border-radius:50%;flex:0 0 auto;