English 日本語
preview
Entwicklung des Price Action Analysis Toolkit (Teil 32): Python-Engine für Kerzenmuster (II) – Erkennung mit Ta-Lib

Entwicklung des Price Action Analysis Toolkit (Teil 32): Python-Engine für Kerzenmuster (II) – Erkennung mit Ta-Lib

MetaTrader 5Handelssysteme |
188 0
Christian Benjamin
Christian Benjamin

Inhalt



Einführung

In meinem letzten Artikel habe ich die Verwendung von Python zur Erkennung von Kerzen-Mustern vorgestellt. Wir begannen mit manuellen Erkennungstechniken, bei denen jedes Kerzen-Muster explizit kodiert wurde. Wenn MQL5 bei diesem Ansatz Daten an Python sendet – einschließlich Open, Close, High, Low und Timestamp – verarbeitet Python diese Informationen, um das Muster durch Berechnungen zu identifizieren.

In diesem Artikel entwickeln wir die Methodik weiter, indem wir die Python-Bibliothek TA-Lib integrieren, die über 60 Kerzen-Muster automatisch erkennen kann. Wir werden es auch mit mplfinance und matplotlib kombinieren, um Kerzen-Charts zu erstellen. 

Hier ein Überblick über die wichtigsten verwendeten Bibliotheken:

from flask import Flask, reque
st, jsonify, send_file
import numpy as np
import pandas as pd
import talib
import json
import matplotlib.pyplot as plt
import mplfinance as mpf

Lassen Sie uns jeden Teil im Folgenden erläutern.

Flask

from flask import Flask, request, jsonify, send_file

  • Ein leichtgewichtiges Web-Framework für Python zum Erstellen von Webanwendungen oder APIs.
  • Die Hauptklasse zur Erstellung einer Flask-App-Instanz.
request: Wird verwendet, um auf eingehende Anfragedaten zuzugreifen (z. B. Daten, die per POST oder GET gesendet werden).

jsonify: Konvertiert Python-Datenstrukturen in das JSON-Format für Antworten.

send_file: Sendet Dateien vom Server an den Client, nützlich für das Herunterladen von generierten Bildern oder Berichten.

import numpy as np

  •  NumPy: Eine grundlegende Bibliothek für numerische Berechnungen in Python.
  • np: Allgemeiner Alias, der für NumPy verwendet wird.

Es verarbeitet Array-Operationen, mathematische Funktionen und Datenmanipulationen effizient.

import pandas as pd

  • Pandas: Eine leistungsstarke Bibliothek zur Datenmanipulation.
  • pd: Standard-Alias.

Wird für Datenstrukturen wie DataFrames verwendet, die sich ideal für die Verarbeitung von Zeitreihendaten wie Kerzen-Daten eignen.

import talib

  • TA-Lib: Technische Analysebibliothek in Python.

Bietet Funktionen zur automatischen Berechnung einer breiten Palette von technischen Indikatoren und Algorithmen zur Erkennung von Kerzen-Mustern.

import json

  • Pythons integrierte Bibliothek für die Arbeit mit JSON-Daten.

Analysiert JSON-Daten aus Anfragen oder konvertiert Python-Objekte in JSON für Antworten.

import matplotlib.pyplot as plt

  • Matplotlib: Eine Plotting-Bibliothek.
  • pyplot: Ein Modul innerhalb von Matplotlib, das eine MATLAB-ähnliche Schnittstelle bietet.
  • plt: Standard-Alias.
  • Dient zur Erstellung statischer, animierter oder interaktiver Charts und Grafiken, wie z. B. Kerzen-Charts.

import mplfinance as mpf

  • mplfinance: Eine Spezialbibliothek für die Visualisierung von Finanzdaten, insbesondere Kerzen- und OHLC-Charts.
  • mpf: Der Einfachheit halber wird ein Alias verwendet.
  • Ermöglicht die einfache Erstellung von Finanzcharts mit erweiterten Anpassungsoptionen.

Nachfolgend sind die Vorteile der Verwendung von TA-Lib für die Mustererkennung aufgeführt:

VorteilBeschreibung
AutomatisierungErkennt über 60 Kerzen-Muster automatisch ohne manuelle Kodierung.
WirkungsgradSchnellere Mustererkennung, geeignet für Echtzeitanalysen.
GenauigkeitVerwendet erprobte Algorithmen für eine zuverlässige Mustererkennung.
Kompatibilität Einfache Integration mit anderen Python-Bibliotheken zur Analyse und Visualisierung.
Nutzerfreundlichkeit Vereinfacht die Implementierung durch unkomplizierte Funktionsaufrufe.


Aufbauend auf unserer letzten Diskussion

Wie ich bereits erwähnt habe, war das vorherige System ein manuell kodiertes Kerzen-Erkennungssystem in Python. Verschaffen wir uns einen Überblick über dieses System.

  • MetaTrader 5 Expert Advisor (der „Chart-Side Orchestrator“)

Im MetaTrader 5 wartet der EA auf jeden neuen Balken und sammelt dann sofort die Eröffnungs-, Hoch-, Tiefst-, Schluss- und Zeitstempel-Daten der letzten 31 Kerzen. Er verpackt sie in eine kompakte JSON-Nutzlast und sendet sie per WebRequest an unseren lokalen Mustererkennungsdienst. Wenn der Server mit einem Array von Kerzen-Namen antwortet,

MQL5 EA ➔ (OHLC JSON POST) ➔ Python Server

Der EA zeichnet automatisch jede Kennzeichnung am Hoch des Balkens, wobei er die von Ihnen gewählte Schriftgröße und -farbe verwendet, und löst bei jedem gültigen Muster einen MetaTrader 5-Alarm aus. Jedes Häkchen bereinigt auch frühere Beschriftungen, damit das Charts makellos bleibt, und beim Entfernen werden alle Objekte gelöscht, damit nichts zurückbleibt.

MQL5 EA draws labels & fires alerts

  • Python Flask Server: Motor zur Mustererkennung

Am Backend habe ich eine Flask-Anwendung erstellt, die den Endpunkt /patterns bedient. Es nimmt das JSON-Array der OHLC-Daten auf, konvertiert UNIX-Zeitstempel in UTC-Datumszeiten und konstruiert einen Pandas DataFrame für eine zuverlässige Indizierung. Dann wende ich meine Reihe klassischer Kerzen-Regeln – Doji, Hammer, Engulfing, Harami, Morning/Evening Star und mehr – in reinem Python an, mit klaren, testbaren Funktionen für jedes Muster.

def detect_patterns(df):
    pats = ["None"]*len(df)
    for i in range(len(df)):
        o,h,l,c = df.iloc[i][["OPEN","HIGH","LOW","CLOSE"]]
        body = abs(c-o); rng = max(h-l,1e-6)
        lower = min(o,c)-l; upper = h-max(o,c)
        # doji
        if body/rng <= 0.1:
            pats[i] = "doji"; continue
        # hammer
        if lower>=2*body and upper<=body:
            pats[i] = "hammer"; continue
        # shooting star
        if upper>=2*body and lower<=body:
            pats[i] = "shootingstar"; continue
        # bullish engulfing
        if i>0:
            po,pc = df.iloc[i-1][["OPEN","CLOSE"]]
            if pc<po and c>o and o<=pc and c>=po:
                pats[i] = "bullishengulfing"; continue
        # bearish engulfing
        if i>0:
            po,pc = df.iloc[i-1][["OPEN","CLOSE"]]
            if pc>po and c<o and o>=pc and c<=po:
                pats[i] = "bearishengulfing"; continue
        # harami
        if i>0:
            po,pc = df.iloc[i-1][["OPEN","CLOSE"]]
            if pc<po and o<c and o>pc and c<po:
                pats[i] = "bullishharami"; continue
            if pc>po and o>c and o<pc and c>po:
                pats[i] = "bearishharami"; continue
        # morning star
        if i>1:
            o1,c1 = df.iloc[i-2][["OPEN","CLOSE"]]
            o2,c2 = df.iloc[i-1][["OPEN","CLOSE"]]
            if c1<o1 and abs(c2-o2)<(df.iloc[i-1]["HIGH"]-df.iloc[i-1]["LOW"])*0.3 \
               and c>o2 and c>(o1+c1)/2:
                pats[i] = "morningstar"; continue
        # evening star
        if i>1:
            o1,c1 = df.iloc[i-2][["OPEN","CLOSE"]]
            o2,c2 = df.iloc[i-1][["OPEN","CLOSE"]]
            if c1>o1 and abs(c2-o2)<(df.iloc[i-1]["HIGH"]-df.iloc[i-1]["LOW"])*0.3 \
               and c<o2 and c<(o1+c1)/2:
                pats[i] = "eveningstar"; continue
    return pats

Nachdem ich jeden Balken markiert habe, zähle ich die nicht „Nicht“-Ereignisse in einer kurzen Protokollzusammenfassung zusammen und messe die Verarbeitungszeit in Millisekunden. Schließlich gebe ich ein JSON-Objekt zurück, das sowohl die vollständige Liste der Musternamen (einen pro Balken) als auch das Protokoll enthält. Durch diese Trennung verbleibt die umfangreiche Datenverarbeitung in Python, wo sie am einfachsten zu warten und zu erweitern ist, während sich MetaTrader 5 weiterhin auf die Chart-E/A und die Visualisierung konzentriert.

Python Server ➔ (patterns & log JSON) ➔ MQL5 EA


Ta-Lib verstehen

TA-Lib (Technical Analysis Library) ist eine Open-Source-Bibliothek, die von Händlern, Investoren und Analysten für die Durchführung komplexer technischer Berechnungen und die Entwicklung von Handelsstrategien verwendet wird. Es wurde ursprünglich von Mario Fortier entwickelt, ist in ANSI C geschrieben und bietet eine umfassende Suite von über 200 technischen Indikatoren – darunter ADX, MACD, RSI, Stochastik-Oszillator, Bollinger-Bänder und andere – sowie die Fähigkeit, mehr als 60 Kerzen-Muster zu erkennen. Sein C/C++-Kern bietet eine API, auf die auch über Python zugegriffen werden kann, was eine nahtlose Integration in verschiedene Anwendungen ermöglicht. Seit der ersten Veröffentlichung im Jahr 2001 unter der BSD-Lizenz hat sich TA-Lib als stabiles und zuverlässiges Werkzeug etabliert, dessen Algorithmen sich bewährt haben und sowohl im Open-Source- als auch im kommerziellen Kontext weit verbreitet sind.

In diesem System sind die umfangreichen Mustererkennungsfunktionen der TA-Lib in eine Python-basierte Analysepipeline integriert, um die Erkennung von Kerzen-Mustern zu automatisieren. Das System lädt dynamisch alle relevanten Kerzen-Musterfunktionen aus der TA-Lib und kann so über 60 verschiedene Muster in den eingehenden Marktdaten identifizieren. Durch die Kombination der zuverlässigen Algorithmen der TA-Lib mit einer nutzerdefinierten Filterlogik erkennt sie präzise Auf- und Abwärtssignale, die dann mithilfe von mplfinance visuell auf Kerzen-Charts eingeblendet werden. Der gesamte Prozess ist in einen Flask-Webdienst verpackt, der die Datenverarbeitung, Mustererkennung und Visualisierung in Echtzeit ermöglicht. Dieses Setup ist ein Beispiel dafür, wie die umfassende Bibliothek der TA-Lib zusammen mit modernen Python-Tools genutzt werden kann, um anspruchsvolle, automatisierte Handelsanalysesysteme zu erstellen, die MQL5-Strategien nahtlos ergänzen.

Nachfolgend finden Sie eine schrittweise Anleitung zur Installation von TA-Lib auf Ihrem Computer:

Schritt 1: TA-Lib .whl herunterladen und installieren

  • Für Windows:

Laden Sie vorkompilierte Binärdateien von einer vertrauenswürdigen Quelle herunter. Laden Sie zum Beispiel die entsprechende .whl-Datei herunter – wie TA_Lib-0.4.0-cp39-cp39-win_amd64.whl – die mit Python 3.9 auf einem 64-Bit-Windows-System kompatibel ist. Die „passende“ .whl bedeutet, dass Sie die Datei auswählen sollten, die sowohl zu Ihrer Python-Version als auch zu Ihrer Systemarchitektur passt, um Kompatibilität zu gewährleisten.

Installation über pip:

pip install path\to\your\downloaded\file.whl

  • Für macOS:

Installieren Sie die TA-Lib C-Bibliothek mit Homebrew:

brew install ta-lib

  • Für Linux (Debian/Ubuntu):

Abhängigkeiten über apt installieren:

sudo apt-get update
sudo apt-get install libta-lib0-dev

Schritt 2: Installieren Sie den Python Wrapper für TA-Lib

Sobald die C-Bibliothek installiert ist, installieren Sie den Python-Wrapper:

pip install ta-lib

Schritt 3: Überprüfen Sie die Installation

Öffnen Sie eine Python-Shell und führen Sie aus:

import talib
print(talib.__version__)

Wenn keine Fehler auftreten und die Version gedruckt wird, war die Installation erfolgreich.

Werfen wir einen Blick auf die verfügbaren Kerzen in der TA-Lib-Bibliothek, die ich installiert habe.

CDL2CROWS
  CDL3BLACKCROWS
  CDL3INSIDE
  CDL3LINESTRIKE
  CDL3OUTSIDE
  CDL3STARSINSOUTH
  CDL3WHITESOLDIERS
  CDLABANDONEDBABY
  CDLADVANCEBLOCK
  CDLBELTHOLD
  CDLBREAKAWAY
  CDLCLOSINGMARUBOZU
  CDLCONCEALBABYSWALL
  CDLCOUNTERATTACK
  CDLDARKCLOUDCOVER
  CDLDOJI
  CDLDOJISTAR
  CDLDRAGONFLYDOJI
  CDLENGULFING
  CDLEVENINGDOJISTAR
  CDLEVENINGSTAR
  CDLGAPSIDESIDEWHITE
  CDLGRAVESTONEDOJI
  CDLHAMMER
  CDLHANGINGMAN
  CDLHARAMI
  CDLHARAMICROSS
  CDLHIGHWAVE
  CDLHIKKAKE
  CDLHIKKAKEMOD
  CDLHOMINGPIGEON
  CDLIDENTICAL3CROWS
  CDLINNECK
  CDLINVERTEDHAMMER
  CDLKICKING
  CDLKICKINGBYLENGTH
  CDLLADDERBOTTOM
  CDLLONGLEGGEDDOJI
  CDLLONGLINE
  CDLMARUBOZU
  CDLMATCHINGLOW
  CDLMATHOLD
  CDLMORNINGDOJISTAR
  CDLMORNINGSTAR
  CDLONNECK
  CDLPIERCING
  CDLRICKSHAWMAN
  CDLRISEFALL3METHODS
  CDLSEPARATINGLINES
  CDLSHOOTINGSTAR
  CDLSHORTLINE
  CDLSPINNINGTOP
  CDLSTALLEDPATTERN
  CDLSTICKSANDWICH
  CDLTAKURI
  CDLTASUKIGAP
  CDLTHRUSTING
  CDLTRISTAR
  CDLUNIQUE3RIVER
  CDLUPSIDEGAP2CROWS
  CDLXSIDEGAP3METHODS

Während die meisten Händler Klassiker wie Doji und Engulfing kennen, können einige weniger bekannte Formationen subtile Verschiebungen in der Marktpsychologie aufzeigen. Das Abandoned Baby ist eine seltene Umkehrung mit drei Balken: Ein Doji entfernt sich von der vorangegangenen Kerze, dann lässt eine weitere Lücke in die entgegengesetzte Richtung alle Balken „verlassen“, was oft eine entscheidende Trendwende ankündigt. Das Stick Sandwich entsteht, wenn zwei starke Kerzen der gleichen Farbe einen kleinen gegenläufigen Balken flankieren, wobei der letzte Balken am – oder sehr nahe am – Schlusskurs des ersten Balkens schließt; dieses „Sandwich“ signalisiert, dass der ursprüngliche Schwung trotz einer kurzen Gegenbewegung intakt bleibt. Das Tasuki Gap ist ein Fortsetzungsmuster mit drei Balken, bei dem eine anfängliche Lücke in der Trendrichtung durch den dritten Balken teilweise, aber nicht vollständig gefüllt wird, was die mangelnde Bereitschaft des Marktes, die Lücke aufzugeben, unterstreicht und die Stärke des vorherrschenden Trends bestätigt.

Zwei weitere schwer fassbare Muster, Hikkake und Belt Hold, sorgen für weitere Nuancen. Der japanische Hikkake („Falle“) beginnt mit einem inneren Balken, auf den ein falscher Ausbruch folgt, der die Händler in eine Richtung lockt, bevor er sich umkehrt und über die entgegengesetzte Grenze hinaus schließt, wodurch die Händler, die in die falsche Richtung gegangen sind, gefangen werden und der zugrunde liegende Trend beschleunigt wird. Im Gegensatz dazu ist der Belt Hold eine einzelne, entscheidende Kerze, die den „Gürtel hält“ gegen die vorangegangene Bewegung: Ein Aufwärts-Belt Hold eröffnet am oder in der Nähe des Tiefs in einem Abwärtstrend und schließt dann deutlich höher, während ein Abwärts-Belt Hold in der Nähe des Hochs in einem Aufwärtstrend eröffnet und deutlich niedriger schließt Da Belt Holds abrupte Kontrollverschiebungen innerhalb eines Balkens widerspiegeln, ohne dass ein vorhergehender Balken „verschluckt“ werden muss, können sie als klare, hochwirksame Umkehrsignale auf wichtigen Unterstützungs- oder Widerstandsniveaus dienen.

In der TA-Lib beginnt jede Kerzen-Musterfunktion mit dem Präfix CDL-, kurz für „Candle“, Kerze. Dieses Präfix zeigt an, dass die Funktion einen der vielen klassischen Kerzen-Muster-Algorithmen implementiert (z.B. CDLDOJI, CDLENGULFING, CDLHAMMER, etc.). Wenn Sie eine dieser Funktionen mit CDL* mit Ihren Open-High-Low-Close (OHLC)-Arrays aufrufen, wird eine ganzzahlige Reihe zurückgegeben, bei der Werte ungleich Null das Vorhandensein einer bestimmten Kerzenformation anzeigen, wobei das Vorzeichen die Richtung angibt.



Aufschlüsselung des Arbeitsablaufs im System

In diesem Abschnitt werde ich Ihnen zeigen, wie das System funktioniert, und eine detaillierte Aufschlüsselung sowohl der MQL5- als auch der Python-Skripte geben. Das Herzstück unseres Setups ist eine enge Anfrage-Antwort-Schleife: Jedes Mal, wenn ein neuer Kerzen schließt, zieht der MQL5 Expert Advisor die Werte der letzten 60 Bars (Open, High, Low, Close und Timestamp), verpackt sie in eine kompakte JSON-Nutzlast und sendet sie an den lokalen Flask-Service unter /patterns.

Der EA wartet dann auf die Antwort des Servers – die nun zwei parallele Arrays der Länge 60 enthält, eines für Muster (Kerzen-Namen) und eines für Signale („aufwärts“ oder „abwärts“) – und analysiert dieses JSON sofort. Im MetaTrader 5 werden zunächst alle vorhandenen Beschriftungen gelöscht, dann werden Textobjekte an den Hochpunkten jedes Balkens, an denen ein echtes Muster auftrat, neu erstellt, wobei sie für Aufwärtstrends kalkfarben und für Abwärtstrends rot eingefärbt werden, bevor ein anschaulicher Alert() ausgelöst wird.

In der Zwischenzeit nimmt der Flask-Endpunkt das JSON auf, normalisiert es in ein Pandas DataFrame, wendet die über 60 Musterdetektoren der TA-Lib an, markiert jeden Balken, bestimmt die aufwärts/abwärts Bias und gibt beide Arrays sowie ein kurzes Protokoll und eine Zeitmetrik zurück. Diese klare Aufteilung – MQL5 für Charts-E/A und Warnungen, Python für die Datennormalisierung und Musterlogik – sorgt dafür, dass beide Seiten fokussiert, effizient und einfach zu erweitern sind.

  • Aufschlüsselung des MQL5 Expert Advisor

Wenn der EA zum ersten Mal geladen wird, protokolliert er sofort eine Startmeldung, die Sie daran erinnert, den Flask-Endpunkt in den Expert Advisor-Einstellungen von MetaTrader 5 auf die Whitelist zu setzen. Dieser einmalige Einrichtungsschritt garantiert, dass nachfolgende HTTP-Aufrufe an Ihren lokalen Mustererkennungsdienst zulässig sind und verhindert stille Fehler zur Laufzeit.

int OnInit()
{
   Log("EA started – allow WebRequest to: " + InpURL);
   return INIT_SUCCEEDED;
}

Bei jedem eingehenden Tick prüft der EA den Zeitstempel der aktuellen Kerze (Null-Index) mit dem des zuletzt verarbeiteten Balkens. Wenn seit der letzten Prüfung kein neuer Balken geschlossen wurde, kehrt er einfach zurück – so wird überflüssige Arbeit vermieden und sichergestellt, dass die Musteranalyse nur einmal pro abgeschlossener Kerze ausgeführt wird.

void OnTick()
{
   datetime bar = iTime(_Symbol, InpTF, 0);
   if(bar == 0 || bar == g_lastBar)
      return;
   g_lastBar = bar;
   // … (continue processing)
}

Sobald ein neuer Balken bestätigt wird, durchläuft der EA die letzten 60 Kerzen rückwärts und extrahiert für jeden Balken den Eröffnungs-, Hoch-, Tief- und Schlussstand sowie den UNIX-Zeitstempel. Diese Werte werden vorübergehend in Arrays fester Größe gespeichert und dann in ein kompaktes JSON-Objekt serialisiert, das das Symbol, den Zeitrahmen und alle 60 Sätze von OHLC-Daten und -Zeiten enthält.

double o[BARS], h[BARS], l[BARS], c[BARS];
long   t[BARS];
for(int i = 0; i < BARS; i++)
{
   int sh = i + 1;
   o[i] = iOpen(_Symbol, InpTF, sh);
   h[i] = iHigh(_Symbol, InpTF, sh);
   l[i] = iLow(_Symbol, InpTF, sh);
   c[i] = iClose(_Symbol, InpTF, sh);
   t[i] = (long)iTime(_Symbol, InpTF, sh);
}
string json = StringFormat(
   "{\"symbol\":\"%s\",\"timeframe\":%d,\"time\":[%s],\"open\":[%s],\"high\":[%s],\"low\":[%s],\"close\":[%s]}",
   _Symbol, InpTF, CSVInt(t), CSV(o), CSV(h), CSV(l), CSV(c)
);
Log("JSON-OUT: " + json);

Mit der zusammengestellten JSON-Nutzlast stellt der EA eine POST-Anfrage an die konfigurierte Flask-URL und wartet bis zum angegebenen Timeout. Es erfasst alle Netzwerk- oder Berechtigungsfehler – und protokolliert detaillierte Meldungen, wenn die Anfrage fehlschlägt – und empfängt ansonsten die JSON-Antwort des Servers als Textstring zur weiteren Verarbeitung.

char body[];
StringToCharArray(json, body, 0, StringLen(json));
char reply[];
string hdr = "Content-Type: application/json\r\n", respHdr;
int code = WebRequest("POST", InpURL, hdr, InpTimeout, body, reply, respHdr);
if(code == -1)
{
   Log("WebRequest failed: " + IntegerToString(GetLastError()));
   return;
}
string resp = CharArrayToString(reply, 0, -1, CP_UTF8);
Log("HTTP " + IntegerToString(code) + " RESP: " + resp);

Nach der Rückkehr des HTTP-Aufrufs sucht der EA in der Antwort nach zwei Array-Einträgen – einem mit der Bezeichnung „patterns“ und einem mit der Bezeichnung „signals“. Er verwendet einfache String-Routinen zum Suchen und Splitten, um diese JSON-Arrays zurück in MQL5-String-Arrays zu konvertieren, wobei überprüft wird, dass jedes Array genau 60 Elemente enthält, bevor es weitergeht.

string patTxt, sigTxt, patt[], sigs[];
if(!ExtractArray(resp, "patterns", patTxt) ||
   !ExtractArray(resp, "signals", sigTxt) ||
   !ParseArray(patTxt, patt) ||
   !ParseArray(sigTxt, sigs) ||
   ArraySize(patt) != BARS ||
   ArraySize(sigs) != BARS)
{
   Log("Malformed patterns or signals");
   return;
}

Für jeden der 60 Balken prüft der EA die entsprechenden Muster und Signaleinträge. Immer wenn ein echtes Muster markiert wird (d.h. nicht „Nicht“), wird die korrekte Kerzenverschiebung berechnet, alle alten Anmerkungen bereinigt und eine neue Textbeschriftung am Hochpunkt des Balkens erstellt. Die Kennzeichnungen sind farblich kodiert – limonenfarben für Aufwärts-, rot für Aufwärtssignale – und lösen jeweils einen beschreibenden MetaTrader 5-Alarm mit Symbol, Zeitrahmen, Richtung, Mustername und Zeitstempel aus.

for(int i = 0; i < BARS; i++)
{
   string pat = patt[i], sig = sigs[i];
   if(pat == "" || pat == "None") continue;

   int shift = BARS - i;
   datetime tm = iTime(_Symbol, InpTF, shift);
   double y = iHigh(_Symbol, InpTF, shift);
   string obj = PREFIX + IntegerToString(shift);
   ObjectCreate(0, obj, OBJ_TEXT, 0, tm, y);
   ObjectSetString(0, obj, OBJPROP_TEXT, pat);

   color col = (sig == "bullish" ? clrLime : clrRed);
   ObjectSetInteger(0, obj, OBJPROP_COLOR, col);
   ObjectSetInteger(0, obj, OBJPROP_FONTSIZE, InpFontSize);
   ObjectSetInteger(0, obj, OBJPROP_SELECTABLE, false);

   Alert(StringFormat("%s %s %s pattern '%s' at %s",
                      _Symbol, EnumToString(InpTF), sig, pat,
                      TimeToString(tm, TIME_DATE|TIME_MINUTES)));
}

Wenn der EA entfernt oder der MetaTrader 5 heruntergefahren wird, durchläuft die Deinitialisierungsroutine alle Chart-Objekte, die mit dem Kennzeichnungs-Tag des EA versehen sind, und löscht sie. Dadurch wird sichergestellt, dass keine veralteten Beschriftungen auf dem Charts verbleiben, wenn der EA nicht mehr aktiv ist, sodass Ihr Arbeitsbereich sauber bleibt.

void OnDeinit(const int reason)
{
   for(int i = ObjectsTotal(0,0,-1)-1; i >= 0; i--)
   {
      string n = ObjectName(0, i, 0, -1);
      if(StringFind(n, PREFIX) == 0)
         ObjectDelete(0, n);
   }
   Log("EA removed");
}

  • Aufschlüsselung des Python Flask Servers

Wenn der Flask-Dienst startet, konfiguriert er die Protokollierung auf INFO-Ebene, um jede eingehende Anfrage und jedes interne Ereignis aufzuzeichnen, sowohl auf der Konsole als auch in einer rotierenden Protokolldatei. Unmittelbar danach durchsucht das Skript die TA-Lib-Bibliothek und sammelt dynamisch alle Kerzen-Musterfunktionen (die mit dem Präfix „CDL“) in einem speicherinternen Wörterbuch. Diese dynamische Erkennung bedeutet, dass der Dienst automatisch alle bestehenden und zukünftigen TA-Lib-Muster unterstützt, ohne dass ein manuelles Eingreifen erforderlich ist. Dadurch wird sichergestellt, dass alle neuen Muster, die in der TA-Lib hinzugefügt werden, Ihrem System zur Verfügung stehen, sobald die Bibliothek aktualisiert wird.

app = Flask(__name__)
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(levelname)s %(message)s')
app.logger.setLevel(logging.INFO)

# load all TA‑Lib candlestick functions
CDL_FUNCS = {
    name: getattr(talib, name)
    for name in talib.get_functions() if name.startswith("CDL")
}

Jedes Mal, wenn der EA einen POST an den /patterns-Endpunkt sendet, liest der Server die rohe Anforderungs-Payload, entfernt alle Null-Bytes, die MetaTrader 5 anhängen könnte, und versucht dann, sie als JSON zu dekodieren. Sollte das Parsen fehlschlagen oder eines der erforderlichen Arrays (open, high, low, close, time) fehlen, gibt der Server sofort einen eindeutigen HTTP 400-Fehler mit einer beschreibenden Meldung zurück. Indem Sie die Nutzdaten von Anfang an validieren, verhindern Sie, dass fehlerhafte oder unvollständige Daten die Analysepipeline durchlaufen und zu unklaren Fehlern in den nachgelagerten Bereichen führen.

@app.route('/patterns', methods=['POST'])
def patterns():
    app.logger.info("Received /patterns request")
    try:
        raw = request.data
        if b'\x00' in raw:
            raw = raw.split(b'\x00', 1)[0]
        data = json.loads(raw.decode('utf-8'))
    except Exception as e:
        return jsonify(error="Invalid JSON", details=str(e)), 400

Sobald mpel und die vier PreisreiJSON die Validierung bestanden hat, extrahiert der Server die fünf Schlüssel-Arrays – Zeitstempel und die vier Zeitreihen der Preise – und kehrt ihre Reihenfolge um, sodass Index 0 dem ältesten Balken entspricht. Anschließend wird die UNIX-Zeitstempel-Liste in einen Pandas DatetimeIndex umgewandelt, um sicherzustellen, dass nachfolgende Operationen zeitabhängig sind. Weichen Arrays in der Länge ab oder enthalten sie nicht-numerische Einträge, erfasst der Dienst die Diskrepanz sofort und gibt einen Fehler zurück, um zu gewährleisten, dass nur perfekt ausgerichtete und korrekt eingegebene Daten die Erkennungslogik erreichen.

try:
    symbol = data.get('symbol', 'Instrument')
    ts     = data.get('time', [])
    open_  = np.array(data['open'][::-1],  dtype=float)
    high   = np.array(data['high'][::-1],  dtype=float)
    low    = np.array(data['low'][::-1],   dtype=float)
    close  = np.array(data['close'][::-1], dtype=float)
    idx    = pd.to_datetime(np.array(ts[::-1], dtype='int64'), unit='s')
    app.logger.info(f"Loaded {len(open_)} bars for {symbol}")
except KeyError as ke:
    return jsonify(error=f"Missing field {ke}"), 400
except Exception as e:
    return jsonify(error="Bad field format", details=str(e)), 400

Mit sauberen NumPy-Arrays in der Hand, iteriert der Dienst durch jede TA-Lib-Kerzen-Funktion und wendet sie auf die gesamte Serie an. Jedes Ergebnis, das nicht Null ist, wird als Kandidatentreffer registriert. Zwei zusätzliche Hilfsroutinen – eine zur Validierung von Harami-Mustern und eine weitere zur Verfeinerung von Engulfing-Mustern – werden bedingt auf der Grundlage von Anforderungsflags angewandt und setzen bei Bedarf strengere Kriterien durch. Die Einbettung jedes TA-Lib-Aufrufs in einen try/except-Block bedeutet, dass eine einzelne problematische Funktion oder eine unerwartete Datenform nicht den gesamten Dienst zum Absturz bringen kann; stattdessen überspringt die Routine einfach diese Funktion und fährt mit der Verarbeitung des Rests fort.

n = len(open_)
all_hits = [[] for _ in range(n)]
for name, func in CDL_FUNCS.items():
    try:
        res = func(open_, high, low, close)
    except Exception:
        continue
    for i, v in enumerate(res):
        if v == 0:
            continue
        if name == "CDLHARAMI" and fh and not is_manual_harami(open_, close, i, tol=HARAMI_TOL):
            continue
        if name == "CDLENGULFING" and fe and not is_manual_engulfing(open_, close, i, tol=ENGULF_TOL):
            continue
        all_hits[i].append((name, v))

Da mehrere Muster auf demselben Balken registriert werden können, verwendet der Dienst eine kleine, konfigurierbare Prioritätenliste, die Engulfing gegenüber Harami und Harami gegenüber Doji bevorzugt, um bei Konflikten das dominante Muster auszuwählen. Ist keines der Prioritätsmuster vorhanden, wird dasjenige mit der größten absoluten TA-Lib-Leistung gewählt. Das numerische Vorzeichen der gewählten Ausgabe wird dann einem „aufwärts“- oder „abwärts“-Label zugewiesen. Dieser deterministische Ansatz mit nur einem Muster pro Balken stellt sicher, dass jede Kerze mit einem eindeutigen Signal versehen wird, was nachgelagerte Chart-Overlays und die Alarmlogik vereinfacht.

PRIORITY = ["CDLENGULFING", "CDLHARAMI", "CDLDOJI"]
detected = [None] * n
signals  = [None] * n
for i, hits in enumerate(all_hits):
    if not hits:
        continue
    pick = next(((nm, val) for pat in PRIORITY for nm, val in hits if nm == pat), None)
    if pick is None:
        pick = max(hits, key=lambda x: abs(x[1]))
    nm, val = pick
    detected[i] = nm
    signals[i]  = "bullish" if val > 0 else "bearish"

Als Nächstes erstellt das Skript einen Pandas DataFrame aus den vier Preis-Arrays und dem Datetime-Index und fügt dann zwei neue Spalten hinzu: eine für den Namen des erkannten Musters und eine weitere für das Aufwärts- bzw. Abwärtssignal. Um die visuelle Kommentierung vorzubereiten, wird ein kleiner Offset auf der Grundlage der gesamten Preisspanne berechnet und eine Liste von Streuungsüberlagerungen erstellt, wobei grüne Aufwärtspfeile direkt unter den Tiefstständen der Balken für Aufwärtssignale und rote Abwärtspfeile direkt über den Höchstständen der Balken für Abwärtssignale platziert werden. Durch die Verankerung der Markerpositionen in Bezug auf den dynamischen Bereich des Chartss vermeiden Sie visuelle Unordnung und gewährleisten Konsistenz über verschiedene Instrumente und Zeitrahmen hinweg.

df = pd.DataFrame({"Open": open_, "High": high, "Low": low, "Close": close}, index=idx)
df["Pattern"] = pd.Series(detected, index=idx).fillna("None")
df["Signal"]  = pd.Series(signals,  index=idx).fillna("")

df.sort_index(inplace=True)
adds = []
price_rng = df["High"].max() - df["Low"].min()
for tstamp, row in df.iterrows():
    if row["Pattern"] == "None":
        continue
    if row["Signal"] == "bullish":
        y, marker, color = row["Low"] - price_rng*0.005, "^", "green"
    else:
        y, marker, color = row["High"] + price_rng*0.005, "v", "red"
    adds.append(mpf.make_addplot(
        [y if i == tstamp else np.nan for i in df.index],
        type="scatter", marker=marker, markersize=80, color=color
    ))

Schließlich definiert der Dienst ein nutzerdefiniertes Farbschema für die Kerzen (z. B. grün für steigende und rot für fallende Balken) und rendert ein vollständiges Kerzen-Charts mit mplfinance, das die zuvor vorbereiteten Streuungsmarkierungen enthält. Eine Legende wird hinzugefügt, um sowohl die Kerzenrichtung als auch die Mustermarkierungen für eine einfache Interpretation abzubilden. Die Größe der Abbildung wird für eine optimale Übersichtlichkeit angepasst, in einer eigenen PNG-Datei im Serververzeichnis gespeichert und dann geschlossen, um Speicherplatz freizugeben. Die JSON-Antwort liefert die umgekehrten Muster- und Signallisten – Index 0 steht also wieder für den jüngsten Balken – eine optionale Protokollzusammenfassung und den Dateinamen des gespeicherten Chartss, das sofort vom EA verwendet oder in andere Analysetools integriert werden kann.

mc = make_marketcolors(up='green', down='red', edge='inherit', wick='inherit')
style = make_mpf_style(marketcolors=mc, base_mpf_style='default')
fig, axes = mpf.plot(df, type="candle", style=style,
                     title=f"{symbol} Patterns", addplot=adds,
                     volume=False, returnfig=True, tight_layout=True)
axes[0].legend(handles=[
    Line2D([0],[0],color='green',lw=4,label='Buy Candle'),
    Line2D([0],[0],color='red',lw=4,label='Sell Candle'),
    Line2D([0],[0],marker='^',linestyle='None',color='green',markersize=12,label='Buy Signal'),
    Line2D([0],[0],marker='v',linestyle='None',color='red',markersize=12,label='Sell Signal')
], loc='upper left', frameon=True)

fname = f"pattern_chart_{uuid.uuid4().hex[:8]}.png"
fig.savefig(path := os.path.join(os.path.dirname(__file__), fname), dpi=100)
plt.close(fig)
app.logger.info(f"Chart saved: {fname}")

return jsonify(
    patterns=[p or "None" for p in detected[::-1]],
    signals =[s or "none" for s in signals [::-1]],
    log=[],
    chart=fname
)


Tests und Ergebnisse

Nachstehend finden Sie eine Darstellung der von uns getesteten Ergebnisse. 

Prüfung des Stufenindex

MQL5-Protokolle:

Die Registerkarte MQL5-Experten zeigt Protokolle mit den an Python gesendeten Daten, den empfangenen Mustern und dem Namen jedes aktuell erkannten Balkens. Diese Informationen werden am Ende jedes neuen Balkens aktualisiert und mit einer Warnmeldung versehen.

2025.07.15 22:56:50.294 Candlestick Label 2 (Step Index,M15)    [CSLAB] JSON-OUT: {"symbol":"Step Index","timeframe":0,"time":[1752558300,1752559200,
1752560100,1752561000,1752561900,1752562800,1752563700,1752564600,1752565500,1752566400,1752567300,1752568200,
1752569100,1752570000,1752570900,1752571800,1752572700,1752573600,1752574500,1752575400,1752576300,1752577200,1752578100,1752579000,
1752579900,1752580800,1752581700,1752582600,1752583500,1752584400,1752585300,1752586200,1752587100,1752588000,1752588900,1752589800,
1752590700,1752591600,1752592500,1752593400,17525943
2025.07.15 22:56:50.804 Candlestick Label 2 (Step Index,M15)    [CSLAB] HTTP 200 RESP: {"chart":"pattern_chart_e06f7a61.png","log":[],"patterns":
["CDLENGULFING","CDLHARAMI","None","CDLCLOSINGMARUBOZU","CDLHARAMI","CDLHIKKAKE","CDLENGULFING","CDLHIGHWAVE","None","CDLLONGLINE",
"CDLHIGHWAVE","CDLSHORTLINE","CDLSHORTLINE","CDLHIKKAKE","CDLHARAMI","CDLENGULFING","CDLDOJI","None","None","None","CDLCLOSINGMARUBOZU",
"None","CDLBELTHOLD","None","CDLHARAMI","CDLBELTHOLD","CDLHIKKAKE","CDLENGULFING","CDLHIKKAKE","CDLHIKKAKE","None","CDLDOJI","CDLHAMMER",
"CDLHARAMI","CDLENGULFING"
2025.07.15 22:56:50.804 Candlestick Label 2 (Step Index,M15)    
2025.07.15 22:56:50.804 Candlestick Label 2 (Step Index,M15)    Alert: Step Index PERIOD_CURRENT bullish pattern 'CDLENGULFING' at 2025.07.15 05:45

Protokolle der Eingabeaufforderung:

  • POST /Patterns: Ein Client (Ihr MQL5 EA) hat eine HTTP POST-Anfrage an den Endpunkt /patterns gestellt.
  • HTTP/1.1: Für die Anfrage wurde das Protokoll HTTP 1.1 verwendet.
  • 200: Der Server antwortete mit dem Statuscode 200, was „OK“ bedeutet – Ihr Endpunkt hat die Anfrage erfolgreich verarbeitet.

2025-07-15 22:54:52,246 INFO Received /patterns request
2025-07-15 22:54:52,250 INFO Loaded 60 bars for Step Index
2025-07-15 22:54:52,808 INFO Chart saved: pattern_chart_a77f2eec.png
2025-07-15 22:54:52,810 INFO 127.0.0.1 - - [15/Jul/2025 22:54:52] "POST /patterns HTTP/1.1" 200 -
2025-07-15 22:55:00,040 INFO Received /patterns request

Nachfolgend finden Sie Charts für dieselben erkannten Muster, die den „Stufenindex“ im Zeitverlauf veranschaulichen. Die Charts werden mit Matplotlib, TA-Lib und mplfinance generiert und zeigen sowohl Preisbalken als auch die von unserem System identifizierten Kerzen-Signale an:

Kerzen  

  • Grüne Körper zeigen Zeiträume an, in denen der Schlusskurs über dem Eröffnungskurs lag (Aufwärtskerzen).
  • Rote Körper zeigen Zeiträume an, in denen der Schlusskurs unter dem Eröffnungskurs lag (Abwärtskerzen).

Signale  

  • Die grünen Markierungen unter den Balken stellen Kaufsignale (Aufwärtsmuster) dar.
  • Rote Markierungen über den Balken zeigen Verkaufssignale (Abwärtsmuster) an.

Prüfung am Crash 1000 Index

MQL5-Protokolle:

2025.07.15 23:30:00.299 Candlestick Label 2 (Crash 1000 Index,M15)      [CSLAB] JSON-OUT: {"symbol":"Crash 1000 Index","timeframe":0,"time":[1752561000,1752561900,
1752562800,1752563700,1752564600,1752565500,1752566400,1752567300,1752568200,1752569100,1752570000,1752570900,1752571800,1752572700,1752573600,1752574500,1752575400
,1752576300,1752577200,1752578100,1752579000,1752579900,1752580800,1752581700,1752582600,1752583500,1752584400,1752585300,1752586200,1752587100,1752588000,1752588900,
1752589800,1752590700,1752591600,1752592500,1752593400,1752594300,1752595200,1752596100,17
2025.07.15 23:30:02.749 Candlestick Label 2 (Crash 1000 Index,M15)      [CSLAB] HTTP 200 RESP: {"chart":"pattern_chart_ebd72b47.png","log":[],"patterns":
["CDLCLOSINGMARUBOZU","CDLBELTHOLD","CDLBELTHOLD","None","CDLBELTHOLD","CDLHIKKAKE","CDLENGULFING","CDLBELTHOLD","CDLHARAMI","CDLENGULFING","None","CDLBELTHOLD",
"None","CDLBELTHOLD","CDLBELTHOLD","CDLBELTHOLD","None","CDLBELTHOLD","CDLBELTHOLD","None","CDLBELTHOLD","CDLBELTHOLD","CDLBELTHOLD","CDLDOJI","CDLBELTHOLD","None",
"CDLSHORTLINE","CDLSHORTLINE","None","CDLENGULFING","CDLHARAMI","CDLCLOSINGMARUBOZU","None","CDLMATCHINGL
2025.07.15 23:30:02.749 Candlestick Label 2 (Crash 1000 Index,M15)      
2025.07.15 23:30:02.769 Candlestick Label 2 (Crash 1000 Index,M15)      Alert: Crash 1000 Index PERIOD_CURRENT bearish pattern 'CDLCLOSINGMARUBOZU' at 2025.07.15 06:30

Protokolle der Eingabeaufforderung:

2025-07-15 23:30:02,719 INFO Chart saved: pattern_chart_ebd72b47.png
2025-07-15 23:30:02,735 INFO 127.0.0.1 - - [15/Jul/2025 23:30:02] "POST /patterns HTTP/1.1" 200 -

Python Kerzen-Muster zeichnen

Die Darstellung gibt einen klaren Überblick darüber, wie jedes erkannte Muster signalisiert und was danach geschieht.


Schlussfolgerung

In dieser Architektur bleibt MetaTrader 5 seinen Stärken treu – der Erfassung von Marktdaten in Echtzeit, der Verwaltung von Chart-Objekten und der nativen Alarmierung – während ein leichtgewichtiger Flask-Dienst TA-Lib und mplfinance nutzt, um alle Kerzen-Muster-Berechnungen durchzuführen und ausgefeilte Visualisierungen zu generieren. Durch die Übertragung von sechzig Balken OHLC- und Zeitstempeldaten als JSON erreicht der EA eine Analyse im Subsekundenbereich, ohne seinen eigenen Platzbedarf zu erhöhen, und das Python-Backend liefert sowohl granulare Pattern-Labels als auch vollständige kommentierte Charts, die zur Überprüfung oder Verteilung bereitstehen.

Diese klare Trennung der Verantwortlichkeiten führt zu einem wirklich modularen System: Sie können die Regeln für die Mustererkennung verfeinern, die Toleranzen für die Signalfilter anpassen oder die Warnlogik des EA unabhängig voneinander erweitern, ohne das Risiko einer gegenseitigen Beeinflussung. Die Verpackung des Flask-Dienstes – ob in einem Docker-Container für eine konsistente Bereitstellung oder hinter einem authentifizierten API-Gateway – erhöht die Portabilität und Sicherheit zusätzlich.

Ich möchte Sie ermutigen, dieses Framework auf Ihre bevorzugten Instrumente anzuwenden, mit nutzerdefinierten Indikator-Overlays zu experimentieren und die generierten Charts in breitere Analyseplattformen zu integrieren. Mit diesem hybriden Ansatz nutzen Sie die volle Leistungsfähigkeit von MQL5 und modernen Python-Bibliotheken und verwandeln das manuelle Lesen von Charts in einen automatisierten, präzisionsgesteuerten Workflow.





  
Chart Projector
Analytical Comment
Analytics Master
Analytics Forecaster 
Volatility Navigator
Der Mean Reversion Signal Reaper
Signal Pulse 
Metrics Board 
External Flow
VWAP
Heikin Ashi  FibVWAP  
RSI DIVERGENCE
Parabolic Stop and Reverse (PSAR) 
Quarters Drawer Script
Intrusion Detector
TrendLoom Tool Quarters Board 
ZigZag Analyzer Correlation Pathfinder Market Structure Flip Detector Tool
Correlation Dashboard  Währungsstärkemesser 
PAQ-Analyse-Tool 
Dual EMA Fractal Breaker
Pin-Bar, Engulfing und RSI-Divergenz
Liquidity SweepWerkzeug zum Ausbrechen aus dem EröffnungsbereichAusleger und Crash InterceptorCCI Zero-Line EA
Erkennen von KerzenmusterKerzenerkennung mit Ta-Lib    

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/18824

Beigefügte Dateien |
candlesticks.py (6.76 KB)
Implementierung von praktischen Modulen aus anderen Sprachen in MQL5 (Teil 02): Aufbau der REQUESTS-Bibliothek, inspiriert von Python Implementierung von praktischen Modulen aus anderen Sprachen in MQL5 (Teil 02): Aufbau der REQUESTS-Bibliothek, inspiriert von Python
In diesem Artikel implementieren wir ein Modul, das den in Python angebotenen Anfragen ähnelt, um das Senden und Empfangen von Web-Anfragen in MetaTrader 5 mit MQL5 zu erleichtern.
MQL5-Assistenz-Techniken, die Sie kennen sollten (Teil 74):  Verwendung von Ichimoku-Mustern und ADX-Wilder mit überwachtem Lernen MQL5-Assistenz-Techniken, die Sie kennen sollten (Teil 74): Verwendung von Ichimoku-Mustern und ADX-Wilder mit überwachtem Lernen
Wir knüpfen an unseren letzten Artikel an, in dem wir das Indikatorenpaar Ichimoku und ADX vorstellten, und untersuchen, wie dieses Duo durch überwachtes Lernen verbessert werden kann. Ichimoku und ADX sind ein Unterstützungs-/Widerstands- und komplementäres Paar bezüglich eines Trends. Unser überwachter Lernansatz verwendet ein neuronales Netzwerk, das den Deep Spectral Mixture Kernel einsetzt, um die Prognosen dieses Indikatorpaares zu verfeinern. Wie üblich erfolgt dies in einer nutzerdefinierten Signalklassendatei, die mit dem MQL5-Assistenten zur Zusammenstellung eines Expert Advisors arbeitet.
Entwicklung eines Replay-Systems (Teil 77): Neuer Chart Trade (IV) Entwicklung eines Replay-Systems (Teil 77): Neuer Chart Trade (IV)
In diesem Artikel werden wir einige der Maßnahmen und Vorsichtsmaßnahmen behandeln, die bei der Erstellung eines Kommunikationsprotokolls zu beachten sind. Dies sind recht einfache und unkomplizierte Dinge, sodass wir in diesem Artikel nicht zu sehr ins Detail gehen werden. Aber um zu verstehen, was passieren wird, müssen Sie den Inhalt des Artikels verstehen.
Statistische Arbitrage durch kointegrierte Aktien (Teil 1): Engle-Granger- und Johansen-Kointegrationstests Statistische Arbitrage durch kointegrierte Aktien (Teil 1): Engle-Granger- und Johansen-Kointegrationstests
Dieser Artikel soll eine handelsfreundliche, sanfte Einführung in die gebräuchlichsten Kointegrationstests bieten, zusammen mit einem einfachen Leitfaden zum Verständnis ihrer Ergebnisse. Die Engle-Granger- und Johansen-Kointegrationstests können statistisch signifikante Paare oder Gruppen von Vermögenswerten aufzeigen, die eine gemeinsame langfristige Dynamik aufweisen. Der Johansen-Test ist besonders nützlich für Portfolios mit drei oder mehr Vermögenswerten, da er die Stärke der kointegrierenden Vektoren auf einmal berechnet.