- Direction d'Indexation dans les Tableaux, Buffers et Séries de Données
- Organisation de l'Accès aux Données
- SeriesInfoInteger
- Bars
- BarsCalculated
- IndicatorCreate
- IndicatorParameters
- IndicatorRelease
- CopyBuffer
- CopyRates
- CopySeries
- CopyTime
- CopyOpen
- CopyHigh
- CopyLow
- CopyClose
- CopyTickVolume
- CopyRealVolume
- CopySpread
- CopyTicks
- CopyTicksRange
- iBars
- iBarShift
- iClose
- iHigh
- iHighest
- iLow
- iLowest
- iOpen
- iTime
- iTickVolume
- iRealVolume
- iVolume
- iSpread
Organiser l'Accès aux Données
Dans cette section, les questions liées à l'obtention, au stockage et à la demande des données des prix (timeseries) sont considérées.
Recevoir les Données du Serveur de Trades
Avant que les données des prix soient disponibles dans le terminal MetaTrader 5, ils doivent être obtenus et traités. Pour obtenir les données, la connexion au serveur de trades MetaTrader 5 doit être établie. Les données sont obtenues sous la forme de blocs compressés de barres 1 minute depuis le serveur suivant la demande d'un terminal.
Le mécanisme de référence du serveur pour les données ne dépend pas de la façon dont la demande a été initiée - par un utilisateur naviguant dans un graphique ou de façon programmatique dans le langage MQL5.
Stocker les Données Intermédiaires
Les données obtenues du serveur sont automatiquement décompréssées et sauvegardées dans le format intermédiaire HCC. Les données de chaque symbole sont écrites dans un dossier séparé : répertoire_du_terminal\bases\nom_du_serveur\history\nom_du_symbole. Par exemple, les données de l'EURUSD reçues du serveur MetaQuotes-Demo seront stockées dans répertoire_du_terminal\bases\MetaQuotes-Demo\history\EURUSD\.
Les données sont écrites dans des fichiers avec l'extension .hcc. Chaque fichier stocke les données des barres 1 minute pour un an. Par exemple, le fichier nommé 2009.hcc dans le dossier EURUSD contient les barres 1 minutes de l'EURUSD pour l'année 2009. Ces fichiers sont utilisés pour préparer les données des prix pour toutes les périodes et ne sont pas prévus pour être accéder directement.
Obtenir les Données sur une Période Désirée à partir des Données Intermédiaires
Les fichiers HCC intermédiaires sont utilisés comme source de données pour construire les données des prix pour les périodes demandées dans le format HC. Les données au format HC sont des timeseries qui sont préparées au maximum pour un accès rapide. Elles sont créées à la demande d'un graphique ou d'un programme MQL5. Le volume des données ne doit pas excéder la valeur du paramètre "Nb max de barres dans les graphiques". Les données sont stockées pour une utilisation ultérieure dans des fichiers avec l'extension hcc.
Pour économiser des ressources, les données d'une période sont stockées et sauvegardées en RAM uniquement si nécessaire. Si elles ne sont pas appelées pendant un long moment, elles sont libérées de la RAM et sauvegardées dans un fichier. Pour chaque période, les données sont préparées indépendamment du fait qu'il y ait des données prêtes pour les autres périodes ou pas. Les règles de formation et d'accès aux données sont les mêmes pour toutes les périodes. C'est à dire qu'en dépit du fait que les données unitaires stockées au format HCC sont les données 1 minute (M1), la disponibilité des données HCC ne signifie pas la disponibilité des données de la période M1 puisque HC est dans le même volume.
La réception des nouvelles données du serveur appelle automatiquement la mise à jour des données des prix au format HC de toutes les périodes. Cela mène aussi au recalcul de tous les indicateurs qui les utilisent implicitement comme données d'entrée pour les calculs.
Paramètre "Nb max de barres dans le graphique"
Le paramètre "Nb max de barres dans le graphique" restreint le nombre de barres au format HC disponibles dans les graphiques, dans les indicateurs et dans les programmes mql5. Ceci est valide pour toutes les périodes disponibles et sert en tout premier lieu à économiser les ressources de l'ordinateur.
Lorsqu'une grande valeur est mise pour ce paramètre, il faut se souvenir que si un historique profond des données des prix est disponible pour les petites périodes, la mémoire utilisée pour stocker les timeseries et les buffers de l'indicateur peut atteindre des centaines de mega-octets et atteindre la limite de RAM pour le programme du terminal client (2 Go pour les applications 32 bits de MS Windows).
Un changement du paramètre "Nb max de barres dans les graphiques" n'est pris en compte qu'après le redémarrage du terminal client. Le changement de ce paramètre ne cause ni la vérification automatique du serveur pour des données supplémentaires, ni la formation de barres supplémentaires des timeseries. Les données supplémentaires des prix sont demandées au serveur, et les timeseries sont mises à jour en prenant en compte la nouvelle limite, dans le cas du défilement de la zone du graphique où il n'y a pas de données, ou lorsque les données sont demandées par un programme mql5.
Le volume des données demandées au serveur correspond au nombre demandé de barres de cette période avec le paramètre "Nb max de barres dans les graphiques" pris en compte. La restriction donnée par ce paramètre n'est pas stricte, et dans certains cas, le nombre de barres disponibles pour une période peut être supérieur à la valeur actuelle du paramètre.
Disponibilité des Données
La présence de données au format HCC ou même préparée pour être utilisées au format HC ne signifie pas toujours la disponibilité absolue de ces données pour être affichées dans un graphique ou pour être utilisées dans des programmes MQL5.
Lors de l'accès aux données des prix ou aux valeurs d'un indicateur depuis un programme mql5, il faut se souvenir que leurs disponibilités à un certain moment ou à partir d'un certain moment ne sont pas garanties. Ceci est dû au fait que dans le but d'économiser des ressources, la copie complète des données nécessaires pour un programme mql5 n'est pas stocké dans MetaTrader 5 ; seul un accès direct à la base de données du terminal est donné.
L'historique des prix pour toutes les périodes est construit à partir des données communes au format HCC, and toute mise à jour des données du serveur conduit à la mise à jour des données pour toutes les périodes et au recalcul des indicateurs. A cause de cela, l'accès aux aux données peut être fermé, même si ces données n'étaient pas disponibles auparavant.
Synchronisation des Données du Terminal et des Données du Serveur #
Puisqu'un programme mql5 peut appeler des données d'un autre symbole et d'une autre période, il y a la possibilité que les données des timeseries nécessaires ne soient pas encore formées dans le terminal ou que les données nécessaires des prix ne sont pas synchronisées avec le serveur de trades. Dans ce cas, prédire le temps de latence est difficile.
Les algorithmes utilisant des boucles "ne-fait-rien" ne sont pas la meilleure solution. La seule exception dans ce cas sont les scripts, car il n'existe pas d'autre choix d'algorithme car ils ne gérent pas d'évènements. Pour les indicateurs personnalisés, de tels algorithmes, ainsi que n'importe quelles autres boucles "ne-fait-rien", sont fortement à éviter, car ils mènent à la fin du calcul de tous les indicateurs et tout autre traitement des données des prix du symbole.
Pour les Expert Advisors et les indicateurs, il est préférable d'utiliser le modèle de gestion d'évènements. Si pendant le traitement de l'évènement OnTick() ou OnCalculate(), la réception des données pour les timeseries requises échoue, vous devriez sortir de la fonction de gestion de l'évènement, en vous basant sur la disponibilité de l'accès à l'appel suivant de la fonction.
Exemple de Script d'Ajout dans l'Historique
Considérons l'exemple d'un script qui exécute une demande d'obtention de l'historique pour le symbole sélectionné auprès du serveur de trades. Le script est prévu pour être exécuté dans le graphique d'un symbole sélectionné ; la période n'importe pas car, comme il a été mentionné auparavant, les données des prix sont reçues du serveur de trades sous la forme de données 1 minutes compréssées à partir desquelles les timeseries prédéfinies sont construites.
Il écrit toutes les actions concernant l'obtention des données dans une fonction CheckLoadHistory(symbol, timeframe, start_date) séparée :
int CheckLoadHistory(string symbol,ENUM_TIMEFRAMES period,datetime start_date)
|
La fonction CheckLoadHistory() est conçue comme fonction universelle qui peut être appelée depuis n'importe quel programme (Expert Advisor, script ou indicateur). Il nécessite donc 3 paramètres d'entrée : nom du symbole, période et date de début pour indiquer le début de l'historique des prix dont vous avez besoin.
Il insère les vérifications nécessaires dans le code de la fonction avant de demander l'historique manquant. Tout d'abord, nous devons nous assurer que le nom du symbole et la période sont corrects :
if(symbol==NULL || symbol=="") symbol=Symbol();
|
Assurons-nous ensuite que le symbole est disponible dans la fenêtre du MarketWatch, c'est à dire que l'historique pour le symbole sera disponible lors de l'envoi d'une demande au serveur de trades. Si un tel symbole n'existe pas dans le MarketWatch, ajoutez-le avec la fonction SymbolSelect().
if(!SymbolInfoInteger(symbol,SYMBOL_SELECT))
|
Nous devons maintenant récupérer la date de départ de l'historique disponible pour la paire symbole/période donnée. Peut être que la valeur du paramètre d'entrée startdate, passé à CheckLoadHistory(), est dans l'historique disponible ; la demande au serveur de trades n'est donc pas nécessaire. Pour obtenir la toute première date de la paire symbole-période à ce moment, la fonction SeriesInfoInteger() est utilisée avec le modificateur SERIES_FIRSTDATE.
SeriesInfoInteger(symbol,period,SERIES_FIRSTDATE,first_date);
|
La prochaine vérification importante est le type du programme à partir duquel la fonction est appelée. Notez qu'il n'est pas souhaitable d'envoyer une demande pour mettre à jour les timeseries depuis l'indicateur dans la même période. Le caractère indésirable de la demande de données sur la même paire symbole-période que celle de l'indicateur est conditionné par le fait que la mise à jour des données de l'historique est effectuée dans le même thread que celui où l'indicateur fonctionne. La possibilité de deadlock est donc élevée. Pour le vérifier, utilisez la fonction MQL5InfoInteger() avec le modificateur MQL5_PROGRAM_TYPE.
if(MQL5InfoInteger(MQL5_PROGRAM_TYPE)==PROGRAM_INDICATOR && Period()==period && Symbol()==symbol)
|
Si toutes les vérifications ont été réalisées avec succès, effectuez la dernière tentative sans vous référer au serveur de trades. Trouvons d'abord la date de dpart pour laquelle les données 1 minute au format HCC sont disponibles. Récupérez cette valeur en utilisation la fonction SeriesInfoInteger() avec le modificateur SERIES_TERMINAL_FIRSTDATE et comparez-la à nouveau avec la valeur du paramètre start_date.
if(SeriesInfoInteger(symbol,PERIOD_M1,SERIES_TERMINAL_FIRSTDATE,first_date))
|
Si après toutes les vérifications, le thread d'exécution est toujours dans le corps de la fonction CheckLoadHistory(), cela signifie qu'il est nécessaire de demander les données manquantes des prix au serveur de trades. Retourne d'abord la valeur du paramètre "Nb max de barres dans le graphique" avec la fonction TerminalInfoInteger() :
int max_bars=TerminalInfoInteger(TERMINAL_MAXBARS); |
Nous en aurons besoin pour éviter de demander des données supplémentaires. Trouvons ensuite la toute première date de l'historique du symbole sur le serveur de trades (indépendamment de la période) en utilisant la fonction SeriesInfoInteger() avec le modificateur SERIES_SERVER_FIRSTDATE.
datetime first_server_date=0;
|
Puisque la demande est une opération asynchrone, la fonction est appelée dans la boucle avec un court délai de 5 millisecondes jusqu'à ce que la variable first_server_date reçoive une valeur, ou que la boucle d'exécution soit stoppée par l'utilisateur (IsStopped() retournera true dans ce cas). Indiquons une valeur correcte de date de départ, à partir de laquelle nous demandons les données des prix au serveur de trades.
if(first_server_date>start_date) start_date=first_server_date;
|
Si la date de départ first_server_date du serveur est inférieure à la date de départ first_date du symbole au format HCC, l'entrée correspondante sera écrite dans le journal.
Nous sommes maintenant prêt à effectuer une demande au serveur de trades pour demandes les données manquantes des prix. Effectuons la demande sous la forme d'une boucle et commençons à remplir son corps :
while(!IsStopped())
|
Les 3 premiers points sont implémentés par des moyens déjà connus.
while(!IsStopped())
|
Il reste le quatrième et dernier point à faire - demander l'historique. Nous ne pouvons pas nous référer à un serveur directement, mais n'importe quelle fonction Copy inities automatiquement l'envoi de la demande à un serveur si l'historique au format HCC n'est pas suffisant. Puisque l'heure de la toute première date dans la variable first_date est le critère simple et naturel pour évaluer le degré d'exécution de la demande, la façon la plus simple est donc d'utiliser la fonction CopyTime().
Lors de l'appel aux fonctions de copie des données à partir des timeseries, il est à noter que le paramètre start (numéro de la barre à partir de laquelle les données des prix sont à copier) doit toujours être dans l'historique disponible du terminal. Si vous n'avez que 100 barres, il est inutile d'essayer de copier 300 barres à partir de la barre d'indice 500. Un telle demande sera considérée comme invalide et ne sera pas traitée, c'est à dire qu'aucun historique supplémentaire ne sera chargé du serveur de trades.
c'est pourquoi nous copierons les barres en groupes de 100 en commençant par la barre avec l'indice bars . Cela permettra un chargement lissé de l'historique manquant depuis le serveur de trades. En fait, un peu plus de 100 barres seront chargées, car le serveur renvoie un historique plus grand.
int copied=CopyTime(symbol,period,bars,100,times); |
Après la copie, nous devons analyser le nombre d'éléments copiés. Si la tentative échoue, alors la valeur de copied sera égale à 0 et la valeur du compteur fail_cnt sera incrémentée de 1. Après 100 échecs, l'exécution de la fonction sera stoppée.
int fail_cnt=0;
|
Donc, non seulement la gestion correcte de la situation correcte à tout moment de l'exécution est implémentée dans la fonction, mais également le code de fin est retourné. Il peut être géré après l'appel à la fonction CheckLoadHistory() pour obtenir des informations supplémentaires. Par exemple, de cette façon :
int res=CheckLoadHistory(InpLoadedSymbol,InpLoadedPeriod,InpStartDate);
|
Le code complet de la fonction est disponible dans l'exemple du script qui montre l'organisation correcte de l'accès à n'importe quelle donnée dans la gestion des résultats de la demande.
Code :
//+------------------------------------------------------------------+
|