![Aufbau des Kerzenmodells Trend-Constraint (Teil 5): Nachrichtensystem (Teil III)](https://c.mql5.com/2/83/Building_A_Candlestick_Trend_Constraint_Model__Part_5___CONT_600x314.jpg)
Aufbau des Kerzenmodells Trend-Constraint (Teil 5): Nachrichtensystem (Teil III)
Inhalt:
- Einführung
- Konfigurieren einer Messaging-API
- Das Skript (send_whatsapp_message.py)
- Ändern des Trendeinschränkungsindikators für WhatsApp-Benachrichtigungen
- Tests
- Sicherheit
- Schlussfolgerung
Einführung
Wir haben jetzt die Signalverfügbarkeit unseres Modells erweitert, sodass es für alle Nutzer von Vorteil ist. Darüber hinaus haben wir zahlreiche aufstrebende Entwickler dazu motiviert, soziale Netzwerke für Signale nahtlos in unsere bekannte MetaTrader 5 Handelsplattform zu integrieren. Abschließend wollen wir uns noch mit den Details der WhatsApp-Integration beschäftigen. Unser Ziel ist es, Signale, die von unseren nutzerdefinierten MetaTrader 5-Indikatoren generiert werden, automatisch an eine WhatsApp-Nummer oder Gruppe zu senden. Meta hat eine neue Kanalfunktion auf WhatsApp eingeführt, mit der Signale ein größeres Publikum erreichen können. Wie Porter Gale in ihrem Buch „Your Network Is Your Net Worth“ schreibt, ist die Zugehörigkeit zu einer Gemeinschaft entscheidend für den Erfolg. Durch Fortschritte wie diese können wir eine große Gemeinschaft beeinflussen, insbesondere auf beliebten Plattformen wie Telegram und WhatsApp.
Ich habe mich entschlossen, ein Flussdiagramm einzufügen, das den Prozess der Integration einer beliebigen Social-Media-Plattform in MetaTrader 5 skizziert. Dies ist eine zusammenfassende, schrittweise Entwicklung auf der Grundlage meiner Forschung. Die kritischen Phasen sind in dem Flussdiagramm klar umrissen. Lassen Sie mich kurz einige der Phasen erläutern. Das Flussdiagramm schildert die Erfahrungen, die während der Entwicklung gemacht wurden. Es ist wichtig, dass Sie darauf vorbereitet sind, bestimmte Vorgänge zu wiederholen, da Fehler auftreten können. In diesem Artikel werde ich mich nur auf das konzentrieren, was ich als wirksam erwiesen habe, obwohl während des Schreibprozesses eine beträchtliche Menge an Fehlersuche durchgeführt wurde. Dies sind die Schritte, die wir in (Teil II) bei der Integration von Telegram mit dem Trend Constraint Indicator für Benachrichtigungen durchlaufen haben.
Integration von sozialen Plattformen mit Meta Trader 5 Flussdiagramm
Das Flussdiagramm vereinfacht das Verständnis des gesamten Prozesses der Integration der letzten Phase, der Entscheidungsphase, die zwei mögliche Ergebnisse hat: Ja oder Nein.
Ist die Prüfung erfolgreich?
Wenn ja:Wenn Nein:
- Integration einführen.
- Überwachen und Warten (alles funktioniert gut und wir können unser neues System wie ursprünglich geplant einsetzen).
- End (Das Ende einer erfolgreichen Integration).
- Debuggen und Beheben von Problemen (Schleife zurück zu Entwicklungsumgebung einrichten, die Idee ist hauptsächlich, alle Schritte noch einmal durchzugehen, um nach Fehlern zu suchen, sie zu korrigieren und erneut zu testen).
- Erkundung anderer Optionen (Schleife zurück, um andere soziale Plattformen auszuprobieren, also die früheren Phasen, wenn keine API verfügbar ist).
Konfigurieren einer Messaging-API
Auf der Grundlage des bereitgestellten Flussdiagramms haben wir beschlossen, in die Integration von WhatsApp vorzudringen, wie wir es für Telegram im vorherigen Artikel getan haben. Beide Plattformen bieten APIs, die mit unseren Zielen übereinstimmen. Die Entscheidung für WhatsApp ist vor allem auf die große Nutzerbasis zurückzuführen. Ich persönlich nutze WhatsApp häufiger als jede andere soziale Plattform, und der Empfang von Signalen über diese Plattform wird mir helfen, mein MetaTrader5-Geschäft effektiv zu überwachen.
Laut whatsthebigdata hatte WhatsApp im Juli 2023 rund 2,78 Milliarden aktive Nutzer weltweit. Die beliebte Messaging-App hat im Jahr 2020 die 2-Milliarden-Marke erreicht und wird bis 2025 voraussichtlich 3,14 Milliarden erreichen.
Bei der Auswahl von Plattformen, die dazu beitragen, unser Vermögen über diese Netze zu steigern, sollten statistische Werte berücksichtigt werden. Im Internet finden sich zahlreiche Anbieter von Messaging-APIs mit unterschiedlichem Grad an leichte Verwendung und Nutzerfreundlichkeit. Viele bieten eine Testversion an, erfordern aber ein Abonnement für den Zugriff auf erweiterte Funktionen. Nach meinen Recherchen gibt es im Internet unter anderem folgende Möglichkeiten:
Ich habe Twilio für dieses Projekt verwendet, weil es einen nutzerfreundlicheren API-Zugang bietet und für die Integration von WhatsApp geeignet ist. Die angebotenen Optionen sind effektiv, auch wenn der Konfigurationsprozess komplex sein kann und für den Zugang zu anderen wichtigen Funktionen ein Abonnement erforderlich ist. Dennoch lohnt es sich, sie zu erforschen, um das eigene Verständnis zu erweitern.
Ich habe mein Twilio-Konto erstellt und alles eingerichtet. Die wichtigsten Elemente, die auf der Website benötigt werden, sind account_sid, auth_token, die Whatsapp-Nummer die in der Twilio-Sandbox zugewiesen wurde, und Ihre eigene Empfangsnummer um Unterhaltungen zu initiieren. Alle erforderlichen Anmeldeinformationen für das Skript finden Sie auf Ihrer Twilio-Kontoseite.
Indem Sie zum Konsolenbereich Ihres Twilio-Kontos navigieren, können Sie herausfinden, wo WhatsApp-Nachrichten gesendet werden. Dort können Sie Ihre Sandbox-Nummer sehen, die auf der API-Seite gespeichert wird, um die von MetaTrader 5 eingehenden Benachrichtigungen an Ihre verbundenen WhatsApp-Nummern zu senden. Es ist bedauerlich, dass es nur an die angeschlossenen Teilnehmer sendet. Der folgende Screenshot zeigt eine Beitrittsnachricht, die Sie an die Sandbox-Nummer senden müssen, um beizutreten. Speichern Sie zunächst die Nummer des Sandkastens in Ihrer Kontaktliste, suchen Sie sie dann und senden Sie „join so-cave“. Sobald dies geschehen ist, können Sie automatisch ein Integrationsskript mit Testmeldungen in der Eingabeaufforderung ausführen und sehen, dass es funktioniert.
Hier ist ein Bildschirmfoto von meinem Beitritt:
Zu diesem Zeitpunkt haben wir die für den Integrationsprozess erforderlichen API-Anmeldeinformationen erhalten, wie im Flussdiagramm dargestellt. Gehen wir nun zur nächsten Phase über, in der wir uns mit der Anwendung dieser Zeugnisse im Detail befassen werden.
Das Skript (send_whatsapp_message.py)
Wir können IDLE für die Skripterstellung verwenden. Der Python-Interpreter ist auf dem System vorinstalliert. Alternativ dazu bevorzuge ich Open-Source-Programme wie Notepad++ für die Skripterstellung. Notepad++ unterstützt verschiedene Sprachen mit korrekter Formatierung. Beginnen Sie mit der Erstellung einer neuen Datei, nennen Sie sie send_whatsapp_nachricht.py. Es ist ratsam, Ihre Skriptdatei zusammen mit dem Python-Interpreter im Ordner scripts zu speichern. Beim Testen des Programms von diesem Verzeichnis aus gab es keine Probleme.
Wir beginnen mit dem Import von Modulen in unser Skript:
import sys import requests
- import sys: Dieses Modul ermöglicht den Zugriff auf einige Variablen, die vom Python-Interpreter verwendet oder verwaltet werden. Es erlaubt Ihnen, mit dem Interpreter zu interagieren.
- import requests: Dieses Modul wird zum Senden von HTTP-Anfragen verwendet. Es vereinfacht die Erstellung von API-Anfragen.
In der nächsten Phase werden die Funktionen definiert:
def send_whatsapp_message(account_sid, auth_token, from_whatsapp_number, to_whatsapp_number, message): url = f"https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Messages.json" data = { "From": f"whatsapp:{from_whatsapp_number}", "To": f"whatsapp:{to_whatsapp_number}", "Body": message, } response = requests.post(url, data=data, auth=(account_sid, auth_token)) if response.status_code == 201: print("Message sent successfully") else: print(f"Failed to send message: {response.status_code} - {response.text}")
send_whatsapp_message: Diese Funktion sendet eine WhatsApp-Nachricht über die Twilio-API.
In der Funktionsdefinition gibt es mehrere Parameter, die für die Ausführung des Skripts erforderlich sind. Viele davon wurden beim Einrichten des Twilio-Kontos erworben.
Parameter:
- account_sid: Die Konto-SID aus Ihrem Twilio-Konto.
- auth_token: Das Auth Token von Ihrem Twilio-Konto.
- from_whatsapp_number: Die WhatsApp-aktivierte Twilio-Nummer, formatiert mit dem Präfix „whatsapp:“.
- to_whatsapp_number: Die WhatsApp-Nummer des Empfängers, formatiert mit dem Präfix „whatsapp:“.
- message: Der zu versendende Nachrichtentext.
requests.post: Sendet eine POST-Anfrage an die Twilio-API mit den Nachrichtendaten und den Authentifizierungsdaten.
response: Erfasst die Antwort von der Twilio-API.
status_code: Überprüft den Statuscode der Antwort, um festzustellen, ob die Nachricht erfolgreich gesendet wurde (201 bedeutet Erfolg).
Der letzte Ausschnitt des Skripts bildet den Hauptcode, und hier findet die Ausführung statt. Wenn dieses Skript ausgeführt wird, wird es:
- Lesen Sie den Nachrichtentext aus den Befehlszeilenargumenten.
- Rufen Sie die Funktion send_whatsapp_message mit den angegebenen Anmeldedaten, Telefonnummern und der Nachricht auf.
- Drucken einer Erfolgs- oder Fehlermeldung basierend auf der Antwort von der Twilio-API
# Replace with your actual Twilio credentials and phone numbers account_sid = "**********************" # Your SID auth_token = "***************************" # Your Auth Token from_whatsapp_number = "+14**********" # Your WhatsApp-enabled Twilio number to_whatsapp_number = "+************" # Recipient's WhatsApp number message = sys.argv[1] send_whatsapp_message(account_sid, auth_token, from_whatsapp_number, to_whatsapp_number, message)
Im Ganzen ergibt das unsere endgültige Arbeitsdatei send_whatsapp_message.py wie folgt
import sys import requests def send_whatsapp_message(account_sid, auth_token, from_whatsapp_number, to_whatsapp_number, message): url = f"https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Messages.json" data = { "From": f"whatsapp:{from_whatsapp_number}", "To": f"whatsapp:{to_whatsapp_number}", "Body": message, } response = requests.post(url, data=data, auth=(account_sid, auth_token)) if response.status_code == 201: print("Message sent successfully") else: print(f"Failed to send message: {response.status_code} - {response.text}") # Replace with your actual Twilio credentials and phone numbers account_sid = "****************" auth_token = "**********************" from_whatsapp_number = "+14***********" to_whatsapp_number = "+***************" message = sys.argv[1] send_whatsapp_message(account_sid, auth_token, from_whatsapp_number, to_whatsapp_number, message)
Wir können nun in der Eingabeaufforderung testen, ob das Skript funktioniert. Öffnen Sie den Pfad zum Verzeichnis der Datei send_whatapp_message.py gespeichert ist, und geben Sie den folgenden Befehl ein:
python send_whatsapp_message.py "Test Message"
Wenn alles in Ordnung ist, wird die Nachricht an Ihre WhatsApp-Nummer gesendet und die Meldung „Nachricht erfolgreich gesendet“ wird im Fenster der Eingabeaufforderung angezeigt. Wenn Sie auf Fehler stoßen, müssen Sie Ihren Code und Ihre Anmeldedaten erneut überprüfen, vor allem, weil der bereitgestellte Code fehlerbereinigt wurde und nun einwandfrei funktioniert. Ich werde im Folgenden einen Screenshot meiner funktionierenden Integration in einigen Abschnitten zeigen.
Ändern des Indikators Trend-Constraint für Whatsapp-Benachrichtigungen
Um die Integration zu vervollständigen, ohne den Code des Indikators wesentlich zu verändern, habe ich beschlossen, mich auf die Anpassung des Blocks myAlert so anzupassen, dass er Whatsapp-Nachrichten unterstützt. Es ist sehr wichtig, dass Sie den Pfad zu Ihrem Python-Interpreter und dem Skript genau eingeben. Dies sind die Schlüsselkomponenten der Integration, wenn man von diesem Codeschnipsel ausgeht. Ich habe den größten Teil des Codes unserer früheren Telegram-Integration unverändert übernommen. Außerdem habe ich eine Testinitialisierungsfunktion eingebaut, die es ermöglicht, beim Start eine Willkommensnachricht zu senden, um die Funktionalität des Systems zu überprüfen, bevor echte Signale empfangen werden.
int OnInit() { // Send test message on launch myAlert("info", "Thank you for subscribing. You shall be receiving Trend Constraint signal alerts via Whatsapp."); return(INIT_SUCCEEDED); }
Enthalten in OnInit() wird sichergestellt, dass die Nachricht an Ihre Nummern gesendet wird, wenn Sie den Indikator zu einem beliebigen Chat hinzufügen.
Im Folgenden finden Sie den wichtigsten Teil unserer Integrationslogik für das Senden von Nachrichten an WhatsApp. Ich habe die Abschnitte des Codes hervorgehoben, die ich im Vergleich zu dem für die Telegram-Integration verwendeten Code geändert habe.
//--- ShellExecuteW declaration ---------------------------------------------- #import "shell32.dll" int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd); #import //--- global variables ------------------------------------------------------ datetime last_alert_time; input int alert_cooldown_seconds = 60; // Cooldown period in seconds //--- myAlert function ------------------------------------------------------ void myAlert(string type, string message) { datetime current_time = TimeCurrent(); if (current_time - last_alert_time < alert_cooldown_seconds) { // Skip alert if within cooldown period return; } last_alert_time = current_time; string full_message = type + " | Trend Constraint V1.06 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message; if (type == "print") { Print(message); } else if (type == "error") { Print(type + " | Trend Constraint V1.06 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message); } else if (type == "order") { // Add order alert handling if needed } else if (type == "modify") { // Add modify alert handling if needed } else if (type == "indicator" || type == "info") { if (Audible_Alerts) { Alert(full_message); } if (Push_Notifications) { SendNotification(full_message); } // Send to WhatsApp //Edit to match your actual path, these I gave as an example for my computer string python_path = "C:\\Users\\******\\AppData\\Local\\Programs\\Python\\Python312\\python.exe"; string script_path = "C:\\Users\\******\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py"; string command = python_path + " \"" + script_path + "\" \"" + full_message + "\""; // Debugging: Print the command being executed Print("Executing command to send WhatsApp message: ", command); // Use cmd.exe to execute the command and then wait for 5 seconds string final_command = "/c " + command + " && timeout 5"; int result = ShellExecuteW(0, "open", "cmd.exe", final_command, NULL, 1); if (result <= 32) { int error_code = GetLastError(); Print("Failed to execute Python script. Error code: ", error_code); } else { Print("Successfully executed Python script. Result code: ", result); } } }
Hier ist das Hauptprogramm nach den Anpassungen, die uns Trend Constraint V1.06 geben:
//+------------------------------------------------------------------+ //| Trend Constraint V1.06.mq5 | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Clemence Benjamin" #property link "https://www.mql5.com" #property version "1.06" #property description "A model that seeks to produce sell signals when D1 candle is Bearish only and buy signals when it is Bullish" //--- indicator settings #property indicator_chart_window #property indicator_buffers 6 #property indicator_plots 6 #property indicator_type1 DRAW_ARROW #property indicator_width1 5 #property indicator_color1 0xFF3C00 #property indicator_label1 "Buy" #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Sell" #property indicator_type3 DRAW_ARROW #property indicator_width3 2 #property indicator_color3 0xE8351A #property indicator_label3 "Buy Reversal" #property indicator_type4 DRAW_ARROW #property indicator_width4 2 #property indicator_color4 0x1A1AE8 #property indicator_label4 "Sell Reversal" #property indicator_type5 DRAW_LINE #property indicator_style5 STYLE_SOLID #property indicator_width5 2 #property indicator_color5 0xFFAA00 #property indicator_label5 "Buy" #property indicator_type6 DRAW_LINE #property indicator_style6 STYLE_SOLID #property indicator_width6 2 #property indicator_color6 0x0000FF #property indicator_label6 "Sell" #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; double Buffer3[]; double Buffer4[]; double Buffer5[]; double Buffer6[]; input double Oversold = 30; input double Overbought = 70; input int Slow_MA_period = 200; input int Fast_MA_period = 100; datetime time_alert; //used when sending alert input bool Audible_Alerts = true; input bool Push_Notifications = true; double myPoint; //initialized in OnInit int RSI_handle; double RSI[]; double Open[]; double Close[]; int MA_handle; double MA[]; int MA_handle2; double MA2[]; int MA_handle3; double MA3[]; int MA_handle4; double MA4[]; double Low[]; double High[]; int MA_handle5; double MA5[]; int MA_handle6; double MA6[]; int MA_handle7; double MA7[]; //--- ShellExecuteW declaration ---------------------------------------------- #import "shell32.dll" int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd); #import //--- global variables ------------------------------------------------------ datetime last_alert_time; input int alert_cooldown_seconds = 60; // Cooldown period in seconds //--- myAlert function ------------------------------------------------------ void myAlert(string type, string message) { datetime current_time = TimeCurrent(); if (current_time - last_alert_time < alert_cooldown_seconds) { // Skip alert if within cooldown period return; } last_alert_time = current_time; string full_message = type + " | Trend Constraint V1.06 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message; if (type == "print") { Print(message); } else if (type == "error") { Print(type + " | Trend Constraint V1.06 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message); } else if (type == "order") { // Add order alert handling if needed } else if (type == "modify") { // Add modify alert handling if needed } else if (type == "indicator" || type == "info") { if (Audible_Alerts) { Alert(full_message); } if (Push_Notifications) { SendNotification(full_message); } // Send to WhatsApp string python_path = "C:\\Users\\****\\AppData\\Local\\Programs\\Python\\Python312\\python.exe"; string script_path = "C:\\Users\\****\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py"; string command = python_path + " \"" + script_path + "\" \"" + full_message + "\""; // Debugging: Print the command being executed Print("Executing command to send WhatsApp message: ", command); // Use cmd.exe to execute the command and then wait for 5 seconds string final_command = "/c " + command + " && timeout 5"; int result = ShellExecuteW(0, "open", "cmd.exe", final_command, NULL, 1); if (result <= 32) { int error_code = GetLastError(); Print("Failed to execute Python script. Error code: ", error_code); } else { Print("Successfully executed Python script. Result code: ", result); } } } //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { SetIndexBuffer(0, Buffer1); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(0, PLOT_ARROW, 241); SetIndexBuffer(1, Buffer2); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(1, PLOT_ARROW, 242); SetIndexBuffer(2, Buffer3); PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(2, PLOT_ARROW, 236); SetIndexBuffer(3, Buffer4); PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(3, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(3, PLOT_ARROW, 238); SetIndexBuffer(4, Buffer5); PlotIndexSetDouble(4, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(4, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); SetIndexBuffer(5, Buffer6); PlotIndexSetDouble(5, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(5, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); // Send test message on launch myAlert("info", "Thank you for subscribing. You shall be receiving Trend Constraint signal alerts via Whatsapp."); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } RSI_handle = iRSI(NULL, PERIOD_CURRENT, 14, PRICE_CLOSE); if(RSI_handle < 0) { Print("The creation of iRSI has failed: RSI_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_SMMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle2 = iMA(NULL, PERIOD_CURRENT, 400, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle2 < 0) { Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle3 = iMA(NULL, PERIOD_CURRENT, 100, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle3 < 0) { Print("The creation of iMA has failed: MA_handle3=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle4 = iMA(NULL, PERIOD_CURRENT, 200, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle4 < 0) { Print("The creation of iMA has failed: MA_handle4=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle5 = iMA(NULL, PERIOD_CURRENT, Fast_MA_period, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle5 < 0) { Print("The creation of iMA has failed: MA_handle5=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle6 = iMA(NULL, PERIOD_CURRENT, Slow_MA_period, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle6 < 0) { Print("The creation of iMA has failed: MA_handle6=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle7 = iMA(NULL, PERIOD_CURRENT, 200, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle7 < 0) { Print("The creation of iMA has failed: MA_handle7=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { int limit = rates_total - prev_calculated; //--- counting from 0 to rates_total ArraySetAsSeries(Buffer1, true); ArraySetAsSeries(Buffer2, true); ArraySetAsSeries(Buffer3, true); ArraySetAsSeries(Buffer4, true); ArraySetAsSeries(Buffer5, true); ArraySetAsSeries(Buffer6, true); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); ArrayInitialize(Buffer3, EMPTY_VALUE); ArrayInitialize(Buffer4, EMPTY_VALUE); ArrayInitialize(Buffer5, EMPTY_VALUE); ArrayInitialize(Buffer6, EMPTY_VALUE); } else limit++; datetime Time[]; datetime TimeShift[]; if(CopyTime(Symbol(), PERIOD_CURRENT, 0, rates_total, TimeShift) <= 0) return(rates_total); ArraySetAsSeries(TimeShift, true); int barshift_M1[]; ArrayResize(barshift_M1, rates_total); int barshift_D1[]; ArrayResize(barshift_D1, rates_total); for(int i = 0; i < rates_total; i++) { barshift_M1[i] = iBarShift(Symbol(), PERIOD_M1, TimeShift[i]); barshift_D1[i] = iBarShift(Symbol(), PERIOD_D1, TimeShift[i]); } if(BarsCalculated(RSI_handle) <= 0) return(0); if(CopyBuffer(RSI_handle, 0, 0, rates_total, RSI) <= 0) return(rates_total); ArraySetAsSeries(RSI, true); if(CopyOpen(Symbol(), PERIOD_M1, 0, rates_total, Open) <= 0) return(rates_total); ArraySetAsSeries(Open, true); if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close) <= 0) return(rates_total); ArraySetAsSeries(Close, true); if(BarsCalculated(MA_handle) <= 0) return(0); if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total); ArraySetAsSeries(MA, true); if(BarsCalculated(MA_handle2) <= 0) return(0); if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total); ArraySetAsSeries(MA2, true); if(BarsCalculated(MA_handle3) <= 0) return(0); if(CopyBuffer(MA_handle3, 0, 0, rates_total, MA3) <= 0) return(rates_total); ArraySetAsSeries(MA3, true); if(BarsCalculated(MA_handle4) <= 0) return(0); if(CopyBuffer(MA_handle4, 0, 0, rates_total, MA4) <= 0) return(rates_total); ArraySetAsSeries(MA4, true); if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); if(BarsCalculated(MA_handle5) <= 0) return(0); if(CopyBuffer(MA_handle5, 0, 0, rates_total, MA5) <= 0) return(rates_total); ArraySetAsSeries(MA5, true); if(BarsCalculated(MA_handle6) <= 0) return(0); if(CopyBuffer(MA_handle6, 0, 0, rates_total, MA6) <= 0) return(rates_total); ArraySetAsSeries(MA6, true); if(BarsCalculated(MA_handle7) <= 0) return(0); if(CopyBuffer(MA_handle7, 0, 0, rates_total, MA7) <= 0) return(rates_total); ArraySetAsSeries(MA7, true); if(CopyTime(Symbol(), Period(), 0, rates_total, Time) <= 0) return(rates_total); ArraySetAsSeries(Time, true); //--- main loop for(int i = limit-1; i >= 0; i--) { if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation if(barshift_M1[i] < 0 || barshift_M1[i] >= rates_total) continue; if(barshift_D1[i] < 0 || barshift_D1[i] >= rates_total) continue; //Indicator Buffer 1 if(RSI[i] < Oversold && RSI[i+1] > Oversold //Relative Strength Index crosses below fixed value && Open[barshift_M1[i]] >= Close[1+barshift_D1[i]] //Candlestick Open >= Candlestick Close && MA[i] > MA2[i] //Moving Average > Moving Average && MA3[i] > MA4[i] //Moving Average > Moving Average ) { Buffer1[i] = Low[1+i]; //Set indicator value at Candlestick Low if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy"); //Alert on next bar open time_alert = Time[1]; } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(RSI[i] > Overbought && RSI[i+1] < Overbought //Relative Strength Index crosses above fixed value && Open[barshift_M1[i]] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close && MA[i] < MA2[i] //Moving Average < Moving Average && MA3[i] < MA4[i] //Moving Average < Moving Average ) { Buffer2[i] = High[1+i]; //Set indicator value at Candlestick High if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell"); //Alert on next bar open time_alert = Time[1]; } else { Buffer2[i] = EMPTY_VALUE; } //Indicator Buffer 3 if(MA5[i] > MA6[i] && MA5[i+1] < MA6[i+1] //Moving Average crosses above Moving Average ) { Buffer3[i] = Low[i]; //Set indicator value at Candlestick Low if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy Reversal"); //Alert on next bar open time_alert = Time[1]; } else { Buffer3[i] = EMPTY_VALUE; } //Indicator Buffer 4 if(MA5[i] < MA6[i] && MA5[i+1] > MA6[i+1] //Moving Average crosses below Moving Average ) { Buffer4[i] = High[i]; //Set indicator value at Candlestick High if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell Reversal"); //Alert on next bar open time_alert = Time[1]; } else { Buffer4[i] = EMPTY_VALUE; } //Indicator Buffer 5, Alert muted by turning it into a comment if(MA3[i] > MA7[i] //Moving Average > Moving Average ) { Buffer5[i] = MA3[i]; //Set indicator value at Moving Average //if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy"); //Alert on next bar open //time_alert = Time[1]; } else { Buffer5[i] = EMPTY_VALUE; } //Indicator Buffer 6, Alert muted by turning it into a comment if(MA3[i] < MA7[i] //Moving Average < Moving Average ) { Buffer6[i] = MA3[i]; //Set indicator value at Moving Average //if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell"); //Alert on next bar open //time_alert = Time[1]; } else { Buffer6[i] = EMPTY_VALUE; } } return(rates_total); } //+------------------------------------------------------------------+
Tests und Ergebnisse
Wir haben in zwei der oben genannten Unterabschnitte Tests durchgeführt. Unser Projekt funktioniert auf meiner Seite einwandfrei. Nachfolgend finden Sie einige Bildschirmfotos der empfangenen Signale.
Der Indikator funktioniert gut, zeichnet entsprechend dem Ziel und sendet wie vorgesehen Signale an meine sozialen Kanäle. Im Anhang finden Sie eine Abbildung des Boom 500 Index-Charts:
Unser Programm öffnet beim Start ein Eingabeaufforderungsfenster, um die laufenden Prozesse anzuzeigen, und sendet einen Eröffnungshinweis. Bei der Übertragung von Signalen über die Zeit wird das gleiche Verfahren angewandt. Das aufspringende Fenster kann jedoch bei der Bearbeitung von Aufgaben störend sein, sodass das Programm so programmiert werden kann, dass es ohne Anzeige des Eingabeaufforderungsfensters funktioniert. Bei diesem Projekt haben wir uns dafür entschieden, das Fenster zur Beobachtung des laufenden Prozesses nicht zu verdecken. Um zu verhindern, dass das Eingabeaufforderungsfenster angezeigt wird, können Sie die folgende Codezeile einfügen...
// execute the command without showing the window string final_command = "/c " + command + " && timeout 5"; int result = ShellExecuteW(0, "open", "cmd.exe", final_command, NULL, 0); // Change the last parameter to 0 (SW_HIDE) if (result <= 32) { int error_code = GetLastError(); Print("Failed to execute Python script. Error code: ", error_code); } else { Print("Successfully executed Python script. Result code: ", result); }
Der letzte Parameter heißt nShowCmd und steuert, wie das Anwendungsfenster angezeigt wird. Durch Ändern der Parameter auf 0 (SW_HIDE) anstelle von 1 (SW_SHOWNORMAL).
Sicherheit
Bei der verwendeten Technik handelt es sich um DLL-Dateien, die als potenzielle Bedrohung angesehen werden. Im Rahmen meiner Nachforschungen habe ich die damit verbundenen Risiken ermittelt, um sie im Folgenden zu erläutern. Achten Sie darauf, Ihre Anmeldedaten für APIs zu schützen, denn ich habe mich bemüht, meine an einer Stelle in diesem Artikel zu verbergen. Geben Sie sie nur an vertrauenswürdige Stellen weiter.
Einige Gefahren im Zusammenhang mit DLL-Dateien:
- Malware: Das Laden einer bösartigen DLL kann schädlichen Code auf Ihrem System ausführen. Dies stellt ein erhebliches Risiko dar, wenn die DLL von einem nicht vertrauenswürdigen oder unbekannten Ort stammt.
- DLL-Hijacking: Wenn ein Angreifer eine bösartige DLL an einem Ort platzieren kann, von dem aus die Anwendung geladen wird, kann er beliebigen Code ausführen. Dies ist besonders gefährlich, wenn die Anwendung mit erhöhten Rechten ausgeführt wird.
- Abstürze und Instabilität: Die falsche Verwendung von DLL-Funktionen oder der Aufruf von Funktionen mit ungültigen Parametern kann zu Anwendungsabstürzen oder Systeminstabilität führen.
- Ressourcenlecks: Ein unsachgemäßer Umgang mit Ressourcen (z. B. Speicher, Datei-Handles) innerhalb von DLL-Funktionen kann zu Ressourcenlecks führen, die die Systemleistung mit der Zeit beeinträchtigen.
- Versionskonflikte: Verschiedene Versionen einer DLL können unterschiedliche Funktionssignaturen oder Verhaltensweisen aufweisen, was zu Kompatibilitätsproblemen führt.
- Abhängigkeit Hölle: Die Verwaltung von Abhängigkeiten von mehreren DLLs und deren Versionen kann komplex und fehleranfällig sein und zu Laufzeitfehlern führen.
Um solche Bedrohungen zu bekämpfen, ist es wichtig, Sicherheitsfunktionen in unser Programm aufzunehmen. Die folgende Codezeile kann Sicherheitsbedenken ausräumen, wenn sie in unserem Modell implementiert wird:
// You can secure the program by adding SecureExecuteCommand(command); below these lines. string python_path = "C:\\Users\\*****\\AppData\\Local\\Programs\\Python\\Python312\\python.exe"; string script_path = "C:\\Users\\*****\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py"; //***** is your computer user name, the rest of the path txt is correct based on the python version being used. string message = "Hello, this is a test message"; string command = python_path + " \"" + script_path + "\" \"" + message + "\""; SecureExecuteCommand(command);
Die Funktion SecureExecuteCommand() prüft auf ungültige Zeichen in der Befehlszeichenfolge, was dazu beitragen kann, Angriffe durch Befehlsinjektion zu verhindern.
Einige bewährte Verfahren zur Bekämpfung der Risiken sind:
- Nur vertrauenswürdige Quellen verwenden: Verwenden Sie nur DLLs aus vertrauenswürdigen und überprüften Quellen.
- Code Signing: Stellen Sie sicher, dass DLLs von einer vertrauenswürdigen Stelle signiert sind, um ihre Integrität und Herkunft zu überprüfen.
- Geringstes Privileg: Führen Sie Anwendungen mit den geringstmöglichen Rechten aus, um die Auswirkungen eines möglichen Missbrauchs zu verringern.
- Eingaben validieren: Überprüfen und bereinigen Sie immer die Eingabeparameter, insbesondere bei der Erstellung von Befehlszeichenfolgen.
- Fehlerbehandlung: Implementieren Sie eine robuste Fehlerbehandlung, um Fehler ordnungsgemäß zu verwalten und zu protokollieren.
- Regelmäßige Updates: Halten Sie Ihre Software und Bibliotheken mit Sicherheits-Patches und Updates auf dem neuesten Stand.
- Isolierung: Verwenden Sie Sandboxing oder andere Isolationstechniken, um potenziell riskante Vorgänge in einer eingeschränkten Umgebung auszuführen.
Schlussfolgerung
Die Integration von WhatsApp wurde erfolgreich abgeschlossen. Unser Modell kann jetzt Signale vom MetaTrader 5 an Telegram und WhatsApp übertragen. Es ist möglich, die Integration in einem einzigen Programm zusammenzufassen und die Signale auf beiden Plattformen gleichzeitig auszustrahlen. Ich habe leichte Diskrepanzen bei der Signalübermittlung beobachtet, wobei Push-Benachrichtigungen etwas früher ankommen als die auf sozialen Plattformen, wenn auch mit einem sehr geringen Zeitunterschied, vielleicht etwa 7 Sekunden. Die Telegram-Signale überholten die WhatsApp-Signale um einige Sekunden. Unser Hauptziel war es jedoch, die Ankunft unserer Signale sicherzustellen, und dieses Ziel wurde erreicht.
Ich hoffe, dieser Artikel hat Sie mit etwas Wertvollem bereichert. Als Entwickler sollten wir nicht aufgeben, sondern das Flussdiagramm in Betrieb halten, bis wir unsere Ziele erreicht haben. Wir müssen die Kraft unserer Gemeinschaft nutzen, um unsere Fähigkeiten in der Programmierung des algorithmischen Handels zu verbessern. Die Diskussionen sind immer offen für alle, sodass Ideen offen ausgetauscht werden können. In unserem nächsten Projekt werden wir auf der bestehenden Grundlage aufbauen und weitere Untersuchungen durchführen. Nachstehend finden Sie die angehängten Dateien und ihre Beschreibung.
Anhänge | Beschreibung |
---|---|
send_whatsapp_message.py | Befürworter Kommunikation MetaTrader 5 zu Twilio und dann zu WhatsApp. |
Trend Constraint V1.06.mq5 | WhatsApp ist integriert, aber Sie müssen die Anmeldedaten und Pfadverzeichnisse aktualisieren, damit es auf Ihrem Computer funktioniert. |
Secure Command.mq5 | Geändert, um das Eingabeaufforderungsfenster zu verbergen und das Programm vor externen Angriffen zu schützen. |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/14969
![Algorithmen zur Optimierung mit Populationen: Der Boids-Algorithmus](https://c.mql5.com/2/74/Population_optimization_algorithms_Boyd_algorithmp_or_flock_algorithm___LOGO.png)
![Entwicklung eines Roboters in Python und MQL5 (Teil 1): Vorverarbeitung der Daten](https://c.mql5.com/2/74/Robot_development_in_Python_and_MQL5_oPart_1z_Data_preprocessing____LOGO.png)
![Eine alternative Log-datei mit der Verwendung der HTML und CSS](https://c.mql5.com/2/14/385_10.gif)
![Entwicklung eines Expertenberaters für mehrere Währungen (Teil 6): Automatisieren der Auswahl einer Instanzgruppe](https://c.mql5.com/2/74/Developing_a_multi-currency_advisor_Part_1___LOGO__4.png)
![MQL5 - Sprache von Handelsstrategien, eingebaut ins Kundenterminal MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- 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.