English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Utilisation de WinInet dans MQL5.  Partie 2 :  Requêtes et fichiers POST

Utilisation de WinInet dans MQL5. Partie 2 : Requêtes et fichiers POST

MetaTrader 5Exemples | 12 janvier 2022, 17:01
330 0
---
---


Introduction

Dans la leçon précédente « Utilisation de WinInet.dll pour l'échange de données entre terminaux via Internet », nous avons appris à travailler avec la bibliothèque, ouvrir des pages Web, envoyer et recevoir des informations à l'aide de requêtes GET.

Dans cette leçon, nous allons apprendre à :

  • créer et envoyer des requêtes POST simples à un serveur ;
  • envoyer des fichiers à un serveur en utilisant la méthode de représentation multipart/form-data ;
  • travailler avec les cookies et lire les informations des sites Web à l'aide de votre identifiant.

Comme précédemment, je recommande fortement de mettre en place un serveur proxy local Charles ; il sera nécessaire pour vos études et vos expériences ultérieures.


Demandes POST

Pour envoyer des informations, nous aurons besoin de ces fonctions wininet.dll et de la classe créée CMqlNet qui ont été décrites en détail dans l'article précédent.

En raison du grand nombre de champs dans les méthodes CMqlNet::Request, nous avons dû créer une structure distincte tagRequest qui contient tous les champs requis pour une demande. 

//------------------------------------------------------------------ struct tagRequest
struct tagRequest
{
  string stVerb;   // method of the request GET/POST/…
  string stObject; // path to an instance of request, for example "/index.htm" или "/get.php?a=1"  
  string stHead;   // request header
  string stData;   // addition string of data
  bool fromFile;   // if =true, then stData designates the name of a data file
  string stOut;    // string for receiving an answer
  bool toFile;     // if =true, then stOut designates the name of a file for receiving an answer

  void Init(string aVerb, string aObject, string aHead, 
            string aData, bool from, string aOut, bool to); // function of initialization of all fields
};
//------------------------------------------------------------------ Init
void tagRequest::Init(string aVerb, string aObject, string aHead, 
                      string aData, bool from, string aOut, bool to)
{
  stVerb=aVerb;     // method of the request GET/POST/…
  stObject=aObject; // path to the page "/get.php?a=1" or "/index.htm"
  stHead=aHead;     // request header, for example "Content-Type: application/x-www-form-urlencoded"
  stData=aData;     // addition string of data
  fromFile=from;    // if =true, the stData designates the name of a data file
  stOut=aOut;       // field for receiving an answer
  toFile=to;        // if =true, then stOut designates the name of a file for receiving an answer
}

De plus, nous devons remplacer l'en-tête de la méthode CMqlNet::Request par un plus court :

//+------------------------------------------------------------------+
bool MqlNet::Request(tagRequest &req)
  {
   if(!TerminalInfoInteger(TERMINAL_DLLS_ALLOWED))
     {
      Print("-DLL not allowed"); return(false);
     }
//--- checking whether DLLs are allowed in the terminal
   if(!MQL5InfoInteger(MQL5_DLLS_ALLOWED))
     {
      Print("-DLL not allowed");
      return(false);
     }
//--- checking whether DLLs are allowed in the terminal
   if(req.toFile && req.stOut=="")
     {
      Print("-File not specified ");
      return(false);
     }
   uchar data[]; 
    int hRequest,hSend;
   string Vers="HTTP/1.1"; 
    string nill="";

//--- read file to array
   if(req.fromFile)
     {
      if(FileToArray(req.stData,data)<0)
        {
         Print("-Err reading file "+req.stData);
         return(false);
        }
     }
   else StringToCharArray(req.stData,data);

   if(hSession<=0 || hConnect<=0)
     {
      Close();
      if(!Open(Host,Port,User,Pass,Service))
        {
         Print("-Err Connect");
         Close();
         return(false);
        }
     }
//--- creating descriptor of the request
   hRequest=HttpOpenRequestW(hConnect,req.stVerb,req.stObject,Vers,nill,0,
   INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_RELOAD|INTERNET_FLAG_PRAGMA_NOCACHE,0);
   if(hRequest<=0)
     {
      Print("-Err OpenRequest");
      InternetCloseHandle(hConnect);
      return(false);
     }
//--- sending the request
   hSend=HttpSendRequestW(hRequest,req.stHead,StringLen(req.stHead),data,ArraySize(data));
//--- sending the file
   if(hSend<=0)
     {
      int err=0;
      err=GetLastError(err);
      Print("-Err SendRequest= ",err);
     }
//--- reading the page
   if(hSend>0) ReadPage(hRequest,req.stOut,req.toFile);
//--- closing all handles
   InternetCloseHandle(hRequest); InternetCloseHandle(hSend);

   if(hSend<=0)
     {
      Close();
      return(false);
     }
   return(true);
  }

Commençons à travailler.


Envoi de données vers un site Web de type « application/x-www-form-urlencoded »

Dans la leçon précédente, nous avons analysé l'exemple de MetaArbitrage (suivi des cotations).

Rappelons que l'EA envoie les prix de l'offre de son symbole à l'aide d'une requête GET ; et en réponse, il reçoit les prix d'autres courtiers qui sont envoyés de la même manière au serveur depuis d'autres terminaux.

Pour changer une requête GET en requête POST, il suffit de « cacher » la ligne de requête elle-même dans le corps de la requête qui vient après son en-tête.

BOOL HttpSendRequest(
  __dans HINTERNET hRequest,
  __dans LPCTSTR lpszHeaders,
  __en DWORD dwHeadersLength,
  __dans LPVOID lpOptional,
  __in DWORD dwOptionalLength
);

  • hRequest [in]
    Handle renvoyé par HttpOpenRequest.
  • lpszHeaders [in]
    Pointeur vers une ligne contenant des en-têtes à ajouter à la requête. Ce paramètre peut être vide.
  • dwHeadersLength [in]
    Taille de l'en-tête en octets.
  • lpOptional [in]
    Pointeur vers un tableau de données uchar qui est envoyé juste après l'en-tête. En général, ce paramètre est utilisé pour les opérations POST et PUT.
  • dwOptionalLength [in]
    Taille des données en octets. Le paramètre peut être =0 ; cela signifie qu'aucune information supplémentaire n'est envoyée.

D'après la description de la fonction, nous pouvons comprendre que les données sont envoyées sous forme d'octet uchar-array (le quatrième paramètre de la fonction). C'est tout ce que nous devons savoir à ce stade.

Dans l'exemple de MetaArbitrage, la requête GET se présente comme suit :

www.fxmaster.de/metaarbitr.php?server=Metaquotes&pair=EURUSD&bid=1.4512&time=13286794


La demande elle-même est mise en évidence par la couleur rouge. Ainsi, si nous devons effectuer une requête POST, nous devons déplacer son texte dans le tableau de données lpOptional.

Créons un script appelé MetaSwap, qui enverra et recevra des informations sur les échanges d'un symbole. 

#include <InternetLib.mqh>

string Server[];        // array of server names
double Long[], Short[]; // array for swap information
MqlNet INet;           // class instance for working

//------------------------------------------------------------------ OnStart
void OnStart()
{
//--- opening a session
  if (!INet.Open("www.fxmaster.de", 80, "", "", INTERNET_SERVICE_HTTP)) return;
 
//--- zeroizing arrays
  ArrayResize(Server, 0); ArrayResize(Long, 0); ArrayResize(Short, 0);
//--- the file for writing an example of swap information
  string file=Symbol()+"_swap.csv";
//--- sending swaps
  if (!SendData(file, "GET")) 
  { 
    Print("-err RecieveSwap"); 
    return; 
  }
//--- read data from the received file
  if (!ReadSwap(file)) return; 
//--- refresh information about swaps on the chart
  UpdateInfo();               
}

Le fonctionnement du script est très simple.

Tout d'abord, la session Internet INet.Open est ouverte. Ensuite, la fonction SendData envoie des informations sur les échanges du symbole actuel. Ensuite, s'il est envoyé avec succès, les swaps reçus sont lus à l'aide de ReadSwap et affichés sur le graphique à l'aide de UpdateInfo.

Pour l'instant, nous nous intéressons uniquement à la fonction SendData.

//------------------------------------------------------------------ SendData bool SendData(string file, string mode) {   string smb=Symbol();   string Head="Content-Type: application/x-www-form-urlencoded"; // header   string Path="/mt5swap/metaswap.php"; // path to the page   string Data="server="+AccountInfoString(ACCOUNT_SERVER)+               "&pair="+smb+               "&long="+DTS(SymbolInfoDouble(smb, SYMBOL_SWAP_LONG))+               "&short="+DTS(SymbolInfoDouble(smb, SYMBOL_SWAP_SHORT));   tagRequest req; // initialization of parameters   if (mode=="GET")  req.Init(mode, Path+"?"+Data, Head, "",   false, file, true);   if (mode=="POST") req.Init(mode, Path,          Head, Data, false, file, true);   return(INet.Request(req)); // sending request to the server }

Dans ce script, deux méthodes d'envoi d'informations sont démontrées - en utilisant GET et POST, pour que vous puissiez sentir la différence entre elles.

Décrivons les variables de la fonction une par une :

  • Tête - en-tête de la demande décrivant le type de son contenu. En réalité, il ne s'agit pas de la totalité de l'en-tête de la demande. Les autres champs de l'en-tête sont créés par la bibliothèque wininet.dll. Cependant, ils peuvent être modifiés à l'aide de la fonction HttpAddRequestHeaders.
  • Chemin - il s'agit du chemin d'accès à l'instance de demande par rapport au domaine initial www.fxmaster.de. En d'autres termes, il s'agit du chemin d'accès à un script php qui traitera la demande. A propos, il n'est pas nécessaire de demander uniquement un script php, il peut s'agir d'une page html ordinaire (nous avons même essayé de demander un fichier mq5 lors de notre première leçon).
  • Données - ce sont les informations qui sont envoyées au serveur. Les données sont écrites selon les règles de passage du paramètre nom=valeur. Le signe « & » est utilisé comme séparateur de données.

Et surtout, faites attention à la différence entre les requêtes GET et POST dans tagRequest::Init.

Dans la méthode GET, le chemin d'accès est envoyé avec le corps de la demande (uni par le signe « ? »), et le champ de données lpOptional (appelé stData dans la structure) est laissé vide.
Dans la méthode POST
, le chemin d'accès existe en tant que tel, et le corps de la demande est déplacé vers lpOptional .

Comme vous pouvez le constater, la différence n'est pas significative. Le script serveur metaswap.php qui reçoit la requête est joint à l'article.


Envoi de données « multipart/form-data »

En fait, les requêtes POST ne sont pas analogues aux requêtes GET (sinon elles ne seraient pas nécessaires). Les requêtes POST présentent un avantage considérable - elles permettent d'envoyer des fichiers au contenu binaire.

Il s'agit d'une requête du type urlencoded qui est autorisée à envoyer un ensemble limité de symboles. Sinon, les symboles « non autorisés » seront remplacés par des codes. Ainsi lors de l'envoi de données binaires, elles seront déformées. Vous n'êtes donc pas en mesure d'envoyer même un petit fichier gif à l'aide d'une requête GET.

Pour résoudre ce problème, des règles spéciales de description d'une requête sont élaborées ; elles permettent d'échanger des fichiers binaires en plus des fichiers texte.

Pour atteindre cet objectif, le corps de la demande est divisé en sections. L'essentiel est que chaque section puisse avoir son propre type de données. Par exemple, le premier est un texte, le suivant est une image/jpeg, etc. En d'autres termes, une requête envoyée au serveur peut contenir plusieurs types de données à la fois.

Voyons la structure d'une telle description à l'aide de l'exemple des données transmises par le script MetaSwap.

L'en-tête de la requête Tête sera le suivant :

Type de contenu : multipart/form-data ; limite=SEPARATOR\r\n


Le mot-clé SEPARATOR – est un ensemble aléatoire de symboles. Cependant, vous devez veiller à ce que cela soit en dehors des données de la demande. En d'autres termes, cette ligne doit être unique - un abracadabra comme hdsJK263shxaDFHLsdhsDdjf9 ou tout autre élément qui vous vient à l'esprit :). En PHP, une telle ligne est formée en utilisant le code MD5 d'une heure courante.

La requête POST elle-même se présente comme suit (pour faciliter la compréhension, les champs sont mis en évidence en fonction de leur signification générale) :

\r\n
--SEPARATOR\r\n

Disposition du contenu : données de formulaire ; nom="Serveur"\r\n
\r\n
MetaQuotes-Demo

\r\n
--SEPARATOR\r\n

Disposition du contenu : données de formulaire ; nom="Pair"\r\n
\r\n
EURUSD

\r\n
--SEPARATOR\r\n

Disposition du contenu : données de formulaire ; nom="Long"\r\n
\r\n
1.02

\r\n
--SEPARATOR\r\n

Disposition du contenu : données de formulaire ; nom="Short"\r\n
\r\n
-0,05

\r\n
--SEPARATOR--\r\n


Nous spécifions explicitement les emplacements des sauts de ligne « \r\n », car ce sont des symboles obligatoires dans une requête. Comme vous pouvez le constater, les quatre mêmes champs sont transmis dans la demande, mais cela se fait de la manière habituelle du texte.

Les particularités importantes de la mise en place des séparateurs :

  • Deux symboles « -- » sont placés avant le séparateur.
  • Pour le séparateur de fermeture, deux symboles supplémentaires « -- » sont ajoutés après celui-ci.


Dans l'exemple suivant, vous pouvez voir une méthode correcte de transmission de fichiers dans une requête.

Imaginez qu'un Expert Advisor réalise un instantané du graphique et un rapport détaillé sur le compte dans un fichier texte lors de la clôture d'une position.

\r\n
--SEPARATOR\r\n

Disposition du contenu : données de formulaire ; nom="ExpertName"\r\n
\r\n
MACD_Sample

\r\n
--SEPARATOR\r\n

Contenu-Disposition : fichier; nom="screen" ; nom de fichier="screen.gif"\r\n
Type de contenu : image/gif\r\n
Codage de transfert de contenu : binaire\r\n
\r\n
......contenu du fichier gif.....

\r\n
--SEPARATOR\r\n

Disposition du contenu : données de formulaire ; nom="statement" ; nom de fichier="statement.csv"\r\n
Type de contenu : application/octet-stream\r\n
Codage de transfert de contenu : binaire\r\n
\r\n
......contenu du fichier csv.....

\r\n
--SEPARATOR--\r\n


Deux nouveaux en-têtes apparaissent dans la requête :

Content-Type - décrit le type de contenu. Tous les types possibles sont décrits avec précision dans la norme RFC[2046]. Nous avons utilisé deux types - image/gif et application/octet-stream.

Deux variantes d'écriture de Content-Disposition - file et formulaire-donné sont équivalentes et sont correctement traitées par PHP dans les deux cas. Vous pouvez donc utiliser le fichier ou le formulaire de données au choix. Vous pouvez mieux voir la différence entre leurs représentations dans Charles.

Content-Transfer-Encoding - il décrit l'encodage du contenu. Il peut être absent pour les données textuelles.

Pour consolider le matériel, écrivons le script ScreenPost, qui envoie des captures d'écran au serveur :

#include <InternetLib.mqh>

MqlNet INet; // class instance for working

//------------------------------------------------------------------ OnStart
void OnStart()
{
  // opening session
  if (!INet.Open("www.fxmaster.de", 80, "", "", INTERNET_SERVICE_HTTP)) return;

  string giffile=Symbol()+"_"+TimeToString(TimeCurrent(), TIME_DATE)+".gif"; // name of file to be sent
 
  // creating screenshot 800х600px
  if (!ChartScreenShot(0, giffile, 800, 600)) { Print("-err ScreenShot "); return; }
 
  // reading gif file to the array
  int h=FileOpen(giffile, FILE_ANSI|FILE_BIN|FILE_READ); if (h<0) { Print("-err Open gif-file "+giffile); return; }
  FileSeek(h, 0, SEEK_SET);
  ulong n=FileSize(h); // determining the size of file
  uchar gif[]; ArrayResize(gif, (int)n); // creating uichar array according to the size of data
  FileReadArray(h, gif); // reading file to the array
  FileClose(h); // closing the file
 
  // creating file to be sent
  string sendfile="sendfile.txt";
  h=FileOpen(sendfile, FILE_ANSI|FILE_BIN|FILE_WRITE); if (h<0) { Print("-err Open send-file "+sendfile); return; }
  FileSeek(h, 0, SEEK_SET);

  // forming a request
  string bound="++1BEF0A57BE110FD467A++"; // separator of data in the request
  string Head="Content-Type: multipart/form-data; boundary="+bound+"\r\n"; // header
  string Path="/mt5screen/screen.php"; // path to the page
 
  // writing data
  FileWriteString(h, "\r\n--"+bound+"\r\n");
  FileWriteString(h, "Content-Disposition: form-data; name=\"EA\"\r\n"); // the "name of EA" field
  FileWriteString(h, "\r\n");
  FileWriteString(h, "NAME_EA");
  FileWriteString(h, "\r\n--"+bound+"\r\n");
  FileWriteString(h, "Content-Disposition: file; name=\"data\"; filename=\""+giffile+"\"\r\n"); // field of the gif file
  FileWriteString(h, "Content-Type: image/gif\r\n");
  FileWriteString(h, "Content-Transfer-Encoding: binary\r\n");
  FileWriteString(h, "\r\n");
  FileWriteArray(h, gif); // writing gif data
  FileWriteString(h, "\r\n--"+bound+"--\r\n");
  FileClose(h); // closing the file

  tagRequest req; // initialization of parameters
  req.Init("POST", Path, Head, sendfile, true, "answer.htm", true);
 
  if (INet.Request(req)) Print("-err Request"); // sending the request to the server
  else Print("+ok Request");
} 

Le script du serveur qui reçoit les informations :

<?php
$ea=$_POST['EA'];
$data=file_get_contents($_FILES['data']['tmp_name']); // information in the file
$file=$_FILES['data']['name'];
$h=fopen(dirname(__FILE__)."/$ea/$file", 'wb'); // creating a file in the EA folder
fwrite($h, $data); fclose($h); // saving data
?>

Il est fortement recommandé de se familiariser avec les règles de réception des fichiers par le serveur pour éviter les problèmes de sécurité !


Travailler avec des cookies

Ce sujet sera brièvement décrit comme un complément à la leçon précédente et une piste de réflexion sur ses caractéristiques.

Comme vous le savez, les cookies sont destinés à éviter que les serveurs ne demandent continuellement des données personnelles. Lorsqu'un serveur reçoit d'un utilisateur les données personnelles requises pour la session de travail en cours, il laisse un fichier texte contenant ces informations sur l'ordinateur de l'utilisateur. De plus, lorsque l'utilisateur passe d'une page à l'autre, le serveur ne demande pas à nouveau ces informations à l'utilisateur ; il les extrait automatiquement du cache du navigateur.

Par exemple, lorsque vous activez l'option « Se souvenir de moi » lors de l'autorisation sur le serveur www.mql5.com, vous enregistrez un cookie avec vos coordonnées sur votre ordinateur. Lors de la prochaine visite du site Web, le navigateur transmettra le Cookie au serveur sans vous le demander.

Si cela vous intéresse, vous pouvez ouvrir le dossier (WinXP) C:\Documents and Settings\<User>\Cookies et afficher le contenu des différents sites Web que vous avez visités.

En ce qui concerne nos besoins, les cookies peuvent être utilisés pour la lecture de vos pages du forum MQL5. En d'autres termes, vous lirez les informations comme si vous étiez autorisé sur le site Web sous votre identifiant, puis vous analyserez les pages obtenues. La variante optimale consiste à analyser les cookies à l'aide d'un serveur proxy local Charles. Il montre des informations détaillées sur toutes les demandes reçues/envoyées, y compris les cookies.

Par exemple :

  • Un Expert Advisor (ou une application externe) qui sollicite la page https://www.mql5.com/en/jobune fois par heure et reçoit la liste des nouvelles offres d'emploi.
  • Il demande également une branche, par exemple https://www.mql5.com/en/forum/53, et vérifie s'il y a de nouveaux messages.
  • De plus, il peut vérifier s'il y a de nouveaux « messages privés » sur les forums.

Pour définir un cookie dans une requête, la fonction InternetSetCookie est utilisée.

BOOL InternetSetCookie(
  __dans LPCTSTR lpszUrl,
  ____dans  LPCTSTR lpszCookieName,
  ____dans  LPCTSTR lpszCookieData
);

  • lpszUrl [in] - Nom d'un serveur, par exemple, www.mql5.com
  • lpszCookieName [in] - Nom d'un cookie
  • lpszCookieData [in] - Données pour le cookie

Pour définir plusieurs Cookies, appelez cette fonction pour chacun d'eux.

Une fonctionnalité intéressante : un appel d'InternetSetCookie peut être effectué à tout moment, même lorsque vous n'êtes pas connecté au serveur.


Conclusion

Nous nous sommes familiarisés avec un autre type de demandes HTTP, nous avons obtenu la possibilité d'envoyer des fichiers binaires, ce qui permet d'étendre les possibilités de travailler avec vos serveurs ; et nous avons appris les méthodes de travail avec les cookies.

Nous pouvons dresser la liste suivante des orientations des développements futurs :

  • Organisation du stockage à distance des rapports ;
  • Echange de fichiers entre utilisateurs, mise à jour des versions des Expert Advisors/indicateurs ;
  • Création de scanners personnalisés qui fonctionnent sous votre compte et surveillent l'activité d'un site web.


Liens utiles

  1. Un serveur proxy pour visualiser les en-têtes envoyés - http://www.charlesproxy.com/
  2. Description de WinHTTP - http://msdn.microsoft.com/en-us/library/aa385331%28VS.85%29.aspx
  3. Description de la session HTTP - http://msdn.microsoft.com/en-us/library/aa384322%28VS.85%29.aspx
  4. La boîte à outils Denwer pour une installation locale d'Apache+PHP - http://www.denwer.ru/
  5. Types d'en-têtes de requête - http://www.codenet.ru/webmast/php/HTTP-POST.php#part_3_2
  6. Types de requêtes - http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type
  7. Types de requêtes - ftp://ftp.isi.edu/in-notes/iana/assignments/media-types/media-types.
  8. Structure d'utilisation de http://msdn.microsoft.com/en-us/library/aa383766%28VS.85%29.aspx
  9. Utilisation de fichiers - http://msdn.microsoft.com/en-us/library/aa364232%28VS.85%29.aspx
  10. Types de données à transmettre à MQL - http://msdn.microsoft.com/en-us/library/aa383751%28VS.85%29.aspx


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

Fichiers joints |
metaswap.zip (0.66 KB)
screenpost.zip (0.33 KB)
internetlib.mqh (12.82 KB)
screenpost.mq5 (2.63 KB)
metaswap.mq5 (4.84 KB)
Paiements et modes de paiement Paiements et modes de paiement
Les services de MQL5.community offrent de grandes possibilités aux traders ainsi qu'aux développeurs d'applications pour le terminal MetaTrader. Dans cet article, nous expliquons comment les paiements pour les services MQL5 sont effectués, comment l'argent gagné peut être retiré et comment la sécurité de l'opération est assurée.
La mise en œuvre de l'analyse automatique des vagues d'Elliott dans MQL5 La mise en œuvre de l'analyse automatique des vagues d'Elliott dans MQL5
L'une des méthodes les plus populaires d'analyse du marché est le principe des vagues d'Elliott. Toutefois, ce processus est assez compliqué, ce qui nous amène à utiliser des outils supplémentaires. L’un de ces instruments est le marqueur automatique. Cet article décrit la création d'un analyseur automatique de vagues d'Elliott en langage MQL5.
Application de la transformation de Fisher et de la transformation inverse de Fisher à l'analyse des marchés dans MetaTrader 5 Application de la transformation de Fisher et de la transformation inverse de Fisher à l'analyse des marchés dans MetaTrader 5
Nous savons maintenant que la fonction de densité de probabilité (PDF) d'un cycle de marché ne rappelle pas une gaussienne mais plutôt une PDF d'une onde sinusoïdale et la plupart des indicateurs supposent que la PDF du cycle de marché est gaussienne ; nous avons besoin d'un moyen de « corriger » cela. La solution consiste à utiliser la transformation de Fisher. La transformation de Fisher change la PDF de n'importe quelle forme d'onde en une forme approximativement gaussienne. Cet article décrit les mathématiques qui sous-tendent la transformation de Fisher et la transformation inverse de Fisher, ainsi que leur application au trading. Un module de signal de trading propriétaire basé sur la transformation inverse de Fisher est présenté et évalué.
Diminution de la consommation de mémoire grâce aux indicateurs auxiliaires Diminution de la consommation de mémoire grâce aux indicateurs auxiliaires
Si un indicateur utilise les valeurs de nombreux autres indicateurs pour ses calculs, il consomme beaucoup de mémoire. L'article décrit plusieurs méthodes pour réduire la consommation de mémoire lors de l'utilisation d'indicateurs auxiliaires. La mémoire sauvegardée permet d'augmenter le nombre de paires de devises, d'indicateurs et de stratégies utilisées simultanément dans le terminal client. Il augmente la fiabilité du portefeuille de trading. Un souci aussi simple des ressources techniques de votre ordinateur peut se transformer en ressources financières à votre disposition.