
MQL5 Cookbook: Position-Eigenschaften auf dem Angepassten Info-Panel
Einleitung
Diesmal erzeugen wir einen einfachen Expert Advisor, der die Position-Eigenschaften auf dem aktuellen Symbol abruft und sie im angepassten Info-Panel während manuell durchgeführtem Handel anzeigt. Das Info-Panel wird mit Hilfe graphischer Objekte erstellt, und die angezeigte Information wird bei jeder Kursschwankung (Tick) aktualisiert. Das ist weitaus bequemer als ständig das im vorangegangenen Beitrag der Reihe "MQL5 Cookbook: Wie man Position-Eigenschaften abruft", beschriebene Script manuell laufen lassen zu müssen.
Den Expert Advisor entwickeln
Beginnen wir mit den grafischen Objekten. Zum Erstellen des Info-Panels, brauchen wir Objekte für den Hintergrund, die Kopfzeile sowie Namen und Werte der Position-Eigenschaften. Der Hintergrund und die Kopfzeile brauchen ein Rechteck, das sich nicht zusammen mit dem Kurs bewegt. Das Rechteck kann mit Hilfe solcher grafischen Objekte wie Rechteck-Kennung oder Bearbeiten erzeugt werden; die Namen und Werte der Objekteigenschaften macht man mit Hilfe von Text-Kennungen.
Bevor wir mit dem Code weitermachen, legen wir zunächst das Layout für das Info-Panel an. Sein Vorteil liegt in der Tatsache, dass wir im Einstellungsfenster rasch jede Eigenschaft ändern und das Aussehen des Info-Panels individuell anpassen können.
Jedes Objekt hat ein Einstellungsfenster, das vom Kontextmenü eines gewählten Objekts aus aufgerufen werden kann. Das Einstellungsfenster kann auch von der 'Objekt-Liste' aus geöffnet werden (Strg+B), indem man das benötigte Objekt auswählt und 'Eigenschaften' anklickt. Unten sehen Sie das Layout des Info-Panels. Es kann auch zur Abschätzung der Größen und Koordinaten beim Schreiben eines Codes verwendet werden. Ist der Code für das Info-Panel fertig, müssen Sie die Layout-Objekte manuell löschen, da der Expert Advisor sie nicht 'sehen' kann und sie dehalb nicht aus dem Chart entfernt.
Abb. 1 Vorbereitung des Layout für das Info-Panel.
Jetzt müssen wir ein Template für den Expert Advisor anlegen. Das geht genauso schnell wie für das Script. Die Expert Advisor (Template) Option ist im MQL5-Assistenten standardmäßig ausgewählt. Wir machen die nächsten Schritte ohne die Optionen zu ändern, da wir sie derzeit noch nicht brauchen. Danach auf 'Beenden' klicken und das Template sollte, so wie unten gezeigt, erscheinen:
//+------------------------------------------------------------------+ //| PositionPropertiesPanel.mq5 | //| Copyright 2012, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2012, MetaQuotes Software Corp." #property link "http://www.mql5.com" #property version "1.00" //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(0); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+
Sie sehen sofort, dass sich das Expert Advisor Template vom Script Template unterscheidet. Abgesehen von den Programmeigenschaften (#property), gibt es dort drei Hauptfunktionen: OnInit(), OnDeinit() und OnTick().
Die OnInit() Funktion wird aufgerufen, wenn das Programm geladen wird, externe Parameter verändert werden und das Programm erstellt wird, vorausgesetzt, das Programm ist in diesem Moment dem Chart hinzugefügt sowie wenn das Symbol oder der Zeitraum verändert werden. Sie können in dieser Funktion ggf. bestimmte Variablen oder Arrays initialisieren, um mit ihnen später arbeiten zu können.
Die OnDeinit() Funktion wird aufgerufen, wenn Sie das Programm vom Chart löschen und das Konto, Symbol oder den Zeitraum wechseln. Alle Gründe für eine mögliche De-Initialisierung stehen in den MQL5 Referenzhinweisen. Dieser Expert Advisor setzt eine benutzerdefinierte Funktion ein, GetDeinitReasonText(), die den Identifikator für den Grund der De-Initialisierung (den OnDeinit() Funktionsparameter) in Text umwandelt.
Und schließlich gibt's da noch die OnTick() Funktion. Sie wird jedes Mal dann aufgerufen, wenn auf dem Symbol auf dessen Chart der Expert Advisor derzeit arbeitet, eine neue Kursschwankung auftritt.
Bereiten wir nun alle Konstanten, Variablen und Arrays vor, die wir im Expert Advisor verwenden werden. Sie alle platzieren wir ganz zu Anfang des Programms. Zunächst müssen wir die Variablen festlegen, deren Werte im gesamten Programm unverändert bleiben:
//--- #define INFOPANEL_SIZE 14 // Size of the array for info panel objects #define EXPERT_NAME MQL5InfoString(MQL5_PROGRAM_NAME) // Name of the Expert Advisor //---
Danach kommen die globalen Variablen für die Position-Eigenschaften dran:
//--- GLOBAL VARIABLES bool pos_open=false; // Flag of presence/absence of an open position string pos_symbol=""; // Symbol long pos_magic=0; // Magic number string pos_comment=""; // Comment double pos_swap=0.0; // Swap double pos_commission=0.0; // Commission double pos_price=0.0; // Position price double pos_cprice=0.0; // Current price of the position double pos_profit=0.0; // Profit/Loss of the position double pos_volume=0.0; // Position volume double pos_sl=0.0; // Stop Loss of the position double pos_tp=0.0; // Take Profit of the position datetime pos_time=NULL; // Position opening time long pos_id=0; // Position identifier ENUM_POSITION_TYPE pos_type=WRONG_VALUE; // Position type
Nach den Variablen, deklarieren wir Arrays mit Namen grafischer Objeke. Diese Objekte zeigen später die Position-Eigenschaften und ihre Werte im Chart Zu diesem Zweck erzeugen wir zwei String-Arrays und initialisieren unmittelbar ihre Elemente zu Werten. In eckigen Klammern verwenden wir den Wert der INFOPANEL_SIZE Konstante, die ganz zu Anfang des Programms deklariert wurde. Es gibt also 14 Elemente in jedem Array.
// Array of names of objects that display names of position properties string positionPropertyNames[INFOPANEL_SIZE]= { "name_pos_symbol", "name_pos_magic", "name_pos_comment", "name_pos_swap", "name_pos_commission", "name_pos_price", "name_pos_cprice", "name_pos_profit", "name_pos_volume", "name_pos_sl", "name_pos_tp", "name_pos_time", "name_pos_id", "name_pos_type" }; //--- // Array of names of objects that display values of position properties string positionPropertyValues[INFOPANEL_SIZE]= { "value_pos_symbol", "value_pos_magic", "value_pos_comment", "value_pos_swap", "value_pos_commission", "value_pos_price", "value_pos_cprice", "value_pos_profit", "value_pos_volume", "value_pos_sl", "value_pos_tp", "value_pos_time", "value_pos_id", "value_pos_type" }; //---
Mit Hilfe dieser Namen können Sie programmatisch das nötige Objekt im Chart finden und seine Eigenschaften einrichten oder verändern, wie z.B. angezeigter Text, Farbe, Größe, usw.Darüber hinaus werden diese Namen in dem Fenster 'Objekt-Liste' (Strg+B) angezeigt, nachdem sie im Chart erzeugt worden sind. Doch Sie können sie dort nicht sehen, da die vom MQL5 Programm erzeugten Objekte standardmäßig verborgen sind Um sie sichtbar zu machen, müssen Sie im Fenster 'Objekt-Liste' auf 'Alle auflisten' klicken. Mit diesem Feature können Sie die manuell erzeugte Objekte von den programmatisch erzeugten abtrennen und unterscheiden - was zugegebenermaßen extrem bequem ist.
Des Weiteren brauchen wir noch benutzerdefinierte Funktionen, die vom Expert Advisor zur Erzeugung grafischer Objekte verwendet werden. Die zur Erzeugung von grafischen Objekten von MQL5 angebotene Funktion ist ObjectCreate(). Doch da wir ja auch Objekt-Eigenschaften einrichten müssen, da die Objekte an sich vielleicht mehr als nur einmal erzeugt werden müssen, ist es besser, sich nach einer bequemeren und kompakteren Methode umzusehen, die in eine einzige Codezeile implementiert werden könnte.
Zur Erzeugung des Hintergrunds und der Kopfzeile für das Info-Panel verwenden wir das grafische Objekt 'Bearbeiten'. Schreiben wir also die CreateEdit() Funktion:
//+------------------------------------------------------------------+ //| CREATING THE EDIT OBJECT | //+------------------------------------------------------------------+ void CreateEdit(long chart_id, // chart id int sub_window, // (sub)window number string name, // object name string text, // displayed text ENUM_BASE_CORNER corner, // chart corner string font_name, // font int font_size, // font size color font_color, // font color int x_size, // width int y_size, // height int x_distance, // X-coordinate int y_distance, // Y-coordinate long z_order, // Z-order color background_color, // background color bool read_only) // Read Only flag { // If the object has been created successfully,... if(ObjectCreate(chart_id,name,OBJ_EDIT,sub_window,0,0)) { // ...set its properties ObjectSetString(chart_id,name,OBJPROP_TEXT,text); // displayed text ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner); // set the chart corner ObjectSetString(chart_id,name,OBJPROP_FONT,font_name); // set the font ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size); // set the font size ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color); // font color ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,background_color); // background color ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,x_size); // width ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,y_size); // height ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance); // set the X coordinate ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance); // set the Y coordinate ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false); // cannot select the object if FALSE ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order); // Z-order of the object ObjectSetInteger(chart_id,name,OBJPROP_READONLY,read_only); // Read Only ObjectSetInteger(chart_id,name,OBJPROP_ALIGN,ALIGN_LEFT); // align left ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n"); // no tooltip if "\n" } }
Jetzt kann das grafische Objekt 'Bearbeiten' (OBJ_EDIT) mittels einer einzigen Codezeile erzeugt werden. Wenn wir eine Funktion erzeugen, die das Info-Pabel auf das Chart setzt, werden wir es durch ein Beispiel veranschaulichen.
Gehen wir jetzt weiter zu den 'Text-Kennung' Objekten, die zur Anzeige der Liste der Position-Eigenschaften und ihrer Werte verwendet werden, und erzeugen die CreateLabel() Funktion auf ähnliche Weise:
//+------------------------------------------------------------------+ //| CREATING THE LABEL OBJECT | //+------------------------------------------------------------------+ void CreateLabel(long chart_id, // chart id int sub_window, // (sub)window number string name, // object name string text, // displayed text ENUM_ANCHOR_POINT anchor, // anchor point ENUM_BASE_CORNER corner, // chart corner string font_name, // font int font_size, // font size color font_color, // font color int x_distance, // X-coordinate int y_distance, // Y-coordinate long z_order) // Z-order { // If the object has been created successfully,... if(ObjectCreate(chart_id,name,OBJ_LABEL,sub_window,0,0)) { // ...set its properties ObjectSetString(chart_id,name,OBJPROP_TEXT,text); // displayed text ObjectSetString(chart_id,name,OBJPROP_FONT,font_name); // set the font ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color); // set the font color ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,anchor); // set the anchor point ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner); // set the chart corner ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size); // set the font size ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance); // set the X-coordinate ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance); // set the Y-coordinate ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false); // cannot select the object if FALSE ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order); // Z-order of the object ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n"); // no tooltip if "\n" } }
Auch hier ist es empfehlenswert, sich die Funktionsbeschreibungen in den MQL5 Referenzhinweisen anzusehen.
Wird sie vom Chart gelöscht wird, muss der Expert Advisor seinerseits alle Objekte löschen, die dem Chart zuvor hinzugefügt wurden. Dies geschieht, indem der Name des Objekts einfach an die DeleteObjectByName() Funktion übertragen wird. Sei sucht dann nach dem per Namen angegebenen Objekt und löscht es (falls es gefunden werden kann) mit Hilfe der eingebauten ObjectFind() Funktion, die nach Objekten sucht und der ObjectDelete() Funktion, die Objekte löscht
//+------------------------------------------------------------------+ //| DELETING THE OBJECT BY NAME | //+------------------------------------------------------------------+ void DeleteObjectByname(string name) { int sub_window=0; // Returns the number of the subwindow where the object is located bool res =false; // Result following an attempt to delete the object //--- Find the object by name sub_window=ObjectFind(ChartID(),name); //--- if(sub_window>=0) // If it has been found,.. { res=ObjectDelete(ChartID(),name); // ...delete it //--- // If an error occurred when deleting the object,.. if(!res) // ...print the relevant message { Print("Error deleting the object: ("+IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError())); } } }
In der DeleteObjectByName() Funktion implementieren wir darüberhinaus auch eine Prüfung nach Fehlern beim Löschen eines Objekts. Sollte ein Fehler auftreten, erscheint eine entsprechende Meldung samt Fehlercode und Beschreibung. Wie Sie im oben stehenden Code sehen können, verwenden wir eine zusätzliche, benutzerdefinierte Funktion, die den Fehlercode in eine Textbeschreibung umwandelt - die Funktion ErrorDescription(). Da es eine Menge Fehlercodes gibt, erkläre ich den obigen Code nur mittels Verwendung eines Teils dieser Funktion (vgl. Code unten). Die vollständige Version des Codes findet sich in der diesem Beitrag angehängten Quellcode-Datei.
//+------------------------------------------------------------------+ //| RETURNING THE ERROR DESCRIPTION | //+------------------------------------------------------------------+ string ErrorDescription(int error_code) { string error_string=""; //--- switch(error_code) { //--- Trade server return codes case 10004: error_string="Requote"; break; case 10006: error_string="Request rejected"; break; case 10007: error_string="Request canceled by trader"; break; case 10008: error_string="Order placed"; break; case 10009: error_string="Request executed"; break; case 10010: error_string="Request executed partially"; break; case 10011: error_string="Request processing error"; break; case 10012: error_string="Request timed out"; break; case 10013: error_string="Invalid request"; break; case 10014: error_string="Invalid request volume"; break; case 10015: error_string="Invalid request price"; break; case 10016: error_string="Invalid Stop orders in the request"; break; case 10017: error_string="Trading forbidden"; break; case 10018: error_string="Market is closed"; break; case 10019: error_string="Insufficient funds"; break; case 10020: error_string="Prices changed"; break; case 10021: error_string="No quotes to process the request"; break; case 10022: error_string="Invalid order expiration in the request"; break; case 10023: error_string="Order status changed"; break; case 10024: error_string="Too many requests"; break; case 10025: error_string="No changes in the request"; break; case 10026: error_string="Automated trading is disabled by trader"; break; case 10027: error_string="Automated trading is disabled by the client terminal"; break; case 10028: error_string="Request blocked for processing"; break; case 10029: error_string="Order or position frozen"; break; case 10030: error_string="The specified type of order execution by balance is not supported"; break; case 10031: error_string="No connection with trade server"; break; case 10032: error_string="Transaction is allowed for live accounts only"; break; case 10033: error_string="You have reached the maximum number of pending orders"; break; case 10034: error_string="You have reached the maximum order and position volume for this symbol"; break; ... } //--- return(error_string); }
Im vorangegangenen Beitrag haben wir uns mit der GetPositionProperties() Funktion beschäftigt, die Position-Eigenschaften abruft. Diesmal ist die Struktur der Funktion jedoch etwas komplexer. Wir suchen ach einer Position, die derzeit offen ist, wobei der Marker vorhanden/nicht vorhanden einer offenen Position in der globalen Variable pos_open abgelegt wird Diese Information ist vielleicht für andere Funktionen notwendig, ohne dass man die Funktion PositionSelect() jedes Mal aufrufen muss.
Wenn eine offene Position vorhanden ist, erhalten wir dann ihre Eigenschaften. Ansonsten weren alle Variablen genullt. Schreiben wir also jetzt eine einfache ZeroPositionProperties() Funktion:
//+------------------------------------------------------------------+ //| ZEROING OUT VARIABLES FOR POSITION PROPERTIES | //+------------------------------------------------------------------+ void ZeroPositionProperties() { pos_symbol =""; pos_comment =""; pos_magic =0; pos_price =0.0; pos_cprice =0.0; pos_sl =0.0; pos_tp =0.0; pos_type =WRONG_VALUE; pos_volume =0.0; pos_commission =0.0; pos_swap =0.0; pos_profit =0.0; pos_time =NULL; pos_id =0; }
Am Ende der GetPositionProperties() Funktion werden wir zudem eine benutzerdefinierte Funktion aufrufen, SetInfoPanel(), die das Info-Panel in das Chart zeichnet/aktualisiert.
//+------------------------------------------------------------------+ //| GETTING POSITION PROPERTIES | //+------------------------------------------------------------------+ void GetPositionProperties() { // Check if there is an open position pos_open=PositionSelect(_Symbol); //--- if(pos_open) // If an open position exists, get its properties { pos_symbol =PositionGetString(POSITION_SYMBOL); pos_comment =PositionGetString(POSITION_COMMENT); pos_magic =PositionGetInteger(POSITION_MAGIC); pos_price =PositionGetDouble(POSITION_PRICE_OPEN); pos_cprice =PositionGetDouble(POSITION_PRICE_CURRENT); pos_sl =PositionGetDouble(POSITION_SL); pos_tp =PositionGetDouble(POSITION_TP); pos_type =(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); pos_volume =PositionGetDouble(POSITION_VOLUME); pos_commission =PositionGetDouble(POSITION_COMMISSION); pos_swap =PositionGetDouble(POSITION_SWAP); pos_profit =PositionGetDouble(POSITION_PROFIT); pos_time =(datetime)PositionGetInteger(POSITION_TIME); pos_id =PositionGetInteger(POSITION_IDENTIFIER); } else // If there is no open position, zero out variables for position properties ZeroPositionProperties(); //--- SetInfoPanel(); // Set/update the info panel }
Schreiben wir jetzt also die SetInfoPanel() Funktion. Unten steht der Code mit detaillierten Anmerkungen:
//+------------------------------------------------------------------+ //| SETTING THE INFO PANEL | //|------------------------------------------------------------------+ void SetInfoPanel() { int y_bg=18; // Y-coordinate for the background and header int y_property=32; // Y-coordinate for the list of properties and their values int line_height=12; // Line height //--- int font_size=8; // Font size string font_name="Calibri"; // Font color font_color=clrWhite; // Font color //--- ENUM_ANCHOR_POINT anchor=ANCHOR_RIGHT_UPPER; // Anchor point in the top right corner ENUM_BASE_CORNER corner=CORNER_RIGHT_UPPER; // Origin of coordinates in the top right corner of the chart //--- X-coordinates int x_first_column=120; // First column (names of properties) int x_second_column=10; // Second column (values of properties) //--- Array of Y-coordinates for the names of position properties and their values int y_prop_array[INFOPANEL_SIZE]={0}; //--- Fill the array with coordinates for each line on the info panel y_prop_array[0]=y_property; y_prop_array[1]=y_property+line_height; y_prop_array[2]=y_property+line_height*2; y_prop_array[3]=y_property+line_height*3; y_prop_array[4]=y_property+line_height*4; y_prop_array[5]=y_property+line_height*5; y_prop_array[6]=y_property+line_height*6; y_prop_array[7]=y_property+line_height*7; y_prop_array[8]=y_property+line_height*8; y_prop_array[9]=y_property+line_height*9; y_prop_array[10]=y_property+line_height*10; y_prop_array[11]=y_property+line_height*11; y_prop_array[12]=y_property+line_height*12; y_prop_array[13]=y_property+line_height*13; //--- Background of the info panel CreateEdit(0,0,"InfoPanelBackground","",corner,font_name,8,clrWhite,230,190,231,y_bg,0,C'15,15,15',true); //--- Header of the info panel CreateEdit(0,0,"InfoPanelHeader","POSITION PROPERTIES",corner,font_name,8,clrWhite,230,14,231,y_bg,1,clrFireBrick,true); //--- List of the names of position properties and their values // Property name CreateLabel(0,0,pos_prop_names[0],"Symbol :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[0],2); // Property value CreateLabel(0,0,pos_prop_values[0],GetValInfoPanel(0),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[0],2); //--- CreateLabel(0,0,pos_prop_names[1],"Magic Number :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[1],2); CreateLabel(0,0,pos_prop_values[1],GetValInfoPanel(1),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[1],2); //--- CreateLabel(0,0,pos_prop_names[2],"Comment :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[2],2); CreateLabel(0,0,pos_prop_values[2],GetValInfoPanel(2),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[2],2); //--- CreateLabel(0,0,pos_prop_names[3],"Swap :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[3],2); CreateLabel(0,0,pos_prop_values[3],GetValInfoPanel(3),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[3],2); //--- CreateLabel(0,0,pos_prop_names[4],"Commission :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[4],2); CreateLabel(0,0,pos_prop_values[4],GetValInfoPanel(4),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[4],2); //--- CreateLabel(0,0,pos_prop_names[5],"Open Price :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[5],2); CreateLabel(0,0,pos_prop_values[5],GetValInfoPanel(5),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[5],2); //--- CreateLabel(0,0,pos_prop_names[6],"Current Price :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[6],2); CreateLabel(0,0,pos_prop_values[6],GetValInfoPanel(6),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[6],2); //--- CreateLabel(0,0,pos_prop_names[7],"Profit :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[7],2); CreateLabel(0,0,pos_prop_values[7],GetValInfoPanel(7),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[7],2); //--- CreateLabel(0,0,pos_prop_names[8],"Volume :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[8],2); CreateLabel(0,0,pos_prop_values[8],GetValInfoPanel(8),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[8],2); //--- CreateLabel(0,0,pos_prop_names[9],"Stop Loss :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[9],2); CreateLabel(0,0,pos_prop_values[9],GetValInfoPanel(9),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[9],2); //--- CreateLabel(0,0,pos_prop_names[10],"Take Profit :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[10],2); CreateLabel(0,0,pos_prop_values[10],GetValInfoPanel(10),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[10],2); //--- CreateLabel(0,0,pos_prop_names[11],"Time :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[11],2); CreateLabel(0,0,pos_prop_values[11],GetValInfoPanel(11),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[11],2); //--- CreateLabel(0,0,pos_prop_names[12],"Identifier :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[12],2); CreateLabel(0,0,pos_prop_values[12],GetValInfoPanel(12),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[12],2); //--- CreateLabel(0,0,pos_prop_names[13],"Type :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[13],2); CreateLabel(0,0,pos_prop_values[13],GetValInfoPanel(13),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[13],2); //--- ChartRedraw(); // Redraw the chart }
Sehen wir uns die SetInfoPanel() Funktion genauer an. Die Variablen, die mit den Eigenschaften der grafischen Objekte zu tun haben (Koordinaten, Farbe, Schriftart, angezeigter Text, usw.) werden zu Anfang der Funktion deklariert. Beachten Sie den Vorgang der Befüllung des Arrays mit den Y-Koordinaten für die Liste der Position-Eigenschaften auf dem Info-Panel. Er wird auf eine Art und Weise implementiert, die für Anfänger klar sein sollte. Doch verwendet man eine Schleife, kann er auf einige wenige Codezeilen reduziert werden. Sie können ihn folgendermaßen schreiben:
//--- Fill the array with coordinates for each line on the info panel for(int i=0; i<INFOPANEL_SIZE; i++) { if(i==0) y_prop_array[i]=y_property; else y_prop_array[i]=y_property+line_height*i; }
Anschließend müssen alle Eigenschaften der Objekte, die auf dem Panel angezgit weren sollen in den Parametern der zuvor erzeugten CreateLabel() und CreateEdit() Funktionen spezifizeirt werden, wobei man jeweils ein Objekt nach dem anderen hernimmt. Mit Hilfe der Schleife kann die gesamte Liste auch in einigen wenigen Codezeilen implementiert werden. Dazu müssen wir ein anderes Array für Objekte anlegen, das den Text der Namen der Position-Eigenschaften im Chart anzeigt. Das habe ich als Hausaufgabe für Sie.
Die GetPropertyValue() Funktion, die Anzahl der Objekte erhält, liefert den Wert, der dann an die CreateLabel() Funktion als vierter Parameter übertragen wird (angezeigter Text). Dies gilt für alle Objekte, die Werte der Position-Eigenschaften anzeigen werden. Der von der Funktion gelieferte Wert ist ein angepasster String-Wert, der letztlich auf dem Panel angezeigt wird. Unten steht der Code der Funktion mit detaillierten Anmerkungen:
//+------------------------------------------------------------------+ //| RETURNING THE STRING WITH POSITION PROPERTY VALUE | //+------------------------------------------------------------------+ string GetPropertyValue(int number) { //--- Sign indicating the lack of an open position or a certain property // E.g. the lack of a comment, Stop Loss or Take Profit string empty="-"; //--- If an open position exists, return the value of the requested property if(pos_open) { switch(number) { case 0 : return(pos_symbol); break; case 1 : return(IntegerToString((int)pos_magic)); break; //--- return the value of the comment, if any, otherwise return the sign indicating the lack of comment case 2 : return(pos_comment!="" ? pos_comment : empty); break; case 3 : return(DoubleToString(pos_swap,2)); break; case 4 : return(DoubleToString(pos_commission,2)); break; case 5 : return(DoubleToString(pos_price,_Digits)); break; case 6 : return(DoubleToString(pos_cprice,_Digits)); break; case 7 : return(DoubleToString(pos_profit,2)); break; case 8 : return(DoubleToString(pos_volume,2)); break; case 9 : return(pos_sl!=0.0 ? DoubleToString(pos_sl,_Digits) : empty); break; case 10 : return(pos_tp!=0.0 ? DoubleToString(pos_tp,_Digits) : empty); break; case 11 : return(TimeToString(pos_time,TIME_DATE|TIME_MINUTES)); break; case 12 : return(IntegerToString((int)pos_id)); break; case 13 : return(PositionTypeToString(pos_type)); break; default : return(empty); } } //--- // If there is no open position, return the sign indicating the lack of the open position "-" return(empty); }
Der Code oben schlägt vor, dass für jede an die Funktion übertragene Zahl ein bestimmter Wert vorbereitet wird, vorausgesetzt es gibt überhaupt eine offene Position. Gibt es derzeit keine offene Position, liefert die Funktion einen Bindestrich (-), der für alle Objekte, die mit Werten von Position-Eigenschaften zu tun haben, angezeigt wird.
Am Ende der SetInfoPanel() Funktion rufen wir die Funktion ChartRedraw() auf, die für eine erzwungene Neuzeichnung des Charts gedacht ist. Wenn sie nicht aufgerufen wird, werden Sie die gemachten Änderungen nicht sehen können.
Jetzt müssen wir eine Funktion schreiben, die alle vom Expert Advisor erzeugten grafischen Objekte löscht. Nennen wir sie mal DeleteInfoPanel():
//+------------------------------------------------------------------+ //| DELETING THE INFO PANEL | //+------------------------------------------------------------------+ void DeleteInfoPanel() { DeleteObjectByName("InfoPanelBackground"); // Delete the panel background DeleteObjectByName("InfoPanelHeader"); // Delete the panel header //--- Delete position properties and their values for(int i=0; i<INFOPANEL_SIZE; i++) { DeleteObjectByName(pos_prop_names[i]); // Delete the property DeleteObjectByName(pos_prop_values[i]); // Delete the value } //--- ChartRedraw(); // Redraw the chart }
Jetzt müssen wir nur noch die Methoden, die wir unter den Hauptfunktionen des Expert Advisors, die ursprünglich im Template nach seiner Erstellung mittels des MQL5-Assistenten vorhanden waren, verteilen. Das ist die leichteste Übung:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Get the properties and set the panel GetPositionProperties(); //--- return(0); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Print the deinitialization reason to the journal Print(GetDeinitReasonText(reason)); //--- When deleting from the chart if(reason==REASON_REMOVE) //--- Delete all objects relating to the info panel from the chart DeleteInfoPanel(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Get the properties and update the values on the panel GetPositionProperties(); } //+------------------------------------------------------------------+
Das einzige worüber Sie vielleicht stolpern könnten, ist die GetDeinitReasonText() Funktion, die eine Text-Beschreibung des Codes für den Grund der De-Initialisierung liefert:
//+---------------------------------------------------------------------+ //| RETURNING A TEXTUAL DESCRIPTION OF THE DEINITIALIZATION REASON CODE | //+---------------------------------------------------------------------+ string GetDeinitReasonText(int reason_code) { string text=""; //--- switch(reason_code) { case REASON_PROGRAM : // 0 text="The Expert Advisor has stopped working calling the ExpertRemove() function."; break; case REASON_REMOVE : // 1 text="The '"+EXPERT_NAME+"' program has been removed from the chart."; break; case REASON_RECOMPILE : // 2 text="The '"+EXPERT_NAME+"' program has been recompiled."; break; case REASON_CHARTCHANGE : // 3 text="Chart symbol or period has been changed."; break; case REASON_CHARTCLOSE : // 4 text="The chart is closed."; break; case REASON_PARAMETERS : // 5 text="Input parameters have been changed by the user."; break; case REASON_ACCOUNT : // 6 text="A different account has been activated."; break; case REASON_TEMPLATE : // 7 text="A different chart template has been applied."; break; case REASON_INITFAILED : // 8 text="A flag specifying that the OnInit() handler returned zero value."; break; case REASON_CLOSE : // 9 text="The terminal has been closed."; break; default : text="The reason is undefined."; } //--- return text; }
Wenn Sie versuchen, den Expert Advisor auf dem Chart-Symbol zu verwenden, das derzeit keine offene Position hat, sehen Sie auf dem Panel Bindestriche anstelle der Werte der Position-Eigenschaften. Wenn Sie eine bestimmte Position schließen, sieht das Panel ganz genauso aus.
Abb. 2 Info-Panel wenn keine offene Position vorhanden ist
Wird der Expert Advisor dem Chart des Symbols mit einer offenen Position hinzugefügt, oder wird eine Position geöffnet, nachdem der Expert Advisor dem Chart hinzugefügt wurde, werden alle Bindestriche durch die entsprechenden Werte der Position-Eigenschaft ersetzt.
Abb. 3 Das Info-Panel zeigt die Eigenschaften der offenen Position.
Es gibt da noch eine kleine Besonderheit. Nachdem eine Position geschlossen wird, werden ihre Werte auf dem Panel erst dann aktualisiert, wenn eine neue Kursschwankung auftritt. Es gibt zwar eine Möglichkeit, die Werte sofort aktualisieren zu lassen, doch was für diese Implementierung erforderlich ist, soll Gegenstand des nächsten Beitrags aus dieser Reihe sein.
Fazit
Einige der in diesem Beitrag vorgestellten Funktionen werden auch in den nächsten Beiträgen der MQL5 Cookbook-Reihe verwendet. Andere hingegen werden, je nach anstehender Aufgabe, modifiziert und verbessert. Es empfiehlt sich daher die Beiträgen der Reihe nach zu lesen, einen nach dem anderen, da jeder neue Beitrag die logische Fortsetzung des vorangegangenen ist. Das alles hängt natürlich auch von Ihrer Kompetenz und dem Grad Ihrer Fähigkeiten ab, daher ist es vermutlich vernünftiger und interessanter mit den neueren Beiträgen zu beginnen.
Die Quellcode-Datei ist an diesen Beitrag angehängt.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/641





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