Manuale MQL5: Proprietà di posizione nel pannello delle informazioni personalizzate
Introduzione
Questa volta creeremo un semplice Expert Advisor che otterrà le proprietà della posizione sul simbolo corrente e le visualizzerà sul pannello informativo personalizzato durante il trading manuale. Il pannello informativo verrà creato utilizzando oggetti grafici e le informazioni visualizzate verranno aggiornate ad ogni tick. Questo sarà molto più conveniente rispetto al dover eseguire manualmente lo script descritto nel precedente articolo della serie chiamata "Manuale MQL5: Ottenere le Proprietà di posizione.
Sviluppare un Expert Advisor
Cominciamo con gli oggetti grafici. Per creare il pannello delle informazioni, abbiamo bisogno di oggetti per lo sfondo, l'intestazione, i nomi e i valori delle proprietà di posizione. Lo sfondo e l'intestazione richiederanno un rettangolo che non si muove col prezzo. Il rettangolo può essere creato utilizzando oggetti grafici come Rectangle Label o Modifica, mentre i nomi ei valori delle proprietà dell'oggetto verranno creati utilizzando Etichette di testo.
Prima di procedere con il codice, prepariamo un layout per il pannello informativo. La sua comodità sta nel fatto che possiamo modificare rapidamente qualsiasi proprietà nella finestra delle impostazioni e personalizzare l'aspetto del pannello delle informazioni.
Ogni oggetto ha una finestra delle impostazioni che può essere aperta dal menu contestuale di un oggetto selezionato. La finestra delle impostazioni può essere aperta anche dall'Elenco oggetti (Ctrl+B) selezionando l'oggetto richiesto e facendo clic su Proprietà. Il layout del pannello delle informazioni è mostrato di seguito. Può anche essere utilizzato per stimare dimensioni e coordinate durante la scrittura di un codice. Quando il codice per il pannello informativo è pronto, dovrai eliminare manualmente gli oggetti del layout poiché l'Expert Advisor non sarà in grado di "vederli" e quindi non li rimuoverà dal grafico.
Fig. 1. Preparazione del layout per il pannello informazioni.
Ora dobbiamo creare un modello per l'Expert Advisor. Questo può essere fatto velocemente come per lo script. Nella procedura guidata MQL5, l'opzione Expert Advisor (modello) è selezionata per impostazione predefinita. Eseguiamo i passaggi successivi senza apportare modifiche alle opzioni poiché questa volta non sono necessarie. Quindi fai clic su Fine e vedrai un modello come di seguito:
//+------------------------------------------------------------------+ //| 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() { //--- } //+------------------------------------------------------------------+
Si può notare subito che il modello Expert Advisor è diverso dal modello di script. Oltre alle proprietà del programma (#property), ci sono tre funzioni principali: OnInit(), OnDeinit() e OnTick().
La funzione OnInit() viene chiamata durante il caricamento del programma, la modifica dei parametri esterni, la compilazione del programma, a condizione che il programma sia in quel momento aggiunto al grafico e quando si modifica il simbolo o il punto. Se necessario, puoi inizializzare determinate variabili o array in questa funzione per poterci lavorare in seguito.
La funzione OnDeinit() viene chiamata quando si elimina il programma dal grafico, si cambia conto, simbolo o periodo. Tutti i possibili motivi di deinizializzazione sono forniti nel riferimento MQL5. Questo Expert Advisor utilizzerà una funzione definita dall'utente, GetDeinitReasonText(), che converte in testo l'identificatore del motivo della deinizializzazione (il parametro della funzione OnDeinit()).
E infine, la funzione OnTick(). Viene chiamato ogni volta che c'è un nuovo segno di spunta sul simbolo sul cui grafico l'Expert Advisor sta attualmente operando.
Ora prepariamo tutte le costanti, le variabili e gli array che utilizzeremo nell'Expert Advisor. Li collocheremo all'inizio del programma. Innanzitutto, definisci le variabili i cui valori rimangono invariati per tutto il programma:
//--- #define INFOPANEL_SIZE 14 // Size of the array for info panel objects #define EXPERT_NAME MQL5InfoString(MQL5_PROGRAM_NAME) // Name of the Expert Advisor //---
Seguono le variabili globali per le proprietà di posizione:
//--- 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
Dopo le variabili, dichiareremo array di nomi di oggetti grafici. Questi oggetti visualizzeranno le proprietà di posizione ei loro valori nel grafico. A questo scopo, creeremo due array di stringhe e inizializzeremo immediatamente i loro elementi in valori. Tra parentesi quadre, utilizziamo il valore della costante INFOPANEL_SIZE dichiarata all'inizio del programma. Cioè, ci saranno 14 elementi in ogni 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" }; //---
Usando questi nomi, puoi trovare programmaticamente l'oggetto necessario nel grafico e impostare o modificare le sue proprietà come testo visualizzato, colore, dimensione, ecc. Inoltre, questi nomi verranno visualizzati nella finestra Elenco oggetti (Ctrl+B) dopo essere stati creati nel grafico. Ma non sarai in grado di vederli lì poiché gli oggetti creati dal programma MQL5 sono nascosti per impostazione predefinita. Per renderli visibili, dovresti fare clic su Elenca tutto nella finestra Elenco oggetti. Questa funzione aiuta a separare gli oggetti creati manualmente da quelli creati a livello di codice, il che è certamente molto conveniente.
Inoltre, avremo bisogno di funzioni definite dall'utente che verranno impiegate dall'Expert Advisor per creare oggetti grafici. La funzione offerta da MQL5 per la creazione di oggetti grafici è ObjectCreate(). Ma poiché occorre impostare anche le proprietà degli oggetti, mentre gli oggetti stessi potrebbero dover essere creati più di una volta, sarebbe meglio pensare a un metodo più comodo e compatto che possa essere implementato in una singola riga di codice.
Per creare lo sfondo e l'intestazione del pannello delle informazioni, utilizzeremo l'oggetto grafico Modifica. Scriviamo la funzione CreateEdit():
//+------------------------------------------------------------------+ //| 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" } }
Ora l'oggetto grafico Edit (OBJ_EDIT) può essere creato utilizzando una singola riga di codice. Lo illustreremo con un esempio durante la creazione di una funzione che imposterà il pannello informativo sul grafico.
Passiamo ora agli oggetti Etichetta di testo che verranno utilizzati per visualizzare l'elenco delle proprietà di posizione e i loro valori e creiamo la funzione CreateLabel() in modo simile:
//+------------------------------------------------------------------+ //| 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" } }
Si consiglia inoltre di dare un'occhiata alle descrizioni delle funzioni in MQL5 Reference.
Quando viene eliminato dal grafico, Expert Advisor deve a sua volta eliminare tutti gli oggetti che ha precedentemente aggiunto al grafico. Per fare ciò, puoi semplicemente passare il nome dell'oggetto alla funzione DeleteObjectByName(). Quindi cercherà l'oggetto in base al nome specificato e lo eliminerà, se trovato, utilizzando la funzione ObjectFind() incorporata che cerca l'oggetto e la funzione ObjectDelete() che elimina l'oggetto.
//+------------------------------------------------------------------+ //| 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())); } } }
Inoltre, nella funzione DeleteObjectByName(), implementiamo anche un controllo degli errori durante l'eliminazione di un oggetto. Se si verifica un errore, apparirà un messaggio relativo contenente il codice di errore e la descrizione. Come puoi vedere nel codice sopra, utilizziamo una funzione aggiuntiva definita dall'utente che converte il codice di errore in una descrizione testuale: la funzione ErrorDescription(). Poiché ci sono molti codici di errore, esemplificherò quanto sopra utilizzando solo una parte di questa funzione (vedi il codice sotto). La versione completa del codice è disponibile nel file del codice sorgente allegato a questo articolo.
//+------------------------------------------------------------------+ //| 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); }
Nell'articolo precedente ci siamo occupati della funzione GetPositionProperties() che ottiene le proprietà di posizione. Questa volta la struttura della funzione sarà un po' più complessa. Verificheremo una posizione attualmente aperta, con il flag di presenza/assenza di una posizione aperta memorizzato nella variabile globale pos_open. Queste informazioni possono essere richieste in altre funzioni, senza dover chiamare ogni volta la funzione PositionSelect().
Quindi, se esiste una posizione aperta, otterremo le sue proprietà, altrimenti tutte le variabili verranno azzerate. Ora scriviamo una semplice funzione ZeroPositionProperties():
//+------------------------------------------------------------------+ //| 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; }
Inoltre, alla fine della funzione GetPositionProperties(), chiameremo una funzione SetInfoPanel() definita dall'utente che disegna/aggiorna il pannello delle informazioni nel grafico.
//+------------------------------------------------------------------+ //| 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 }
Scriviamo ora la funzione SetInfoPanel(). Di seguito il codice della funzione con commenti dettagliati:
//+------------------------------------------------------------------+ //| 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 }
Diamo un'occhiata più da vicino alla funzione SetInfoPanel(). Le variabili che hanno a che fare con le proprietà degli oggetti grafici (coordinate, colore, font, testo visualizzato, ecc.) sono dichiarate all'inizio della funzione. Prestare attenzione al processo di riempimento dell'array di coordinate Y per l'elenco delle proprietà di posizione nel pannello delle informazioni. È implementato in modo chiaro ai principianti. Ma può essere ridotto a un paio di righe di codice quando si utilizza un ciclo. Puoi scriverlo come segue:
//--- 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; }
Quindi, tutte le proprietà degli oggetti che devono essere visualizzate sul pannello devono essere specificate nei parametri delle funzioni CreateLabel() e CreateEdit() create in precedenza, prendendo un oggetto alla volta. L'intero elenco può anche essere implementato in poche righe di codice utilizzando un ciclo. Per fare ciò, dobbiamo creare un altro array per gli oggetti che visualizzano il testo dei nomi delle proprietà di posizione nel grafico. Pensalo come un compito.
La funzione GetPropertyValue() che riceve il numero dell'oggetto restituisce il valore che viene quindi passato alla funzione CreateLabel() come quarto parametro (testo visualizzato). Ciò riguarda tutti gli oggetti che visualizzeranno i valori delle proprietà di posizione. Il valore restituito dalla funzione è un valore di stringa modificato che verrà infine visualizzato sul pannello. Di seguito il codice della funzione con commenti dettagliati:
//+------------------------------------------------------------------+ //| 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); }
Il codice sopra suggerisce che viene preparato un certo valore per ogni numero passato alla funzione, a condizione che ci sia una posizione aperta. Se al momento non è presente alcuna posizione aperta, la funzione restituirà un trattino (-) visualizzato per tutti gli oggetti che hanno a che fare con i valori della proprietà di posizione.
Alla fine della funzione SetInfoPanel(), chiamiamo la funzione ChartRedraw() progettata per un ridisegno forzato del grafico. A meno che non venga chiamato, non sarai in grado di vedere le modifiche apportate.
Ora dobbiamo scrivere una funzione che cancellerà tutti gli oggetti grafici creati dall'Expert Advisor. Chiamiamolo 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 }
Ora non ci resta che distribuire i metodi che abbiamo creato tra le principali funzioni dell'Expert Advisor che erano originariamente presenti nel template dopo averlo creato in MQL5 Wizard. Questa è la parte più semplice:
//+------------------------------------------------------------------+ //| 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(); } //+------------------------------------------------------------------+
L'unica cosa in cui potresti imbatterti è la funzione GetDeinitReasonText() che restituisce una descrizione testuale del codice motivo della deinizializzazione:
//+---------------------------------------------------------------------+ //| 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; }
Se provi a utilizzare l'Expert Advisor sul simbolo del grafico che attualmente non ha una posizione aperta, vedrai dei trattini invece dei valori delle proprietà della posizione sul pannello. Il pannello avrà lo stesso aspetto dopo aver chiuso una determinata posizione.
Fig. 2. Pannello informativo in assenza di posizione aperta.
Se l'Expert Advisor viene aggiunto al grafico del simbolo che ha una posizione aperta o se una posizione viene aperta dopo aver aggiunto l'Expert Advisor al grafico, tutti i trattini verranno sostituiti con i valori appropriati della proprietà di posizione:
Fig. 3. Pannello informativo che mostra le proprietà della posizione aperta.
C'è una piccola particolarità. Dopo aver chiuso la posizione, i valori sul pannello vengono aggiornati solo al nuovo tick. Esiste un modo per aggiornare immediatamente i valori, ma ciò che è necessario fare per implementarlo verrà discusso nel prossimo articolo della serie.
Conclusione
Alcune delle funzioni introdotte in questo articolo verranno utilizzate anche nei successivi articoli della serie Manuale MQL5, mentre altre verranno modificate e migliorate a seconda dell'attività da svolgere. Si consiglia di leggere gli articoli in ordine, uno dopo l'altro in quanto ogni nuovo articolo è una logica continuazione del precedente. Sicuramente dipende anche dal tuo livello di competenza e abilità, quindi potrebbe essere più ragionevole e interessante iniziare con pubblicazioni più recenti.
Il file del codice sorgente è allegato all'articolo.
Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/641
- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso