Muster als gefuellte geometrische Formen im MT5-Chart (v1.47)

User-Vorgabe: Dreiecke/Rechtecke/Ellipsen ueber OBJ_* an den berechneten
Swings verankern, mit leichtem Grauton gefuellt.

PT-Zeile traegt jetzt die Geometrie:
  PT;<TF>;<name>;<dir>;<trigger>;<ziel>;<form>;<t1>;<p1>;<t2>;<p2>;...

  dreieck  (3 Anker) -> OBJ_TRIANGLE   Doppeltop/-boden, Dreiecke, Keile, Wimpel
  dreieck2 (5 Anker) -> 2x OBJ_TRIANGLE  SKS, inv. SKS, Dreifach-Top/-Boden
  rechteck (2 Anker) -> OBJ_RECTANGLE  Rechteck (Range), Flagge
  ellipse  (3 Anker) -> OBJ_ELLIPSE    Tasse+Henkel, inverse Tasse

dreieck2 braucht ZWEI Objekte, weil OBJ_TRIANGLE nur drei Punkte kennt; die
beiden Dreiecke (Schulter-Kopf, Kopf-Schulter) kacheln die Silhouette exakt.

OBJPROP_FILL faerbt mit OBJPROP_COLOR - ein Objekt kann keine graue Flaeche UND
einen farbigen Rand haben. Deshalb Flaeche neutral grau (InpMusterFill) und
OBJPROP_BACK (hinter den Kerzen); die Richtungsaussage tragen Trigger- und
Ziellinie darueber. Inhaltlich richtig: die Form ist eine Beobachtung, keine
Richtungsprognose.

Python (core/patterns.py): add() nimmt form + punkte, legt sie als form/anker
in den Muster-dict. REIN ADDITIV - kein bestehender Schluessel aendert sich.

Neuer Helfer _keil(): schneidet die beiden Linien und DECKELT den Apex auf
last_idx+40 (ein fast paralleles Paar schneidet sich im Unendlichen); nach
links begrenzt, damit der Apex nicht im Muster liegt.

_anker() rechnet einen Index jenseits des letzten Bars ueber die Bar-Dauer
hoch - sonst waere der Apex auf den letzten Bar geklemmt und jedes Dreieck
haette einen senkrechten rechten Rand. Bar-Dauer aus den DATEN, nicht aus der
TF-Konstante.

Zeitstempel sind ROHE Broker-Zeit (rates["time"]) - genau das, was iTime()
liefert. Keine Offset-Rechnung, gleiche Konvention wie EQ; und TR;.

Vor dem Export wird geprueft, dass Form und Punktzahl zueinander passen - ein
Dreieck mit zwei Punkten wuerde der Indikator still verwerfen.
Abwaertsvertraeglich in beide Richtungen.

Verifiziert: 6 synthetische Muster (Form, Punktzahl, aufsteigende Zeitstempel,
Apex in der Zukunft) + live Snapshot patterns_tf.M5 form=dreieck anker=3 +
CSV-Zeile mit Geometrie. Compile 0 errors, Pipeline gruen, deployt.
This commit is contained in:
Axel Hocks
2026-08-21 15:55:36 +02:00
parent c512863e5f
commit 72c2aedc1a
4 changed files with 264 additions and 19 deletions
+26 -2
View File
@@ -2989,6 +2989,10 @@ class TradingEngine:
"target": best.get("target"),
"height_atr": best.get("height_atr"),
"bild": _PAT_BILD.get(best.get("type")),
# Geometrie fuer den MT5-Export (User-Vorgabe 2026-08-21:
# die Muster als gefuellte Formen zeichnen).
"form": best.get("form"),
"anker": best.get("anker"),
}
except Exception:
out[lbl] = None
@@ -3602,7 +3606,14 @@ class TradingEngine:
except Exception:
pass
# ── BESTAETIGTES CHARTMUSTER je Zeitebene (User-Wunsch 2026-08-21)
# PT;<TF>;<name>;<dir>;<trigger>;<ziel>
# PT;<TF>;<name>;<dir>;<trigger>;<ziel>;<form>;<t1>;<p1>;<t2>;<p2>;…
# <form> = dreieck (3 Anker) | dreieck2 (5) | rechteck (2) |
# ellipse (3). Der Indikator zeichnet daraus das
# passende native OBJ_* und fuellt es grau.
# ⚠ Die Zeitstempel sind ROHE BROKER-Zeit (aus `rates["time"]`) —
# genau das, was `iTime()` liefert und was ein OBJ_*-Anker
# erwartet. KEINE Offset-Rechnung: die waere hier falsch (wie bei
# `EQ;`/`TR;`, die dieselbe Konvention nutzen).
# Der Indikator zeichnet NUR die Zeile, deren <TF> zu SEINEM Chart
# passt — so bekommt jedes Fenster (M1/M5/M15/H1) sein eigenes
# Muster, ohne dass fuenf Linien uebereinander liegen.
@@ -3623,8 +3634,21 @@ class TradingEngine:
if not _trg or not _zl:
continue
_nm = str(_m.get("name") or "").replace(";", ",")[:28]
_fm = str(_m.get("form") or "")
_ak = _m.get("anker") or []
# ⚠ Nur exportieren, wenn Form UND Punktzahl zueinander
# passen — ein Dreieck mit zwei Punkten wuerde der
# Indikator still verwerfen, und der Fehler waere von
# aussen unsichtbar (die Klasse "Erfolg melden, wo nichts
# geprueft wurde").
_soll = {"dreieck": 3, "dreieck2": 5, "rechteck": 2,
"ellipse": 3}.get(_fm, 0)
_geo = ""
if _soll and len(_ak) == _soll:
_geo = ";" + _fm + "".join(
f";{int(_pt[0])};{float(_pt[1]):.3f}" for _pt in _ak)
lines.append(f"PT;{_tf};{_nm};{_m.get('dir') or ''};"
f"{float(_trg):.3f};{float(_zl):.3f}")
f"{float(_trg):.3f};{float(_zl):.3f}{_geo}")
except Exception as _pe:
log.debug(f"PT-Export: {_pe}")