
MQL5-Handelswerkzeuge (Teil 1): Aufbau eines interaktiven visuellen Handelsassistenten für schwebende Aufträge
Einführung
Die Entwicklung effektiver Handelswerkzeuge ist für die Vereinfachung komplexer Aufgaben im Devisenhandel unerlässlich, doch die Schaffung intuitiver Schnittstellen, die die Entscheidungsfindung verbessern, bleibt eine Herausforderung. Wie wäre es, wenn Sie ein visuelles, interaktives Tool entwerfen könnten, das die Platzierung ausstehender Aufträge innerhalb von MetaTrader 5 rationalisiert? In diesem Artikel stellen wir einen nutzerdefinierten MetaQuotes Language 5 (MQL5) Expert Advisor (EA) vor, der Händlern ein Handelsassistenz-Tool zur Verfügung stellt, das grafische Präzision mit nutzerfreundlichen Steuerelementen kombiniert, um Kauf-/Verkaufsstopps und Limit-Orders effizient zu platzieren. Wir gehen diese Schritte in dieser Reihenfolge durch:
Am Ende haben Sie ein klares Verständnis davon, wie man dieses Tool aufbaut und testet, was den Weg für fortgeschrittene Erweiterungen in den vorangehenden Teilen ebnet.
Konzeption und Zielsetzung des Trade Assistant Tools
Unser Ziel ist es, ein Handelsassistententool zu entwickeln, das uns eine nahtlose und effiziente Erfahrung bietet, indem es den Prozess der Platzierung von schwebenden Aufträgen im Devisenhandel vereinfacht. Wir stellen uns das Tool als eine graphische Nutzeroberfläche (GUI) vor, die direkt in den MetaTrader 5 integriert ist und es uns ermöglicht, Aufträge wie Buy Stop, Sell Stop, Buy Limit und Sell Limit über ein intuitives Bedienfeld einzurichten. Unser Entwurf soll Schaltflächen zur Auswahl der gewünschten Auftragsart und ein Eingabefeld zur Angabe der Losgröße enthalten. Wir legen Wert auf visuelle Interaktion und ermöglichen es, Einstiegskurse, Stop-Loss (SL) und Take-Profit (TP) durch Ziehen interaktiver Elemente auf dem Chart zu definieren, was ein unmittelbares Feedback zu den Kursniveaus und den Punktunterschieden zwischen ihnen liefert.
Unser Hauptaugenmerk liegt auf der Zugänglichkeit und Reaktionsfähigkeit des Tools. Wir werden die Schnittstelle so gestalten, dass sie reaktionsschnell ist und es uns ermöglicht, die Preise präzise anzupassen und Bestellungen mit einem einzigen Klick zu bestätigen, sodass der Zeitaufwand für die Einrichtung minimiert wird. Außerdem werden wir die Möglichkeit einbauen, die Schnittstelle zu kündigen oder zu schließen, was uns die Flexibilität gibt, uns schnell an veränderte Marktbedingungen anzupassen. Durch die Entwicklung eines optisch ansprechenden und reaktionsschnellen Tools wollen wir unsere Entscheidungsfindung verbessern, Fehler bei der Auftragsvergabe reduzieren und eine Grundlage für künftige Verbesserungen, wie z. B. erweiterte Risikomanagementfunktionen, schaffen, die wir in späteren Iterationen erforschen werden. Kurz gesagt, hier ist eine Visualisierung dessen, was wir zu schaffen gedenken.
Implementation in MQL5
Um das Programm in MQL5 zu erstellen, müssen wir die Programm-Metadaten definieren, dann einige Objektnamenskonstanten festlegen und schließlich einige Bibliotheksdateien einfügen, die es uns ermöglichen, die Handelsaktivitäten durchzuführen.
//+------------------------------------------------------------------+ //| TRADE ASSISTANT GUI TOOL | //| Copyright 2025, ALLAN MUNENE MUTIIRIA. #@Forex Algo-Trader. | //| https://youtube.com/@ForexAlgo-Trader? | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, ALLAN MUNENE MUTIIRIA. #@Forex Algo-Trader" #property link "https://youtube.com/@ForexAlgo-Trader?" #property version "1.00" #include <Trade/Trade.mqh> //--- Include the Trade library for trading operations // Control panel object names #define PANEL_BG "PANEL_BG" //--- Define constant for panel background object name #define LOT_EDIT "LOT_EDIT" //--- Define constant for lot size edit field object name #define PRICE_LABEL "PRICE_LABEL" //--- Define constant for price label object name #define SL_LABEL "SL_LABEL" //--- Define constant for stop-loss label object name #define TP_LABEL "TP_LABEL" //--- Define constant for take-profit label object name #define BUY_STOP_BTN "BUY_STOP_BTN" //--- Define constant for buy stop button object name #define SELL_STOP_BTN "SELL_STOP_BTN" //--- Define constant for sell stop button object name #define BUY_LIMIT_BTN "BUY_LIMIT_BTN" //--- Define constant for buy limit button object name #define SELL_LIMIT_BTN "SELL_LIMIT_BTN" //--- Define constant for sell limit button object name #define PLACE_ORDER_BTN "PLACE_ORDER_BTN" //--- Define constant for place order button object name #define CANCEL_BTN "CANCEL_BTN" //--- Define constant for cancel button object name #define CLOSE_BTN "CLOSE_BTN" //--- Define constant for close button object name #define REC1 "REC1" //--- Define constant for rectangle 1 (TP) object name #define REC2 "REC2" //--- Define constant for rectangle 2 object name #define REC3 "REC3" //--- Define constant for rectangle 3 (Entry) object name #define REC4 "REC4" //--- Define constant for rectangle 4 object name #define REC5 "REC5" //--- Define constant for rectangle 5 (SL) object name #define TP_HL "TP_HL" //--- Define constant for take-profit horizontal line object name #define SL_HL "SL_HL" //--- Define constant for stop-loss horizontal line object name #define PR_HL "PR_HL" //--- Define constant for price (entry) horizontal line object name double Get_Price_d(string name) { return ObjectGetDouble(0, name, OBJPROP_PRICE); } //--- Function to get price as double for an object string Get_Price_s(string name) { return DoubleToString(ObjectGetDouble(0, name, OBJPROP_PRICE), _Digits); } //--- Function to get price as string with proper digits string update_Text(string name, string val) { return (string)ObjectSetString(0, name, OBJPROP_TEXT, val); } //--- Function to update text of an object int xd1, yd1, xs1, ys1, //--- Variables for rectangle 1 position and size xd2, yd2, xs2, ys2, //--- Variables for rectangle 2 position and size xd3, yd3, xs3, ys3, //--- Variables for rectangle 3 position and size xd4, yd4, xs4, ys4, //--- Variables for rectangle 4 position and size xd5, yd5, xs5, ys5; //--- Variables for rectangle 5 position and size // Control panel variables bool tool_visible = false; //--- Flag to track if trading tool is visible string selected_order_type = ""; //--- Variable to store selected order type double lot_size = 0.01; //--- Default lot size for trades CTrade obj_Trade; //--- Trade object for executing trading operations int panel_x = 10, panel_y = 30; //--- Panel position coordinates
Hier legen wir das Fundament für unser Trade Assistant Tool, indem wir die wesentlichen Komponenten, Variablen und Funktionen definieren, die die grafischen und handelstechnischen Funktionalitäten des Tools ermöglichen. Wir beginnen mit der Einbindung der Bibliothek „Trade.mqh“, die die Klasse „CTrade“ für die Ausführung von Handelsoperationen, wie z. B. die Platzierung schwebender Aufträge, bereitstellt. Anschließend definieren wir eine Reihe von Konstanten mit #define, um eindeutige Namen für GUI-Elemente zu vergeben, z. B. „PANEL_BG“ für den Hintergrund des Bedienfelds, „LOT_EDIT“ für das Eingabefeld für die Losgröße und Schaltflächen wie „BUY_STOP_BTN“ und „SELL_STOP_BTN“ für die Auswahl der Auftragsart und vieles mehr.
Wir implementieren drei Funktionen zur Verwaltung der Eigenschaften von Chart-Objekten: Die Funktion „Get_Price_d“ ruft den Preis eines Objekts als Double ab, die Funktion „Get_Price_s“ wandelt diesen Preis mit der Funktion DoubleToString in einen String um, der mit der entsprechenden Anzahl von Dezimalstellen formatiert ist, und die Funktion „update_Text“ aktualisiert den Text eines Objekts mit der Funktion ObjectSetString, um Echtzeit-Preisinformationen anzuzeigen.
Um die Positionierung und Größe der interaktiven Rechtecke zu handhaben, werden für jedes Rechteck („REC1“ bis „REC5“) ganzzahlige Variablen wie „xd1“, „yd1“, „xs1“ und „ys1“ deklariert, die den x-Abstand, den y-Abstand, die x-Größe und die y-Größe auf dem Chart darstellen.
Schließlich definieren wir wichtige Variablen für das Bedienfeld: „tool_visible“ als boolescher Wert, um die Sichtbarkeit des Werkzeugs zu verfolgen, „selected_order_type“ als String, um den gewählten Ordertyp zu speichern, „lot_size“ als Double, initialisiert auf 0.01 für das Handelsvolumen, „obj_Trade“ als „CTrade“-Objekt für die Ausführung von Handelsgeschäften und „panel_x“ und „panel_y“ als Ganzzahlen, um die Position des Bedienfelds an den Koordinaten (10, 30) festzulegen.
Diese Elemente bilden zusammen das strukturelle Rückgrat für die interaktive Schnittstelle und die Handelsfunktionen unseres Tools. Jetzt können wir mit der Erstellung des Bedienfelds fortfahren, aber zunächst benötigen wir eine Funktion zur Erstellung einer nutzerdefinierten Schaltfläche.
//+------------------------------------------------------------------+ //| Create button | //+------------------------------------------------------------------+ bool createButton(string objName, string text, int xD, int yD, int xS, int yS, color clrTxt, color clrBG, int fontsize = 12, color clrBorder = clrNONE, bool isBack = false, string font = "Calibri") { ResetLastError(); //--- Reset last error code if(!ObjectCreate(0, objName, OBJ_BUTTON, 0, 0, 0)) { //--- Create button object Print(__FUNCTION__, ": Failed to create Btn: Error Code: ", GetLastError()); //--- Print error message return false; //--- Return failure } ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); //--- Set button x-position ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); //--- Set button y-position ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); //--- Set button width ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); //--- Set button height ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); //--- Set button corner ObjectSetString(0, objName, OBJPROP_TEXT, text); //--- Set button text ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontsize); //--- Set font size ObjectSetString(0, objName, OBJPROP_FONT, font); //--- Set font ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); //--- Set text color ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBG); //--- Set background color ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, clrBorder); //--- Set border color ObjectSetInteger(0, objName, OBJPROP_BACK, isBack); //--- Set background/foreground ObjectSetInteger(0, objName, OBJPROP_STATE, false); //--- Reset button state ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); //--- Disable selection ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); //--- Disable selected state ChartRedraw(0); //--- Redraw chart return true; //--- Return success }
Wir definieren die Funktion „createButton“, um anpassbare Schaltflächen für unser Werkzeug zu erstellen. Sie akzeptiert Parameter wie „objName“ für den Namen der Schaltfläche, „text“ für ihre Beschriftung, „xD“ und „yD“ für die Position, „xS“ und „yS“ für die Größe, „clrTxt“ und „clrBG“ für Text- und Hintergrundfarben, „fontsize“ (Standardwert 12), „clrBorder“ (Standardwert „clrNONE“), „isBack“ (Standardwert false) und „font“ (Standardwert „Calibri“).
Wir verwenden die Funktion ResetLastError, um Fehlercodes zu löschen, und dann die Funktion ObjectCreate, um einen OBJ_BUTTON zu erstellen. Wenn es fehlschlägt, rufen wir die Funktion Print mit __FUNCTION__ und GetLastError auf, um den Fehler zu protokollieren und false zurückzugeben.
Bei Erfolg werden Eigenschaften wie Position, Größe und Farben mit den Funktionen ObjectSetInteger und ObjectSetString festgelegt, Status und Auswahl deaktiviert und die Funktion ChartRedraw aufgerufen, um das Chart zu aktualisieren, wobei true zurückgegeben wird. So können wir interaktive Schaltflächen erstellen. Mit dieser Funktion können wir also die Funktion für das Bedienfeld erstellen.
//+------------------------------------------------------------------+ //| Create control panel | //+------------------------------------------------------------------+ void createControlPanel() { // Background rectangle ObjectCreate(0, PANEL_BG, OBJ_RECTANGLE_LABEL, 0, 0, 0); //--- Create panel background rectangle ObjectSetInteger(0, PANEL_BG, OBJPROP_XDISTANCE, panel_x); //--- Set background x-position ObjectSetInteger(0, PANEL_BG, OBJPROP_YDISTANCE, panel_y); //--- Set background y-position ObjectSetInteger(0, PANEL_BG, OBJPROP_XSIZE, 250); //--- Set background width ObjectSetInteger(0, PANEL_BG, OBJPROP_YSIZE, 280); //--- Set background height ObjectSetInteger(0, PANEL_BG, OBJPROP_BGCOLOR, C'070,070,070'); //--- Set background color ObjectSetInteger(0, PANEL_BG, OBJPROP_BORDER_COLOR, clrWhite); //--- Set border color ObjectSetInteger(0, PANEL_BG, OBJPROP_BACK, false); //--- Set background to foreground createButton(CLOSE_BTN, CharToString(203), panel_x + 209, panel_y + 1, 40, 25, clrWhite, clrCrimson, 12, C'070,070,070', false, "Wingdings"); //--- Create close button // Lot size input ObjectCreate(0, LOT_EDIT, OBJ_EDIT, 0, 0, 0); //--- Create lot size edit field ObjectSetInteger(0, LOT_EDIT, OBJPROP_XDISTANCE, panel_x + 70); //--- Set edit field x-position ObjectSetInteger(0, LOT_EDIT, OBJPROP_YDISTANCE, panel_y + 40); //--- Set edit field y-position ObjectSetInteger(0, LOT_EDIT, OBJPROP_XSIZE, 110); //--- Set edit field width ObjectSetInteger(0, LOT_EDIT, OBJPROP_YSIZE, 25); //--- Set edit field height ObjectSetString(0, LOT_EDIT, OBJPROP_TEXT, "0.01"); //--- Set default lot size text ObjectSetInteger(0, LOT_EDIT, OBJPROP_COLOR, clrBlack); //--- Set text color ObjectSetInteger(0, LOT_EDIT, OBJPROP_BGCOLOR, clrWhite); //--- Set background color ObjectSetInteger(0, LOT_EDIT, OBJPROP_BORDER_COLOR, clrBlack); //--- Set border color ObjectSetInteger(0, LOT_EDIT, OBJPROP_ALIGN, ALIGN_CENTER); //--- Center text ObjectSetString(0, LOT_EDIT, OBJPROP_FONT, "Arial"); //--- Set font ObjectSetInteger(0, LOT_EDIT, OBJPROP_FONTSIZE, 13); //--- Set font size ObjectSetInteger(0, LOT_EDIT, OBJPROP_BACK, false); //--- Set to foreground // Entry price label ObjectCreate(0, PRICE_LABEL, OBJ_LABEL, 0, 0, 0); //--- Create entry price label ObjectSetInteger(0, PRICE_LABEL, OBJPROP_XDISTANCE, panel_x + 10); //--- Set label x-position ObjectSetInteger(0, PRICE_LABEL, OBJPROP_YDISTANCE, panel_y + 70); //--- Set label y-position ObjectSetInteger(0, PRICE_LABEL, OBJPROP_XSIZE, 230); //--- Set label width ObjectSetString(0, PRICE_LABEL, OBJPROP_TEXT, "Entry: -"); //--- Set default text ObjectSetString(0, PRICE_LABEL, OBJPROP_FONT, "Arial Bold"); //--- Set font ObjectSetInteger(0, PRICE_LABEL, OBJPROP_FONTSIZE, 13); //--- Set font size ObjectSetInteger(0, PRICE_LABEL, OBJPROP_COLOR, clrWhite); //--- Set text color ObjectSetInteger(0, PRICE_LABEL, OBJPROP_ALIGN, ALIGN_CENTER); //--- Center text ObjectSetInteger(0, PRICE_LABEL, OBJPROP_BACK, false); //--- Set to foreground // SL and TP labels ObjectCreate(0, SL_LABEL, OBJ_LABEL, 0, 0, 0); //--- Create stop-loss label ObjectSetInteger(0, SL_LABEL, OBJPROP_XDISTANCE, panel_x + 10); //--- Set label x-position ObjectSetInteger(0, SL_LABEL, OBJPROP_YDISTANCE, panel_y + 95); //--- Set label y-position ObjectSetInteger(0, SL_LABEL, OBJPROP_XSIZE, 110); //--- Set label width ObjectSetString(0, SL_LABEL, OBJPROP_TEXT, "SL: -"); //--- Set default text ObjectSetString(0, SL_LABEL, OBJPROP_FONT, "Arial Bold"); //--- Set font ObjectSetInteger(0, SL_LABEL, OBJPROP_FONTSIZE, 12); //--- Set font size ObjectSetInteger(0, SL_LABEL, OBJPROP_COLOR, clrYellow); //--- Set text color ObjectSetInteger(0, SL_LABEL, OBJPROP_ALIGN, ALIGN_CENTER); //--- Center text ObjectSetInteger(0, SL_LABEL, OBJPROP_BACK, false); //--- Set to foreground ObjectCreate(0, TP_LABEL, OBJ_LABEL, 0, 0, 0); //--- Create take-profit label ObjectSetInteger(0, TP_LABEL, OBJPROP_XDISTANCE, panel_x + 130); //--- Set label x-position ObjectSetInteger(0, TP_LABEL, OBJPROP_YDISTANCE, panel_y + 95); //--- Set label y-position ObjectSetInteger(0, TP_LABEL, OBJPROP_XSIZE, 110); //--- Set label width ObjectSetString(0, TP_LABEL, OBJPROP_TEXT, "TP: -"); //--- Set default text ObjectSetString(0, TP_LABEL, OBJPROP_FONT, "Arial Bold"); //--- Set font ObjectSetInteger(0, TP_LABEL, OBJPROP_FONTSIZE, 12); //--- Set font size ObjectSetInteger(0, TP_LABEL, OBJPROP_COLOR, clrLime); //--- Set text color ObjectSetInteger(0, TP_LABEL, OBJPROP_ALIGN, ALIGN_CENTER); //--- Center text ObjectSetInteger(0, TP_LABEL, OBJPROP_BACK, false); //--- Set to foreground // Order type buttons createButton(BUY_STOP_BTN, "Buy Stop", panel_x + 10, panel_y + 140, 110, 30, clrWhite, clrForestGreen, 10, clrBlack, false, "Arial"); //--- Create Buy Stop button createButton(SELL_STOP_BTN, "Sell Stop", panel_x + 130, panel_y + 140, 110, 30, clrWhite, clrFireBrick, 10, clrBlack, false, "Arial"); //--- Create Sell Stop button createButton(BUY_LIMIT_BTN, "Buy Limit", panel_x + 10, panel_y + 180, 110, 30, clrWhite, clrForestGreen, 10, clrBlack, false, "Arial"); //--- Create Buy Limit button createButton(SELL_LIMIT_BTN, "Sell Limit", panel_x + 130, panel_y + 180, 110, 30, clrWhite, clrFireBrick, 10, clrBlack, false, "Arial"); //--- Create Sell Limit button // Place Order and Cancel buttons createButton(PLACE_ORDER_BTN, "Place Order", panel_x + 10, panel_y + 240, 110, 30, clrWhite, clrDodgerBlue, 10, clrBlack, false, "Arial"); //--- Create Place Order button createButton(CANCEL_BTN, "Cancel", panel_x + 130, panel_y + 240, 110, 30, clrWhite, clrSlateGray, 10, clrBlack, false, "Arial"); //--- Create Cancel button }
Hier definieren wir die Funktion „createControlPanel“, um die graphisches Nutzerschnittstelle (GUI) für unser Trade Assistant Tool zu erstellen. Wir beginnen mit der Funktion ObjectCreate, um ein Hintergrundrechteck mit dem Namen „PANEL_BG“ vom Typ OBJ_RECTANGLE_LABEL zu erstellen, das bei „panel_x“ und „panel_y“ positioniert ist. (auf 10 und 30 gesetzt), mit einer Größe von 250x280 Pixeln, einem dunkelgrauen Hintergrund („C'070,070,070'“), einem weißen Rand („clrWhite“) und einer Platzierung im Vordergrund (OBJPROP_BACK auf false gesetzt).
Dann rufen wir die Funktion „createButton“ auf, um in der rechten oberen Ecke eine Schaltfläche zum Schließen („CLOSE_BTN“) hinzuzufügen, die ein Kreuzsymbol (Zeichen 203 aus „Wingdings“) in purpurner Farbe anzeigt. Die Eingabe ist in der MQL5-Dokumentation wie unten definiert, aber Sie können eine Eingabe nach Ihrem Geschmack verwenden.
Für die Eingabe der Losgröße verwenden wir die Funktion ObjectCreate, um ein Eingabefeld („LOT_EDIT“) vom Typ OBJ_EDIT an den Positionen „panel_x + 70“ und „panel_y + 40“ zu erstellen. Das Feld hat eine Größe von 110x25 Pixeln, ist mit „0,01“ initialisiert und mit den Funktionen ObjectSetInteger und ObjectSetString mit schwarzem Text, weißem Hintergrund und zentrierter Arial-Schrift gestaltet.
Mit der Funktion „ObjectCreate“ erstellen wir drei Etiketten für die Anzeige von Handelsinformationen: „PRICE_LABEL“ für den Einstiegspreis bei „panel_x + 10“, „panel_y + 70“, über 230 Pixel mit dem Standardtext „Entry: -“; „SL_LABEL“ für den Stop-Loss bei „panel_x + 10“, „panel_y + 95“, mit gelbem Text und dem Standardtext „SL: -“; und „TP_LABEL“ für Take-Profit bei „panel_x + 130“, „panel_y + 95“, mit Text in „lime“ und dem Standardtext „TP: -“, alle in fetter Arial-Schrift und zentrierter Ausrichtung.
Schließlich fügen wir mit der Funktion „createButton“ Schaltflächen für den Auftragstyp - „BUY_STOP_BTN“ und „SELL_STOP_BTN“ bei „panel_y + 140“, „BUY_LIMIT_BTN“ und „SELL_LIMIT_BTN“ bei „panel_y + 180“ in grüner bzw. roter Farbe und die Aktionsschaltflächen „PLACE_ORDER_BTN“ und „CANCEL_BTN“ bei „panel_y + 240“ in blauer und grauer Farbe, alle in der Größe 110x30 Pixel mit Arial-Schrift. Diese Einrichtung bildet das interaktive Bedienfeld für unser Tool. Wir können die Funktion in OnInit aufrufen, um das Panel zu initialisieren.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Create control panel createControlPanel(); //--- Call function to create the control panel ChartRedraw(0); //--- Redraw chart to display panel return(INIT_SUCCEEDED); //--- Return successful initialization }
In OnInit rufen wir die Funktion „createControlPanel“ auf, um die grafische Nutzeroberfläche zu erstellen und das Bedienfeld mit Schaltflächen, Beschriftungen und Eingabefeldern einzurichten. Als Nächstes verwenden wir die Funktion ChartRedraw, um das Chart zu aktualisieren und sicherzustellen, dass das Panel sofort angezeigt wird. Schließlich geben wir INIT_SUCCEEDED zurück, um die erfolgreiche Initialisierung anzuzeigen. Nach dem Kompilieren erhalten wir die folgende Ausgabe.
Aus dem Bild können wir ersehen, dass wir das Bedienfeld erstellt haben. Was wir jetzt erstellen müssen, ist das Assistenten-Panel, mit dem wir die Chart-Preise dynamisch abrufen und automatisch in das Kontroll-Panel übertragen können, um auf dieser Grundlage zu handeln. Dazu ist es erforderlich, die Skala der Karte und die Skala des Bildschirms zu integrieren, aber dafür haben wir gesorgt. Wir werden alles in einer Funktion unterbringen. Dann fügen wir Ereignis-Listener hinzu, die die entsprechenden Funktionen aufrufen, wenn die Schaltfläche des Steuerelements betätigt wird.
//+------------------------------------------------------------------+ //| Expert onchart event function | //+------------------------------------------------------------------+ void OnChartEvent( const int id, //--- Event ID const long& lparam, //--- Long parameter (e.g., x-coordinate for mouse) const double& dparam, //--- Double parameter (e.g., y-coordinate for mouse) const string& sparam //--- String parameter (e.g., object name) ) { if(id == CHARTEVENT_OBJECT_CLICK) { //--- Handle object click events // Handle order type buttons if(sparam == BUY_STOP_BTN) { //--- Check if Buy Stop button clicked selected_order_type = "BUY_STOP"; //--- Set order type to Buy Stop } } }
Hier implementieren wir die Ereignisbehandlung durch OnChartEvent, um Nutzerinteraktionen mit dem Tool zu verarbeiten. Die Funktion erhält folgende Parameter: „id“ für den Ereignistyp, „lparam“ für Daten wie x-Koordinaten, „dparam“ für Daten wie y-Koordinaten und „sparam“ für String-Daten wie Objektnamen. Wir prüfen, ob „id“ gleich CHARTEVENT_OBJECT_CLICK ist, um Objektklicks zu erkennen, und wenn „sparam“ mit „BUY_STOP_BTN“ übereinstimmt, setzen wir die Variable „selected_order_type“ auf „BUY_STOP“, sodass wir die Auswahl eines Kaufstoppauftrags durch den Nutzer registrieren können. Wenn das der Fall ist, brauchen wir eine Funktion, die das Werkzeug anzeigt.
//+------------------------------------------------------------------+ //| Show main tool | //+------------------------------------------------------------------+ void showTool() { // Hide panel ObjectSetInteger(0, PANEL_BG, OBJPROP_BACK, false); //--- Hide panel background ObjectSetInteger(0, LOT_EDIT, OBJPROP_BACK, false); //--- Hide lot edit field ObjectSetInteger(0, PRICE_LABEL, OBJPROP_BACK, false); //--- Hide price label ObjectSetInteger(0, SL_LABEL, OBJPROP_BACK, false); //--- Hide SL label ObjectSetInteger(0, TP_LABEL, OBJPROP_BACK, false); //--- Hide TP label ObjectSetInteger(0, BUY_STOP_BTN, OBJPROP_BACK, false); //--- Hide Buy Stop button ObjectSetInteger(0, SELL_STOP_BTN, OBJPROP_BACK, false); //--- Hide Sell Stop button ObjectSetInteger(0, BUY_LIMIT_BTN, OBJPROP_BACK, false); //--- Hide Buy Limit button ObjectSetInteger(0, SELL_LIMIT_BTN, OBJPROP_BACK, false); //--- Hide Sell Limit button ObjectSetInteger(0, PLACE_ORDER_BTN, OBJPROP_BACK, false); //--- Hide Place Order button ObjectSetInteger(0, CANCEL_BTN, OBJPROP_BACK, false); //--- Hide Cancel button ObjectSetInteger(0, CLOSE_BTN, OBJPROP_BACK, false); //--- Hide Close button // Create main tool 150 pixels from the right edge int chart_width = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS); //--- Get chart width int tool_x = chart_width - 400 - 50; //--- Calculate tool x-position (400 is REC1 width, 50 is margin) if(selected_order_type == "BUY_STOP" || selected_order_type == "BUY_LIMIT") { //--- Check for buy orders // Buy orders: TP at top, entry in middle, SL at bottom createButton(REC1, "", tool_x, 20, 350, 30, clrWhite, clrGreen, 13, clrBlack, false, "Arial Black"); //--- Create TP rectangle xd1 = (int)ObjectGetInteger(0, REC1, OBJPROP_XDISTANCE); //--- Get REC1 x-distance yd1 = (int)ObjectGetInteger(0, REC1, OBJPROP_YDISTANCE); //--- Get REC1 y-distance xs1 = (int)ObjectGetInteger(0, REC1, OBJPROP_XSIZE); //--- Get REC1 x-size ys1 = (int)ObjectGetInteger(0, REC1, OBJPROP_YSIZE); //--- Get REC1 y-size xd2 = xd1; //--- Set REC2 x-distance yd2 = yd1 + ys1; //--- Set REC2 y-distance xs2 = xs1; //--- Set REC2 x-size ys2 = 100; //--- Set REC2 y-size xd3 = xd2; //--- Set REC3 x-distance yd3 = yd2 + ys2; //--- Set REC3 y-distance xs3 = xs2; //--- Set REC3 x-size ys3 = 30; //--- Set REC3 y-size xd4 = xd3; //--- Set REC4 x-distance yd4 = yd3 + ys3; //--- Set REC4 y-distance xs4 = xs3; //--- Set REC4 x-size ys4 = 100; //--- Set REC4 y-size xd5 = xd4; //--- Set REC5 x-distance yd5 = yd4 + ys4; //--- Set REC5 y-distance xs5 = xs4; //--- Set REC5 x-size ys5 = 30; //--- Set REC5 y-size } else { //--- Handle sell orders // Sell orders: SL at top, entry in middle, TP at bottom createButton(REC5, "", tool_x, 20, 350, 30, clrWhite, clrRed, 13, clrBlack, false, "Arial Black"); //--- Create SL rectangle xd5 = (int)ObjectGetInteger(0, REC5, OBJPROP_XDISTANCE); //--- Get REC5 x-distance yd5 = (int)ObjectGetInteger(0, REC5, OBJPROP_YDISTANCE); //--- Get REC5 y-distance xs5 = (int)ObjectGetInteger(0, REC5, OBJPROP_XSIZE); //--- Get REC5 x-size ys5 = (int)ObjectGetInteger(0, REC5, OBJPROP_YSIZE); //--- Get REC5 y-size xd2 = xd5; //--- Set REC2 x-distance yd2 = yd5 + ys5; //--- Set REC2 y-distance xs2 = xs5; //--- Set REC2 x-size ys2 = 100; //--- Set REC2 y-size xd3 = xd2; //--- Set REC3 x-distance yd3 = yd2 + ys2; //--- Set REC3 y-distance xs3 = xs2; //--- Set REC3 x-size ys3 = 30; //--- Set REC3 y-size xd4 = xd3; //--- Set REC4 x-distance yd4 = yd3 + ys3; //--- Set REC4 y-distance xs4 = xs3; //--- Set REC4 x-size ys4 = 100; //--- Set REC4 y-size xd1 = xd4; //--- Set REC1 x-distance yd1 = yd4 + ys4; //--- Set REC1 y-distance xs1 = xs4; //--- Set REC1 x-size ys1 = 30; //--- Set REC1 y-size } datetime dt_tp = 0, dt_sl = 0, dt_prc = 0; //--- Variables for time double price_tp = 0, price_sl = 0, price_prc = 0; //--- Variables for price int window = 0; //--- Chart window ChartXYToTimePrice(0, xd1, yd1 + ys1, window, dt_tp, price_tp); //--- Convert REC1 coordinates to time and price ChartXYToTimePrice(0, xd3, yd3 + ys3, window, dt_prc, price_prc); //--- Convert REC3 coordinates to time and price ChartXYToTimePrice(0, xd5, yd5 + ys5, window, dt_sl, price_sl); //--- Convert REC5 coordinates to time and price createHL(TP_HL, dt_tp, price_tp, clrTeal); //--- Create TP horizontal line createHL(PR_HL, dt_prc, price_prc, clrBlue); //--- Create entry horizontal line createHL(SL_HL, dt_sl, price_sl, clrRed); //--- Create SL horizontal line if(selected_order_type == "BUY_STOP" || selected_order_type == "BUY_LIMIT") { //--- Check for buy orders createButton(REC2, "", xd2, yd2, xs2, ys2, clrWhite, clrHoneydew, 12, clrBlack, true); //--- Create REC2 createButton(REC3, "", xd3, yd3, xs3, ys3, clrBlack, clrLightGray, 13, clrBlack, false, "Arial Black"); //--- Create REC3 createButton(REC4, "", xd4, yd4, xs4, ys4, clrWhite, clrLinen, 12, clrBlack, true); //--- Create REC4 createButton(REC5, "", xd5, yd5, xs5, ys5, clrWhite, clrRed, 13, clrBlack, false, "Arial Black"); //--- Create REC5 } else { //--- Handle sell orders createButton(REC2, "", xd2, yd2, xs2, ys2, clrWhite, clrHoneydew, 12, clrBlack, true); //--- Create REC2 createButton(REC3, "", xd3, yd3, xs3, ys3, clrBlack, clrLightGray, 13, clrBlack, false, "Arial Black"); //--- Create REC3 createButton(REC4, "", xd4, yd4, xs4, ys4, clrWhite, clrLinen, 12, clrBlack, true); //--- Create REC4 createButton(REC1, "", xd1, yd1, xs1, ys1, clrWhite, clrGreen, 13, clrBlack, false, "Arial Black"); //--- Create REC1 } update_Text(REC1, "TP: " + DoubleToString(MathAbs((Get_Price_d(TP_HL) - Get_Price_d(PR_HL)) / _Point), 0) + " Points | " + Get_Price_s(TP_HL)); //--- Update REC1 text update_Text(REC3, selected_order_type + ": | Lot: " + DoubleToString(lot_size, 2) + " | " + Get_Price_s(PR_HL)); //--- Update REC3 text update_Text(REC5, "SL: " + DoubleToString(MathAbs((Get_Price_d(PR_HL) - Get_Price_d(SL_HL)) / _Point), 0) + " Points | " + Get_Price_s(SL_HL)); //--- Update REC5 text update_Text(PRICE_LABEL, "Entry: " + Get_Price_s(PR_HL)); //--- Update entry label text update_Text(SL_LABEL, "SL: " + Get_Price_s(SL_HL)); //--- Update SL label text update_Text(TP_LABEL, "TP: " + Get_Price_s(TP_HL)); //--- Update TP label text tool_visible = true; //--- Set tool visibility flag ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); //--- Enable mouse move events ChartRedraw(0); //--- Redraw chart }
Um das Preisdiagramm-Tool anzuzeigen, implementieren wir die Funktion „showTool“ und beginnen damit, das Kontrollfeld mit der Funktion ObjectSetInteger auszublenden, indem wir OBJPROP_BACK auf false für Objekte wie „PANEL_BG“, „LOT_EDIT“, „PRICE_LABEL“, „SL_LABEL“, „TP_LABEL“, „BUY_STOP_BTN“, „SELL_STOP_BTN“, „BUY_LIMIT_BTN“, „SELL_LIMIT_BTN“, „PLACE_ORDER_BTN“, „CANCEL_BTN“, und „CLOSE_BTN“.
Wir berechnen die x-Position des Werkzeugs mit der Funktion ChartGetInteger, um CHART_WIDTH_IN_PIXELS zu erhalten und setzen „tool_x“ auf 450 Pixel vom rechten Rand. Für „BUY_STOP“- oder „BUY_LIMIT“-Aufträge erstellen wir mit der Funktion „createButton“ „REC1“ (TP) bei „tool_x“, y=20, Größe 350x30 in grün, und setzen die Variablen „xd1“, „yd1“, „xs1“, „ys1“ über „ObjectGetInteger“, dann positioniere „REC2“ bis „REC5“ vertikal (TP, Eintrag, SL) mit „xd2“ zu „xd5“, „yd2“ zu „yd5“, „xs2“ zu „xs5“, „ys2“ zu „ys5“.
Für Verkaufsaufträge legen wir „REC5“ (SL) in rot an und ordnen „REC2“ bis „REC1“ (SL, Entry, TP).
Wir deklarieren „dt_tp“, „dt_sl“, „dt_prc“ für die Zeit, „price_tp“, „price_sl“ und „price_prc“ für die Preise und „window“ für das Chart, wobei die Funktion ChartXYToTimePrice verwendet wird, um die Koordinaten von „REC1“, „REC3“ und „REC5“ in Preis und Zeit umzuwandeln. Wir rufen die Funktion „createHL“ auf, um „TP_HL“, „PR_HL“ und „SL_HL“ in den Farben Türkis, Blau und Rot zu zeichnen.
Je nach „selected_order_type“ werden mit „createButton“ die restlichen Rechtecke („REC2“, „REC3“, „REC4“, „REC5“ für Kaufen; „REC2“, „REC3“, „REC4“, „REC1“ für Verkaufen) mit entsprechenden Farben. Wir aktualisieren den Text mit der Funktion „update_Text“ für „REC1“, „REC3“, „REC5“, „PRICE_LABEL“, „SL_LABEL“ und „TP_LABEL“ und berechnen die Punktdifferenzen mit „Get_Price_d“, „Get_Price_s“, DoubleToString und MathAbs.
Schließlich setzen wir „tool_visible“ auf true, aktivieren Mausereignisse mit ChartSetInteger und rufen ChartRedraw auf, um das Werkzeug anzuzeigen. Um die horizontalen Linien zu erstellen, verwenden wir die folgende Funktion.
//+------------------------------------------------------------------+ //| Create horizontal line | //+------------------------------------------------------------------+ bool createHL(string objName, datetime time1, double price1, color clr) { ResetLastError(); //--- Reset last error code if(!ObjectCreate(0, objName, OBJ_HLINE, 0, time1, price1)) { //--- Create horizontal line Print(__FUNCTION__, ": Failed to create HL: Error Code: ", GetLastError()); //--- Print error message return false; //--- Return failure } ObjectSetInteger(0, objName, OBJPROP_TIME, time1); //--- Set line time ObjectSetDouble(0, objName, OBJPROP_PRICE, price1); //--- Set line price ObjectSetInteger(0, objName, OBJPROP_COLOR, clr); //--- Set line color ObjectSetInteger(0, objName, OBJPROP_BACK, false); //--- Set to foreground ObjectSetInteger(0, objName, OBJPROP_STYLE, STYLE_DASHDOTDOT); //--- Set line style ChartRedraw(0); //--- Redraw chart return true; //--- Return success }
Hier erstellen wir einfach das Objekt OBJ_HLINE und setzen die notwendigen Objektparameter, wie wir es bereits bei der Funktion zum Erstellen von Schaltflächen getan haben. Wir brauchen auch eine Funktion, um das Panel wie unten dargestellt anzuzeigen.
//+------------------------------------------------------------------+ //| Show control panel | //+------------------------------------------------------------------+ void showPanel() { // Show panel ObjectSetInteger(0, PANEL_BG, OBJPROP_BACK, false); //--- Show panel background ObjectSetInteger(0, LOT_EDIT, OBJPROP_BACK, false); //--- Show lot edit field ObjectSetInteger(0, PRICE_LABEL, OBJPROP_BACK, false); //--- Show price label ObjectSetInteger(0, SL_LABEL, OBJPROP_BACK, false); //--- Show SL label ObjectSetInteger(0, TP_LABEL, OBJPROP_BACK, false); //--- Show TP label ObjectSetInteger(0, BUY_STOP_BTN, OBJPROP_BACK, false); //--- Show Buy Stop button ObjectSetInteger(0, SELL_STOP_BTN, OBJPROP_BACK, false); //--- Show Sell Stop button ObjectSetInteger(0, BUY_LIMIT_BTN, OBJPROP_BACK, false); //--- Show Buy Limit button ObjectSetInteger(0, SELL_LIMIT_BTN, OBJPROP_BACK, false); //--- Show Sell Limit button ObjectSetInteger(0, PLACE_ORDER_BTN, OBJPROP_BACK, false); //--- Show Place Order button ObjectSetInteger(0, CANCEL_BTN, OBJPROP_BACK, false); //--- Show Cancel button ObjectSetInteger(0, CLOSE_BTN, OBJPROP_BACK, false); //--- Show Close button // Reset panel state update_Text(PRICE_LABEL, "Entry: -"); //--- Reset entry label text update_Text(SL_LABEL, "SL: -"); //--- Reset SL label text update_Text(TP_LABEL, "TP: -"); //--- Reset TP label text update_Text(PLACE_ORDER_BTN, "Place Order"); //--- Reset Place Order button text selected_order_type = ""; //--- Clear selected order type tool_visible = false; //--- Hide tool ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); //--- Disable mouse move events ChartRedraw(0); //--- Redraw chart }
Wir definieren die Funktion „showPanel“, um unser Bedienfeld anzuzeigen. Wir verwenden die Funktion ObjectSetInteger, um „OBJPROP_BACK“ auf false zu setzen für „PANEL_BG“, „LOT_EDIT“, „PRICE_LABEL“, „SL_LABEL“, „TP_LABEL“, „BUY_STOP_BTN“, „SELL_STOP_BTN“, „BUY_LIMIT_BTN“, „SELL_LIMIT_BTN“, „PLACE_ORDER_BTN“, „CANCEL_BTN“ und „CLOSE_BTN“ zu setzen, damit sie sichtbar werden.
Wir setzen den Status mit der Funktion „update_Text“ zurück, setzen „PRICE_LABEL“ auf „Entry: -“, „SL_LABEL“ auf „SL: -“, „TP_LABEL“ auf „TP: -“ und „PLACE_ORDER_BTN“ auf „Place Order“, löschen „selected_order_type“, setzen Sie „tool_visible“ auf false, deaktivieren Mausereignisse über ChartSetInteger und rufen ChartRedraw auf, um den Chart zu aktualisieren.
Um das Werkzeug und das Panel zu löschen, verwenden wir die folgenden Funktionen, indem wir die Funktion ObjectDelete für die jeweiligen Objekte aufrufen.
//+------------------------------------------------------------------+ //| Delete main tool objects | //+------------------------------------------------------------------+ void deleteObjects() { ObjectDelete(0, REC1); //--- Delete REC1 object ObjectDelete(0, REC2); //--- Delete REC2 object ObjectDelete(0, REC3); //--- Delete REC3 object ObjectDelete(0, REC4); //--- Delete REC4 object ObjectDelete(0, REC5); //--- Delete REC5 object ObjectDelete(0, TP_HL); //--- Delete TP horizontal line ObjectDelete(0, SL_HL); //--- Delete SL horizontal line ObjectDelete(0, PR_HL); //--- Delete entry horizontal line ChartRedraw(0); //--- Redraw chart } //+------------------------------------------------------------------+ //| Delete control panel objects | //+------------------------------------------------------------------+ void deletePanel() { ObjectDelete(0, PANEL_BG); //--- Delete panel background ObjectDelete(0, LOT_EDIT); //--- Delete lot edit field ObjectDelete(0, PRICE_LABEL); //--- Delete price label ObjectDelete(0, SL_LABEL); //--- Delete SL label ObjectDelete(0, TP_LABEL); //--- Delete TP label ObjectDelete(0, BUY_STOP_BTN); //--- Delete Buy Stop button ObjectDelete(0, SELL_STOP_BTN); //--- Delete Sell Stop button ObjectDelete(0, BUY_LIMIT_BTN); //--- Delete Buy Limit button ObjectDelete(0, SELL_LIMIT_BTN); //--- Delete Sell Limit button ObjectDelete(0, PLACE_ORDER_BTN); //--- Delete Place Order button ObjectDelete(0, CANCEL_BTN); //--- Delete Cancel button ObjectDelete(0, CLOSE_BTN); //--- Delete Close button ChartRedraw(0); //--- Redraw chart }
Um die Aufträge zu erteilen, wenn die entsprechende Schaltfläche angeklickt wird, verwenden wir die folgende Funktion.
//+------------------------------------------------------------------+ //| Place order based on selected type | //+------------------------------------------------------------------+ void placeOrder() { double price = Get_Price_d(PR_HL); //--- Get entry price double sl = Get_Price_d(SL_HL); //--- Get stop-loss price double tp = Get_Price_d(TP_HL); //--- Get take-profit price string symbol = Symbol(); //--- Get current symbol datetime expiration = TimeCurrent() + 3600 * 24; //--- Set 24-hour order expiration // Validate lot size if(lot_size <= 0) { //--- Check if lot size is valid Print("Invalid lot size: ", lot_size); //--- Print error message return; //--- Exit function } // Validate prices if(price <= 0 || sl <= 0 || tp <= 0) { //--- Check if prices are valid Print("Invalid prices: Entry=", price, ", SL=", sl, ", TP=", tp, " (all must be positive)"); //--- Print error message return; //--- Exit function } // Validate price relationships based on order type if(selected_order_type == "BUY_STOP" || selected_order_type == "BUY_LIMIT") { //--- Check for buy orders if(sl >= price) { //--- Check if SL is below entry Print("Invalid SL for ", selected_order_type, ": SL=", sl, " must be below Entry=", price); //--- Print error message return; //--- Exit function } if(tp <= price) { //--- Check if TP is above entry Print("Invalid TP for ", selected_order_type, ": TP=", tp, " must be above Entry=", price); //--- Print error message return; //--- Exit function } } else if(selected_order_type == "SELL_STOP" || selected_order_type == "SELL_LIMIT") { //--- Check for sell orders if(sl <= price) { //--- Check if SL is above entry Print("Invalid SL for ", selected_order_type, ": SL=", sl, " must be above Entry=", price); //--- Print error message return; //--- Exit function } if(tp >= price) { //--- Check if TP is below entry Print("Invalid TP for ", selected_order_type, ": TP=", tp, " must be below Entry=", price); // AMPK--- Print error message return; //--- Exit function } } else { //--- Handle invalid order type Print("Invalid order type: ", selected_order_type); //--- Print error message return; //--- Exit function } // Place the order if(selected_order_type == "BUY_STOP") { //--- Handle Buy Stop order if(!obj_Trade.BuyStop(lot_size, price, symbol, sl, tp, ORDER_TIME_DAY, expiration)) { //--- Attempt to place Buy Stop order Print("Buy Stop failed: Entry=", price, ", SL=", sl, ", TP=", tp, ", Error=", GetLastError()); //--- Print error message } else { //--- Order placed successfully Print("Buy Stop placed: Entry=", price, ", SL=", sl, ", TP=", tp); //--- Print success message } } else if(selected_order_type == "SELL_STOP") { //--- Handle Sell Stop order if(!obj_Trade.SellStop(lot_size, price, symbol, sl, tp, ORDER_TIME_DAY, expiration)) { //--- Attempt to place Sell Stop order Print("Sell Stop failed: Entry=", price, ", SL=", sl, ", TP=", tp, ", Error=", GetLastError()); //--- Print error message } else { //--- Order placed successfully Print("Sell Stop placed: Entry=", price, ", SL=", sl, ", TP=", tp); //--- Print success message } } else if(selected_order_type == "BUY_LIMIT") { //--- Handle Buy Limit order if(!obj_Trade.BuyLimit(lot_size, price, symbol, sl, tp, ORDER_TIME_DAY, expiration)) { //--- Attempt to place Buy Limit order Print("Buy Limit failed: Entry=", price, ", SL=", sl, ", TP=", tp, ", Error=", GetLastError()); //--- Print error message } else { //--- Order placed successfully Print("Buy Limit placed: Entry=", price, ", SL=", sl, ", TP=", tp); //--- Print success message } } else if(selected_order_type == "SELL_LIMIT") { //--- Handle Sell Limit order if(!obj_Trade.SellLimit(lot_size, price, symbol, sl, tp, ORDER_TIME_DAY, expiration)) { //--- Attempt to place Sell Limit order Print("Sell Limit failed: Entry=", price, ", SL=", sl, ", TP=", tp, ", Error=", GetLastError()); //--- Print error message } else { //--- Order placed successfully Print("Sell Limit placed: Entry=", price, ", SL=", sl, ", TP=", tp); //--- Print success message } } }
Wir implementieren die Funktion „placeOrder“, um schwebende Aufträge für unser Tool auszuführen, und beginnen mit dem Abrufen des Einstiegspreises („price“), des Stop-Loss („sl“) und des Take-Profit („tp“) mit der Funktion „Get_Price_d“ für „PR_HL“, „SL_HL“ und „TP_HL“ abrufen, das aktuelle „Symbol“ mit der Funktion „Symbol“ ermitteln und einen 24-Stunden-“Ablauf“ mit der Funktion „TimeCurrent„ festlegen.
Wir überprüfen „lot_size“ (>0) und vergewissern uns, dass „price“, „sl“ und „tp“ positiv sind und beenden den Vorgang mit der Funktion Print, wenn sie ungültig sind. Bei „BUY_STOP“ oder „BUY_LIMIT“ wird geprüft, ob „sl“ unter „price“ und „tp“ darüber liegt, und bei „SELL_STOP“ oder „SELL_LIMIT“ wird geprüft, ob „sl“ über und „tp“ unter „price“ liegt, wobei „Print“ verwendet wird, um Fehler zu protokollieren und den Vorgang zu beenden, wenn die Bedingungen nicht erfüllt sind. Wenn „selected_order_type“ ungültig ist, wird eine „Print“-Meldung ausgegeben.
Dann verwenden wir die Methoden von „obj_Trade“ - „BuyStop“, „SellStop“, „BuyLimit“ oder „SellLimit“ - um die Order zu platzieren und protokollieren den Erfolg oder bei Misserfolg „Print“ und GetLastError. Mit diesen Funktionen ausgestattet, können wir sie bei entsprechenden Schaltflächenklicks wie folgt aufrufen.
if(id == CHARTEVENT_OBJECT_CLICK) { //--- Handle object click events // Handle order type buttons if(sparam == BUY_STOP_BTN) { //--- Check if Buy Stop button clicked selected_order_type = "BUY_STOP"; //--- Set order type to Buy Stop showTool(); //--- Show trading tool update_Text(PLACE_ORDER_BTN, "Place Buy Stop"); //--- Update place order button text } else if(sparam == SELL_STOP_BTN) { //--- Check if Sell Stop button clicked selected_order_type = "SELL_STOP"; //--- Set order type to Sell Stop showTool(); //--- Show trading tool update_Text(PLACE_ORDER_BTN, "Place Sell Stop"); //--- Update place order button text } else if(sparam == BUY_LIMIT_BTN) { //--- Check if Buy Limit button clicked selected_order_type = "BUY_LIMIT"; //--- Set order type to Buy Limit showTool(); //--- Show trading tool update_Text(PLACE_ORDER_BTN, "Place Buy Limit"); //--- Update place order button text } else if(sparam == SELL_LIMIT_BTN) { //--- Check if Sell Limit button clicked selected_order_type = "SELL_LIMIT"; //--- Set order type to Sell Limit showTool(); //--- Show trading tool update_Text(PLACE_ORDER_BTN, "Place Sell Limit");//--- Update place order button text } else if(sparam == PLACE_ORDER_BTN) { //--- Check if Place Order button clicked placeOrder(); //--- Execute order placement deleteObjects(); //--- Delete tool objects showPanel(); //--- Show control panel } else if(sparam == CANCEL_BTN) { //--- Check if Cancel button clicked deleteObjects(); //--- Delete tool objects showPanel(); //--- Show control panel } else if(sparam == CLOSE_BTN) { //--- Check if Close button clicked deleteObjects(); //--- Delete tool objects deletePanel(); //--- Delete control panel } ObjectSetInteger(0, sparam, OBJPROP_STATE, false); //--- Reset button state ChartRedraw(0); //--- Redraw chart }
Nach der Kompilierung erhalten wir folgendes Ergebnis.
Aus dem Bild können wir ersehen, dass wir das entsprechende Preisdiagramm-Tool dynamisch erstellen können. Als Nächstes müssen wir das Werkzeug unbeweglich machen, um es auf dem Chart verschieben zu können. Hier ist die Logik, die wir in OnChartEvent verwenden.
//+------------------------------------------------------------------+ //| Chart event handler | //+------------------------------------------------------------------+ int prevMouseState = 0; //--- Variable to track previous mouse state int mlbDownX1 = 0, mlbDownY1 = 0, mlbDownXD_R1 = 0, mlbDownYD_R1 = 0; //--- Variables for mouse down coordinates for REC1 int mlbDownX2 = 0, mlbDownY2 = 0, mlbDownXD_R2 = 0, mlbDownYD_R2 = 0; //--- Variables for mouse down coordinates for REC2 int mlbDownX3 = 0, mlbDownY3 = 0, mlbDownXD_R3 = 0, mlbDownYD_R3 = 0; //--- Variables for mouse down coordinates for REC3 int mlbDownX4 = 0, mlbDownY4 = 0, mlbDownXD_R4 = 0, mlbDownYD_R4 = 0; //--- Variables for mouse down coordinates for REC4 int mlbDownX5 = 0, mlbDownY5 = 0, mlbDownXD_R5 = 0, mlbDownYD_R5 = 0; //--- Variables for mouse down coordinates for REC5 bool movingState_R1 = false; //--- Flag for REC1 movement state bool movingState_R3 = false; //--- Flag for REC3 movement state bool movingState_R5 = false; //--- Flag for REC5 movement state
Zunächst definieren wir Variablen für die Funktion OnChartEvent, um Drag-and-Drop in unserem Handelsassistenten-Tool zu ermöglichen. „prevMouseState“ verfolgt Änderungen des Mausstatus, während „mlbDownX1“, „mlbDownY1“, „mlbDownXD_R1“, „mlbDownYD_R1“ (und ähnlich für „REC2“ bis „REC5“) die Maus- und Rechteckkoordinaten für „REC1“ (TP), „REC3“ (Eintrag) und „REC5“ (SL) bei Klicks speichern. Die booleschen Flags „movingState_R1“, „movingState_R3“ und „movingState_R5“ zeigen an, ob diese Rechtecke gezogen werden. Anhand dieser Kontrollvariablen können wir dann die Bewegung des Preisinstruments definieren.
if(id == CHARTEVENT_MOUSE_MOVE && tool_visible) { //--- Handle mouse move events when tool is visible int MouseD_X = (int)lparam; //--- Get mouse x-coordinate int MouseD_Y = (int)dparam; //--- Get mouse y-coordinate int MouseState = (int)sparam; //--- Get mouse state int XD_R1 = (int)ObjectGetInteger(0, REC1, OBJPROP_XDISTANCE); //--- Get REC1 x-distance int YD_R1 = (int)ObjectGetInteger(0, REC1, OBJPROP_YDISTANCE); //--- Get REC1 y-distance int XS_R1 = (int)ObjectGetInteger(0, REC1, OBJPROP_XSIZE); //--- Get REC1 x-size int YS_R1 = (int)ObjectGetInteger(0, REC1, OBJPROP_YSIZE); //--- Get REC1 y-size int XD_R2 = (int)ObjectGetInteger(0, REC2, OBJPROP_XDISTANCE); //--- Get REC2 x-distance int YD_R2 = (int)ObjectGetInteger(0, REC2, OBJPROP_YDISTANCE); //--- Get REC2 y-distance int XS_R2 = (int)ObjectGetInteger(0, REC2, OBJPROP_XSIZE); //--- Get REC2 x-size int YS_R2 = (int)ObjectGetInteger(0, REC2, OBJPROP_YSIZE); //--- Get REC2 y-size int XD_R3 = (int)ObjectGetInteger(0, REC3, OBJPROP_XDISTANCE); //--- Get REC3 x-distance int YD_R3 = (int)ObjectGetInteger(0, REC3, OBJPROP_YDISTANCE); //--- Get REC3 y-distance int XS_R3 = (int)ObjectGetInteger(0, REC3, OBJPROP_XSIZE); //--- Get REC3 x-size int YS_R3 = (int)ObjectGetInteger(0, REC3, OBJPROP_YSIZE); //--- Get REC3 y-size int XD_R4 = (int)ObjectGetInteger(0, REC4, OBJPROP_XDISTANCE); //--- Get REC4 x-distance int YD_R4 = (int)ObjectGetInteger(0, REC4, OBJPROP_YDISTANCE); //--- Get REC4 y-distance int XS_R4 = (int)ObjectGetInteger(0, REC4, OBJPROP_XSIZE); //--- Get REC4 x-size int YS_R4 = (int)ObjectGetInteger(0, REC4, OBJPROP_YSIZE); //--- Get REC4 y-size int XD_R5 = (int)ObjectGetInteger(0, REC5, OBJPROP_XDISTANCE); //--- Get REC5 x-distance int YD_R5 = (int)ObjectGetInteger(0, REC5, OBJPROP_YDISTANCE); //--- Get REC5 y-distance int XS_R5 = (int)ObjectGetInteger(0, REC5, OBJPROP_XSIZE); //--- Get REC5 x-size int YS_R5 = (int)ObjectGetInteger(0, REC5, OBJPROP_YSIZE); //--- Get REC5 y-size if(prevMouseState == 0 && MouseState == 1) { //--- Check for mouse button down mlbDownX1 = MouseD_X; //--- Store mouse x-coordinate for REC1 mlbDownY1 = MouseD_Y; //--- Store mouse y-coordinate for REC1 mlbDownXD_R1 = XD_R1; //--- Store REC1 x-distance mlbDownYD_R1 = YD_R1; //--- Store REC1 y-distance mlbDownX2 = MouseD_X; //--- Store mouse x-coordinate for REC2 mlbDownY2 = MouseD_Y; //--- Store mouse y-coordinate for REC2 mlbDownXD_R2 = XD_R2; //--- Store REC2 x-distance mlbDownYD_R2 = YD_R2; //--- Store REC2 y-distance mlbDownX3 = MouseD_X; //--- Store mouse x-coordinate for REC3 mlbDownY3 = MouseD_Y; //--- Store mouse y-coordinate for REC3 mlbDownXD_R3 = XD_R3; //--- Store REC3 x-distance mlbDownYD_R3 = YD_R3; //--- Store REC3 y-distance mlbDownX4 = MouseD_X; //--- Store mouse x-coordinate for REC4 mlbDownY4 = MouseD_Y; //--- Store mouse y-coordinate for REC4 mlbDownXD_R4 = XD_R4; //--- Store REC4 x-distance mlbDownYD_R4 = YD_R4; //--- Store REC4 y-distance mlbDownX5 = MouseD_X; //--- Store mouse x-coordinate for REC5 mlbDownY5 = MouseD_Y; //--- Store mouse y-coordinate for REC5 mlbDownXD_R5 = XD_R5; //--- Store REC5 x-distance mlbDownYD_R5 = YD_R5; //--- Store REC5 y-distance if(MouseD_X >= XD_R1 && MouseD_X <= XD_R1 + XS_R1 && //--- Check if mouse is within REC1 bounds MouseD_Y >= YD_R1 && MouseD_Y <= YD_R1 + YS_R1) { movingState_R1 = true; //--- Enable REC1 movement } if(MouseD_X >= XD_R3 && MouseD_X <= XD_R3 + XS_R3 && //--- Check if mouse is within REC3 bounds MouseD_Y >= YD_R3 && MouseD_Y <= YD_R3 + YS_R3) { movingState_R3 = true; //--- Enable REC3 movement } if(MouseD_X >= XD_R5 && MouseD_X <= XD_R5 + XS_R5 && //--- Check if mouse is within REC5 bounds MouseD_Y >= YD_R5 && MouseD_Y <= YD_R5 + YS_R5) { movingState_R5 = true; //--- Enable REC5 movement } } if(movingState_R1) { //--- Handle REC1 (TP) movement ChartSetInteger(0, CHART_MOUSE_SCROLL, false); //--- Disable chart scrolling bool canMove = false; //--- Flag to check if movement is valid if(selected_order_type == "BUY_STOP" || selected_order_type == "BUY_LIMIT") { //--- Check for buy orders if(YD_R1 + YS_R1 < YD_R3) { //--- Ensure TP is above entry for buy orders canMove = true; //--- Allow movement ObjectSetInteger(0, REC1, OBJPROP_YDISTANCE, mlbDownYD_R1 + MouseD_Y - mlbDownY1); //--- Update REC1 y-position ObjectSetInteger(0, REC2, OBJPROP_YDISTANCE, YD_R1 + YS_R1); //--- Update REC2 y-position ObjectSetInteger(0, REC2, OBJPROP_YSIZE, YD_R3 - (YD_R1 + YS_R1)); //--- Update REC2 y-size } } else { //--- Handle sell orders if(YD_R1 > YD_R3 + YS_R3) { //--- Ensure TP is below entry for sell orders canMove = true; //--- Allow movement ObjectSetInteger(0, REC1, OBJPROP_YDISTANCE, mlbDownYD_R1 + MouseD_Y - mlbDownY1); //--- Update REC1 y-position ObjectSetInteger(0, REC4, OBJPROP_YDISTANCE, YD_R3 + YS_R3); //--- Update REC4 y-position ObjectSetInteger(0, REC4, OBJPROP_YSIZE, YD_R1 - (YD_R3 + YS_R3)); //--- Update REC4 y-size } } if(canMove) { //--- If movement is valid datetime dt_TP = 0; //--- Variable for TP time double price_TP = 0; //--- Variable for TP price int window = 0; //--- Chart window ChartXYToTimePrice(0, XD_R1, YD_R1 + YS_R1, window, dt_TP, price_TP); //--- Convert chart coordinates to time and price ObjectSetInteger(0, TP_HL, OBJPROP_TIME, dt_TP); //--- Update TP horizontal line time ObjectSetDouble(0, TP_HL, OBJPROP_PRICE, price_TP); //--- Update TP horizontal line price update_Text(REC1, "TP: " + DoubleToString(MathAbs((Get_Price_d(TP_HL) - Get_Price_d(PR_HL)) / _Point), 0) + " Points | " + Get_Price_s(TP_HL)); //--- Update REC1 text update_Text(TP_LABEL, "TP: " + Get_Price_s(TP_HL)); //--- Update TP label text } ChartRedraw(0); //--- Redraw chart } if(movingState_R5) { //--- Handle REC5 (SL) movement ChartSetInteger(0, CHART_MOUSE_SCROLL, false); //--- Disable chart scrolling bool canMove = false; //--- Flag to check if movement is valid if(selected_order_type == "BUY_STOP" || selected_order_type == "BUY_LIMIT") { //--- Check for buy orders if(YD_R5 > YD_R4) { //--- Ensure SL is below entry for buy orders canMove = true; //--- Allow movement ObjectSetInteger(0, REC5, OBJPROP_YDISTANCE, mlbDownYD_R5 + MouseD_Y - mlbDownY5); //--- Update REC5 y-position ObjectSetInteger(0, REC4, OBJPROP_YDISTANCE, YD_R3 + YS_R3); //--- Update REC4 y-position ObjectSetInteger(0, REC4, OBJPROP_YSIZE, YD_R5 - (YD_R3 + YS_R3)); //--- Update REC4 y-size } } else { //--- Handle sell orders if(YD_R5 + YS_R5 < YD_R3) { //--- Ensure SL is above entry for sell orders canMove = true; //--- Allow movement ObjectSetInteger(0, REC5, OBJPROP_YDISTANCE, mlbDownYD_R5 + MouseD_Y - mlbDownY5); //--- Update REC5 y-position ObjectSetInteger(0, REC2, OBJPROP_YDISTANCE, YD_R5 + YS_R5); //--- Update REC2 y-position ObjectSetInteger(0, REC2, OBJPROP_YSIZE, YD_R3 - (YD_R5 + YS_R5)); //--- Update REC2 y-size } } if(canMove) { //--- If movement is valid datetime dt_SL = 0; //--- Variable for SL time double price_SL = 0; //--- Variable for SL price int window = 0; //--- Chart window ChartXYToTimePrice(0, XD_R5, YD_R5 + YS_R5, window, dt_SL, price_SL); //--- Convert chart coordinates to time and price ObjectSetInteger(0, SL_HL, OBJPROP_TIME, dt_SL); //--- Update SL horizontal line time ObjectSetDouble(0, SL_HL, OBJPROP_PRICE, price_SL); //--- Update SL horizontal line price update_Text(REC5, "SL: " + DoubleToString(MathAbs((Get_Price_d(PR_HL) - Get_Price_d(SL_HL)) / _Point), 0) + " Points | " + Get_Price_s(SL_HL)); //--- Update REC5 text update_Text(SL_LABEL, "SL: " + Get_Price_s(SL_HL)); //--- Update SL label text } ChartRedraw(0); //--- Redraw chart } if(movingState_R3) { //--- Handle REC3 (Entry) movement ChartSetInteger(0, CHART_MOUSE_SCROLL, false); //--- Disable chart scrolling ObjectSetInteger(0, REC3, OBJPROP_XDISTANCE, mlbDownXD_R3 + MouseD_X - mlbDownX3); //--- Update REC3 x-position ObjectSetInteger(0, REC3, OBJPROP_YDISTANCE, mlbDownYD_R3 + MouseD_Y - mlbDownY3); //--- Update REC3 y-position ObjectSetInteger(0, REC1, OBJPROP_XDISTANCE, mlbDownXD_R1 + MouseD_X - mlbDownX1); //--- Update REC1 x-position ObjectSetInteger(0, REC1, OBJPROP_YDISTANCE, mlbDownYD_R1 + MouseD_Y - mlbDownY1); //--- Update REC1 y-position ObjectSetInteger(0, REC2, OBJPROP_XDISTANCE, mlbDownXD_R2 + MouseD_X - mlbDownX2); //--- Update REC2 x-position ObjectSetInteger(0, REC2, OBJPROP_YDISTANCE, mlbDownYD_R2 + MouseD_Y - mlbDownY2); //--- Update REC2 y-position ObjectSetInteger(0, REC4, OBJPROP_XDISTANCE, mlbDownXD_R4 + MouseD_X - mlbDownX4); //--- Update REC4 x-position ObjectSetInteger(0, REC4, OBJPROP_YDISTANCE, mlbDownYD_R4 + MouseD_Y - mlbDownY4); //--- Update REC4 y-position ObjectSetInteger(0, REC5, OBJPROP_XDISTANCE, mlbDownXD_R5 + MouseD_X - mlbDownX5); //--- Update REC5 x-position ObjectSetInteger(0, REC5, OBJPROP_YDISTANCE, mlbDownYD_R5 + MouseD_Y - mlbDownY5); //--- Update REC5 y-position datetime dt_PRC = 0, dt_SL1 = 0, dt_TP1 = 0; //--- Variables for time double price_PRC = 0, price_SL1 = 0, price_TP1 = 0; //--- Variables for price int window = 0; //--- Chart window ChartXYToTimePrice(0, XD_R3, YD_R3 + YS_R3, window, dt_PRC, price_PRC); //--- Convert REC3 coordinates to time and price ChartXYToTimePrice(0, XD_R5, YD_R5 + YS_R5, window, dt_SL1, price_SL1); //--- Convert REC5 coordinates to time and price ChartXYToTimePrice(0, XD_R1, YD_R1 + YS_R1, window, dt_TP1, price_TP1); //--- Convert REC1 coordinates to time and price ObjectSetInteger(0, PR_HL, OBJPROP_TIME, dt_PRC); //--- Update entry horizontal line time ObjectSetDouble(0, PR_HL, OBJPROP_PRICE, price_PRC); //--- Update entry horizontal line price ObjectSetInteger(0, TP_HL, OBJPROP_TIME, dt_TP1); //--- Update TP horizontal line time ObjectSetDouble(0, TP_HL, OBJPROP_PRICE, price_TP1); //--- Update TP horizontal line price ObjectSetInteger(0, SL_HL, OBJPROP_TIME, dt_SL1); //--- Update SL horizontal line time ObjectSetDouble(0, SL_HL, OBJPROP_PRICE, price_SL1); //--- Update SL horizontal line price update_Text(REC1, "TP: " + DoubleToString(MathAbs((Get_Price_d(TP_HL) - Get_Price_d(PR_HL)) / _Point), 0) + " Points | " + Get_Price_s(TP_HL)); //--- Update REC1 text update_Text(REC3, selected_order_type + ": | Lot: " + DoubleToString(lot_size, 2) + " | " + Get_Price_s(PR_HL)); //--- Update REC3 text update_Text(REC5, "SL: " + DoubleToString(MathAbs((Get_Price_d(PR_HL) - Get_Price_d(SL_HL)) / _Point), 0) + " Points | " + Get_Price_s(SL_HL)); //--- Update REC5 text update_Text(PRICE_LABEL, "Entry: " + Get_Price_s(PR_HL)); //--- Update entry label text update_Text(SL_LABEL, "SL: " + Get_Price_s(SL_HL)); //--- Update SL label text update_Text(TP_LABEL, "TP: " + Get_Price_s(TP_HL)); //--- Update TP label text ChartRedraw(0); //--- Redraw chart } if(MouseState == 0) { //--- Check if mouse button is released movingState_R1 = false; //--- Disable REC1 movement movingState_R3 = false; //--- Disable REC3 movement movingState_R5 = false; //--- Disable REC5 movement ChartSetInteger(0, CHART_MOUSE_SCROLL, true); //--- Enable chart scrolling } prevMouseState = MouseState; //--- Update previous mouse state }
Hier erweitern wir die Funktion OnChartEvent, um Mausbewegungen für das Ziehen von Chart-Objekten in unserem Werkzeug zu verarbeiten, wenn „tool_visible“ wahr ist und „id“ CHARTEVENT_MOUSE_MOVE ist. Wir extrahieren „MouseD_X“, „MouseD_Y“, und „MouseState“ aus „lparam“, „dparam“, und „sparam“und verwenden die Funktion ObjectGetInteger, um Position und Größe zu ermitteln („XD_R1“, „YD_R1“, „XS_R1“, „YS_R1“ für „REC1“, und ähnlich für „REC2“ bis „REC5“).
Bei einem Mausklick („prevMouseState“ 0 bis „MouseState“ 1) speichern wir die Mauskoordinaten in „mlbDownX1“, „mlbDownY1“ und die Rechteckpositionen in „mlbDownXD_R1“, „mlbDownYD_R1“ (und für „REC2“ bis „REC5“), wobei „movingState_R1“, „movingState_R3“ oder „movingState_R5“ auf true gesetzt wird, wenn der Klick innerhalb der Grenzen von „REC1“, „REC3“ oder „REC5“ liegt.
Für „movingState_R1“ (TP) deaktivieren wir das Scrollen mit ChartSetInteger, validieren die TP-Position (oberhalb der Eingabe für „BUY_STOP“/“BUY_LIMIT“, unterhalb für „Sell“), aktualisieren „REC1“ und „REC2“/“REC4“ Positionen und Größen mit ObjectSetInteger aktualisieren, Koordinaten mit ChartXYToTimePrice in Preise umwandeln, „TP_HL“ mit ObjectSetDouble aktualisieren und Text mit „update_Text“, „Get_Price_d“, „Get_Price_s“, DoubleToString und MathAbs aktualisieren.
In ähnlicher Weise wird für „movingState_R5“ (SL) „REC5“ und „REC4“/“REC2“ angepasst, „SL_HL“ aktualisiert und der Text aktualisiert. Für „movingState_R3“ (Eintrag) verschieben wir alle Rechtecke und aktualisieren „PR_HL“, „TP_HL“, „SL_HL“ und den Text.
Beim Loslassen der Maus („MouseState“ 0) setzen wir die „movingState“-Flags zurück, aktivieren den Bildlauf und aktualisieren „prevMouseState“, indem wir ChartRedraw aufrufen, um die Änderungen zu berücksichtigen. Schließlich müssen wir die Objekte vollständig löschen, wenn wir das Programm entfernen, und die Losgröße auf dem Häkchen aktualisieren, um die Änderungen widerzuspiegeln, obwohl Sie dies lassen können, da es nicht sehr notwendig ist.
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { deleteObjects(); //--- Delete tool objects deletePanel(); //--- Delete control panel objects } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Update lot size from edit field string lot_text = ObjectGetString(0, LOT_EDIT, OBJPROP_TEXT); //--- Get lot size text from edit field double new_lot = StringToDouble(lot_text); //--- Convert lot size text to double if(new_lot > 0) lot_size = new_lot; //--- Update lot size if valid }
Hier implementieren wir zwei wesentliche Event-Handler für unser Tool: OnDeinit und OnTick. In der Funktion OnDeinit, die ausgelöst wird, wenn der Expert Advisor aus dem Chart entfernt wird, rufen wir die Funktion „deleteObjects“ auf, um Chart-Objekte wie „REC1“ bis „REC5“, „TP_HL“, „SL_HL“ und „PR_HL“ zu entfernen, und die Funktion „deletePanel“, um Kontrollfeldobjekte wie „PANEL_BG“, „LOT_EDIT“ und Schaltflächen wie „BUY_STOP_BTN“ zu löschen und so einen sauberen Ausstieg zu gewährleisten.
In der Funktion OnTick, die bei jedem Preis-Tick ausgeführt wird, verwenden wir die Funktion ObjectGetString, um den Text aus dem Feld „LOT_EDIT“ abzurufen, ihn mit der Funktion StringToDouble in ein Double zu konvertieren und die Variable „lot_size“ zu aktualisieren, wenn der Wert „new_lot“ positiv ist, damit die Losgröße unseres Tools mit den Nutzereingaben synchronisiert wird.
Nach dem Kompilieren erhalten wir die folgende Ausgabe.
Anhand der Visualisierung können wir sehen, dass beim Klicken auf eine der Handelsschaltflächen das entsprechende Handelspreis-Tool generiert wird. Wenn es dann gezogen wird, wird es in Echtzeit aktualisiert und die Preise werden im Handelspanel angezeigt, damit sie für Handelszwecke verwendet werden können, wenn auf die Schaltfläche geklickt wird, die den Handel platziert, werden die entsprechenden Handelsgeschäfte dynamisch platziert. Damit ist sichergestellt, dass wir unser Ziel erreicht haben, und es bleibt nur noch, die Platte zu testen, um sicherzustellen, dass sie perfekt ist, und das wird im nächsten Abschnitt behandelt.
Backtests
Wir haben die Tests durchgeführt und zeigen hier die kompilierte Visualisierung in einem einzigen Graphics Interchange Format (GIF) Bitmap-Bildformat.
Schlussfolgerung
Abschließend haben wir in MQL5 ein interaktives Handelsassistententool entwickelt, das visuelle Präzision mit intuitiven Bedienelementen kombiniert und die Platzierung von schwebenden Aufträgen vereinfacht. Wir haben gezeigt, wie man die nutzerfreundliche grafische Nutzeroberfläche (GUI) gestaltet, sie mit Funktionen wie „createControlPanel“ und „placeOrder“ implementiert und ihre Zuverlässigkeit durch strukturierte Implementierung und Validierung sicherstellt. Sie können dieses Tool an Ihren Handelsstil anpassen und so die Effizienz Ihrer Orderplatzierung verbessern. Freuen Sie sich auf die vorangehenden Teile, in denen wir fortgeschrittene Funktionen wie Risikomanagement und verschiebbare Panels vorstellen werden. Bleiben Sie am Ball.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/17931
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.





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