Entwicklung des Price Action Analysis Toolkit (Teil 32): Python-Engine für Kerzenmuster (II) – Erkennung mit Ta-Lib
Inhalt
- Einführung
- Aufbauend auf unserer letzten Diskussion
- TA-Lib verstehen
- System Workflow Breakdown
- Tests und Ergebnisse
- Schlussfolgerung
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.
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:
| Vorteil | Beschreibung |
|---|---|
| Automatisierung | Erkennt über 60 Kerzen-Muster automatisch ohne manuelle Kodierung. |
| Wirkungsgrad | Schnellere Mustererkennung, geeignet für Echtzeitanalysen. |
| Genauigkeit | Verwendet 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 EATa-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.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/18824
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Implementierung von praktischen Modulen aus anderen Sprachen in MQL5 (Teil 02): Aufbau der REQUESTS-Bibliothek, inspiriert von Python
MQL5-Assistenz-Techniken, die Sie kennen sollten (Teil 74): Verwendung von Ichimoku-Mustern und ADX-Wilder mit überwachtem Lernen
Entwicklung eines Replay-Systems (Teil 77): Neuer Chart Trade (IV)
Statistische Arbitrage durch kointegrierte Aktien (Teil 1): Engle-Granger- und Johansen-Kointegrationstests
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.