
Erstellen eines Expert Advisor, der Telegram integriert (Teil 7): Befehlsanalyse für die Automatisierung von Indikatoren auf Charts
Einführung
In diesem Artikel bauen wir auf den Fortschritten des vorherigen Teils (Teil 6) auf, in dem wir responsive Inline-Buttons zur Verbesserung der Bot-Interaktion integriert haben. Jetzt konzentrieren wir uns auf die Automatisierung des Hinzufügens von Indikatoren zu MetaTrader 5 Charts mit Hilfe von Befehlen, die von Telegram gesendet werden. Wir werden ein System erstellen, bei dem der Expert Advisor nutzerdefinierte Indikatorparameter über Telegram erfasst, die Daten analysiert und die angegebenen Indikatoren in Echtzeit auf die Handels-Charts anwendet.
Die folgenden Themen werden uns Schritt für Schritt durch die Implementierung dieses Indikator-Automatisierungsprozesses führen:
- Überblick über den indikatorbasierten Handel bei Telegram: Wir werden untersuchen, wie Händler Telegram-Befehle verwenden können, um Indikatoren auf MetaTrader 5 zu steuern.
- Parsen und Verarbeiten der Indikatorbefehle von Telegram: In diesem Abschnitt erfahren Sie, wie Sie Indikatorparameter aus Telegram-Nachrichten extrahieren und verarbeiten können.
- Ausführen von Indikatoren in MQL5: Wir werden zeigen, wie man geparste Befehle verwendet, um Indikatoren direkt in MetaTrader 5 hinzuzufügen und zu automatisieren.
- Testen des Indikatorhandelssystems: Ein gründlicher Testprozess gewährleistet den reibungslosen Betrieb des Systems für eine genaue Automatisierung der Indikatoren.
- Schlussfolgerung: Abschließend werden wir den gesamten Prozess zusammenfassen und die wichtigsten Erkenntnisse erörtern.
Am Ende dieses Artikels werden Sie über ein voll funktionsfähiges Automatisierungssystem von Telegram-zu-MetaTrader 5 Indikator verfügen, das in der Lage ist, Befehle von Telegram zu empfangen und zu verarbeiten, um technische Indikatoren nahtlos in MQL5 anzuwenden. Fangen wir an!
Überblick über den indikatorbasierten Handel mit Telegram
In diesem Abschnitt befassen wir uns mit der Verwendung von Telegram zum Senden von Indikatorbefehlen, die die Chartanalyse automatisieren können. Viele Händler nutzen Telegram, um mit Bots und Expert Advisors (EAs) zu interagieren, die es ihnen ermöglichen, technische Indikatoren direkt auf MetaTrader 5 hinzuzufügen, zu ändern oder zu entfernen. Diese Befehle enthalten in der Regel wichtige Informationen wie die Art des Indikators, den Zeitrahmen, den Zeitraum und die Preisanwendung, die für die Chartanalyse unerlässlich sind. Bei der manuellen Anwendung dieser Indikatoren kann es jedoch zu Verzögerungen oder Fehlern kommen, insbesondere auf schnelllebigen Märkten.
Durch die Automatisierung des Prozesses der Anwendung von Indikatoren über die Befehle Telegram können Händler ihre technische Analyse verbessern, ohne sich um die manuelle Verwaltung von Charts kümmern zu müssen. Bei richtiger Integration können diese Telegrambefehle geparst und in MetaTrader 5 in ausführbare Befehle umgewandelt werden, sodass Indikatoren in Echtzeit zu Charts hinzugefügt werden können. Dies gewährleistet nicht nur Genauigkeit, sondern auch einen effizienteren Handelsablauf, der es den Händlern ermöglicht, sich auf die Interpretation der Ergebnisse zu konzentrieren, anstatt das Setup zu verwalten. Eine typische Visualisierung der Indikatorbefehle sieht wie folgt aus:
Das Ergebnis ist ein System, das die Lücke zwischen Telegram und MetaTrader 5 schließt und es Händlern ermöglicht, ihre Chartanalyse zu rationalisieren, Fehler zu minimieren und Marktchancen in Echtzeit durch automatisiertes Indikatorenmanagement voll auszunutzen.
Parsen und Verarbeiten von Telegramindikatorbefehlen
Als Erstes müssen wir die angebotenen Befehle über Telegram für die Indikatoren erfassen und anschließend in MetaQuotes Language 5 (MQL5) kodieren, parsen und verarbeiten, damit wir sie interpretieren und die entsprechenden Indikatoren auf MetaTrader 5 Charts anwenden können. Für den Kodierungs- und Parsing-Teil haben wir bereits in Teil 5 dieser Serie die notwendigen Klassen eingeführt. In diesem Teil werden wir diese Klassen jedoch noch einmal überarbeiten, um für Klarheit zu sorgen, zumal sich Teil 6 auf andere Funktionalitäten wie Inline-Schaltflächen konzentrierte. Nachfolgend finden Sie das Codeschnipsel, das für das Parsen und Verarbeiten von Telegram-Indikatorbefehlen verantwortlich ist:
//+------------------------------------------------------------------+ //| Class_Bot_EA | //+------------------------------------------------------------------+ class Class_Bot_EA{ private: string member_token; //--- Stores the bot’s token. string member_name; //--- Stores the bot’s name. long member_update_id; //--- Stores the last update ID processed by the bot. CArrayString member_users_filter; //--- An array to filter users. bool member_first_remove; //--- A boolean to indicate if the first message should be removed. protected: CList member_chats; //--- A list to store chat objects. public: void Class_Bot_EA(); //--- Declares the constructor. ~Class_Bot_EA(){}; //--- Declares the destructor. int getChatUpdates(); //--- Declares a function to get updates from Telegram. void ProcessMessages(); //--- Declares a function to process incoming messages. }; void Class_Bot_EA::Class_Bot_EA(void){ //--- Constructor member_token=NULL; //--- Initialize the bot's token as NULL. member_token=getTrimmedToken(InpToken); //--- Assign the trimmed bot token from InpToken. member_name=NULL; //--- Initialize the bot's name as NULL. member_update_id=0; //--- Initialize the last update ID to 0. member_first_remove=true; //--- Set the flag to remove the first message to true. member_chats.Clear(); //--- Clear the list of chat objects. member_users_filter.Clear(); //--- Clear the user filter array. } //+------------------------------------------------------------------+ int Class_Bot_EA::getChatUpdates(void){ //--- Check if the bot token is NULL if(member_token==NULL){ Print("ERR: TOKEN EMPTY"); //--- Print an error message if the token is empty return(-1); //--- Return with an error code } string out; //--- Variable to store the response from the request string url=TELEGRAM_BASE_URL+"/bot"+member_token+"/getUpdates"; //--- Construct the URL for the Telegram API request string params="offset="+IntegerToString(member_update_id); //--- Set the offset parameter to get updates after the last processed ID //--- Send a POST request to get updates from Telegram int res=postRequest(out, url, params, WEB_TIMEOUT); // THIS IS THE STRING RESPONSE WE GET // "ok":true,"result":[]} //--- If the request was successful if(res==0){ //Print(out); //--- Optionally print the response //--- Create a JSON object to parse the response CJSONValue obj_json(NULL, jv_UNDEF); //--- Deserialize the JSON response bool done=obj_json.Deserialize(out); //--- If JSON parsing failed // Print(done); if(!done){ Print("ERR: JSON PARSING"); //--- Print an error message if parsing fails return(-1); //--- Return with an error code } //--- Check if the 'ok' field in the JSON is true bool ok=obj_json["ok"].ToBool(); //--- If 'ok' is false, there was an error in the response if(!ok){ Print("ERR: JSON NOT OK"); //--- Print an error message if 'ok' is false return(-1); //--- Return with an error code } //--- Create a message object to store message details Class_Message obj_msg; //--- Get the total number of updates in the JSON array 'result' int total=ArraySize(obj_json["result"].m_elements); //--- Loop through each update for(int i=0; i<total; i++){ //--- Get the individual update item as a JSON object CJSONValue obj_item=obj_json["result"].m_elements[i]; //--- Extract message details from the JSON object obj_msg.update_id=obj_item["update_id"].ToInt(); //--- Get the update ID obj_msg.message_id=obj_item["message"]["message_id"].ToInt(); //--- Get the message ID obj_msg.message_date=(datetime)obj_item["message"]["date"].ToInt(); //--- Get the message date obj_msg.message_text=obj_item["message"]["text"].ToStr(); //--- Get the message text obj_msg.message_text=decodeStringCharacters(obj_msg.message_text); //--- Decode any HTML entities in the message text //--- Extract sender details from the JSON object obj_msg.from_id=obj_item["message"]["from"]["id"].ToInt(); //--- Get the sender's ID obj_msg.from_first_name=obj_item["message"]["from"]["first_name"].ToStr(); //--- Get the sender's first name obj_msg.from_first_name=decodeStringCharacters(obj_msg.from_first_name); //--- Decode the first name obj_msg.from_last_name=obj_item["message"]["from"]["last_name"].ToStr(); //--- Get the sender's last name obj_msg.from_last_name=decodeStringCharacters(obj_msg.from_last_name); //--- Decode the last name obj_msg.from_username=obj_item["message"]["from"]["username"].ToStr(); //--- Get the sender's username obj_msg.from_username=decodeStringCharacters(obj_msg.from_username); //--- Decode the username //--- Extract chat details from the JSON object obj_msg.chat_id=obj_item["message"]["chat"]["id"].ToInt(); //--- Get the chat ID obj_msg.chat_first_name=obj_item["message"]["chat"]["first_name"].ToStr(); //--- Get the chat's first name obj_msg.chat_first_name=decodeStringCharacters(obj_msg.chat_first_name); //--- Decode the first name obj_msg.chat_last_name=obj_item["message"]["chat"]["last_name"].ToStr(); //--- Get the chat's last name obj_msg.chat_last_name=decodeStringCharacters(obj_msg.chat_last_name); //--- Decode the last name obj_msg.chat_username=obj_item["message"]["chat"]["username"].ToStr(); //--- Get the chat's username obj_msg.chat_username=decodeStringCharacters(obj_msg.chat_username); //--- Decode the username obj_msg.chat_type=obj_item["message"]["chat"]["type"].ToStr(); //--- Get the chat type //--- Update the ID for the next request member_update_id=obj_msg.update_id+1; //--- If it's the first update, skip processing if(member_first_remove){ continue; } //--- Filter messages based on username if(member_users_filter.Total()==0 || //--- If no filter is applied, process all messages (member_users_filter.Total()>0 && //--- If a filter is applied, check if the username is in the filter member_users_filter.SearchLinear(obj_msg.from_username)>=0)){ //--- Find the chat in the list of chats int index=-1; for(int j=0; j<member_chats.Total(); j++){ Class_Chat *chat=member_chats.GetNodeAtIndex(j); if(chat.member_id==obj_msg.chat_id){ //--- Check if the chat ID matches index=j; break; } } //--- If the chat is not found, add a new chat to the list if(index==-1){ member_chats.Add(new Class_Chat); //--- Add a new chat to the list Class_Chat *chat=member_chats.GetLastNode(); chat.member_id=obj_msg.chat_id; //--- Set the chat ID chat.member_time=TimeLocal(); //--- Set the current time for the chat chat.member_state=0; //--- Initialize the chat state chat.member_new_one.message_text=obj_msg.message_text; //--- Set the new message text chat.member_new_one.done=false; //--- Mark the new message as not processed } //--- If the chat is found, update the chat message else{ Class_Chat *chat=member_chats.GetNodeAtIndex(index); chat.member_time=TimeLocal(); //--- Update the chat time chat.member_new_one.message_text=obj_msg.message_text; //--- Update the message text chat.member_new_one.done=false; //--- Mark the new message as not processed } } } //--- After the first update, set the flag to false member_first_remove=false; } //--- Return the result of the POST request return(res); }
Hier stellen wir die „Class_Bot_EA“ vor und implementieren ihre Funktion „getChatUpdates“, um eingehende Updates von Telegram zu verarbeiten. Im Konstruktor werden das Token, der Name und andere relevante Variablen des Bots initialisiert. Wir setzen auch ein Flag, um zu bestimmen, ob wir die erste Nachricht löschen und einige alte Daten löschen sollen, einschließlich der Chatliste und aller Nutzerfilter.
Die Funktion „getChatUpdates“ erstellt eine URL für die Telegram-API, die uns Updates für den angegebenen Bot liefert. Die letzte verarbeitete Aktualisierungs-ID wird als Offset in der URL verwendet, d. h. wir erhalten keine Aktualisierungen, die bereits verarbeitet wurden. Nachdem wir die URL erstellt haben, senden wir eine POST-Anfrage an die API und bearbeiten die Antwort des Servers. Da wir JavaScript Object Notation (JSON) Daten vom Server zurückerwarten, prüfen wir auf Fehler, indem wir versuchen, die Daten zu parsen. Wenn das Parsing fehlschlägt oder das Feld „ok“ in der JSON-Antwort „false“ ist, wird eine Fehlermeldung ausgegeben und ein Fehlercode zurückgegeben.
Nachdem wir erfolgreich geantwortet haben, ziehen wir die relevanten Informationen aus der Nachricht - update ID, message ID, sender info, and chat details - die uns Aufschluss über den Verlauf der Unterhaltung geben. Dann schauen wir uns die Liste der bisherigen Chats an und sehen, wo diese neue Information hinpasst. Wenn der Chat, der mit dieser neuen Nachricht verbunden ist, nicht in der Liste enthalten ist, fügen wir ihn hinzu. Wenn sie in der Liste enthalten ist, aktualisieren wir ihre Informationen mit der neuen Nachricht.
Schließlich kümmern wir uns um die nutzerdefinierte Nachrichtenfilterung und die Handhabung des Status jedes Chats. Nachdem die notwendigen Aktualisierungen abgeschlossen sind, stellen wir sicher, dass die zuletzt bearbeitete Nachricht jedes Chats auf dem neuesten Stand ist. Schließlich geben wir das Ergebnis unserer POST-Anfrage zurück, das entweder den Erfolg oder einen entsprechend beschriebenen Fehler angibt.
Das ist alles, was wir brauchen, um die empfangenen Befehle zu verarbeiten. Wir müssen dann die empfangenen Indikatorbefehle interpretieren, den gewünschten Indikator identifizieren und ihn automatisch zur weiteren Analyse in das Chart einfügen. Dies geschieht im nächsten Abschnitt.
Ausführen von Indikatoren in MQL5
Um die empfangenen Indikatorbefehle zu verarbeiten, rufen wir die Funktion auf, die für die Nachrichtenverarbeitung zuständig ist, sodass wir die Nachrichten als Ganzes verarbeiten und dann die Details der Nachrichten in Segmenten interpretieren. Die folgende Funktion ist anwendbar.
void Class_Bot_EA::ProcessMessages(void){ //... }
In dieser Funktion beginnt nun die eigentliche Bearbeitung. Als Erstes müssen wir alle empfangenen Nachrichten in einer Schleife durchgehen und einzeln verarbeiten. Dies ist wichtig, weil der Anbieter die Signale gleichzeitig und in großen Mengen für mehrere Handelssymbole gesendet haben könnte, z. B. „AUDUSD, EURUSD, GBPUSD, XAUUSD, XRPUSD, USDKES, USDJPY, EURCHF“ und viele mehr. Wir erreichen dies durch die folgende Logik.
//--- Loop through all chats for(int i=0; i<member_chats.Total(); i++){ Class_Chat *chat=member_chats.GetNodeAtIndex(i); //--- Get the current chat if(!chat.member_new_one.done){ //--- Check if the message has not been processed yet chat.member_new_one.done=true; //--- Mark the message as processed string text=chat.member_new_one.message_text; //--- Get the message text //... } }
Zunächst durchlaufen wir die gespeicherten Chats in der Liste „member_chats“. Jedes Chat-Objekt wird mit der Funktion „GetNodeAtIndex“ abgerufen. Wir prüfen, ob die mit diesem Chat verbundene Nachricht bearbeitet wurde, indem wir ein Flag in der Struktur „member_new_one“ auswerten. Wenn die Nachricht noch nicht bearbeitet wurde, wird das „done“-Flag auf „true“ gesetzt, was bedeutet, dass dieselbe Nachricht nicht mehrmals bearbeitet wird.
Als Nächstes wird der Inhalt der Nachricht extrahiert. Sie werden im Feld „message_text“ der Struktur „member_new_one“ gespeichert. So können wir direkt mit dem Text arbeiten, ohne uns Gedanken darüber zu machen, was bereits verarbeitet wurde.
Als Erstes müssen wir nun die Befehlsdetails für die Analyse abrufen. Hier ist die Logik.
string user_text = text; Print("USER'S PLAIN TEXT IS AS BELOW:\n",user_text); StringToUpper(user_text); Print("USER'S TRANSFORMED UPPERCASE TEXT IS AS BELOW:\n",user_text);
Hier speichern wir zunächst den eingehenden Nachrichtentext aus der Variablen „text“ in einer neuen Variablen namens „user_text“. So können wir mit dem Inhalt der Nachricht arbeiten, ohne die ursprüngliche Variable zu verändern. Anschließend drucken wir den reinen Nachrichtentext des Nutzers mit der Funktion „Print“ aus, die die Nachricht zu Protokollierungszwecken auf dem Terminal MetaTrader 5 ausgibt.
Als Nächstes wird die gesamte Zeichenkette „user_text“ mit der Funktion StringToUpper in Großbuchstaben umgewandelt. Dadurch werden alle Zeichen in der Nachricht in ihre Entsprechung in Großbuchstaben umgewandelt. Das ist notwendig, weil wir die Zeichen der Nachricht angleichen werden und es so einfacher ist, damit zu arbeiten. Nach der Umwandlung geben wir die aktualisierte Nachricht erneut auf dem Terminal aus und zeigen die umgewandelte Version der Nutzereingabe in Großbuchstaben an. Dieser Prozess ermöglicht es uns, sowohl die ursprüngliche als auch die geänderte Version der Nachricht für die weitere Bearbeitung oder Beantwortung zu sehen. Wenn wir das Programm erneut ausführen, erhalten wir die folgende Ausgabe im Protokollabschnitt.
Nachdem wir die Signalnachricht in Großbuchstaben umgewandelt haben, müssen wir die Variablen, die unsere Daten enthalten werden, wie folgt initialisieren:
// MOVING AVERAGE //--- Initialize variables to hold extracted data string indicator_type = NULL; string indicator_symbol = NULL; string indicator_timeframe = NULL; long indicator_period = 0; long indicator_shift = 0; string indicator_method = NULL; string indicator_app_price = NULL;
Wir beginnen mit dem Indikator Gleitender Durchschnitt. Wir initialisieren mehrere Variablen, die die extrahierten Daten für die Konfiguration eines Moving Average (MA) Indikators in MetaTrader 5 auf der Grundlage von Nutzereingaben aus Telegram enthalten werden. Die einzelnen Variablen stehen für Folgendes:
- indicator_type: Der Indikatortyp ist in diesem Fall ein gleitender Durchschnitt.
- indikator_symbol: Das Symbol (Währungspaar oder Vermögenswert), auf das der Indikator angewendet werden soll.
- indicator_timeframe: Der Zeitrahmen für das Chart (z.B. M1, H1, D1), in dem der Indikator dargestellt werden soll.
- indicator_period: Die Anzahl der Perioden (oder Balken), die der gleitende Durchschnitt bei seiner Berechnung berücksichtigt.
- indicator_shift: Der Offset- oder Verschiebungswert, um den Indikator auf dem Chart vorwärts oder rückwärts zu bewegen.
- indicator_method: Die Berechnungsmethode für den MA (z. B. SMA, EMA).
- indicator_app_price: Der für die MA-Berechnung verwendete Preis (z. B. Schlusskurs, Eröffnungskurs).
Um die mit einem Indikator verbundenen Datenelemente zu extrahieren, müssen wir die Nachricht nach Zeilen aufteilen und in einer Schleife über jede Zeile nach den Details suchen. Dies wird durch die nachstehende Logik erreicht.
//--- Split the message by lines string lines[]; StringSplit(user_text,'\n',lines); Print("SPLIT TEXT SEGMENTS IS AS BELOW:"); ArrayPrint(lines,0,",");
Hier haben wir die transformierte Nachricht des Nutzers in einzelne Zeilen aufgeteilt, um die Extraktion der relevanten Indikatorinformationen zu erleichtern. Zuerst deklarieren wir ein Array mit dem Namen „lines“, um jede Zeile der Nachricht zu speichern, sobald sie aufgeteilt ist. Dann wenden wir die Funktion StringSplit an und verwenden das Zeilenumbruchzeichen ('\n') als Trennzeichen, um die Nachricht in einzelne Zeilen aufzuteilen. Diese Funktion füllt das Array „lines“ für immer mit jedem Teil des Textes, der durch eine neue Zeile getrennt wurde.
Sobald die Nachricht aufgeteilt ist, werden die resultierenden Segmente mit der Funktion ArrayPrint gedruckt, die jede Zeile als einzelnes Element ausgibt. Dieser Schritt ist zwingend erforderlich, um die Struktur der Nachricht zu visualisieren und sicherzustellen, dass der Aufteilungsprozess korrekt funktioniert hat. Indem wir die Nachricht auf diese Weise organisieren, können wir jede Zeile leichter verarbeiten, um wichtige Elemente wie das Handelssymbol, den Indikatortyp und andere Details zu extrahieren. Um die Einzelheiten zu erfahren, müssen wir also eine Schleife über jede Zeile ziehen.
//--- Iterate over each line to extract information for (int i=0; i<ArraySize(lines); i++){ StringTrimLeft(lines[i]); StringTrimRight(lines[i]); string selected_line = lines[i]; Print(i,". ",selected_line); //... }
Wir iterieren über das Array „lines“, um spezifische Indikatorinformationen aus jeder Zeile der geteilten Nachricht zu extrahieren. Wir verwenden eine for-Schleife, um jedes Element des Arrays zu durchlaufen und sicherzustellen, dass jede Zeile einzeln verarbeitet wird. Zu Beginn der Schleife werden die Funktionen StringTrimLeft und StringTrimRight auf jede Zeile angewandt, um führende und nachfolgende Leerzeichen zu entfernen. Dadurch wird sichergestellt, dass keine überzähligen Leerzeichen den Parsing-Prozess stören.
Anschließend wird jede abgeschnittene Zeile der Variablen „selected_line“ zugewiesen, die die aktuell bearbeitete Zeile enthält. Da jede Zeile sauber geschnitten und in der Variablen „selected_line“ gespeichert ist, können wir weitere Operationen durchführen, z. B. prüfen, ob die Zeile bestimmte Handelssignale oder Befehle enthält. Um zu überprüfen, ob wir die richtigen Informationen haben, drucken wir jede Zeile aus, und hier ist die Ausgabe.
Das war ein Erfolg. Wir können nun nach bestimmten Details in der ausgewählten Zeile suchen. Beginnen wir mit der Suche nach dem Typ des technischen Handelsindikators. Wir suchen zunächst nach dem Text für den gleitenden Durchschnittsindikator, d. h. „INDICATOR TYPE“.
if (StringFind(selected_line,"INDICATOR TYPE") >= 0){ indicator_type = StringSubstr(selected_line,16); Print("Line @ index ",i," Indicator Type = ",indicator_type); //--- Print the extracted details }
Hier verarbeiten wir die Telegram-Nachricht des Nutzers, um den Indikatortyp zu extrahieren. Wir verwenden die Funktion StringFind, um in der aktuellen Zeile („selected_line“) nach dem Text „INDICATOR TYPE“ zu suchen. Wenn dieser Text gefunden wird, gibt die Funktion die Anfangsposition der Übereinstimmung zurück, also einen Wert größer oder gleich Null. Sobald eine Übereinstimmung festgestellt wird, wird der Indikatortyp mit der Funktion StringSubstr extrahiert, die eine Teilzeichenkette von der Position nach „INDICATOR TYPE“ (ab Index 16) bis zum Ende der Zeile abruft. Der extrahierte Wert wird in der Variablen „indicator_type“ gespeichert. Abschließend wird der Index der Zeile und der extrahierte „indicator_type“ mit der Funktion Print ausgedruckt, um zu bestätigen, dass die Daten erfolgreich abgerufen wurden. Wenn wir dies ausführen, erhalten wir die folgende Ausgabe.
Wir sehen, dass wir erfolgreich eine Schleife über alle Befehlssegmente durchlaufen und den Indikatornamen identifiziert haben. Als Nächstes müssen wir das Symbol identifizieren. Es wird eine ähnliche, aber etwas komplexere Logik verwendet.
//--- Check for symbol in the list of available symbols and assign it for(int k = 0; k < SymbolsTotal(true); k++) { //--- Loop through all available symbols string selected_symbol = SymbolName(k, true); //--- Get the symbol name if (StringCompare(selected_line,selected_symbol,false) == 0){ //--- Compare the line with the symbol name indicator_symbol = selected_symbol; //--- Assign the symbol if a match is found Print("Line @ index ",i," SYMBOL = ",indicator_symbol); //--- Print the found symbol } }
In diesem Codeblock wird die Eingabe des Nutzers mit der Liste der verfügbaren Handelssymbole abgeglichen und das richtige Symbol der Variablen „indicator_symbol“ zugewiesen. Zunächst verwenden wir die Funktion SymbolsTotal, die die Gesamtzahl der derzeit auf der Plattform verfügbaren Symbole angibt. Das Argument „true“ gibt an, dass wir die Anzahl der sichtbaren Symbole haben wollen. Anschließend durchlaufen wir alle verfügbaren Symbole in einer for-Schleife mit der Variablen „k“ als Index.
Innerhalb der Schleife verwenden wir die Funktion SymbolName, um den Namen des Symbols bei Index „k“ zu erhalten. Das zweite Argument, „true“, gibt an, dass wir den Namen des Symbols in seiner Kurzform haben wollen. Nachdem wir den Symbolnamen abgerufen und in der Variablen „selected_symbol“ gespeichert haben, verwenden wir die Funktion StringCompare, um dieses „selected_symbol“ mit der Eingabe des Nutzers („selected_line“) zu vergleichen. Das Argument „false“ gibt an, dass der Vergleich unabhängig von der Groß- und Kleinschreibung erfolgen soll.
Wenn die Funktion Null zurückgibt, bedeutet dies, dass die beiden Zeichenfolgen übereinstimmen, und wir weisen „selected_symbol“ der Variablen „indicator_symbol“ zu. Abschließend wird der Index der Zeile und das entsprechende „indicator_symbol“ mit der Funktion Print ausgedruckt, um zu bestätigen, dass das Symbol aus der Nutzereingabe korrekt identifiziert und zugeordnet wurde. Diese enthält keinen zusätzlichen Text und wird daher direkt durchsucht. Bei der Ausführung werden wir mit dem aktuellen Codeschnipsel keine Ergebnisse erhalten, da der extrahierte Text und die Standardsymbole nicht ähnlich sind, da sie Groß- und Kleinschreibung unterscheiden, d. h. „XAUUSDM“ ist nicht gleich „XAUUSDm“. Hier ist der Name des Symbols, das wir haben:
Daher müssen wir das Standardsystemsymbol in Großbuchstaben umwandeln, um den Vergleich durchführen zu können. Das neue, aktualisierte Codeschnipsel sieht wie folgt aus:
//--- Check for symbol in the list of available symbols and assign it for(int k = 0; k < SymbolsTotal(true); k++) { //--- Loop through all available symbols string selected_symbol = SymbolName(k, true); //--- Get the symbol name StringToUpper(selected_symbol); if (StringCompare(selected_line,selected_symbol,false) == 0){ //--- Compare the line with the symbol name indicator_symbol = selected_symbol; //--- Assign the symbol if a match is found Print("Line @ index ",i," SYMBOL = ",indicator_symbol); //--- Print the found symbol } }
Mit der neuen Transformation können wir mit dem Vergleich fortfahren, und wir erhalten die folgenden Ergebnisse:
Das war ein Erfolg. Um die anderen Details zu erhalten, wenden wir eine ähnliche Logik an.
if (StringFind(selected_line,"TIMEFRAME") >= 0){ indicator_timeframe = StringSubstr(selected_line,12); Print("Line @ index ",i," Indicator Timeframe = ",indicator_timeframe); //--- Print the extracted details } if (StringFind(selected_line,"PERIOD") >= 0){ indicator_period = StringToInteger(StringSubstr(selected_line,9)); Print("Line @ index ",i," Indicator Period = ",indicator_period); } if (StringFind(selected_line,"SHIFT") >= 0){ indicator_shift = StringToInteger(StringSubstr(selected_line,8)); Print("Line @ index ",i," Indicator Shift = ",indicator_shift); } if (StringFind(selected_line,"METHOD") >= 0){ indicator_method = StringSubstr(selected_line,9); Print("Line @ index ",i," Indicator Method = ",indicator_method); } if (StringFind(selected_line,"APPLIED PRICE") >= 0){ indicator_app_price = StringSubstr(selected_line,16); Print("Line @ index ",i," Indicator Applied Price = ",indicator_app_price); } }
Wenn wir dies ausführen, erhalten wir die folgende Ausgabe.
Um die Daten strukturierter zu betrachten, können wir alle erfassten und extrahierten Informationen wie unten dargestellt ausdrucken:
//--- Final data Print("\nFINAL EXTRACTED DATA:"); //--- Print the final data for confirmation Print("Type = ",indicator_type); Print("Symbol = ",indicator_symbol); Print("Timeframe = ",indicator_timeframe); Print("Period = ",indicator_period); Print("Shift = ",indicator_shift); Print("Method = ",indicator_method); Print("Applied Price = ",indicator_app_price);
Wir drucken die endgültigen extrahierten Daten aus, um zu bestätigen, dass die Variablen korrekt ausgefüllt wurden. Zunächst verwenden wir die Funktion „Print“, um eine Kopfzeile anzuzeigen: „\nFINAL EXTRACTED DATA:“. Dies dient als visueller Hinweis in den Protokollen, um zu markieren, wo die verarbeiteten Daten angezeigt werden sollen.
Danach werden hintereinander die Werte der Schlüsselvariablen „indicator_type“, „indicator_symbol“, „indicator_timeframe“, „indicator_period“, „indicator_shift“, „indicator_method“ und „indicator_app_price“ ausgedruckt. Jeder Aufruf von Print gibt den Namen der Variablen und ihren aktuellen Wert aus. Dies ist wichtig für das Debugging und die Überprüfung, da es sicherstellt, dass die aus den Nutzereingaben analysierten Daten (z. B. die Art des Indikators, das Symbol, der Zeitrahmen usw.) korrekt erfasst wurden, bevor das System mit dem Hinzufügen des Indikators zum Chart in MetaTrader 5 fortfährt. Das Ergebnis wird im Folgenden dargestellt:
Perfekt! Da wir nun alle notwendigen Details eines gleitenden Durchschnittsindikators kennen, können wir ihn dem Chart hinzufügen. Bevor wir es jedoch hinzufügen, können wir gegenprüfen, ob wir den richtigen Indikator haben, wie von Telegram angewiesen. Wir erreichen dies durch die Verwendung einer if-Anweisung.
if (indicator_type=="MOVING AVERAGE"){ //... }
Nach der Bestätigung des Indikators können wir dann die extrahierten Eingaben in ihre jeweiligen Datentypstrukturen umwandeln. Beachten Sie, dass die aktuellen Werte, die wir haben, entweder in String- oder Integer-Datentypen sind. Das System wird z.B. nicht verstehen, dass die vom Nutzer eingegebene Methode des gleitenden Durchschnitts „SMA“ als „SIMPLE MOVING AVERAGE“ unter der Enumeration ENUM_MA_METHOD (siehe unten) gemeint ist.
Das müssen wir dem Programm also weiter erklären. Um systematisch vorzugehen, beginnen wir mit dem Offensichtlichsten, nämlich dem Zeitrahmen.
//--- Convert timeframe to ENUM_TIMEFRAMES ENUM_TIMEFRAMES timeframe_enum = _Period; if (indicator_timeframe == "M1") { timeframe_enum = PERIOD_M1; } else if (indicator_timeframe == "M5") { timeframe_enum = PERIOD_M5; } else if (indicator_timeframe == "M15") { timeframe_enum = PERIOD_M15; } else if (indicator_timeframe == "M30") { timeframe_enum = PERIOD_M30; } else if (indicator_timeframe == "H1") { timeframe_enum = PERIOD_H1; } else if (indicator_timeframe == "H4") { timeframe_enum = PERIOD_H4; } else if (indicator_timeframe == "D1") { timeframe_enum = PERIOD_D1; } else if (indicator_timeframe == "W1") { timeframe_enum = PERIOD_W1; } else if (indicator_timeframe == "MN1") { timeframe_enum = PERIOD_MN1; } else { Print("Invalid timeframe: ", indicator_timeframe); }
In diesem Abschnitt konvertieren wir den vom Nutzer bereitgestellten Zeitrahmen aus dem extrahierten „indicator_timeframe“-String in die entsprechende Enumeration des MetaTrader 5 „ENUM_TIMEFRAMES". Dieser Schritt ist wichtig, da MetaTrader 5 vordefinierte Zeitrahmen wie „PERIOD_M1“ für 1-Minuten-Charts, „PERIOD_H1“ für 1-Stunden-Charts usw. verwendet. Diese Zeitrahmen werden als Teil des Typs „ENUM_TIMEFRAMES“ definiert.
Zunächst wird die Variable „timeframe_enum“ mit dem Zeitrahmen des aktuellen Charts initialisiert, der durch _Period dargestellt wird. Dies dient als Ausweichstandard für den Fall, dass der vom Nutzer angegebene Zeitrahmen ungültig ist.
Als Nächstes verwenden wir eine Reihe von bedingten if-else-Anweisungen, um den Wert der Zeichenkette „indicator_timeframe“ zu überprüfen. Jede Bedingung vergleicht die extrahierte Zeichenkette mit bekannten Zeitrahmenkennungen, wie „M1“ (1 Minute), „H1“ (1 Stunde) usw. Wird eine Übereinstimmung gefunden, wird der entsprechende „ENUM_TIMEFRAMES“-Wert (wie „PERIOD_M1“ oder „PERIOD_H1“) der Variablen „timeframe_enum“ zugewiesen.
Trifft keine der Bedingungen zu, wird der abschließende else-Block ausgelöst, der eine Fehlermeldung in das Protokoll einträgt, die einen „Ungültigen Zeitrahmen“ zusammen mit dem Wert von „indicator_timeframe“ angibt. Dadurch wird sichergestellt, dass während der Erstellung des Indikators nur gültige Zeitrahmen an MetaTrader 5 übergeben werden. In ähnlicher Weise transformieren wir die anderen Variablen in ihre jeweiligen Formen.
//--- Convert MA method to ENUM_MA_METHOD ENUM_MA_METHOD ma_method = MODE_SMA; if (indicator_method == "SMA") { ma_method = MODE_SMA; } else if (indicator_method == "EMA") { ma_method = MODE_EMA; } else if (indicator_method == "SMMA") { ma_method = MODE_SMMA; } else if (indicator_method == "LWMA") { ma_method = MODE_LWMA; } else { Print("Invalid MA method: ", indicator_method); } //--- Convert applied price to ENUM_APPLIED_PRICE ENUM_APPLIED_PRICE app_price_enum = PRICE_CLOSE; if (indicator_app_price == "CLOSE") { app_price_enum = PRICE_CLOSE; } else if (indicator_app_price == "OPEN") { app_price_enum = PRICE_OPEN; } else if (indicator_app_price == "HIGH") { app_price_enum = PRICE_HIGH; } else if (indicator_app_price == "LOW") { app_price_enum = PRICE_LOW; } else if (indicator_app_price == "MEDIAN") { app_price_enum = PRICE_MEDIAN; } else if (indicator_app_price == "TYPICAL") { app_price_enum = PRICE_TYPICAL; } else if (indicator_app_price == "WEIGHTED") { app_price_enum = PRICE_WEIGHTED; } else { Print("Invalid applied price: ", indicator_app_price); }
Sobald der Transformationsprozess abgeschlossen ist, können wir mit der Erstellung des Indikator-Handles fortfahren, mit dem wir den Indikator zum Chart hinzufügen werden.
int handle_ma = iMA(indicator_symbol,timeframe_enum,(int)indicator_period,(int)indicator_shift,ma_method,app_price_enum);
Hier erstellen wir mit der Funktion iMA einen Handle für den Indikator Gleitender Durchschnitt (MA). Diese Funktion erzeugt ein Indikator-Handle auf der Grundlage der Parameter, die wir zuvor extrahiert und verarbeitet haben. Mit dem Handle können wir später im Code auf den Indikator im Chart verweisen und ihn manipulieren. Wir übergeben der Funktion „iMA“ mehrere Argumente, die jeweils einem Parameter entsprechen, den wir dem Telegrambefehl entnommen haben:
- „Indikator_Symbol“: Hier wird das Finanzinstrument (z. B. EURUSD) angegeben, für das der Indikator angewendet wird.
- „Zeitrahmen_Enum“: Dieses Argument bezieht sich auf den Zeitrahmen (z. B. M1 für 1 Minute, H1 für 1 Stunde), der zuvor aus den Eingaben des Nutzers umgerechnet wurde.
- „(int)indicator_period“: Damit wird der extrahierte „indicator_period“ von einem Long-Datentyp in eine ganze Zahl umgewandelt, die die Anzahl der Perioden für den MA darstellt.
- „(int)indicator_shift“: Auf ähnliche Weise wird „indicator_shift“ in eine ganze Zahl umgewandelt, die angibt, um wie viele Balken der Indikator im Chart verschoben werden soll.
- „ma_method“: Hier wird die Berechnungsmethode für den gleitenden Durchschnitt angegeben, z. B. einfacher gleitender Durchschnitt (SMA) oder exponentieller gleitender Durchschnitt (EMA), basierend auf den Eingaben des Nutzers.
- „app_price_enum“: Hier wird der angewandte Preistyp (z. B. Schlusskurs oder Eröffnungskurs) angegeben, auf dessen Grundlage der MA berechnet wird.
Das Ergebnis der Funktion „iMA“ wird in der Variablen „handle_ma“ gespeichert. Wenn die Funktion erfolgreich einen Indikator-Handle erstellt, enthält „handle_ma“ einen gültigen Verweis. Schlägt die Erstellung fehl, wird INVALID_HANDLE zurückgegeben, was darauf hinweist, dass es ein Problem mit einem oder mehreren Parametern gab. Da wir wissen, dass INVALID HANDLE eine Fehlerdarstellung ist, können wir sie für die weitere Verarbeitung verwenden.
if (handle_ma != INVALID_HANDLE){ Print("Successfully created the indicator handle!"); //... } else if (handle_ma == INVALID_HANDLE){ Print("Failed to create the indicator handle!"); }
Hier wird überprüft, ob der Handle des Indikators Moving Average (MA) erfolgreich erstellt wurde, indem der Wert von „handle_ma“ überprüft wird. Wenn das Handle gültig ist, gibt die Funktion iMA einen Wert zurück, der nicht gleich INVALID_HANDLE ist. In diesem Fall geben wir eine Erfolgsmeldung aus: „Der Indikatorgriff wurde erfolgreich erstellt!“. Dies bedeutet, dass alle Parameter (Symbol, Zeitrahmen, Periode, Methode usw.) korrekt interpretiert wurden und der MA-Indikator bereit ist, im Chart verwendet zu werden.
Wenn die Handle-Erstellung fehlschlägt, d.h. „handle_ma“ gleich INVALID_HANDLE ist, wird eine Fehlermeldung ausgegeben: „Der Indikator-Handle konnte nicht erstellt werden“. Diese Bedingung weist darauf hin, dass bei der Erstellung des Indikators ein Fehler aufgetreten ist, z. B. ein ungültiges Symbol, ein falscher Zeitrahmen oder ein anderer falscher Parameter. Diese Fehlerbehandlung trägt dazu bei, dass das System Probleme erkennen kann und während des Einrichtungsprozesses des Indikators informative Rückmeldungen gibt. Anschließend können wir ein Chart mit dem angegebenen Symbol und Zeitrahmen öffnen, sicherstellen, dass es mit den neuesten Daten synchronisiert ist, und seine Einstellungen für mehr Übersichtlichkeit anpassen.
long chart_id=ChartOpen(indicator_symbol,timeframe_enum); ChartSetInteger(ChartID(),CHART_BRING_TO_TOP,true); // update chart int wait=60; while(--wait>0){//decrease the value of wait by 1 before loop condition check if(SeriesInfoInteger(indicator_symbol,timeframe_enum,SERIES_SYNCHRONIZED)){ break; // if prices up to date, terminate the loop and proceed } } ChartSetInteger(chart_id,CHART_SHOW_GRID,false); ChartSetInteger(chart_id,CHART_SHOW_PERIOD_SEP,false); ChartRedraw(chart_id); Sleep(7000);
Zunächst verwenden wir die Funktion ChartOpen, um ein neues Chart auf der Grundlage von „indicator_symbol“ und „timeframe_enum“ zu öffnen, die wir zuvor aus dem Telegrambefehl extrahiert haben. Die Chart-ID wird zurückgegeben und in der Variablen „chart_id“ gespeichert. Um diesen Chart in MetaTrader 5 in den Vordergrund zu bringen, verwenden wir die Funktion ChartSetInteger und übergeben die Chart-ID zusammen mit der Konstante „CHART_BRING_TO_TOP“, um sicherzustellen, dass der Chart für die Interaktion sichtbar ist.
Als Nächstes implementieren wir eine Synchronisationsprüfung, um sicherzustellen, dass die Preisdaten für das Chart vollständig aktualisiert sind. Dazu wird die Funktion SeriesInfoInteger bis zu 60 Mal in einer Schleife verwendet, um zu prüfen, ob die Preisdatenreihe synchronisiert ist. Wenn die Synchronisierung vor dem Abschluss der Schleife erfolgt, brechen wir vorzeitig ab. Nachdem wir uns vergewissert haben, dass die Daten auf dem neuesten Stand sind, können wir das Aussehen des Charts anpassen. Das Raster und die Perioden-Trennzeichen werden mit der Funktion ChartSetInteger ausgeblendet, wobei wir „CHART_SHOW_GRID“ und „CHART_SHOW_PERIOD_SEP“ als „false“ übergeben, wodurch eine übersichtlichere Chartansicht entsteht.
Nach diesen Anpassungen wird das Chart mit der Funktion ChartRedraw visuell aktualisiert. Schließlich wird mit Sleep eine 7-Sekunden-Pause eingefügt, damit der Chart und die Daten vollständig geladen werden können, bevor weitere Operationen durchgeführt werden. Dieser gesamte Prozess stellt sicher, dass das Chart für die Interaktion und die Anzeige bereit ist, mit aktualisierten Daten und einem sauberen visuellen Aufbau. Danach können wir den Indikator in das Chart einfügen.
if (ChartIndicatorAdd(chart_id,0,handle_ma)) { Print("SUCCESS. Indicator added to the chart."); isIndicatorAddedToChart = true; } else { Print("FAIL: Indicator not added to the chart."); }
Hier fügen wir den zuvor erstellten Indikator für den gleitenden Durchschnitt (MA) zu dem zuvor geöffneten Chart hinzu. Dazu verwenden wir die Funktion ChartIndicatorAdd, bei der wir die „chart_id“, eine Null (die anzeigt, dass wir den Indikator zum Hauptdiagramm hinzufügen), und „handle_ma“, das den Handle des von uns erstellten MA-Indikators darstellt, übergeben. Wenn die Addition erfolgreich war, wird die Erfolgsmeldung „SUCCESS Indicator added to the chart“ ausgegeben, und die boolesche Variable „isIndicatorAddedToChart“ wird auf true gesetzt, was anzeigt, dass der Indikator nun im Chart aktiv ist. Wir haben die boolesche Variable definiert und sie außerhalb der „if“-Anweisung wie gezeigt auf false initialisiert.
bool isIndicatorAddedToChart = false;
Schlägt die Addition hingegen fehl, wird eine Fehlermeldung mit dem Wortlaut „FAIL:“ Indicator not added to the chart“ ausgegeben. Diese Prüfung ist von entscheidender Bedeutung, da sie sicherstellt, dass wir bestätigen können, ob der Indikator erfolgreich auf das Chart angewendet wurde, was für die nachfolgenden Handelsoperationen und die visuelle Analyse unerlässlich ist. Indem wir beide Ergebnisse behandeln, behalten wir die Transparenz in unserem Prozess bei und sind über den Stand des Indikators auf dem Chart informiert. Wenn wir den Indikator erstellen und zum Chart hinzufügen, können wir den Nutzer in derselben Codestruktur über den Erfolg informieren.
if (isIndicatorAddedToChart){ string message = "\nSUCCESS! THE INDICATOR WAS ADDED TO THE CHART WITH THE FOLLOWING DETAILS:\n"; //--- Prepare success message message += "\nType = "+indicator_type+"\n"; message += "Symbol = "+indicator_symbol+"\n"; message += "Timeframe = "+indicator_timeframe+"\n"; message += "Period = "+IntegerToString(indicator_period)+"\n"; message += "Shift = "+IntegerToString(indicator_shift)+"\n"; message += "Applied Price = "+indicator_app_price+"\n"; message+="\nHAPPY TRADING!"; //--- Add final message line Print(message); //--- Print the message in the terminal sendMessageToTelegram(chat.member_id,message,NULL); //--- Send the success message to Telegram }
Hier wird geprüft, ob der Indikator erfolgreich zum Chart hinzugefügt wurde, indem die boolesche Variable „isIndicatorAddedToChart“ ausgewertet wird. Wenn diese Bedingung erfüllt ist, wird eine Erfolgsmeldung erstellt, die die Konfiguration des Indikators enthält. Wir beginnen mit der Initialisierung einer String-Variablen namens „message“ mit der Kopfzeile einer Erfolgsmeldung: „\nSUCCESS! THE INDICATOR WAS ADDED TO THE CHART WITH THE FOLLOWING DETAILS:\n“. Anschließend werden verschiedene Informationen über den Indikator miteinander verknüpft, darunter Typ, Symbol, Zeitrahmen, Zeitraum, Verschiebung und angewandter Preis. Für die numerischen Werte verwenden wir die Funktion IntegerToString, um sicherzustellen, dass sie für die richtige Verkettung in das String-Format konvertiert werden.
Nachdem wir all diese Informationen zusammengetragen haben, fügen wir der Nachricht eine letzte Zeile hinzu, in der es heißt: „\nHAPPY TRADING!“, um eine positive Stimmung zu vermitteln. Mit der Funktion Print geben wir dann die vollständige Meldung auf dem Terminal aus, sodass die Hinzufügung des Indikators und seine Einzelheiten eindeutig bestätigt werden können. Schließlich rufen wir die Funktion „sendMessageToTelegram“ auf, um dieselbe Erfolgsmeldung an Telegram zu senden und sicherzustellen, dass der betreffende Chat, der durch „chat.member_id“ identifiziert wird, über den erfolgreichen Vorgang informiert wird. Wenn wir dies ausführen, erhalten wir die folgende Ausgabe.
Wir sehen, dass wir trotz der Aufnahme des Symbols in die Marktbeobachtung eine Fehlermeldung erhalten. Das liegt daran, dass wir in die korrekte Struktur des Symbolnamens eingegriffen haben, indem wir alles in Großbuchstaben umgewandelt haben. Um die korrekte Struktur wiederherzustellen und gleichzeitig die korrekte Symbolinterpretation und den korrekten Vergleich beizubehalten, können wir eine Vielzahl von Optionen verwenden, aber die einfachste ist das direkte Anhängen des ursprünglichen Symbolnamens an die Haltervariable, wie gezeigt.
//--- Check for symbol in the list of available symbols and assign it for(int k = 0; k < SymbolsTotal(true); k++) { //--- Loop through all available symbols string selected_symbol = SymbolName(k, true); //--- Get the symbol name StringToUpper(selected_symbol); if (StringCompare(selected_line,selected_symbol,false) == 0){ //--- Compare the line with the symbol name indicator_symbol = SymbolName(k, true); //--- Assign the symbol if a match is found Print("Line @ index ",i," SYMBOL = ",indicator_symbol); //--- Print the found symbol } }
Die einzige Änderung, die in dem Ausschnitt vorgenommen wurde, ist in gelber Farbe hervorgehoben. Bei einer erneuten Ausführung erhalten wir die korrekte Ausgabe wie unten dargestellt:
Bis zu diesem Punkt haben wir den Indikator erfolgreich zum Chart hinzugefügt. Auf Telegram erhalten wir die unten abgebildete Erfolgsmeldung:
Auf dem Handelsterminal wird ein neues Chart geöffnet und der Indikator wird hinzugefügt. Nachstehend finden Sie eine visuelle Bestätigung.
Bis zu diesem Punkt können wir sagen, dass wir unser Ziel erreicht haben, die technischen Indikatoren des gleitenden Durchschnitts automatisch zu den Charts hinzuzufügen. Eine ähnliche Methodik lässt sich auch auf andere Indikatoren anwenden, z. B. den Awesome Oscillator. Indem wir das gleiche Format für die Identifizierung des Befehls, die Extraktion der relevanten Parameter und die Ausführung der Hinzufügung des Indikators befolgen, können wir verschiedene Indikatoren nahtlos in unser Handelssystem integrieren und die Konsistenz und Effizienz während der gesamten Implementierung beibehalten. Wir müssen jedoch die Umsetzung testen und bestätigen, dass alles gut funktioniert. Dies geschieht im nächsten Abschnitt.
Testen des Indikatorhandelssystems
In diesem Abschnitt werden wir uns darauf konzentrieren, die Funktionalität unseres Indikatorhandelssystems zu überprüfen. Bei den Tests wird geprüft, ob die Indikatoren korrekt konfiguriert sind und angemessen auf die von Telegram empfangenen Befehle reagieren. Wir werden den Prozess des Hinzufügens von Indikatoren zum Chart untersuchen und sicherstellen, dass alle Parameter korrekt eingestellt sind und die Indikatoren korrekt im Chart angezeigt werden.
Zur Veranschaulichung dieses Prozesses haben wir ein Video beigefügt, in dem die Einrichtung und Konfiguration von Indikatoren in MetaTrader 5, insbesondere des gleitenden Durchschnitts, demonstriert wird. Dabei wird die Funktionsweise des Systems hervorgehoben und seine Eignung für reale Handelsszenarien bestätigt (siehe unten).
Schlussfolgerung
Insgesamt haben wir in diesem Artikel gezeigt, wie Sie Indikatorbefehle, die Sie über Telegram erhalten, analysieren und verarbeiten können, um das Hinzufügen von Indikatoren zu Ihren MetaTrader 5 Charts zu automatisieren. Durch die Einführung dieser Techniken haben wir den Prozess gestrafft, die Effizienz des Handels erhöht und das Potenzial für menschliche Fehler verringert.
Mit dem Wissen, das Sie bei dieser Implementierung erworben haben, sind Sie in der Lage, anspruchsvollere Systeme zu entwickeln, die zusätzliche Indikatoren und Befehle enthalten. Diese Grundlage wird Sie in die Lage versetzen, Ihre Handelsstrategien zu verfeinern, sich an veränderte Marktbedingungen anzupassen und letztendlich Ihre Handelsleistung zu verbessern. Wir hoffen, dass der Artikel für Sie leicht verständlich war und Ihnen die nötigen Erkenntnisse zur Verbesserung Ihrer Handelssysteme vermittelt hat. Sollten Sie Fragen haben oder weitere Erläuterungen benötigen, können Sie gerne zusätzliche Ressourcen nutzen oder mit den in dieser Reihe vorgestellten Konzepten experimentieren. Viel Spaß beim Handeln!
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/15962





- 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.