Entwicklung des Price Action Analysis Toolkit (Teil 36): Direkter Python-Zugang zu MetaTrader 5 Market Streams freischalten
Inhalt
- Einführung
- Überblick über die Systemarchitektur
- Detaillierte Untersuchung des Python-Backends
- Erforschung der MQL5 EA-Client-Architektur
- Bewertung und Leistungsergebnisse
- Schlussfolgerung
Einführung
In unserem vorigen Artikel haben wir gezeigt, wie ein einfaches MQL5-Skript historische Balken in Python übertragen, Merkmale entwickeln, ein maschinelles Lernmodell trainieren und dann Signale zur Ausführung an MetaTrader zurücksenden kann – ohne manuelle CSV-Exporte, Excel-basierte Analysen und Versionskontrollprobleme. Händler erhielten eine Ende-zu-Ende-Pipeline, die rohe Minutenbar-Daten in statistisch gesteuerte Einstiegspunkte umwandelte, komplett mit dynamisch berechneten Levels von Stop-Loss (SL) und Take-Profit (TP).
Mit diesem System wurden drei wichtige Probleme des algorithmischen Handels gelöst:
- Fragmentierung von Daten: Das Kopieren und Einfügen von CSV-Dateien oder der Umgang mit komplexen Tabellenkalkulationsformeln entfällt – Ihr MetaTrader 5 Chart kommuniziert direkt mit Python.
- Verspätete Einsicht: Die Automatisierung des Feature-Engineerings und der Modellableitung ermöglichte Echtzeitsignale und damit den Übergang vom reaktiven zum proaktiven Handel auf der Grundlage von Live-Daten.
- Inkonsistentes Risikomanagement: Durch die Einbeziehung von ATR-basierten SL/TP sowohl in Backtests als auch in den Live-Handel wurde sichergestellt, dass alle Handelsgeschäften volatilitätsangepassten Regeln folgten und Ihr Vorteil erhalten blieb.

Wenn man sich jedoch auf einen Expert Advisor (EA) verlässt, um Daten in Python einzuspeisen, kann dies zu Latenzzeiten und Komplexität führen. Die neue Version nutzt die Fähigkeit von Python, als Client von MetaTrader 5 zu agieren und die MetaTrader 5-Bibliothek zum direkten Abrufen und Aktualisieren von Daten zu nutzen. Dieser Ansatz macht das Warten auf einen EA-Timer überflüssig; Python kann Daten bei Bedarf einlesen, effizient in einen Parquet-Speicher schreiben und intensive Berechnungen asynchron ausführen.
Aufbauend auf dieser Grundlage bietet unser erweitertes Python-MQL5-Hybrid-Tool noch mehr Möglichkeiten:
- Python-Seite: Echtzeit-MetaTrader 5-Dateneingabe über die systemeigene Bibliothek, fortschrittliches Feature-Engineering (z. B. Spike-Z-Scores, MACD-Differenzen, ATR-Bänder, Prophet-Trend-Deltas) und eine TimeSeries-fähige Gradient-Boosting-Pipeline, die auf rollenden Fenstern retrainiert – alles über eine leichtgewichtige Flask-API zugänglich.
- MQL5 Seite: Ein robuster REST-Polling EA mit Wiederholungslogik, ein On-Chart-Dashboard, das Signale, Konfidenzniveaus und den Verbindungsstatus anzeigt, Pfeilmarkierungen für Ein- und Ausstiege und eine optionale automatische Auftragsausführung unter strengen Risikomanagementregeln.
Während unser erster Artikel ein Proof-of-Concept darstellte, verkürzt dieses produktionsreife Framework die Einrichtungszeit erheblich, beschleunigt Feedbackschleifen und ermöglicht es Ihnen, mit datengestütztem Vertrauen und Präzision zu handeln. Tauchen wir ein
Überblick über die Systemarchitektur
Nachfolgend finden Sie eine Übersicht über den Daten- und Signalfluss zwischen MetaTrader 5 und Ihrem Python Dienst, gefolgt von den Hauptaufgaben der einzelnen Komponenten:

MetaTrader 5-Terminal
Das MetaTrader 5-Terminal dient als primäre Marktschnittstelle und Charting-Plattform. Er enthält die Live- und historischen Kursbalken für das von Ihnen gewählte Symbol und bietet die Ausführungsumgebung für den Expert Advisor (EA). Durch seine integrierte Funktion von WebRequest() sammelt der EA regelmäßig die neuesten Balkendaten und zeigt eingehende Signale, SL/TP-Linien und Einstiegs-/Ausstiegspfeile direkt auf Ihrem Chart an. Das MetaTrader 5-Terminal ist für die Auftragserteilung (wenn aktiviert), die lokale Objektverwaltung (Panels, Pfeile, Etiketten) und die nutzerorientierte Visualisierung der Systemausgaben zuständig.
Python-Dateneinspeisung
Anstatt sich auf einen EA zu verlassen, um Balkendaten zu pushen, verwendet Python Data Feed die offizielle Python-Bibliothek von MetaTrader 5, um bei Bedarf sowohl historische als auch OHLC-Echtzeitdaten der Minutenbalken zu beziehen. Es nutzt einen komprimierten Parquet-Datenspeicher, um die Kursdaten der vergangenen Tage zu erhalten, und fügt dann neue Balken hinzu, sobald sie eintreffen. Dieses Setup eliminiert die Abhängigkeiten von Zeitintervallen in MQL5 und stellt sicher, dass der Python-Dienst immer sofortigen, zufälligen Zugriff auf die vollständige Preishistorie hat, die sowohl für Backtests als auch für Live-Inferenz benötigt wird.
Technische Merkmale
Sobald die Rohdaten im Speicher oder auf der Festplatte verfügbar sind, werden sie von der Feature-Engineering-Schicht in statistisch aussagekräftige Eingaben für das maschinelle Lernen umgewandelt. Es berechnet normalisierte Spike-Z-Scores, die MACD-Histogramm-Differenz, 14-Perioden-RSI-Werte, 14-Perioden-ATR für Volatilität und dynamische EMA-basierte Envelope-Bänder. Darüber hinaus nutzt es die Prophet-Bibliothek von Facebook, um ein Trend-Delta auf Minutenebene zu schätzen, das die Abweichung zwischen Mittelwert und Trend erfasst. Diese automatisierte Pipeline garantiert, dass Live- und historische Daten identisch verarbeitet werden und die Modelltreue erhalten bleibt.
ML-Modell
Das Herzstück des Systems ist ein Gradient-Boosting-Klassifikator, der in eine scikit-learn-Pipeline mit Standardskalierung eingebettet ist. Das Modell wird auf rollierenden Fenstern vergangener Balken trainiert, wobei TimeSeriesSplit zur Vermeidung von Vorausschauverzerrungen und RandomizedSearchCV zur Optimierung von Hyperparametern verwendet werden. Die Etiketten werden generiert, indem die Kurse zehn Minuten im Voraus betrachtet und die Bewegungen anhand eines konfigurierbaren Schwellenwerts in Kauf-, Verkaufs- oder Warteklassen eingeteilt werden. Der trainierte Schätzer wird in die Datei model.pkl serialisiert, was eine geringe Latenz beim Laden und bei der Inferenz sowohl in Backtests als auch in Live-Läufen gewährleistet.
Flask-API
Die Flask-API dient als Brücke zwischen dem datenwissenschaftlichen Ökosystem von Python und dem MQL5 EA. Es stellt einen Single/Analyze-Endpunkt zur Verfügung, der eine JSON-Nutzlast mit aktuellen Schließungen und Zeitstempeln akzeptiert, die Feature-Pipeline und das geladene Modell anwendet, um Klassenwahrscheinlichkeiten zu berechnen, und eine kurze JSON-Antwort mit Signal, sl, tp und conf (Konfidenz) zurückgibt. Diese leichtgewichtige REST-Schnittstelle kann in Containern oder auf einem beliebigen Server bereitgestellt werden, wodurch Ihre Python-Rechenressourcen von der Laufzeitumgebung des MetaTrader entkoppelt werden und die Skalierbarkeit vereinfacht wird.
MQL5 Expert Advisor
Auf der Client-Seite konzentriert sich der MQL5 EA ausschließlich auf die Nutzerinteraktion und die Handelsausführung. Es fragt regelmäßig die Flask-API ab, analysiert eingehende JSON-Daten, protokolliert jedes Signal sowohl auf der Registerkarte Experten als auch in einer lokalen CSV-Datei und aktualisiert ein Dashboard, das das aktuelle Signal, die Vertrauensstufe, den Verbindungsstatus und den Zeitstempel anzeigt. Wenn ein gültiges Kauf-, Verkaufs- oder Schließsignal eintrifft, zeichnet der EA Pfeile und SL/TP-Linien und – wenn EnableTrading wahr ist – platziert oder schließt Aufträge über die CTrade-Klasse. Durch die Verlagerung der gesamten Datenwissenschaft auf Python bleibt der EA schlank, reaktionsschnell und leicht zu pflegen.
Detaillierte Untersuchung des Python-Backends
Die Grundlage unseres Backends bildet eine robuste Datenverarbeitungspipeline, die auf das offiziellen MetaTrader 5 Python-Paket. Beim ersten Start „bootet“ der Dienst, indem er die OHLC-Minutenbalken-Daten der letzten Tage abruft und in eine komprimierte Parquet-Datei schreibt. Das spaltenorientierte Format von Parquet und die Zstandard-Komprimierung ermöglichen blitzschnelle Lesevorgänge für Zeitserien-Slices, während die Festplattennutzung minimal ist. Danach werden durch ein einfaches inkrementelles Update nur neu gebildete Balken hinzugefügt – so werden redundante Downloads vermieden und sichergestellt, dass sowohl Live-Inferenz als auch Backtests auf einer aktuellen, einzigen Quelle der Wahrheit basieren.
import datetime as dt import pandas as pd import MetaTrader5 as mt5 from pathlib import Path PARQUET_FILE = "hist.parquet.zst" DAYS_TO_PULL = 60 UTC = dt.timezone.utc def bootstrap(): """Fetch last DAYS_TO_PULL days of M1 bars and write to Parquet.""" now = dt.datetime.utcnow() start = now - dt.timedelta(days=DAYS_TO_PULL) mt5.initialize() mt5.symbol_select("Boom 300 Index", True) bars = mt5.copy_rates_range("Boom 300 Index", mt5.TIMEFRAME_M1, start.replace(tzinfo=UTC), now.replace(tzinfo=UTC)) df = pd.DataFrame(bars) df['time'] = pd.to_datetime(df['time'], unit='s') df.set_index('time').to_parquet(PARQUET_FILE, compression='zstd') def append_new_bars(): """Append only the newest bars since last timestamp.""" df = pd.read_parquet(PARQUET_FILE) last = df.index[-1] now = dt.datetime.utcnow() new = mt5.copy_rates_range("Boom 300 Index", mt5.TIMEFRAME_M1, last.replace(tzinfo=UTC) + dt.timedelta(minutes=1), now.replace(tzinfo=UTC)) if new: new_df = pd.DataFrame(new) new_df['time'] = pd.to_datetime(new_df['time'], unit='s') merged = pd.concat([df, new_df.set_index('time')]) merged[~merged.index.duplicated()].to_parquet(PARQUET_FILE, compression='zstd')
Auf der Grundlage der Rohbalken berechnet unsere Pipeline eine Reihe von Merkmalen, mit denen Momentum, Volatilität und extreme Bewegungen erfasst werden können. Wir normalisieren die erste Preisdifferenz zu einem Score von „Z-Spike“, indem wir sie durch ihre rollierende 20-Balken-Standardabweichung dividieren, um plötzliche Preissprünge zu isolieren. Die MACD-Histogramm-Differenz und der 14-Perioden-RSI quantifizieren den Trend bzw. die überkauften/überverkauften Bedingungen, während der 14-Perioden-ATR die aktuelle Volatilität misst. Ein 20-Perioden-EMA definiert die Envelope-Bänder (EMA×0,997 und EMA×1,003), die sich an wechselnde Situationen anpassen. Und schließlich nimmt die Prophet-Bibliothek von Facebook die gesamte Zeitreihe der Schlusskurse auf, um ein Trend-Delta auf Minutenebene zu prognostizieren, das eine differenziertere, zeitabhängige Saisonalität und Drift erfasst.
import numpy as np import pandas as pd import ta from prophet import Prophet def engineer(df: pd.DataFrame) -> pd.DataFrame: df = df.copy() # z-spike (20-bar rolling std) df['r'] = df['close'].diff() df['z_spike'] = df['r'] / (df['r'].rolling(20).std() + 1e-9) # MACD histogram diff, RSI, ATR df['macd'] = ta.trend.macd_diff(df['close']) df['rsi'] = ta.momentum.rsi(df['close'], window=14) df['atr'] = ta.volatility.average_true_range(df['high'], df['low'], df['close'], window=14) # EMA envelopes ema = df['close'].ewm(span=20).mean() df['env_low'] = ema * 0.997 df['env_up'] = ema * 1.003 # Prophet trend delta (minute-level) if len(df) > 200: m = Prophet(daily_seasonality=False, weekly_seasonality=False) m.fit(pd.DataFrame({'ds': df.index, 'y': df['close']})) df['delta'] = m.predict(m.make_future_dataframe(periods=0, freq='min'))['yhat'] - df['close'] else: df['delta'] = 0.0 return df.dropna()
Wir betrachten die Vorhersage als eine Drei-Klassen-Klassifizierung: „KAUFEN“, wenn der Kurs in den nächsten 10 Minuten um mehr als einen Schwellenwert steigt, „VERKAUFEN“, wenn er um mehr als diesen Schwellenwert fällt, und ansonsten „WARTEN“. Sobald die Bezeichnungen zugewiesen sind, werden die Merkmale und Bezeichnungen für das Training in rollierende Zeitfenster aufgeteilt. Eine Pipeline von scikit-learn standardisiert zunächst jedes Merkmal und passt dann einen GradientBoostingClassifier an. Hyperparameter (Lernrate, Baumanzahl, maximale Tiefe) werden mittels RandomizedSearchCV unter einer TimeSeriesSplit Kreuzvalidierungsschema optimiert, wodurch sichergestellt wird, dass keine Lecks in der Vorausschau auftreten. Das beste Modell wird in die Datei model.pkl serialisiert, die sofort und mit geringer Latenz zur Inferenz bereit ist.
import numpy as np import joblib from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.ensemble import GradientBoostingClassifier from sklearn.model_selection import TimeSeriesSplit, RandomizedSearchCV LOOKAHEAD_MIN = 10 LABEL_THRESHOLD = 0.0015 FEATS = ['z_spike','macd','rsi','atr','env_low','env_up','delta'] def label_and_train(df: pd.DataFrame): # Look-ahead return chg = (df['close'].shift(-LOOKAHEAD_MIN) - df['close']) / df['close'] df['label'] = np.where(chg > LABEL_THRESHOLD, 1, np.where(chg < -LABEL_THRESHOLD, 2, 0)) X = df[FEATS].dropna() y = df.loc[X.index, 'label'] pipe = Pipeline([ ('scaler', StandardScaler()), ('gb', GradientBoostingClassifier(random_state=42)) ]) param_dist = { 'gb__learning_rate': [0.01, 0.05, 0.1], 'gb__n_estimators': [300, 500, 700], 'gb__max_depth': [2, 3, 4] } cv = TimeSeriesSplit(n_splits=5) rs = RandomizedSearchCV(pipe, param_dist, n_iter=12, cv=cv, scoring='roc_auc_ovr', n_jobs=-1, random_state=42) rs.fit(X, y) joblib.dump(rs.best_estimator_, 'model.pkl')Um eine Brücke zwischen Python und MetaTrader zu schlagen, stellen wir einen einzigen Flask-Endpunkt zur Verfügung: /analyze. Clients senden einen JSON-Payload, der ein Symbol, ein Array von Schlusskursen und entsprechende UNIX-Zeitstempel enthält. Der Endpunkt spielt unsere Feature-Pipeline auf diese Nutzlast ab, lädt das vorab trainierte Modell, berechnet die Klassenwahrscheinlichkeiten, bestimmt das Signal mit der höchsten Konfidenz und leitet dynamisch Stop-Loss- und Take-Profit-Levels aus dem ATR-Merkmal ab. Die Antwort ist ein kompaktes JSON-Objekt:
from flask import Flask, request, jsonify import joblib import pandas as pd app = Flask(__name__) model = joblib.load('model.pkl') @app.route('/analyze', methods=['POST']) def analyze(): payload = request.get_json(force=True) closes = payload['prices'] times = pd.to_datetime(payload['timestamps'], unit='s') df = pd.DataFrame({'close': closes}, index=times) # duplicate open/high/low for completeness df[['open','high','low']] = df[['close']] feat = engineer(df).iloc[-1:] probs = model.predict_proba(feat[FEATS])[0] p_buy, p_sell = probs[1], probs[2] signal = ('BUY' if p_buy > 0.55 else 'SELL' if p_sell > 0.55 else 'WAIT') atr = feat['atr'] entry = feat['close'] sl = entry - atr if signal=='BUY' else entry + atr tp = entry + 2*atr if signal=='BUY' else entry - 2*atr return jsonify(signal=signal, sl=round(sl,5), tp=round(tp,5), conf=round(max(p_buy,p_sell),2)) if __name__ == '__main__': app.run(port=5000)
Erforschung der MQL5 EA-Client-Architektur
Der Kern der EA-Schleife befindet sich entweder in einem Timer-Ereignis (OnTimer) oder in einer Prüfung auf einen neuen Balken, wo er WebRequest() aufruft, um HTTP-Nachrichten zu senden und zu empfangen. Zunächst werden die letzten N Balken über CopyRates gesammelt, das Array MqlRates in eine UTF-8-JSON-Payload konvertiert, die die Symbol- und Schlusskurssequenz enthält, und die erforderlichen HTTP-Header gesetzt. Wenn WebRequest() fehlschlägt (Rückgabe ≤0), erfasst der EA GetLastError(), erhöht einen Zähler für Wiederholungsversuche, protokolliert den Fehler und verschiebt weitere Anfragen, bis entweder die Wiederholungsversuche erschöpft sind oder der nächste Timer-Tick kommt. Erfolgreiche Antworten (Status ≥200) setzen die Anzahl der Wiederholungsversuche zurück und aktualisieren lastStatus. Dieses Muster gewährleistet eine robuste, asynchrone Signalisierung, ohne den Chart-Thread zu blockieren oder bei vorübergehenden Netzwerkproblemen abzustürzen.
// In OnTimer() or OnNewBar(): MqlRates rates[]; // Copy the last N bars into `rates` if(CopyRates(_Symbol, _Period, 0, InpBufferBars, rates) != InpBufferBars) return; ArraySetAsSeries(rates, true); // Build payload string payload = "{"; payload += StringFormat("\"symbol\":\"%s\",", _Symbol); payload += "\"prices\":["; for(int i=0; i<InpBufferBars; i++) { payload += DoubleToString(rates[i].close, _digits); if(i < InpBufferBars-1) payload += ","; } payload += "]}"; // Send request string headers = "Content-Type: application/json\r\nAccept: application/json\r\n\r\n"; char req[], resp[]; int len = StringToCharArray(payload, req, 0, WHOLE_ARRAY, CP_UTF8); ArrayResize(req, len); ArrayResize(resp, 8192); int status = WebRequest("POST", InpServerURL, headers, "", InpTimeoutMs, req, len, resp, headers); if(status <= 0) { int err = GetLastError(); PrintFormat("WebRequest error %d (attempt %d/%d)", err, retryCount+1, MaxRetry); ResetLastError(); retryCount = (retryCount+1) % MaxRetry; lastStatus = StringFormat("Err%d", err); return; } retryCount = 0; lastStatus = StringFormat("HTTP %d", status);
Sobald eine gültige JSON-Antwort in ein Signal, sl und tp geparst wurde, aktualisiert der EA sein On-Chart-Dashboard und zeichnet alle neuen Pfeile oder Linien. Das Dashboard besteht aus einem einzigen OBJ_RECTANGLE_LABEL mit vier Textbeschriftungen, die das Symbol, das aktuelle Signal, den HTTP-Status und den Zeitstempel anzeigen. Bei Abschlüssen werden alle vorhandenen vorangestellten Objekte gelöscht, bevor ein neuer Pfeil (OBJ_ARROW) zum aktuellen Preis erstellt wird, wobei unterschiedliche Pfeilcodes und Farben für Kaufen (grün aufwärts), Verkaufen (rot abwärts) oder Schließen (orange) verwendet werden. Horizontale Linien (OBJ_HLINE) markieren Stop-Loss- und Take-Profit-Ebenen, die rot bzw. grün eingefärbt sind. Indem jedes Objekt mit einem eindeutigen Präfix versehen und bei Signaländerungen oder Deinitialisierung bereinigt wird, bleibt Ihr Chart klar und übersichtlich.
// Panel (rectangle + labels) void DrawPanel() { const string pid = "SigPanel"; if(ObjectFind(0, pid) < 0) ObjectCreate(0, pid, OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, pid, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, pid, OBJPROP_XDISTANCE, PanelX); ObjectSetInteger(0, pid, OBJPROP_YDISTANCE, PanelY); ObjectSetInteger(0, pid, OBJPROP_XSIZE, PanelW); ObjectSetInteger(0, pid, OBJPROP_YSIZE, PanelH); ObjectSetInteger(0, pid, OBJPROP_BACK, true); ObjectSetInteger(0, pid, OBJPROP_BGCOLOR, PanelBG); ObjectSetInteger(0, pid, OBJPROP_COLOR, PanelBorder); string lines[4] = { StringFormat("Symbol : %s", _Symbol), StringFormat("Signal : %s", lastSignal), StringFormat("Status : %s", lastStatus), StringFormat("Time : %s", TimeToString(TimeLocal(), TIME_MINUTES)) }; for(int i=0; i<4; i++) { string lbl = pid + "_L" + IntegerToString(i); if(ObjectFind(0, lbl) < 0) ObjectCreate(0, lbl, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, lbl, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, lbl, OBJPROP_XDISTANCE, PanelX + 6); ObjectSetInteger(0, lbl, OBJPROP_YDISTANCE, PanelY + 4 + i*(TxtSize+2)); ObjectSetString(0, lbl, OBJPROP_TEXT, lines[i]); ObjectSetInteger(0, lbl, OBJPROP_FONTSIZE, TxtSize); ObjectSetInteger(0, lbl, OBJPROP_COLOR, TxtColor); } } // Arrows & SL/TP lines void ActOnSignal(ESignal code, double sl, double tp) { // remove old arrows/lines for(int i=ObjectsTotal(0)-1; i>=0; i--) if(StringFind(ObjectName(0,i), objPrefix) == 0) ObjectDelete(0, ObjectName(0,i)); // arrow int arrCode = (code==SIG_BUY ? 233 : code==SIG_SELL ? 234 : 158); color clr = (code==SIG_BUY ? clrLime : code==SIG_SELL ? clrRed : clrOrange); string name = objPrefix + "Arr_" + TimeToString(TimeCurrent(), TIME_SECONDS); ObjectCreate(0, name, OBJ_ARROW, 0, TimeCurrent(), SymbolInfoDouble(_Symbol, SYMBOL_BID)); ObjectSetInteger(0, name, OBJPROP_ARROWCODE, arrCode); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); // SL line if(sl > 0) { string sln = objPrefix + "SL_" + name; ObjectCreate(0, sln, OBJ_HLINE, 0, 0, sl); ObjectSetInteger(0, sln, OBJPROP_COLOR, clrRed); } // TP line if(tp > 0) { string tpn = objPrefix + "TP_" + name; ObjectCreate(0, tpn, OBJ_HLINE, 0, 0, tp); ObjectSetInteger(0, tpn, OBJPROP_COLOR, clrLime); } }
Die tatsächliche Auftragserteilung ist durch das Flag EnableTrading geschützt, sodass Sie mühelos zwischen dem reinen Anzeige- und dem Live-Ausführungsmodus wechseln können. Vor jeder Market-Order prüft der EA PositionSelect(_Symbol), um doppelte Positionen zu vermeiden. Für ein Kaufsignal wird CTrade.Buy() mit FixedLots, SL und TP aufgerufen, für einen Verkauf CTrade.Sell() und für ein CLOSE-Signal CTrade.PositionClose(). Die Schlupftoleranz (SlippagePoints) wird beim Schließen angewendet. Diese minimale, zustandsabhängige Logik stellt sicher, dass Sie nie versehentlich dieselbe Seite zweimal eingeben und dass alle Aufträge Ihre vordefinierten Risikoparameter einhalten.
void ExecuteTrade(ESignal code, double sl, double tp) { if(!EnableTrading) return; bool hasPosition = PositionSelect(_Symbol); if(code == SIG_BUY && !hasPosition) trade.Buy(FixedLots, _Symbol, 0, sl, tp); else if(code == SIG_SELL && !hasPosition) trade.Sell(FixedLots, _Symbol, 0, sl, tp); else if(code == SIG_CLOSE && hasPosition) trade.PositionClose(_Symbol, SlippagePoints); }
Installation und Konfiguration
Bevor Sie mit der Erzeugung von Live-Signalen beginnen können, müssen Sie sowohl Ihre Python-Umgebung als auch Ihre MetaTrader 5-Plattform vorbereiten. Beginnen Sie mit der Installation von Python 3.8 oder neuer auf demselben Rechner, auf dem auch Ihr MetaTrader 5 Terminal läuft. Erstellen und aktivieren Sie eine virtuelle Umgebung (Python-m venv venv dann unter Windows venv\Scripts\activate, oder unter macOS/Linux venv/bin/activate) und installieren Sie alle Abhängigkeiten mit:Öffnen Sie auf der MetaTrader 5-Seite
Zum Beispiel (http://127.0.0.1:5000) in das Feld „WebRequest für folgende URLS erlauben“. Dieser Schritt der Whitelist ist von entscheidender Bedeutung – ohne ihn verwirft MetaTrader 5 alle POST-Payloads stillschweigend.
Kopieren Sie in Ihrem Projektordner das Python-Service-Skript (z.B. market_ai_engine.py) in ein Arbeitsverzeichnis Ihrer Wahl. Bearbeiten Sie den oberen Teil des Skripts, um Ihr Handelssymbol (MAIN_SYMBOL), Ihre MetaTrader 5-Anmeldedaten (LOGIN_ID, PASSWORD, SERVER) und Dateipfade (PARQUET_FILE, MODEL_FILE) festzulegen. Wenn Sie einen anderen als den Standard-Port für den Flask-Server bevorzugen, können Sie diesen beim Start des Dienstes mit --port übergeben.
Um den Expert Advisor einzusetzen, platzieren Sie die kompilierte EA.ex5 (oder die .mq5-Quelldatei) in Ihrer MetaTrader 5-Installation unter MQL5 → Experts.
Starten Sie MetaTrader 5 neu oder aktualisieren Sie den Navigator, damit der EA in Ihrer Liste erscheint. Ziehen Sie es auf ein M1-Chart des gleichen Symbols, das Sie in Python konfiguriert haben. In den Eingaben des EA, Punkt InpServerURL auf http://127.0.0.1:5000/analyze setzen Sie InpBufferBars (z.B. 60),InpPollInterval (z. B. 60 Sekunden) und InpTimeoutMs (z. B. 5000 ms). Lssen Sie EnableTrading zunächst ausgeschaltet, damit Sie die Signale überprüfen können, ohne dass es zu echten Aufträgen kommt.
Schließlich starten Sie Ihr Python-Backend in der folgenden Reihenfolge:
1. python market_ai_engine.py bootstrap
2. python market_ai_engine.py collect
3. python market_ai_engine.py train
4. python market_ai_engine.py serve --port 5000
Wenn der Flask-Server läuft und AutoTrading in MetaTrader aktiviert ist, beginnt der EA mit der Abfrage von Live-Signalen, dem Zeichnen von Pfeilen und SL/TP-Linien auf Ihrem Chart und – sobald Sie sich sicher sind – dem Platzieren von Handelsgeschäften nach Ihren vordefinierten Risikoregeln.
Fehlersuche
Wenn der EA keine Daten anzeigt oder immer „WAIT“ zurückgibt, vergewissern Sie sich, dass Ihre API-URL in den Einstellungen des MetaTrader 5 Expert Advisor auf der Whitelist steht. Bei gemischten HTTP/HTTPS-Umgebungen sollten Sie für lokale Tests ein einfaches HTTP (127.0.0.1) verwenden und für den Handel auf HTTPS mit einem vertrauenswürdigen Zertifikat umstellen. Vergewissern Sie sich, dass die Uhren Ihres Servers und Ihres MetaTrader 5-Terminals synchronisiert sind (entweder in UTC oder in der gleichen lokalen Zeitzone), um falsch ausgerichtete Balken-Anforderungen zu vermeiden. Vergewissern Sie sich schließlich, dass AutoTrading aktiviert ist und dass keine globalen Berechtigungen oder andere EAs Ihren Experten blockieren.
Bewertung und Leistungsergebnisse
Um die Arbeit mit dem hybriden Python-MQL5-Maschinenlernsystem zu beginnen, muss man zunächst historische Daten mit dem Befehl
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py bootstrap 2025-08-04 23:39:23 | INFO | Bootstrapped historical data: 86394 rows
Nach dem Bootstrapping können kontinuierlich aktualisieren durch das Ausführen von
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py collect 2025-08-04 23:41:01 | INFO | Appended 2 new bars 2025-08-04 23:42:01 | INFO | Appended 1 new bars 2025-08-04 23:43:01 | INFO | Appended 1 new bars
Wenn ein aktueller Datensatz vorliegt, ist der nächste Schritt das Modelltraining.
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py train 23:48:44 - cmdstanpy - INFO - Chain [1] start processing 23:51:24 - cmdstanpy - INFO - Chain [1] done processing 2025-08-05 02:59:08 | INFO | Model training complete
Um herauszufinden, wie gut das Modell im realen Handel funktioniert, können Sie einen Backtest mit folgenden Befehl durchführen:
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py backtest --days 30 06:57:33 - cmdstanpy - INFO - Chain [1] start processing 06:58:30 - cmdstanpy - INFO - Chain [1] done processing 2025-08-05 06:59:20 | INFO | Backtest results saved to backtest_results_30d.csv
Backtest-Ergebnisse
Nachfolgend finden Sie ausgewählte Kennzahlen und Handelsdetails, die aus den 30-Tage-Backtest-Ergebnissen extrahiert wurden:

Kumulative Kapitalkurve im Zeitverlauf

Hier finden Sie eine Zusammenfassung der wichtigsten Kennzahlen:
* **Average Entry Price:** 3099.85 * **Average Exit Price:** 3096.53 * **Average PNL (Profit and Loss):** 3.32 * **Total PNL:** 195.69 * **Average Cumulative Equity:** 96.34 * **First Trade Time:** 2025-07-11 14:18:00 * **Last Trade Time:** 2025-07-27 02:00:00
Gewinnrate:
win_rate 72.88135528564453 The win rate is 72.88%. This means that approximately 73% of the trades resulted in a profit.
Nachdem das Modell trainiert und validiert wurde, starten Sie den Live-Inferenzserver mit
2025-08-05 12:41:53 | INFO | analyze: signal=%s, sl=%.5f, tp=%.5f 127.0.0.1 - - [05/Aug/2025 12:41:53] "POST /analyze HTTP/1.1" 200 -
Auf der MetaTrader-Seite muss der EA richtig konfiguriert sein, um den Python-Server abzufragen. In den Eingaben des EA sollte die Server-URL (z. B. http://127.0.0.1:5000/analyze) definiert werden, und der EA muss mit demselben Symbol und Zeitrahmen verknüpft werden, mit dem das Modell trainiert wurde – in der Regel M1. Sobald der EA läuft, holt er in regelmäßigen Abständen Signale ab, stellt sie als Pfeile auf dem Chart dar und handelt optional auf der Grundlage strenger Risikoregeln aus.
2025.08.05 12:41:53.532 trained model (1) (Boom 300 Index,M1) >>> JSON: {"symbol":"Boom 300 Index","prices":[2701.855,2703.124, 2704.408,2705.493,2705.963,2696.806,2698.278,2699.877,2701.464,2702.788,2691.762,2693.046,2694.263,2695.587,2696.863,2698. 179,2699.775,2701.328,2702.888,2698.471,2699.887,2695.534,2696.952,2698.426,2699.756,2699.552,2700.954,2702.131,2703.571, 2699.549,2700.868,2702.567,2703.798,2705.067,2706.874,2698.084,2699.538,2700.856,2702.227,2703.692,2705.102,2706.188,2707.609,2709.001, 2710.335,2711.716,2712.919,2712.028,2713.529,2715.052,2716.578,2717. 2025.08.05 12:41:53.943 trained model (1) (Boom 300 Index,M1) <<< HTTP 200 hdr: 2025.08.05 12:41:53.943 trained model (1) (Boom 300 Index,M1) {"conf":0.43,"signal":"WAIT","sl":2725.04317,"tp":2720.18266} 2025.08.05 12:41:53.943 trained model (1) (Boom 300 Index,M1) [2025.08.05 12:41:53] Signal → WAIT | SL=2725.04317 | TP=2720.18266 | Conf=0.43
Schlussfolgerung
In diesem Artikel haben wir einen MQL5 Expert Advisor entwickelt, der sich die Stärken von Python im Bereich der Datenwissenschaft zunutze macht. Hier ist, was Sie jetzt haben:- Datenabruf: Ihr EA zieht die Minutenbalken aus dem MetaTrader 5 und schreibt sie ins Parquet.
- Merkmalsanalyse: Es wird Spike-Z, MACD, RSI, ATR, Envelope-Bänder und sogar Prophet-basierte Trenddeltas berechnet.
- Modellierung und Bereitstellung: Sie trainieren ein zeitbewusstes Gradient-Boosting-Modell und stellen Vorhersagen über Flask bereit.
- On-Chart-Aktion: MQL5 nutzt diese Signale, um Pfeile und SL/TP-Linien zu zeichnen – und kann automatisch Handelsgeschäfte platzieren.
Sie können versuchen, einen anderen Algorithmus (XGBoost, LSTM, usw.) einzusetzen, Ihre Regeln für das Risikomanagement zu verbessern oder den Python-Dienst mit Docker zu containerisieren, um eine sauberere Bereitstellung zu erreichen. Mit dieser Grundlage können Sie Ihre Backtests verfeinern und Ihre automatisierten Strategien noch weiter ausbauen.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/19065
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.
MetaTrader Tick-Info-Zugang von MQL5-Diensten zur Python-Anwendung über Sockets
Automatisieren von Handelsstrategien in MQL5 (Teil 25): Trendlinien-Händler mit der Anpassung der kleinsten Quadrate und dynamischer Signalgenerierung
Eine alternative Log-datei mit der Verwendung der HTML und CSS
CRUD-Operationen in Firebase mit MQL
- 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.