English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Come preparare le quotazioni MetaTrader 5 per altre applicazioni

Come preparare le quotazioni MetaTrader 5 per altre applicazioni

MetaTrader 5Esempi | 11 gennaio 2022, 15:37
76 0
Anatoli Kazharski
Anatoli Kazharski

Contenuto

Introduzione
1. Argomenti trattati
2. Formato dati
3. Parametri esterni del programma
4. Controllo dei parametri immessi da un utente
5. Variabili globali
6. Pannello informativo
7. Blocco principale dell'applicazione
8. Creazione di cartelle e archiviazione dei dati
Conclusione


Introduzione

Prima di iniziare a studiare MQL5, ho provato molte altre applicazioni per lo sviluppo di sistemi di trading. Non posso dire di aver sprecato il mio tempo. Alcuni di essi contengono alcuni strumenti utili che consentono agli utenti di risparmiare tempo, affrontare molti problemi, distruggere alcuni miti e selezionare rapidamente alcune ulteriori direzioni per lo sviluppo senza la conoscenza dei linguaggi di programmazione.

Queste applicazioni necessitano di dati cronologici. A causa dell'assenza di alcuni formati di dati standard, spesso dovevano essere modificati prima di poter essere utilizzati (ad esempio, in Excel) per conformarsi al formato applicabile al programma necessario. Anche se sei in grado di capire tutti i dettagli necessari, molte cose devono comunque essere fatte manualmente. Gli utenti possono trovare diverse versioni di script progettati per copiare le quotazioni da MetaTrader 4 nel formato necessario. Se c'è una tale richiesta, possiamo anche sviluppare la versione dello script per MQL5.


1. Argomenti trattati

L'articolo tratta i seguenti argomenti:

  • Utilizzo dell'elenco dei simboli nella finestra Market Watch e dell'elenco dei simboli comuni sul server.
  • Controllo della profondità dei dati disponibili e download della quantità mancante se necessario con una corretta gestione delle varie situazioni.
  • Visualizzazione delle informazioni sui dati richiesti sul pannello personalizzato e sul journal.
  • Preparazione dei dati per l'archiviazione in un formato definito dall'utente.
  • Creazione di directory di file.
  • Archiviazione dei dati.


2. Formato dati

Farò un esempio di preparazione dei dati destinati ad essere utilizzati su NeuroShell DayTrader Professional (NSDT). Ho provato NSDT nelle versioni 5 e 6 e ho scoperto che hanno requisiti diversi per il formato dei dati. I dati riguardanti data e ora di NSDT versione 5 devono essere in colonne diverse. La prima riga del file deve avere il seguente aspetto:

"Date" "Time" "Open" "High" "Low" "Close" "Volume"

La riga di intestazione su NSDT versione 6 deve avere un aspetto diverso per consentire all'applicazione di accettare un file. Significa che la data e l'ora devono essere nella stessa colonna:

Date,Open,High,Low,Close,Volume

MetaTrader 5 consente agli utenti di salvare le quotazioni in file *.csv. I dati in un file sono i seguenti:

Fig.1. Dati salvati dal terminale MetaTrader 5

Fig.1. Dati salvati dal terminale MetaTrader 5


Tuttavia, non possiamo semplicemente modificare la riga di intestazione poiché la data deve avere un altro formato. Per NSDT v.5:

dd.mm.yyyy,hh:mm,Open,High,Low,Close,Volume
Per NSDT v.6:
dd/mm/yyyy hh:mm,Open,High,Low,Close,Volume

Gli elenchi a discesa verranno utilizzati nei parametri esterni dello script in cui gli utenti sono in grado di selezionare il formato necessario. Oltre a selezionare i formati di intestazione e data, concederemo agli utenti la possibilità di selezionare il numero dei simboli, dati su cui vogliono scrivere nei file. Per fare ciò, prepareremo tre versioni:

  • Scrivi i dati solo sul simbolo corrente, sul cui grafico (SOLO SIMBOLO CORRENTE) è stato lanciato lo script.
  • Scrivi i dati sui simboli che si trovano nella finestra Market Watch (SIMBOLI MARKET WATCH).
  • Scrivi i dati su tutti i simboli disponibili sul server (ELENCO DI TUTTI I SIMBOLI).

Inseriamo il seguente codice prima dei parametri esterni nel codice dello script per creare tali elenchi:

//_________________________________
// HEADER_FORMATS_ENUMERATION
enum FORMAT_HEADERS
  {
   NSDT_5 = 0, // "Date" "Time" "Open" "High" "Low" "Close" "Volume"
   NSDT_6 = 1  // Date,Open,High,Low,Close,Volume
  };
//---
//___________________________
// ENUMERATION_OF_DATA_FORMATS
enum FORMAT_DATETIME
  {
   SEP_POINT1 = 0, // dd.mm.yyyy hh:mm
   SEP_POINT2 = 1, // dd.mm.yyyy, hh:mm
   SEP_SLASH1 = 2, // dd/mm/yyyy hh:mm
   SEP_SLASH2 = 3  // dd/mm/yyyy, hh:mm
  };
//---
//____________________________
// ENUMERATION_OF_FILING_MODES
enum CURRENT_MARKETWATCH
  {
   CURRENT          = 0, // ONLY CURRENT SYMBOLS
   MARKETWATCH      = 1, // MARKETWATCH SYMBOLS
   ALL_LIST_SYMBOLS = 2  // ALL LIST SYMBOLS
  };

Ulteriori informazioni sulle enumerazioni sono disponibili nel Reference di MQL5.


3. Parametri esterni del programma

Ora possiamo creare l'intero elenco di tutti i parametri esterni dello script:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| EXTERNAL_PARAMETERS                                              |
//+------------------------------------------------------------------+
input datetime            start_date     = D'01.01.2011'; // Start Date
input datetime            end_date       = D'18.09.2012'; // End Date
input FORMAT_HEADERS      format_headers = NSDT_5;     // Format Headers
input FORMAT_DATETIME     format_date    = SEP_POINT2; // Format Datetime
input CURRENT_MARKETWATCH curr_mwatch    = CURRENT;    // Mode Write Symbols
input bool                clear_mwatch   = true;        // Clear Market Watch
input bool                show_progress  = true;        // Show Progress (%)

I parametri esterni vengono utilizzati per i seguenti scopi:

  • Gli utenti possono specificare un intervallo di date utilizzando i parametri data inizio (start_date) e data di fine (end_date).
  • L'elenco a discesa nel formato intestazioni (format_headers) consente agli utenti di scegliere un formato di intestazione.
  • L'elenco a discesa nel formato data/ora (format_date) consente agli utenti di scegliere i formati di data e ora.
  • L'elenco a discesa nella modalità simboli di scrittura (curr_mwatch) consente agli utenti di selezionare il numero di simboli da archiviare.
  • Se il parametro Clear Market Watch (clear_mwatch) è true, ciò consente agli utenti di eliminare tutti i simboli dalla finestra Market Watch dopo il deposito. Questo riguarda solo i simboli con i grafici che non sono attivi al momento.
  • Il parametro Show Progress (%) (show_progress) consente di visualizzare l'avanzamento del file nel pannello dati. L'archiviazione verrà eseguita più rapidamente se questo parametro è disabilitato.

Di seguito è riportato come appariranno i parametri esterni durante il lancio:

Fig.2. Parametri esterni dell'applicazione

Fig.2. Parametri esterni dell'applicazione


4. Controllo dei parametri immessi da un utente

Creiamo la funzione per il controllo dei parametri inseriti dagli utenti prima del codice di base. Ad esempio, la data di inizio nel parametro data inizio deve essere precedente a quella in data di fine. Il formato delle intestazioni deve corrispondere ai formati di data e ora. Se un utente ha commesso alcuni errori durante l'impostazione dei parametri, viene visualizzato il seguente messaggio di avviso e il programma viene arrestato.

Messaggio di avviso di esempio:

Fig.3. Avviso di valori specificati in modo errato

Fig.3. Messaggio di errore di esempio sui parametri specificati in modo errato


Funzione ValidationParameters():

//____________________________________________________________________
//+------------------------------------------------------------------+
//| CHECKING_CORRECTNESS_OF_PARAMETERS                               |
//+------------------------------------------------------------------+
bool ValidationParameters()
  {
   if(start_date>=end_date)
     {
      MessageBox("The start date should be earlier than the ending one!\n\n"
                 "Application cannot continue. Please retry.",
                 //---
                 "Parameter error!",MB_ICONERROR);
      //---
      return(true);
     }
//---
   if(format_headers==NSDT_5 && 
      (format_date==SEP_POINT1 || format_date==SEP_SLASH1))
     {
      MessageBox("For the headers of the following format:\n\n"
                 "\"Date\" ""\"Time\" ""\"Open\" ""\"High\" ""\"Low\" ""\"Close\" ""\"Volume\"\n\n"
                 "Date/time format can be selected out of two versions:\n\n"
                 "dd.mm.yyyy, hh:mm\n"
                 "dd/mm/yyyy, hh:mm\n\n"
                 "Application cannot continue. Please retry.",
                 //---
                 "Header and date/time formats do not match!",MB_ICONERROR);
      //---
      return(true);
     }
//---
   if(format_headers==NSDT_6 && 
      (format_date==SEP_POINT2 || format_date==SEP_SLASH2))
     {
      MessageBox("For the headers of the following format:\n\n"
                 "Date,Open,High,Low,Close,Volume\n\n"
                 "Date/time format can be selected out of two versions:\n\n"
                 "dd.mm.yyyy hh:mm\n"
                 "dd/mm/yyyy hh:mm\n\n"
                 "Application cannot continue. Please retry.",
                 //---
                 "Header and date/time formats do not match!",MB_ICONERROR);
      //---
      return(true);
     }
//---
   return(false);
  }


5. Variabili globali

Successivamente, dobbiamo determinare tutte le variabili globali e gli array che verranno utilizzate nello script:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| GLOBAL_VARIABLES_AND_ARRAYS                                      |
//+------------------------------------------------------------------+
MqlRates rates[]; // Array for copying data
//---
string symbols[]; // Symbol array
//---
// Array of graphic object names
string arr_nmobj[22]=
  {
   "fon","hd01",
   "nm01","nm02","nm03","nm04","nm05","nm06","nm07","nm08","nm09","nm10",
   "nm11","nm12","nm13","nm14","nm15","nm16","nm17","nm18","nm19","nm20"
  };
//---
// Array of displayed text containing graphic objects
string arr_txtobj[21];
//---
string path="";         // File path
int cnt_symb=0;         // Number of symbols
int sz_arr_symb=0;      // Symbol array size
int bars=0;             // Number of bars according to the specified TF
int copied_bars=0;      // Number of bars copied for writing
double pgs_pcnt=0;      // Writing progress
int hFl=INVALID_HANDLE;  // File handle
//---
string   // Variables for data formatting
sdt="",  // Date line
dd="",   // Day
mm="",   // Month
yyyy="", // Year
tm="",   // Time
sep="";  // Separator
//---
int max_bars=0; // Maximum number of bars in the terminal settings
//---
datetime
first_date=0,        // First available data in a specified period
first_termnl_date=0, // First available data in the terminal's database
first_server_date=0, // First available data in the server's database
check_start_date=0;  // Checked correct date value


6. Pannello informativo

Ora, dobbiamo occuparci degli elementi che devono essere visualizzati nel pannello informativo. Tre tipi di oggetti grafici possono essere utilizzati come sfondo:

  • Il più semplice e ovvio – "Etichetta rettangolare" (OBJ_RECTANGLE_LABEL).
  • Coloro che vogliono che la loro interfaccia abbia un aspetto unico possono utilizzare l'oggetto "Bitmap" (OBJ_BITMAP).
  • L'oggetto "Modifica" (OBJ_EDIT) può essere utilizzato anche come sfondo. Imposta la proprietà "sola lettura" per rimuovere la possibilità di immettere un testo. C'è anche un altro vantaggio nell'usare l'oggetto "Modifica". Se è stato creato un pannello informativo in un Expert Advisor e si desidera che abbia lo stesso aspetto durante i test in modalità di visualizzazione, l'ultimo tipo è l'unico metodo per raggiungere questo obiettivo finora. Né OBJ_RECTANGLE_LABEL né OBJ_BITMAP vengono visualizzati durante i test in modalità di visualizzazione.

Sebbene nel nostro caso venga sviluppato solo uno script anziché un Expert Advisor, lo sfondo con OBJ_EDIT oggetto verrà fatto come esempio. Il risultato è mostrato nella figura seguente:

Fig.4. Pannello informativo

Fig.4. Pannello informativo


Descriviamo tutti i dati mostrati sul pannello:

  • Symbol (corrente/totale) – simbolo i cui dati vengono scaricati/copiati/scritti al momento. Il numero sinistro tra parentesi mostra il numero di simbolo corrente. Il numero giusto mostra il numero comune di simboli con cui lo script funzionerà.
  • Path Symbol: il percorso del simbolo o la categoria a cui appartiene. Se apri il menu di scelta rapida facendo clic con il pulsante destro del mouse nella finestra Market Watch e selezioni "Simboli ...", apparirà la finestra con l'elenco di tutti i simboli. Puoi trovare ulteriori informazioni su questo nella Guida per l'utente del terminale.
  • Timeframe – periodo (intervallo di tempo). Deve essere utilizzato il periodo di tempo in cui verrà avviato lo script.
  • Input Start Date: data di inizio dei dati specificata da un utente nei parametri dello script.
  • First Date (H1) – la prima data di dati disponibile (barra) dell'intervallo di tempo corrente.
  • First Terminal Date (M1) – la prima data disponibile dell'intervallo di tempo M1 nei dati terminali già esistenti.
  • First Server Date (M1): la prima data disponibile dell'intervallo di tempo M1 sul server.
  • Max. Bars In Options Terminal – numero massimo di barre da visualizzare sul grafico specificato nelle impostazioni del terminale.
  • Copied Bars: numero di barre copiate per la scrittura.
  • Progress Value Current Symbol – valore percentuale dei dati scritti del simbolo corrente.

Di seguito è riportato il codice di tale pannello informativo:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| INFORMATION_PANEL                                                |
//|------------------------------------------------------------------+
void InfoTable(int s)
  {
   int fnt_sz=8;            // Font size
   string fnt="Calibri";     // Header font
   color clr=clrWhiteSmoke;  // Color
//---
   int xH=300;
   int height_pnl=0;
   int yV1=1,yV2=12,xV1=165,xV2=335,xV3=1;
//---
   string sf="",stf="",ssf="";
   bool flg_sf=false,flg_stf=false,flg_ssf=false;
//---
   if(show_progress) { height_pnl=138; } else { height_pnl=126; }
//---
   flg_sf=SeriesInfoInteger(symbols[s],_Period,SERIES_FIRSTDATE,first_date);
   flg_stf=SeriesInfoInteger(symbols[s],PERIOD_M1,SERIES_TERMINAL_FIRSTDATE,first_termnl_date);
   flg_ssf=SeriesInfoInteger(symbols[s],PERIOD_M1,SERIES_SERVER_FIRSTDATE,first_server_date);
//---
   if(flg_sf) { sf=TSdm(first_date); } else { sf="?"; }
   if(flg_stf) { stf=TSdm(first_termnl_date); } else { stf="?"; }
   if(flg_ssf) { ssf=TSdm(first_server_date); } else { ssf="?"; }
//---
   if(cnt_symb==0) { cnt_symb=1; }
//---
   int anchor1=ANCHOR_LEFT_UPPER,anchor2=ANCHOR_RIGHT_UPPER,corner=CORNER_LEFT_UPPER;
//---
   string path_symbol=SymbolInfoString(symbols[s],SYMBOL_PATH);
   path_symbol=StringSubstr(path_symbol,0,StringLen(path_symbol)-StringLen(symbols[s]));
//---
   arr_txtobj[0]="INFO TABLE";
   arr_txtobj[1]="Symbol (current / total) : ";
   arr_txtobj[2]=""+symbols[s]+" ("+IS(s+1)+"/"+IS(cnt_symb)+")";
   arr_txtobj[3]="Path Symbol : ";
   arr_txtobj[4]=path_symbol;
   arr_txtobj[5]="Timeframe : ";
   arr_txtobj[6]=gStrTF(_Period);
   arr_txtobj[7]="Input Start Date : ";
   arr_txtobj[8]=TSdm(start_date);
   arr_txtobj[9]="First Date (H1) : ";
   arr_txtobj[10]=sf;
   arr_txtobj[11]="First Terminal Date (M1) : ";
   arr_txtobj[12]=stf;
   arr_txtobj[13]="First Server Date (M1) : ";
   arr_txtobj[14]=ssf;
   arr_txtobj[15]="Max. Bars In Options Terminal : ";
   arr_txtobj[16]=IS(max_bars);
   arr_txtobj[17]="Copied Bars : ";
   arr_txtobj[18]=IS(copied_bars);
   arr_txtobj[19]="Progress Value Current Symbol : ";
   arr_txtobj[20]=DS(pgs_pcnt,2)+"%";
//---
   Create_Edit(0,0,arr_nmobj[0],"",corner,fnt,fnt_sz,clrDimGray,clrDimGray,345,height_pnl,xV3,yV1,2,C'15,15,15');
//---
   Create_Edit(0,0,arr_nmobj[1],arr_txtobj[0],corner,fnt,8,clrWhite,C'64,0,0',345,12,xV3,yV1,2,clrFireBrick);
//---
   Create_Label(0,arr_nmobj[2],arr_txtobj[1],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2,0);
   Create_Label(0,arr_nmobj[3],arr_txtobj[2],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2,0);
//---
   Create_Label(0,arr_nmobj[4],arr_txtobj[3],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*2,0);
   Create_Label(0,arr_nmobj[5],arr_txtobj[4],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*2,0);
//---
   Create_Label(0,arr_nmobj[6],arr_txtobj[5],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*3,0);
   Create_Label(0,arr_nmobj[7],arr_txtobj[6],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*3,0);
//---
   Create_Label(0,arr_nmobj[8],arr_txtobj[7],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*4,0);
   Create_Label(0,arr_nmobj[9],arr_txtobj[8],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*4,0);
//---
   Create_Label(0,arr_nmobj[10],arr_txtobj[9],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*5,0);
   Create_Label(0,arr_nmobj[11],arr_txtobj[10],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*5,0);
//---
   Create_Label(0,arr_nmobj[12],arr_txtobj[11],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*6,0);
   Create_Label(0,arr_nmobj[13],arr_txtobj[12],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*6,0);
//---
   Create_Label(0,arr_nmobj[14],arr_txtobj[13],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*7,0);
   Create_Label(0,arr_nmobj[15],arr_txtobj[14],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*7,0);
//---
   Create_Label(0,arr_nmobj[16],arr_txtobj[15],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*8,0);
   Create_Label(0,arr_nmobj[17],arr_txtobj[16],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*8,0);
//---
   Create_Label(0,arr_nmobj[18],arr_txtobj[17],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*9,0);
   Create_Label(0,arr_nmobj[19],arr_txtobj[18],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*9,0);
//---
   if(show_progress)
     {
      Create_Label(0,arr_nmobj[20],arr_txtobj[19],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*10,0);
      Create_Label(0,arr_nmobj[21],arr_txtobj[20],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*10,0);
     }
  }
//____________________________________________________________________
//+------------------------------------------------------------------+
//| CREATING_LABEL_OBJECT                                            |
//+------------------------------------------------------------------+
void Create_Label(long   chrt_id,   // chart id
                  string lable_nm,  // object name
                  string rename,    // displayed name
                  long   anchor,    // anchor point
                  long   corner,    // attachment corner
                  string font_bsc,  // font
                  int    font_size, // font size
                  color  font_clr,  // font color
                  int    x_dist,    // X scale coordinate
                  int    y_dist,    // Y scale coordinate
                  long   zorder)    // priority
  {
   if(ObjectCreate(chrt_id,lable_nm,OBJ_LABEL,0,0,0)) // creating object
     {
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TEXT,rename);          // set name
      ObjectSetString(chrt_id,lable_nm,OBJPROP_FONT,font_bsc);        // set font
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_COLOR,font_clr);      // set font color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ANCHOR,anchor);       // set anchor point
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_CORNER,corner);       // set attachment corner
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_FONTSIZE,font_size);  // set font size
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_XDISTANCE,x_dist);    // set X coordinates
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_YDISTANCE,y_dist);    // set Y coordinates
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_SELECTABLE,false);     // unable to highlight the object, if FALSE
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ZORDER,zorder);       // Higher/lower priority
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TOOLTIP,"\n");         // no tooltip, if "\n"
     }
  }
//____________________________________________________________________
//+------------------------------------------------------------------+
//| CREATING_EDIT_OBJECT                                             |
//+------------------------------------------------------------------+
void Create_Edit(long   chrt_id,       // chart id
                 int    nmb_win,       // window (subwindow) index
                 string lable_nm,      // object name
                 string text,          // displayed text
                 long   corner,        // attachment corner
                 string font_bsc,      // font
                 int    font_size,     // font size
                 color  font_clr,      // font color
                 color  font_clr_brd,  // font color
                 int    xsize,         // width
                 int    ysize,         // height
                 int    x_dist,        // X scale coordinate
                 int    y_dist,        // Y scale coordinate
                 long   zorder,        // priority
                 color  clr)           // background color
  {
   if(ObjectCreate(chrt_id,lable_nm,OBJ_EDIT,nmb_win,0,0)) // creating object
     {
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TEXT,text);                     // set name
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_CORNER,corner);                // set attachment corner
      ObjectSetString(chrt_id,lable_nm,OBJPROP_FONT,font_bsc);                 // set font
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ALIGN,ALIGN_CENTER);         // center alignment
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_FONTSIZE,font_size);           // set font size
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_COLOR,font_clr);               // font color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_BORDER_COLOR,font_clr_brd);    // background color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_BGCOLOR,clr);                  // background color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_XSIZE,xsize);                  // width
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_YSIZE,ysize);                  // height
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_XDISTANCE,x_dist);             // set X coordinate
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_YDISTANCE,y_dist);             // set Y coordinate
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_SELECTABLE,false);              // unable to highlight the object, if FALSE
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ZORDER,zorder);                // Higher/lower priority
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_READONLY,true);                // Read only
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TOOLTIP,"\n");                  // no tooltip if "\n"
     }
  }

Una volta completata l'operazione di script o eliminato lo script da un utente in anticipo, tutti gli oggetti grafici creati dallo script devono essere eliminati. A tal riguardo verranno utilizzate le seguenti funzioni:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| DELETE_ALL_GRAPHICAL_OBJECTS_CREATED_BY_THE_SCRIPT               |
//+------------------------------------------------------------------+
void DelAllScriptObjects()
  {
// Receive the size of graphical object names array
   int sz_arr1=ArraySize(arr_nmobj);
//---
// Delete all objects
   for(int i=0; i<sz_arr1; i++)
     { DelObjbyName(arr_nmobj[i]);  }
  }
//____________________________________________________________________
//+------------------------------------------------------------------+
//| DELETE_OBJECTS_BY_NAME                                           |
//+------------------------------------------------------------------+
int DelObjbyName(string Name)
  {
   int nm_obj=0;
   bool res=false;
//---
   nm_obj=ObjectFind(ChartID(),Name);
//---
   if(nm_obj>=0)
     {
      res=ObjectDelete(ChartID(),Name);
      //---
      if(!res) { Print("Object deletion error: - "+ErrorDesc(Error())+""); return(false); }
     }
//---
   return(res);
  }


7. Blocco principale dell'applicazione

La funzione principale degli script è OnStart(). Questa è la funzione utilizzata per chiamare tutte le altre funzioni per l'esecuzione. I dettagli del funzionamento del programma sono mostrati nel codice:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| SCRIPT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |
//+------------------------------------------------------------------+
void OnStart()
  {
// If user-defined parameters are incorrect,
// error message is shown and the program is closed
   if(ValidationParameters()) { return; }
//---
   max_bars=TerminalInfoInteger(TERMINAL_MAXBARS); // Receive available number of bars in the window
//---
   GetSymbolsToArray();           // Filling symbol array with names
   sz_arr_symb=ArraySize(symbols); // Receive symbol array size
//---
   SetSeparateForFormatDate();    // Set a separator for date format
//---
// Revise all symbols and write their data to file
   for(int s=0; s<=sz_arr_symb-1; s++)
     {
      copied_bars=0; // Reset copied bars variable to zero for writing
      pgs_pcnt=0.0;  // Reset variable of the symbol data writing progress 
      //---
      InfoTable(s); ChartRedraw();
      //---
      // Receive current symbol data
      int res=GetDataCurrentSymbol(s);
      //---
      if(res==0) { BC } // If zero, break the loop or start the next iteration
      //---
      if(res==2)        // Program operation interrupted by user
        {
         DelAllScriptObjects(); // Deleted objects created by the script from the chart
         //---
         Print("------\nUser deleted the script!"); break;
        }
      //---
      // Receive the path for creating the file and create directories for them
      // If the string is empty, break the loop or start the next iteration
      if((path=CheckCreateGetPath(s))=="") { BC }
      //---
      WriteDataToFile(s); // Write data to file
     }
//---
// Delete symbols from Market Watch window if necessary
   DelSymbolsFromMarketWatch();
//---
// Delete objects created by the script from the chart
   Sleep(1000); DelAllScriptObjects();
  }

Esaminiamo le funzioni in cui si svolgono le attività chiave.

L’array di simboli (symbols[]) è riempita con i nomi dei simboli nella funzione GetSymbolsToArray(). La dimensione dell’array e il numero di simboli in essa contenuti dipendono dalla variante scelta da un utente nel parametro Mode Write Symbols (curr_mwatch).

Se un utente deve disporre di dati da un solo simbolo, la dimensione dell’array è uguale a 1.

ArrayResize(symbols,1); // Set the array size to be equal to 1
symbols[0]=_Symbol;     // Specify the current symbol's name

Se un utente desidera ricevere i dati su tutti i simboli dalla finestra Market Watch o tutti i simboli disponibili, la dimensione dell’array verrà definita dalla seguente funzione:

int SymbolsTotal(
   bool selected   // true – only MarketWatch symbols
);

Per evitare la creazione di due blocchi per due varianti con codice quasi identico, faremo in modo che MWatchOrAllList() funzioni di puntamento, il che restituirà true o false. Questo valore definisce da dove deve essere preso l'elenco dei simboli: solo dalla finestra Market Watch (true) o dall'elenco comune dei simboli disponibili (false).

//____________________________________________________________________
//+------------------------------------------------------------------+
//| POINTER_TO_MARKET_WATCH_WINDOW_OR_TO_COMMON_LIST                 |
//+------------------------------------------------------------------+
bool MWatchOrAllList()
  {
   if(curr_mwatch==MARKETWATCH) { return(true); }
   if(curr_mwatch==ALL_LIST_SYMBOLS) { return(false); }
//---
   return(true);
  }

Dopo aver ottenuto il numero di simboli nel ciclo, dobbiamo esaminare l'intero elenco e inserire il nome del simbolo nell'array ad ogni iterazione aumentando la dimensione dell'array di uno. Il nome del simbolo, a sua volta, è ottenuto dal numero di indice utilizzando la funzione SymbolName().

int SymbolName(
   int pos,        // list index number
   bool selected   // true – only MarketWatch symbols
);

La funzione puntatore MWatchOrAllList() viene utilizzata anche nella funzione SymbolName() per selezionare l'elenco dei simboli. Codice completo della funzione GetSymbolsToArray():

//____________________________________________________________________
//+------------------------------------------------------------------+
//| FILLING_SYMBOL_ARRAY_WITH_NAMES                                  |
//+------------------------------------------------------------------+
void GetSymbolsToArray()
  {
// If only the current symbol data is required
   if(curr_mwatch==CURRENT)
     { ArrayResize(symbols,1); symbols[0]=_Symbol; }
//---
// If data on all symbols  from Market Watch window or
// or the entire symbol list is required
   if(curr_mwatch==MARKETWATCH || curr_mwatch==ALL_LIST_SYMBOLS)
     {
      // Receive the number of symbols in Market Watch window
      cnt_symb=SymbolsTotal(MWatchOrAllList());
      //---
      for(int i=0; i<=cnt_symb-1; i++)
        {
         string nm_symb="";
         //---
         ArrayResize(symbols,i+1); // Increase the array size by one once again
         //---
         // Receive a name of a symbol from Market Watch window
         nm_symb=SymbolName(i,MWatchOrAllList());
         symbols[i]=nm_symb; // Put the symbol name into the array
        }
     }
  }

La funzione SetSeparateForFormatDate() è molto semplice. Viene utilizzata per definire il tipo di separatore che verrà utilizzato nella data a seconda della scelta dell'utente nell'elenco a discesa del parametro Format Date (format_date).

//____________________________________________________________________
//+------------------------------------------------------------------+
//| DEFINING_SEPARATOR_FOR_DATE_FORMAT                               |
//+------------------------------------------------------------------+
void SetSeparateForFormatDate()
  {
   switch(format_date)
     {
      case SEP_POINT1 : case SEP_POINT2 : sep="."; break; // Full point as a separator
      case SEP_SLASH1 : case SEP_SLASH2 : sep="/"; break; // Slash as a separator
     }
  }

Il ciclo di base con vari controlli viene dopo. Se tutti i controlli hanno esito positivo, i dati vengono scritti nel file. In caso contrario, il ciclo viene interrotto, tutti gli oggetti vengono eliminati dal grafico e lo script viene rimosso (nel caso di un simbolo) o viene avviata l'iterazione successiva (nel caso di più di un simbolo). Ogni simbolo di array symbols[] viene costantemente chiamato nel ciclo. Il numero di indice viene inviato a ciascuna funzione del ciclo. Pertanto, la sequenza accurata in tutte le funzioni viene preservata.

I dati sul simbolo corrente nel ciclo vengono ricevuti a ogni iterazione all'inizio del corpo del ciclo. La funzione GetDataCurrentSymbol() viene utilizzata a tal proposito. Vediamo cosa succede in questa funzione.

La disponibilità dei dati viene verificata utilizzando la funzione CheckLoadHistory() prima di copiare i dati dei simboli nell’array rate[]. Questa funzione è fornita dagli sviluppatori come esempio. La sua versione iniziale può essere trovata nel Reference di MQL5. Ho apportato solo lievi correzioni per l'utilizzo in questo script. Il riferimento contiene una descrizione dettagliata (sarebbe una buona idea studiarlo), quindi non ho intenzione di visualizzare la mia versione qui in quanto è quasi la stessa. Inoltre, può essere trovata nel codice con commenti dettagliati.

L'unica cosa da menzionare ora è che la funzione CheckLoadHistory() restituisce l'errore o il codice di esecuzione riuscito, in base al quale il messaggio appropriato dal blocco dell'operatore dello switch viene salvato nel journal. In base al codice ricevuto, la funzione GetDataCurrentSymbol() continua con il suo funzionamento o restituisce il suo codice.

Se tutto va bene, i dati della cronologia vengono copiati utilizzando la funzione CopyRates(). La dimensione della matrice viene salvata nella variabile globale. Quindi viene eseguita l'uscita dalla funzione accompagnata dalla restituzione del codice 1. Se qualcosa va storto, la funzione interrompe il suo funzionamento nell'operatore dello switch e restituisce il codice 0 o 2.

//____________________________________________________________________
//+------------------------------------------------------------------+
//| RECEIVE_SYMBOL_DATA                                              |
//+------------------------------------------------------------------+
int GetDataCurrentSymbol(int s)
  {
   Print("------\n№"+IS(s+1)+" >>>"); // Save a symbol number in the journal
//---
// Check and download the necessary amount of requested data
   int res=CheckLoadHistory(s,_Period);
//---
   InfoTable(s); ChartRedraw(); // Update the data in the data table
//---
   switch(res)
     {
      case -1 : Print("Unknown symbol "+symbols[s]+" (code: -1)!");                        return(0);
      case -2 :
         Print("Number of requested bars exceeds the maximum number that can be displayed on a chart (code: -2)!...\n"
               "...The available amount of data will be used for writing.");                break;
      //---
      case -3 : Print("Execution interrupted by user (code: -3)!");                         return(2);
      case -4 : Print("Download failed (code: -4)!");                                      return(0);
      case  0 : Print("All symbol data downloaded (code: 0).");                             break;
      case  1 : Print("Time series data is sufficient (code: 1).");                          break;
      case  2 : Print("Time series created based on existing terminal data (code: 2).");      break;
      //---
      default : Print("Execution result is not defined!");
     }
//---
// Copy data to the array
   if(CopyRates(symbols[s],_Period,check_start_date,end_date,rates)<=0)
     { Print("Error when copying symbol data "+symbols[s]+" - ",ErrorDesc(Error())+""); return(0); }
   else
     {
      copied_bars=ArraySize(rates); // Receive array size
      //---
      Print("Symbol: ",symbols[s],"; Timeframe: ",gStrTF(_Period),"; Copied bars: ",copied_bars);
     }
//---
   return(1); // Return 1, if all is well
  }

Successivamente, il programma si trova nuovamente nel corpo del ciclo principale della funzione OnStart(). Il codice viene assegnato dalla variabile locale res e il controllo viene eseguito in base al suo valore. Il valore zero sta per un errore. Significa che i dati del simbolo corrente nel ciclo non possono essere scritti. La spiegazione dell'errore è stata salvata nel journal e viene presa la decisione se il ciclo deve essere interrotto (interruzione) o se deve essere avviata l'iterazione successiva (continua).

if(res==0) { BC } // If zero, the loop is interrupted or the next iteration starts

La riga di codice sopra mostra che questa selezione viene eseguita da alcuni misteriosi personaggi BC. Questa è una macro espansione. Ulteriori informazioni a riguardo sono disponibili nel Reference di MQL5. L'unica cosa che deve essere menzionata qui è che le espressioni intere (digitate in una riga) possono essere incollate in una voce breve come mostrato nell'esempio precedente (BC). In alcuni casi, questo metodo può essere ancora più conveniente e compatto di una funzione. Nel caso corrente, questo appare come segue:

// Macro expansion with further action selection
#define BC if(curr_mwatch==CURRENT) { break; } if(curr_mwatch==MARKETWATCH || curr_mwatch==ALL_LIST_SYMBOLS) { continue; }

Di seguito sono riportati altri esempi di espansioni macro utilizzate in questo script:

#define nmf __FUNCTION__+": " // Macro expansion of the function name before sending the message to the journal
//---
#define TRM_DP TerminalInfoString(TERMINAL_DATA_PATH) // Folder for storing the terminal data

Se GetDataCurrentSymbol() restituisce 2, il programma è stato eliminato da un utente. MQL5 ha la funzione IsStopped() per identificare questo evento. Questa funzione può essere molto utile nei loop per interrompere il funzionamento del programma correttamente e nel tempo. Se la funzione restituisce true, ci sono circa tre secondi per eseguire tutte le azioni prima che il programma venga eliminato forzatamente. Nel nostro caso, tutti gli oggetti grafici vengono rimossi e il messaggio viene inviato al journal:

if(res==2) // Program execution interrupted by user
   {
    DelAllScriptObjects(); // Delete all objects created by the script from the chart
    //---
    Print("------\nUser deleted the script!"); break;
   }


8. Creazione di cartelle e archiviazione dei dati

La funzione CheckCreateGetPath() controlla la presenza della cartella dei dati radice. Chiamiamolo DATA_OHLC e mettiamolo in C: \ Metatrader 5 \ MQL5 \ Files. Conterrà cartelle con i nomi dei simboli. I file per la scrittura dei dati verranno creati lì.

Se la cartella principale o la cartella per il simbolo corrente nel ciclo non esiste, la funzione la crea. Se tutto va bene, la funzione restituisce una stringa contenente il percorso per la creazione di un file. La funzione restituisce una stringa vuota in caso di errore o tentativo di eliminare il programma dal grafico eseguito da un utente.

Il codice seguente contiene commenti dettagliati che lo rendono facile da capire:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| CHECK_DIRECTORY_AND_CREATE_NECESSARY_DATA_FOLDERS                |
//+------------------------------------------------------------------+
string CheckCreateGetPath(int s)
  {
   int i=1;
   long search=-1;
   string ffname="",lpath="";
   string file="*.csv",folder="*";
   string
   root="DATA_OHLC\\",         // Root data folder
   fSmb=symbols[s]+"\\",     // Symbol name
   fTF=gStrTF(_Period)+"\\"; // Symbol time frame
//---
   bool flgROOT=false,flgSYMBOL=false;
//---
//+------------------------------------------------------------------+
//| SEARCHING_FOR_DATA_OHLC_ROOT_FOLDER                              |
//+------------------------------------------------------------------+
   lpath=folder;
   search=FileFindFirst(lpath,ffname); // Set search handle in Metatrader 5\MQL5\Files
//---
   Print("Directory: ",TRM_DP+"\\MQL5\\Files\\");
//---
// Set the flag if the first folder is a root one
   if(ffname==root)
     { flgROOT=true; Print("Root folder "+root+" present"); }
//---
   if(search!=INVALID_HANDLE) // If search handle received
     {
      if(!flgROOT) // If the first folder is not a root one
        {
         // Sort out all files searching for the root folder
         while(FileFindNext(search,ffname))
           {
            if(IsStopped()) // Execution interrupted by user
              {
               // Delete objects created by the script from the chart
               DelAllScriptObjects();
               //---
               Print("------\nUser deleted the script!"); return("");
              }
            //---
            if(ffname==root) // Set the flag if found
              { flgROOT=true; Print("Root folder "+root+" present"); break; }
           }
        }
      //---
      FileFindClose(search); search=-1; // Close root folder search handle
     }
   else { Print("Error when receiving the search handle or directory "+TRM_DP+" is empty: ",ErrorDesc(Error())); }
//---
//+------------------------------------------------------------------+
//| SEARCHING_SYMBOL_FOLDER                                          |
//+------------------------------------------------------------------+
   lpath=root+folder;
//---
// Set search handle in the root folder ..\Files\DATA OHLC\
   search=FileFindFirst(lpath,ffname);
//---
// Set the flag if the first folder of the current symbol
   if(ffname==fSmb) { flgSYMBOL=true; Print("Symbol folder "+fSmb+" present"); }
//---
   if(search!=INVALID_HANDLE) // If search handle is received
     {
      if(!flgSYMBOL) // If the first folder is not of the current symbol
        {
         // Sort out all the files in the root folder searching the symbol folder
         while(FileFindNext(search,ffname))
           {
            if(IsStopped()) // Execution interrupted by user
              {
               // Delete objects created by the script from the chart
               DelAllScriptObjects();
               //---
               Print("------\nUser deleted the script!"); return("");
              }
            //---
            if(ffname==fSmb) // Set the flag if found
              { flgSYMBOL=true; Print("Symbol folder"+fSmb+" present"); break; }
           }
        }
      //---
      FileFindClose(search); search=-1; // Close symbol folder search handle
     }
   else { Print("Error when receiving search handle or the directory "+path+" is empty"); }
//---
//+------------------------------------------------------------------+
//| CREATE_NECESSARY_DIRECTORIES_ACCORDING_TO_CHECK_RESULTS          |
//+------------------------------------------------------------------+
   if(!flgROOT) // If there is no DATA_OHLC... root folder
     {
      if(FolderCreate("DATA_OHLC")) // ...we should create it
        { Print("..\DATA_OHLC\\ root folder created"); }
      else
        { Print("Error when creating DATA_OHLC: root folder",ErrorDesc(Error())); return(""); }
     }
//---
   if(!flgSYMBOL) // If there is no folder of the symbol, the values of which should be received...
     {
      if(FolderCreate(root+symbols[s])) // ...we should create it
        {
         Print("..\DATA_OHLC\\" symbol folder created+fSmb+"");
         //---
         return(root+symbols[s]+"\\"); // Return the path for creating the file for writing
        }
      else
        { Print("Error when creating ..\DATA_OHLC\\ symbol folder"+fSmb+"\: ",ErrorDesc(Error())); return(""); }
     }
//---
   if(flgROOT && flgSYMBOL)
     {
      return(root+symbols[s]+"\\"); // Return the path for creating the file for writing
     }
//---
   return("");
  }

Se la funzione CheckCreateGetPath() restituisce una riga vuota, il ciclo viene interrotto o l'iterazione successiva inizia utilizzando l'espansione macro (BC) già familiare:

// Receive the path for creating a file and create directories for them
// If the line is empty, the loop is interrupted or the next iteration starts
if((path=CheckCreateGetPath(s))=="") { BC }

Se si è raggiunta questa fase, significa che i dati sono stati copiati correttamente e la variabile della stringa di percorso contiene il percorso per la creazione del file per la scrittura dei dati del simbolo corrente nel ciclo.

Creare la funzione WriteDataToFile() per scrivere dati nel file. [Path]+[file name] viene generato all'inizio della funzione. Il nome di un file è costituito da un nome di simbolo e dall'intervallo di tempo corrente. Ad esempio, EURUSD_H1.csv. Se il file con tale nome è già presente, viene aperto per la scrittura. I dati scritti in precedenza verranno cancellati. I nuovi dati verranno invece scritti in esso. Se il file viene creato/aperto correttamente, la funzione FileOpen() restituisce l'handle che verrà utilizzato per accedere al file.

Controllo dell’handle. Se è presente, viene scritta la riga di intestazione. La riga appropriata verrà scritta in base alle intestazioni selezionate da un utente. Il ciclo principale di scrittura dei dati cronologici inizia in seguito.

Prima di scrivere la riga successiva, deve essere convertita nel formato specificato dall'utente. Per fare ciò, dobbiamo ricevere l'ora di apertura della barra e ordinare giorno, mese, anno e ora separatamente per variabili usando la funzione StringSubstr(). Poi dobbiamo definire se la data e l'ora si troveranno in una colonna singola o separata a seconda del formato specificato dall'utente. Quindi tutte le parti vengono unite in un'unica riga utilizzando la funzione StringConcatenate(). Dopo aver scritto tutte le righe, il file viene chiuso dalla funzione FileClose().

L'intero codice della funzione WriteDataToFile() è mostrato di seguito:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| WRITE_DATA_TO_FILE                                               |
//+------------------------------------------------------------------+
void WriteDataToFile(int s)
  {
// Number of decimal places in the symbol price
   int dgt=(int)SymbolInfoInteger(symbols[s],SYMBOL_DIGITS);
//---
   string nm_fl=path+symbols[s]+"_"+gStrTF(_Period)+".csv"; // File name
//---
// Receive file handle for writing
   hFl=FileOpen(nm_fl,FILE_WRITE|FILE_CSV|FILE_ANSI,',');
//---
   if(hFl>0) // If the handle is received
     {
      // Write the headers
      if(format_headers==NSDT_5)
        { FileWrite(hFl,"\"Date\" ""\"Time\" ""\"Open\" ""\"High\" ""\"Low\" ""\"Close\" ""\"Volume\""); }
      //---
      if(format_headers==NSDT_6)
        { FileWrite(hFl,"Date","Open","High","Low","Close","Volume"); }
      //---
      // Write the data
      for(int i=0; i<=copied_bars-1; i++)
        {
         if(IsStopped()) // If program execution interrupted by a user
           {
            DelAllScriptObjects(); // Delete objects created by the script from the chart
            //---
            Print("------\nUser deleted the script!"); break;
           }
         //---
         sdt=TSdm(rates[i].time); // Bar open time
         //---
         // Divide the date by year, month and time
         yyyy=StringSubstr(sdt,0,4);
         mm=StringSubstr(sdt,5,2);
         dd=StringSubstr(sdt,8,2);
         tm=StringSubstr(sdt,11);
         //---
         string sep_dt_tm=""; // Separator of Date and Time columns
         //---
         // Join the data with the separator in the necessary order
         if(format_date==SEP_POINT1 || format_date==SEP_SLASH1) { sep_dt_tm=" "; }
         if(format_date==SEP_POINT2 || format_date==SEP_SLASH2) { sep_dt_tm=","; }
         //---
         // Join everything in one line
         StringConcatenate(sdt,dd,sep,mm,sep,yyyy,sep_dt_tm,tm);
         //---
         FileWrite(hFl,
                   sdt,// Date-time
                   DS_dgt(rates[i].open,dgt),      // Open price
                   DS_dgt(rates[i].high,dgt),      // High price
                   DS_dgt(rates[i].low,dgt),       // Low price
                   DS_dgt(rates[i].close,dgt),     // Close price
                   IS((int)rates[i].tick_volume)); // Tick volume price
         //---
         // Update writing progress value for the current symbol
         pgs_pcnt=((double)(i+1)/copied_bars)*100;
         //---
         // Update data in the table
         InfoTable(s); if(show_progress) { ChartRedraw(); }
        }
      //---
      FileClose(hFl); // Close the file
     }
   else { Print("Error when creating/opening file!"); }
  }

Questa è stata l'ultima funzione nel ciclo di base della funzione OnStart(). Se non fosse stato l'ultimo simbolo, allora tutto sarebbe stato ripetuto per il prossimo. In caso contrario, il ciclo viene interrotto. Se l'utente ha specificato di cancellare l'elenco dei simboli nella finestra Market Watch nei parametri dello script, i simboli con grafici attualmente non attivi verranno eliminati dalla funzione DelSymbolsFromMarketWatch(). Successivamente, tutti gli oggetti grafici creati dallo script vengono eliminati e il programma si interrompe. I dati sono pronti per l'uso.

I dettagli su come scaricare i dati su NeuroShell DayTrader Professional possono essere trovati nel mio blog. Di seguito è riportato il video che mostra l'operazione di script:



Conclusione

Qualunque sia il programma che ho usato per sviluppare strategie di trading, ho sempre raggiunto alcune limitazioni che mi impediscono di sviluppare ulteriormente le mie idee. Alla fine, mi sono reso conto che la programmazione è essenziale qui. MQL5 è la soluzione migliore per chi vuole davvero avere successo. Tuttavia, altri programmi per l'analisi dei dati e lo sviluppo di strategie di trading possono anche essere utili quando si cercano nuove idee. Mi ci sarebbe voluto molto più tempo per trovarli, se avessi usato un solo strumento.

Buona Fortuna!

Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/502

File allegati |
writedatatofile.mq5 (68.96 KB)
Comunicare con MetaTrader 5 utilizzando pipe denominate senza utilizzare DLL Comunicare con MetaTrader 5 utilizzando pipe denominate senza utilizzare DLL
Molti sviluppatori affrontano lo stesso problema: come accedere alla sandbox del terminale di trading senza utilizzare DLL non sicure. Uno dei metodi più semplici e sicuri consiste nell'utilizzare pipe denominate standard che funzionano come normali operazioni sui file. Consentono di organizzare la comunicazione client-server interprocessore tra i programmi. Dai un'occhiata agli esempi pratici in C++ e MQL5 che includono server, client, scambio di dati tra loro e benchmark delle prestazioni.
Come acquistare un robot di trading dal Market MetaTrader e installarlo? Come acquistare un robot di trading dal Market MetaTrader e installarlo?
Un prodotto del Market MetaTrader può essere acquistato sul sito MQL5.com o direttamente dalle piattaforme di trading MetaTrader 4 e MetaTrader 5. Scegli il prodotto che desideri e che si adatta al tuo stile di trading, pagalo utilizzando il tuo metodo di pagamento preferito e attiva il prodotto.
Come abbonarsi ai segnali di trading Come abbonarsi ai segnali di trading
Il servizio Segnali introduce il social trading con MetaTrader 4 e MetaTrader 5. Il servizio è integrato nella piattaforma di trading e consente a chiunque di copiare facilmente le operazioni di trader professionisti. Seleziona una delle migliaia di fornitori di segnali, iscriviti in pochi clic e le operazioni del fornitore verranno copiate sul tuo account.
Reti neurali: dalla teoria alla pratica Reti neurali: dalla teoria alla pratica
Al giorno d'oggi, ogni trader deve aver sentito parlare delle reti neurali e sa quanto sia bello usarle. La maggioranza crede che coloro che possono occuparsi delle reti neurali siano una sorta di super umani. In questo articolo cercherò di spiegarti l'architettura della rete neurale, descriverne le applicazioni e mostrare esempi di utilizzo pratico.