Chartmuster grafisch: SVG-Skizze in Karte + Trigger/Ziel-Linien im PWA-Chart

- patterns.py: nur AKTIVE, kursnahe Muster (abgearbeitete/Ziel erreicht raus,
  _MAX_DIST_ATR=5.0 Distanz-Filter)
- get_bars liefert bei M30 die Muster (patterns.snapshot) fürs Chart-Overlay
- app.js: _patternSvg-Skizze je Muster-Karte + 2 stärkste Muster als
  Trigger-/Ziel-Preislinien im M30-Chart; Gitternetz dezenter (#10151c)
- style.css: .pt-svg; index.html v=116->117; CLAUDE.md aktualisiert

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-07-27 19:13:47 +02:00
co-authored by Claude Opus 4.8
parent 21d855b163
commit ae6bbb2f35
6 changed files with 78 additions and 10 deletions
+15 -2
View File
@@ -38,6 +38,8 @@ _MIN_HEIGHT_ATR = 1.2 # Muster-Höhe muss ≥ so viel ATR sein (sonst Rausche
_TOL_ATR = 0.7 # zwei "gleiche" Extrema dürfen so weit auseinander (×ATR)
_NECK_TOL_ATR = 0.9 # Nackenlinie "flach": zwei Tröge/Hochs so weit (×ATR)
_MAX_LOOKBACK = 9 # nur die letzten N Swings betrachten (aktuelle Muster)
_MAX_DIST_ATR = 5.0 # Trigger max. so weit vom AKTUELLEN Kurs (sonst nicht mehr
# aktionabel — alte, weit weg gelaufene Muster ausblenden)
def _atr(highs, lows, closes, p=14):
@@ -189,8 +191,19 @@ def _detect(piv, cur, atr, last_idx):
key = (m["type"], round(m["trigger"], 2))
if key not in best or m["quality"] > best[key]["quality"]:
best[key] = m
# ungültige raus, dann nach Status (confirmed/forming) + Qualität + Recency
res = [m for m in best.values() if m["status"] != "invalidated"]
def played_out(m):
"""Ziel bereits erreicht → Muster abgearbeitet, nicht mehr zeigen."""
t = m.get("target")
if t is None:
return False
return (cur <= t) if m["dir"] == "bear" else (cur >= t)
# raus: ungültig · abgearbeitet (Ziel erreicht) · zu weit vom Kurs (nicht mehr
# aktionabel — nur AKTIVE, kursnahe Muster zeigen).
res = [m for m in best.values()
if m["status"] != "invalidated"
and not played_out(m)
and abs(m["trigger"] - cur) <= _MAX_DIST_ATR * atr]
rank = {"confirmed": 2, "forming": 1}
res.sort(key=lambda m: (rank.get(m["status"], 0), m["quality"], -m["bars_ago"]), reverse=True)
return res