English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Comment préparer des cotations MetaTrader 5 pour d'autres applications

Comment préparer des cotations MetaTrader 5 pour d'autres applications

MetaTrader 5Exemples | 12 janvier 2022, 17:20
599 0
Anatoli Kazharski
Anatoli Kazharski

Contenu

Introduction
1. Sujets couverts
2. Format des données
3. Paramètres externes du programme
4. Vérification des paramètres entrés par un utilisateur
5. Variables globales
6. Panneau d'information
7. Bloc principal de l'application
8. Création de dossiers et classement des données
Conclusion


Introduction

Avant de commencer à étudier MQL5, j'ai essayé de nombreuses autres applications pour le développement de systèmes de trading. Je ne peux pas dire que j'ai perdu mon temps. Certains d'entre eux contiennent quelques outils utiles permettant aux utilisateurs de gagner du temps, de traiter de nombreux problèmes, de détruire certains mythes et de sélectionner rapidement une autre direction de développement sans connaître les langages de programmation.

Ces applications ont besoin de données historiques. En raison de l'absence d'un certain format de données standard, elles ont souvent dû être modifiées avant d'être utilisées (par exemple, dans Excel) pour se conformer au format applicable au programme nécessaire. Même si vous êtes en mesure de régler tous les détails nécessaires, de nombreuses choses doivent encore être effectuées manuellement. Les utilisateurs peuvent trouver différentes versions de scripts conçus pour copier les cotations de MetaTrader 4 au format nécessaire. S'il y a une telle demande, nous pouvons également développer la version du script pour MQL5.


1. Sujets couverts

L'article traite des sujets suivants :

  • Travailler avec la liste de symboles dans la fenêtre Market Watch et la liste de symboles commune sur le serveur.
  • Vérification de la profondeur des données disponibles et téléchargement de la quantité manquante si nécessaire avec une gestion correcte des différentes situations.
  • Affichage d'informations sur les données demandées sur le graphique de panneau personnalisé et le journal.
  • Préparation des données pour le classement dans un format défini par l'utilisateur.
  • Création de répertoires de fichiers.
  • Archivage des données.


2. Format des données

Je vais donner un exemple de préparation des données destinées à être utilisées dans NeuroShell DayTrader Professional (NSDT). J'ai essayé les versions 5 et 6 du NSDT et j'ai découvert qu'elles avaient des exigences différentes en matière de format de données. Les données de date et d'heure de la version 5 de NSDT doivent être dans des colonnes différentes. La première ligne du fichier doit avoir l'aspect suivant :

« Date » « Heure » « Ouvrir » « Élevé » « Bas » « Fermer » « Volume »

La ligne d'en-tête dans NSDT version 6 doit avoir un aspect différent pour permettre à l'application d'accepter un fichier. Cela signifie que la date et l'heure doivent figurer dans la même colonne :

Date, Ouvrir, Haut, Bas, Fermer, Volume

MetaTrader 5 permet aux utilisateurs d'enregistrer les cotations dans des fichiers *.csv. Les données d'un fichier se présentent comme suit :

Fig. 1. Données enregistrées par le terminal MetaTrader 5

Fig. 1. Données enregistrées par le terminal MetaTrader 5


Cependant, nous ne pouvons pas simplement modifier la ligne d'en-tête car la date doit avoir un autre format. Pour NSDT v.5 :

jj.mm.aaaa,hh:mm,Ouvert,Haut,Bas,Ferme,Volume
Pour NSDT v.6 :
jj/mm/aaaa hh:mm,Ouvert,Haut,Bas,Ferme,Volume

Des listes déroulantes seront utilisées dans les paramètres externes du script où les utilisateurs pourront sélectionner le format nécessaire. Outre la sélection des formats d'en-tête et de date, nous donnerons aux utilisateurs la possibilité de sélectionner le nombre de symboles, données sur lesquelles ils veulent écrire dans les fichiers. Pour ce faire, nous allons préparer trois versions :

  • Ecrire les données sur le symbole courant uniquement, sur le graphique duquel le script (ONLY CURRENT SYMBOL) a été lancé.
  • Écrire les données sur les symboles situés dans la fenêtre Market Watch (MARKETWATCH SYMBOLS).
  • Ecrire les données sur tous les symboles disponibles sur le serveur (ALL LIST SYMBOLS).

Entrons le code suivant avant les paramètres externes dans le code du script pour créer de telles listes :

//_________________________________
// 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
  };

Plus d'informations sur les énumérations peuvent être trouvées dans la référence MQL5.


3. Paramètres externes du programme

Maintenant, nous pouvons créer la liste complète de tous les paramètres externes du 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 (%)

Les paramètres externes sont utilisés aux fins suivantes :

  • Les utilisateurs peuvent spécifier un intervalle de dates à l'aide des paramètres Date de début (start_date) et Date de fin (end_date).
  • La liste déroulante Format Headers (format_headers) permet aux utilisateurs de choisir un format d'en-tête.
  • La liste déroulante Format Datetime (format_date) permet aux utilisateurs de choisir les formats de date et d'heure.
  • La liste déroulante Mode Write Symbols (curr_mwatch) permet aux utilisateurs de sélectionner le nombre de symboles à classer.
  • Si le paramètre Clear Market Watch (clear_mwatch) est vrai, cela permet aux utilisateurs de supprimer tous les symboles de la fenêtre Market Watch après le dépôt. Cela ne concerne que les symboles avec les graphiques qui ne sont pas actifs pour le moment.
  • Le paramètre Show Progress (%) (show_progress) affiche la progression du classement dans l'écran de contrôle. L'archivage sera effectué plus rapidement si ce paramètre est désactivé.

Voici comment se présenteront les paramètres externes lors du lancement :

Fig. 2. Paramètres externes de l'application

Fig. 2. Paramètres externes de l'application


4. Vérification des paramètres entrés par un utilisateur

Créons la fonction de vérification des paramètres saisis par les utilisateurs avant le code de base. Par exemple, la date de début dans le paramètre Date de début doit être antérieure à celle de Date de fin. Le format des en-têtes doit correspondre aux formats de date et d'heure. Si un utilisateur a commis des erreurs lors du réglage des paramètres, le message d'avertissement suivant s'affiche et le programme est arrêté.

Exemple de message d'avertissement :

Fig. 3. Avertissement de valeurs incorrectement spécifiées

Fig. 3. Exemple de message d'erreur sur des paramètres incorrectement spécifiés


Fonction 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. Variables Globales

Ensuite, nous devons déterminer toutes les variables globales et les tableaux qui seront utilisés dans le 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. Panneau d'information

Maintenant, nous devons traiter les éléments qui doivent être affichés dans le panneau d'information. Trois types d'objets graphiques peuvent être utilisés comme arrière-plan :

  • Le plus simple et le plus évident - « Etiquette rectangle » (OBJ_RECTANGLE_LABEL).
  • Ceux qui veulent que leur interface ait un aspect unique peuvent utiliser l'objet « Bitmap » (OBJ_BITMAP).
  • L'objet « Editer » (OBJ_EDIT) peut également être utilisé comme arrière-plan. Définissez la propriété « lecture seule » pour supprimer la possibilité de saisir un texte. L'utilisation de l'objet « Modifier » présente également un autre avantage. Si vous avez créé un panneau d'information dans un Expert Advisor et que vous souhaitez qu'il ait le même aspect lors des tests en mode visualisation, le dernier type est la seule méthode pour y parvenir jusqu'à présent. Ni OBJ_RECTANGLE_LABEL, ni OBJ_BITMAP ne sont affichés lors des tests en mode visualisation.

Bien que nous ne développions qu'un script au lieu d'un Expert Advisor dans notre cas, l'arrière-plan avec l'objet OBJ_EDIT servira d'exemple. Le résultat est montré sur la figure ci-dessous :

Fig. 4. Panneau d'information

Fig. 4. Panneau d'information


Décrivons toutes les données affichées sur le panneau :

  • Symbole (actuel/total) – symbole dont les données sont actuellement téléchargées/copiées/écrites. Le nombre de gauche entre parenthèses indique le numéro de symbole actuel. Le chiffre de droite indique le nombre commun de symboles avec lesquels le script va travailler.
  • Symbole du chemin - symbole du chemin ou de la catégorie à laquelle il appartient. Si vous affichez le menu contextuel en cliquant avec le bouton droit dans la fenêtre Market Watch et sélectionnez « Symboles… », la fenêtre avec la liste de tous les symboles apparaîtra. Vous trouverez plus d'informations à ce sujet dans le guide de l'utilisateur du terminal.
  • Délai – période (délai). Le délai auquel le script sera lancé doit être utilisé.
  • Date de début d'entrée – date de début des données spécifiée par un utilisateur dans les paramètres de script.
  • Première date (H1) – la première date de données disponible (barre) de la période actuelle.
  • Première date de terminal (M1) - la première date disponible de la période M1 dans les données de terminal déjà existantes.
  • Date du premier serveur (M1) - la première date disponible de la période M1 sur le serveur.
  • Max. Barres dans le terminal d'options – nombre maximal de barres à afficher sur le graphique spécifié dans les paramètres du terminal.
  • Barres copiées – nombre de barres copiées pour l'écriture.
  • Valeur de progression Symbole actuel – valeur en pourcentage des données écrites du symbole actuel.

Vous trouverez ci-dessous le code de ce panneau d'information :

//____________________________________________________________________
//+------------------------------------------------------------------+
//| 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"
     }
  }

Une fois que l'opération du script est terminée ou que le script est supprimé par un utilisateur à l'avance, tous les objets graphiques créés par le script doivent être supprimés. Les fonctions suivantes seront utilisées pour cela :

//____________________________________________________________________
//+------------------------------------------------------------------+
//| 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. Bloc principal de l'application

La fonction principale des scripts est OnStart(). Il s'agit de la fonction utilisée pour appeler toutes les autres fonctions en vue de leur exécution. Les détails du fonctionnement du programme sont indiqués dans le code :

//____________________________________________________________________
//+------------------------------------------------------------------+
//| 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();
  }

Examinons les fonctions où se déroulent les activités clés.

Le tableau de symboles (symbols[]) est rempli de noms de symboles dans la fonction GetSymbolsToArray(). La taille du tableau, ainsi que le nombre de symboles qu'il contient, dépendent de la variante choisie par l'utilisateur dans le paramètre Mode Write Symbols (curr_mwatch).

Si un utilisateur ne doit disposer que des données d'un seul symbole, la taille du tableau est égale à 1.

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

Si un utilisateur souhaite recevoir les données sur tous les symboles de la fenêtre Market Watch ou tous les symboles disponibles, la taille du tableau sera définie par la fonction suivante :

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

Pour éviter la création de deux blocs pour deux variantes avec un code presque identique, nous allons faire fonction pointeur MWatchOrAllList(), qui retournera vrai ou faux. Cette valeur définit l'endroit d'où la liste des symboles doit être extraite - uniquement de la fenêtre Market Watch (true) ou de la liste commune des symboles disponibles (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);
  }

Après avoir obtenu le nombre de symboles dans la boucle, nous devons parcourir toute la liste et placer le nom du symbole dans le tableau à chaque itération en augmentant la taille du tableau d'une unité. Le nom du symbole, à son tour, est obtenu par le numéro d'index à l'aide de la fonction SymbolName().

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

La fonction de pointeur MWatchOrAllList() est également utilisée dans la fonction SymbolName() pour sélectionner la liste de symboles. Code complet de la fonction 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 fonction SetSeparateForFormatDate() est très simple. Elle est utilisée pour définir le type de séparateur qui sera utilisé dans la date en fonction du choix de l'utilisateur dans la liste déroulante du paramètre 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
     }
  }

La boucle de base avec divers contrôles vient ensuite. Si toutes les vérifications sont réussies, les données sont écrites dans le fichier. Sinon, la boucle est interrompue, tous les objets sont supprimés du graphique et le script est supprimé (dans le cas d'un symbole) ou l'itération suivante commence (dans le cas de plusieurs symboles). Chaque symbole du tableau symbols[] est systématiquement appelé dans la boucle. Le numéro d'index est envoyé à chaque fonction de la boucle. Ainsi, la séquence précise de toutes les fonctions est préservée.

Les données sur le symbole actuel dans la boucle sont reçues à chaque itération au tout début du corps de la boucle. La fonction GetDataCurrentSymbol() est utilisée pour cela. Voyons ce qui se passe dans cette fonction.

La disponibilité des données est vérifiée à l'aide de la fonction CheckLoadHistory() avant de copier les données de symboles dans le tableau rate[]. Cette fonction est fournie par les développeurs à titre d'exemple. Sa version initiale se trouve dans MQL5 Reference. Je n'ai apporté que de légères corrections pour l'utilisation dans ce script. La Référence contient une description détaillée (il serait bon de l'étudier également), je ne vais donc pas exposer ici ma version car elle est presque identique. En outre, on peut la trouver dans le code avec des commentaires détaillés.

La seule chose que l'on peut mentionner maintenant est que la fonction CheckLoadHistory() renvoie le code d'erreur ou d'exécution réussie, en fonction duquel le message approprié du bloc opérateur switch est enregistré dans le journal. Selon le code reçu, la fonction GetDataCurrentSymbol() poursuit son opération ou renvoie son code.

Si tout va bien, les données de l'historique sont copiées à l'aide de la fonction CopyRates(). La taille du tableau est enregistrée dans la variable globale. Ensuite, la sortie de la fonction accompagnée du retour du code 1 est effectuée. Si quelque chose ne va pas, la fonction arrête son fonctionnement dans l'opérateur de commutation et renvoie le code 0 ou 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
  }

Après cela, le programme se trouve à nouveau dans le corps de la boucle principale de la fonction OnStart(). Le code est affecté par la variable locale res et le contrôle est effectué en fonction de sa valeur. La valeur zéro correspond à une erreur. Cela signifie que les données du symbole actuel dans la boucle ne peuvent pas être écrites. L'explication de l'erreur a été enregistrée dans le journal et la décision est prise si la boucle doit être interrompue (break) ou si l'itération suivante doit être lancée (continue).

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

La ligne de code ci-dessus montre que cette sélection est effectuée par de mystérieux caractères BC. Il s'agit d'une macro-expansion. Vous trouverez de plus amples informations à ce sujet dans MQL5 Reference. La seule chose à mentionner ici est que l'ensemble des expressions (tapées sur une ligne) peut être collé dans une entrée courte comme le montre l'exemple ci-dessus (BC). Dans certains cas, cette méthode peut être encore plus pratique et compacte qu'une fonction. Dans le cas présent, cela se présente comme suit :

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

Vous trouverez ci-dessous d'autres exemples d'extensions de macros utilisées dans ce 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

Si GetDataCurrentSymbol() renvoie 2, le programme a été supprimé par un utilisateur. MQL5 a la fonction IsStopped() pour identifier cet événement. Cette fonction peut être très utile dans les boucles pour arrêter le fonctionnement du programme correctement et à temps. Si la fonction renvoie true, il y a environ trois secondes pour effectuer toutes les actions avant que le programme ne soit supprimé de force. Dans notre cas, tous les objets graphiques sont supprimés et le message est envoyé au 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. Création de dossiers et classement des données

La fonction CheckCreateGetPath() vérifie la présence du dossier de données racine. Appelons-le DATA_OHLC et plaçons-le dans C:\Metatrader 5\MQL5\Files. Il contiendra des dossiers avec les noms des symboles. Les fichiers pour l'écriture des données seront créés à cet endroit.

Si le dossier racine ou le dossier du symbole actuel dans la boucle n'existe pas, la fonction le crée. Si tout se passe bien, la fonction renvoie une chaîne contenant le chemin de création d'un fichier. La fonction renvoie une chaîne vide en cas d'erreur ou de tentative de suppression du programme du graphique effectuée par un utilisateur.

Le code ci-dessous contient des commentaires détaillés facilitant la compréhension :

//____________________________________________________________________
//+------------------------------------------------------------------+
//| 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("");
  }

Si la fonction CheckCreateGetPath() renvoie une ligne vide, la boucle est interrompue ou l'itération suivante commence en utilisant l'expansion de macro déjà connue (BC) :

// 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 }

Si vous avez atteint cette étape, cela signifie que les données ont été copiées avec succès et que la variable de chaîne de chemin contient le chemin de création du fichier d'écriture des données du symbole courant dans la boucle.

Créez la fonction WriteDataToFile() pour écrire des données dans le fichier. [Chemin]+[nom du fichier] est généré au début de la fonction. Un nom de fichier se compose d'un nom de symbole et de la période actuelle. Par exemple, EURUSD_H1.csv. Si le fichier portant ce nom est déjà présent, il est simplement ouvert à l'écriture. Les données précédemment écrites seront supprimées. De nouvelles données y seront écrites à la place. Si le fichier est créé/ouvert avec succès, la fonction FileOpen() renvoie le handle qui sera utilisé pour accéder au fichier.

Vérification du handle. S'il est présent, la ligne d'en-tête est écrite. La ligne appropriée sera écrite en fonction des en-têtes sélectionnés par un utilisateur. La boucle principale d'écriture des données historiques commence ensuite.

Avant d'écrire la ligne suivante, elle doit être convertie au format spécifié par l'utilisateur. Pour ce faire, nous devons recevoir l'heure d'ouverture de la barre et trier le jour, le mois, l'année et l'heure séparément par variables à l'aide de la fonction StringSubstr(). Ensuite, nous devons définir si la date et l'heure seront situées dans une seule ou plusieurs colonnes, selon le format spécifié par l'utilisateur. Ensuite, toutes les parties sont réunies en une seule ligne à l'aide de la fonction StringConcatenate(). Une fois toutes les lignes écrites, le fichier est fermé par la fonction FileClose().

L'intégralité du code de la fonction WriteDataToFile() est illustré ci-dessous :

//____________________________________________________________________
//+------------------------------------------------------------------+
//| 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!"); }
  }

C'était la dernière fonction de la boucle de base de la fonction OnStart(). Si ce n'était pas le dernier symbole, tout est répété pour le suivant. Sinon, la boucle est rompue. Si l'utilisateur a spécifié d'effacer la liste des symboles dans la fenêtre Market Watch dans les paramètres de script, les symboles avec des graphiques actuellement non actifs seront supprimés par la fonction DelSymbolsFromMarketWatch(). Après cela, tous les objets graphiques créés par le script sont supprimés et le programme s'arrête. Les données sont prêtes à être utilisées.

Les détails sur la façon de télécharger les données vers NeuroShell DayTrader Professional peuvent être trouvés dans mon blog . Vous trouverez ci-dessous la vidéo montrant le fonctionnement du script :



Conclusion

Quel que soit le programme que j'ai utilisé pour développer des stratégies de trading, j'ai toujours rencontré des limites qui m'empêchaient de poursuivre le développement de mes idées. Finalement, j'ai réalisé que la programmation est essentielle ici. MQL5 est la meilleure solution pour ceux qui veulent vraiment réussir. Cependant, d'autres programmes d'analyse de données et de développement de stratégies de trading peuvent également être utiles lors de la recherche de nouvelles idées. Il m'aurait fallu beaucoup plus de temps pour les trouver, si j'avais utilisé un seul outil.

Bonne chance !

Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/502

Fichiers joints |
writedatatofile.mq5 (68.96 KB)
Communiquer avec MetaTrader 5 en utilisant Named Pipes sans utiliser de DLL Communiquer avec MetaTrader 5 en utilisant Named Pipes sans utiliser de DLL
De nombreux développeurs sont confrontés au même problème : comment accéder au sandbox du terminal de trading sans utiliser de DLL non sécurisées. L'une des méthodes les plus simples et les plus sûres consiste à utiliser des Named Pipes standard qui fonctionnent comme des opérations de fichier normales. Ils vous permettent d'organiser la communication inter-processeur client-serveur entre les programmes. Regardez les exemples pratiques en C++ et MQL5 qui incluent le serveur, le client, l'échange de données entre eux et l'évaluation des performances.
Comment acheter un robot de trading sur MetaTrader Market et l'installer ? Comment acheter un robot de trading sur MetaTrader Market et l'installer ?
Un produit de MetaTrader Market peut être acheté sur le site Web MQL5.com ou directement depuis les plateformes de trading MetaTrader 4 et MetaTrader 5. Choisissez un produit qui convient à votre style de trading, payez-le en utilisant votre méthode de paiement préférée et activez le produit.
Comment s'abonner aux signaux de trading Comment s'abonner aux signaux de trading
Le service Signals introduit le trading social avec MetaTrader 4 et MetaTrader 5. Le Service est intégré à la plateforme de trading, et permet à quiconque de copier facilement les trades des traders professionnels. Sélectionnez l'un des milliers de fournisseurs de signaux, abonnez-vous en quelques clics et les transactions du fournisseur seront copiées sur votre compte.
Réseaux neuronaux : De la théorie à la pratique Réseaux neuronaux : De la théorie à la pratique
De nos jours, tout trader doit avoir entendu parler des réseaux neuronaux et sait à quel point il est cool de les utiliser. La majorité pense que ceux qui peuvent traiter les réseaux neuronaux sont des sortes de surhommes. Dans cet article, je vais essayer de vous expliquer l'architecture des réseaux neuronaux, de décrire leurs applications et de montrer des exemples d'utilisation pratique.