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
+80 -1
View File
@@ -12,7 +12,7 @@
//| 4) Der Bot muss laufen (schreibt die CSV alle ~5 s). |
//+------------------------------------------------------------------+
#property copyright "Oil Trading Bot"
#property version "1.46"
#property version "1.47"
// v1.42 (2026-08-19): Y-Stapel oben rechts GEMESSEN statt geschaetzt. Der
// Faktor 1,8 aus v1.41 war nur die naechste Schaetzung; jetzt liefert
// TextGetSize die TATSAECHLICHE Pixelhoehe (LabelH). Ausserdem wird Y bei
@@ -276,6 +276,9 @@ input color InpZoneSupColor = C'20,45,35'; // Support-Zone (dunkelgruen)
input bool InpShowMuster = true; // bestaetigtes Chartmuster zeichnen
input color InpMusterBullColor = C'70,180,100';// bullisch
input color InpMusterBearColor = C'220,90,80'; // baerisch
// ⚠ "leichter Grauton" (User-Vorgabe 2026-08-21). Die Flaeche traegt KEINE
// Richtungsaussage — die steht in den farbigen Trigger-/Ziellinien darueber.
input color InpMusterFill = C'205,205,205';// Fuellung der Musterform
const string PFX = "SRB_"; // Präfix S/R-Linien (aus Datei)
const string RPFX = "SRR_"; // Präfix dynamische Range (aus Chart)
@@ -342,6 +345,33 @@ string TFName(ENUM_TIMEFRAMES tf)
return EnumToString(tf);
}
//+------------------------------------------------------------------+
//| Gefuellte Muster-Form (User-Vorgabe 2026-08-21). |
//| ⚠⚠ OBJPROP_FILL faerbt mit OBJPROP_COLOR — ein Objekt kann NICHT |
//| gleichzeitig eine graue Flaeche und einen farbigen Rand haben. |
//| Deshalb: Flaeche grau und OBJPROP_BACK (hinter den Kerzen), die |
//| Richtungsaussage tragen Trigger- und Ziellinie darueber. |
//| ⚠ Kein Aufraeumen noetig: `ObjectsDeleteAll(0, PFX)` loescht bei |
//| jedem Redraw alle PFX-Objekte, es kann also keine Form aus einem|
//| vorherigen Muster stehenbleiben. |
//+------------------------------------------------------------------+
void DrawMusterForm(string name, ENUM_OBJECT otyp,
datetime &t[], double &pz[], int n)
{
if(ObjectFind(0, name) >= 0) ObjectDelete(0, name);
bool ok = false;
if(n == 2)
ok = ObjectCreate(0, name, otyp, 0, t[0], pz[0], t[1], pz[1]);
else if(n == 3)
ok = ObjectCreate(0, name, otyp, 0, t[0], pz[0], t[1], pz[1], t[2], pz[2]);
if(!ok) return;
ObjectSetInteger(0, name, OBJPROP_COLOR, InpMusterFill);
ObjectSetInteger(0, name, OBJPROP_FILL, true);
ObjectSetInteger(0, name, OBJPROP_BACK, true);
ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
}
//| ⚠ MT5 kann bei OBJ_RECTANGLE KEIN echtes Alpha (nur Canvas- |
//| Objekte könnten das). Da der Hintergrund bekannt und einfarbig |
//| ist, sieht die Mischung exakt aus wie eine transparente Füllung. |
@@ -1066,6 +1096,55 @@ void Redraw()
+ DoubleToString(zl, (int)_Digits) + " (trifft 13-38 %)");
ObjectSetInteger(0, plb, OBJPROP_COLOR, pc);
ObjectMove(0, plb, 0, RightTime(), trg);
// ── GEFUELLTE MUSTER-FORM (User-Vorgabe 2026-08-21) ──────────
// Feldlage: p[6]=form, danach je Anker t;preis.
// dreieck (3 Punkte) → OBJ_TRIANGLE · rechteck (2) →
// OBJ_RECTANGLE · ellipse (3) → OBJ_ELLIPSE · dreieck2 (5) →
// ZWEI Dreiecke, weil OBJ_TRIANGLE nur drei Punkte kennt.
// ⚠ Aeltere CSV ohne Geometrie faellt still auf "nur Linien"
// zurueck — der Indikator bleibt damit zu beiden Staenden
// vertraeglich.
if(k >= 9)
{
string form = p[6];
int need = 3;
if(form == "rechteck") need = 2;
else if(form == "dreieck2") need = 5;
if(k >= 7 + 2 * need)
{
datetime at[5]; double ap[5];
bool gut = true;
for(int q = 0; q < need; q++)
{
at[q] = (datetime)StringToInteger(p[7 + 2 * q]);
ap[q] = StringToDouble(p[8 + 2 * q]);
if(at[q] <= 0 || ap[q] <= 0) gut = false;
}
if(gut)
{
if(form == "rechteck")
DrawMusterForm(PFX + "MUST_F0", OBJ_RECTANGLE, at, ap, 2);
else if(form == "ellipse")
DrawMusterForm(PFX + "MUST_F0", OBJ_ELLIPSE, at, ap, 3);
else if(form == "dreieck")
DrawMusterForm(PFX + "MUST_F0", OBJ_TRIANGLE, at, ap, 3);
else if(form == "dreieck2")
{
// SKS / Dreifach-Top: fuenf Swings. Die beiden Dreiecke
// (Schulter..Kopf und Kopf..Schulter) kacheln genau die
// Silhouette — ein Dreieck allein koennte sie nicht fassen.
datetime a1[3], a2[3]; double b1[3], b2[3];
for(int q = 0; q < 3; q++)
{
a1[q] = at[q]; b1[q] = ap[q];
a2[q] = at[q + 2]; b2[q] = ap[q + 2];
}
DrawMusterForm(PFX + "MUST_F0", OBJ_TRIANGLE, a1, b1, 3);
DrawMusterForm(PFX + "MUST_F1", OBJ_TRIANGLE, a2, b2, 3);
}
}
}
}
continue;
}
if(typ == "RZ" || typ == "SZ")