Quelqu'un sait-il comment développer un indicateur multi-devises ? - page 4

 

Bon les gars, la première partie est faite (lecture des taux de toutes les paires).

Maintenant je dois utiliser les taux de toutes les paires copiées avec la fonction ArrayCopyRates pour créer des indicateurs graphiques comme un RSI... comme je le dessine dans l'image ci-dessous :

Dans ma question initiale, j'ai l'intention de savoir comment faire cela... et non de lire les taux. Je ne pense pas que j'aurai besoin de copier les taux avant de les dessiner, mais il était bon de savoir comment faire... maintenant je dois juste découvrir un moyen de diviser la zone de l'indicateur pour tracer toutes les paires...

 
WHRoeder:

Il n'y a aucun moyen de diviser la zone de l'indicateur. Tout doit être dessiné séparément, pas de tampons, pas de mise à l'échelle automatique. Voir

Avez-vous vu une telle image ? (MetaQuotes Software Corp.) - MQL4 forum - Page 12
Avez-vous vu une telle image ? (MetaQuotes Software Corp.) - MQL4 forum - Page 14
Avez-vous vu une telle photo ? (MetaQuotes Software Corp.) - MQL4 forum - Page 36

Comprendre. Alors tous les éléments doivent être dessinés comme des objets.
 

C'est un indicateur que j'ai trouvé quelque part, je n'ai jamais essayé de le déchiffrer. Il montre une représentation de 3 timeframes du graphique actuel. Ce qui est fou, c'est que les bougies sont dessinées avec des histogrammes. C'est joli mais ce n'est pas ce qui m'intéresse en ce moment.

Meilleurs voeux

Dossiers :
 
Ok, merci. Je suis en déplacement au travail et dès mon retour, je le testerai.
 
Fernando Carreiro:

Une mise à jour pour ceux qui suivent ce fil !

J'ai aidé l'OP via PM à corriger son code car il a des difficultés en anglais et nous parlons tous les deux portugais. Lors de nos tests, nous sommes tombés sur un autre phénomène "bizarre" qui se produit avec la fonction"ArrayCopyRates()". Lorsque l'on utilise un tableau MqlRates avec"ArrayCopyRates()" dans un EA, le tableau de données est un tableau virtuel qui rapporte toujours l'état actuel des choses, donc les données sont toujours fraîches.

Cependant, dans un Indicateur, cela ne semble pas être le cas. Le tableau n'est pas une copie virtuelle mais plutôt une copie statique fixée dans le temps au moment où"ArrayCopyRates()" a été appelé. Les données ne sont pas mises à jour lorsque le symbole est différent du symbole du graphique. Lorsqu'il s'agit du même symbole que le graphique, les données du tableau sont "vivantes" et se mettent à jour comme prévu, mais lorsqu'il s'agit d'un autre symbole, il s'agit d'une copie statique.

Donc, pour que cela fonctionne dans un indicateur, on doit appeler la fonction "ArrayCopyRates()" à chaque appel à l'événement OnCalculate() si des données fraîches sont nécessaires.

Pour développer vos conclusions, Fernando, même si le symbole est le même que celui du graphique, si l'horizon temporel est différent, le tableau est statique.

Donc pour avoir une copie virtuelle, dans un indicateur, il doit s'agir du même symbole ET de la même période. Tout le reste est statique.

 
honest_knave: Pour approfondir vos conclusions, Fernando, même si le symbole est le même que celui du graphique, si l'horizon temporel est différent, le tableau est statique. Donc pour avoir une copie virtuelle, dans un indicateur, il doit s'agir du même symbole ET de la même période. Tout le reste est statique.
Merci pour la mise à jour !
 
Bonjour,

J'ai cherché partout une solution à ce problème et je tiens à remercier tous les participants à ce fil de discussion.

C'est mon premier message dans le forum, donc s'il vous plaît faites-moi savoir si j'ai manqué un protocole et je serais heureux de corriger sur le prochain message.

J'essaie de développer un indicateur très simple, mais ma logique semble sensible au fait que le graphique soit entièrement à jour, c'est pourquoi je suis si intéressé par cette discussion.

Mon indicateur cherche à tracer une fibre sur la fourchette du jour précédent (du plus haut au plus bas du jour ou du plus bas au plus haut du jour) et sur le jour actuel, à tracer des lignes au niveau du plus haut, du plus bas et de 50% de la fibre. Si l'indicateur est utilisé sur un courtier GMT (bougie quotidienne du dimanche), l'utilisateur peut définir un paramètre d'entrée pour choisir si le lundi il utilise seulement la plage du vendredi ou du dimanche, ou le vendredi + le dimanche. Sur un courtier avec une fermeture NY (GMT+2), cela ne fait pas de différence étant donné qu'il n'y a pas de bougies du dimanche.

Une autre caractéristique de cet indicateur est de permettre à l'utilisateur de déplacer la fib et les lignes (haut, 50% et bas) du jour en cours s'ajusteront à la nouvelle fourchette définie par la fib. Cela permettra à l'utilisateur d'ajuster la fourchette dans le cas où la fourchette se contracte.

L'indicateur sera principalement utilisé sur plusieurs graphiques 1h, mais l'utilisateur devrait être capable de changer d'échelle temporelle sans perdre les changements effectués sur la fib.

Pour tracer la fib, je dois trouver non seulement le haut et le bas du jour précédent, mais aussi l'heure de ces points.

L'idée est simple mais j'ai été confronté à quelques difficultés.

En supposant que nous sommes en milieu de semaine, pour trouver le haut et le bas du jour précédent, j'utilise simplement :

       Hi = iHigh(NULL, PERIOD_D1, 1);
       Lo = iLow(NULL, PERIOD_D1, 1);

C'est bien, mais maintenant je dois trouver le jour précédent à quelle heure était le plus haut et le plus bas. J'ai décidé d'approximer l'heure de la bougie d'une heure au plus haut et au plus bas en utilisant iHighest et iLowest. Et c'est là que les problèmes ont commencé.


Pour utiliser iHighest et iLowest je dois spécifier la première bougie d'une heure et la taille de l'intervalle, donc dans mon cas ce sera la première et la dernière bougie d'une heure du jour précédent. J'ai donc utilisé l'ouverture de la bougie quotidienne précédente pour le début du jour précédent et l'ouverture de la bougie quotidienne du jour courant -1, pour trouver la fin du jour précédent :

       PrevDayBegin = iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 1));                
       PrevDayEnd = iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 0)-1);

Et cela fonctionne très bien si vous n'utilisez l'indicateur que sur les devises (encore une fois en supposant que c'est en milieu de semaine) parce que PrevDayBegin sera l'indice de la bougie de 0:00 1h et PrevDayEnd sera l'indice de la bougie de 23:00 1h. Le problème se situe sur les futures (indices, or, brut, etc). L'ouverture de la bougie quotidienne est toujours à 0:00, mais la 1ère bougie sur les futures est à 1h du matin sur les courtiers GMT+2, donc la ligne de code ci-dessus qui calcule PrevDayBegin renvoie la bougie de 1h de 23:00 le jour précédent.

J'ai donc décidé d'inclure un morceau de code pour tenir compte de cette situation et déplacer le PrevDayBegin jusqu'à ce qu'il soit le même jour de la semaine que le PrevDayEnd :

       if(TimeDayOfWeek(iTime(NULL, PERIOD_H1, PrevDayBegin)) != TimeDayOfWeek(iTime(NULL, PERIOD_H1, PrevDayEnd)))
         PrevDayBegin--;  

Et toute cette logique fonctionne très bien si vous avez toutes les bougies d'une heure à jour, mais jetez un coup d'oeil au journal ci-dessous montrant quelques impressions de ce qui s'est passé aujourd'hui. Juste pour référence, j'ai fermé MT4 la veille dans la soirée et je l'ai rouvert aujourd'hui dans la matinée (vers 7h du matin UK), donc il n'y avait que quelques heures de données manquantes dans les graphiques.

2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : == AUTRE JOUR DE LA SEMAINE ==
2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR PrevDayEnd = 1 (2017.02.08 19:00)
2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR PrevDayBegin = 20 (2017.02.08 00:00)

En regardant le log, il semble que la bougie la plus récente sur le graphique 1h était 2017.02.08 20:00 (index 0), donc iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 0)-1) est en train de l'approximer à (index 1) 2017.02.08 19:00. Par conséquent, tous les calculs de l'indicateur sont mélangés, car iHighest et iLowest utilisent la mauvaise plage.

Sur la base des discussions précédentes, j'ai essayé et utilisé certaines des solutions suggérées pour attendre que toutes les bougies soient chargées avant de faire les calculs, mais apparemment cela ne fonctionne toujours pas.

Par exemple, à OnInit() j'ai inclus les lignes de code suivantes pour déclencher la mise à jour des graphiques sur le 1h, le Daily et le timeframe actuel (juste au cas où la plateforme était fermée lorsque le graphique était ouvert sur un timeframe différent) :

   // Triggers history update
   MqlRates mqlrates_array_d1[];
   MqlRates mqlrates_array_h1[];
   MqlRates mqlrates_array[];
  
   ArrayCopyRates(mqlrates_array_d1,NULL,PERIOD_D1);
   ArrayCopyRates(mqlrates_array_h1,NULL,PERIOD_H1);
   ArrayCopyRates(mqlrates_array,NULL,0);  
Une autre chose que j'ai remarquée est qu'il semble que MT4 mette à jour la bougie la plus récente Time[0] sur le timeframe qui est ouvert dans le graphique avant de charger tout l'historique manquant, donc j'ai décidé de tester si Time[1] était aussi un prix valide.

Ce code a été inséré sur OnCalculate() et il était basé sur les codes de @whroeder1(ici) et @Fernando Carreiro& @Wemerson Guimaraes(ici) :

bool isHistoryLoading;

OnInit();
:
isHistoryLoading = true;
:

OnCalculate( ... )
:
      MqlRates mqlrates_array_d1[];
      MqlRates mqlrates_array_h1[];
      MqlRates mqlrates_array[];
      
      if(isHistoryLoading)
        {      
         ResetLastError();        
        
         if(ArrayCopyRates(mqlrates_array_d1,NULL,PERIOD_D1)>0)
           {
            if(GetLastError() == 0)
              {
               if((iTime(NULL,PERIOD_D1,0) > 0) && (iTime(NULL,PERIOD_D1,1) > 0))
                 {
                  ResetLastError();
  
                  if(ArrayCopyRates(mqlrates_array_h1,NULL,PERIOD_H1)>0)
                    {
                     if(GetLastError() == 0)
                       {
                        if((iTime(NULL,PERIOD_H1,0) > 0) && (iTime(NULL,PERIOD_H1,1) > 0))
                          {
                           ResetLastError();
      
                           if(ArrayCopyRates(mqlrates_array,NULL,0)>0)
                             {
                              if(GetLastError() == 0)
                                {
                                 if((iTime(NULL,0,0) > 0) && (iTime(NULL,0,1) > 0))                            
                                   {
                                    isHistoryLoading = false;
                                
                                    if(DebugLog)
                                      Print("Chart up-to-date!");        
                                    }
                                }
                             }
                          }
                       }
                    }                      
                 }
              }
           }
        }
        
      if(isHistoryLoading)
        {
         if(DebugLog)
           Print("Waiting for chart to update!");
         return(rates_total);
        }    

:

Et voici le log lors de l'ouverture de la plateforme et le chargement de l'indicateur pour la première fois :

2017.02.09 06:56:18.492 Indicateur personnalisé Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : chargé avec succès.
2017.02.09 06:56:18.630 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : initialisé
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Graphique à jour !
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : L'indicateur n'existe pas ! Nous le créons.
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : == AUTRE JOUR DE LA SEMAINE ==
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR PrevDayEnd = 20 (2017.02.07 23:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR PrevDayBegin = 42 (2017.02.07 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR CurrDayBegin = (2017.02.08 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR PERIOD_D1 [0] = (2017.02.08 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR PERIOD_D1 [1] = (2017.02.07 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR PERIOD_D1 [2] = (2017.02.06 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR Jour de la semaine = 3
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR iHighest (Candle = 28) (Price = 2299.33) (Time = 2017.02.07 14:00:001)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR iLowest (Candle = 20) (Price = 2287.88) (Time = 2017.02.07 23:00:001)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Fib de Time1=2017.02.07 14:00 Prix1=2299.33 à Time2=2017.02.07 23:00 Prix2=2287.88
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Ligne de tendance 'PDRTrend1 131296489639296384' de Time1=2017.02.08 00:00 Price1=2299.33 à Time2=2017.02.09 00:00 Price2=2299.33
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Ligne de tendance 'PDRTrend2 131296489639296384' de Time1=2017.02.08 00:00 Price1=2293.605 à Time2=2017.02.09 00:00 Price2=2293.605
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Ligne de tendance 'PDRTrend3 131296489639296384' de Time1=2017.02.08 00:00 Price1=2287.88 à Time2=2017.02.09 00:00 Price2=2287.88

Il semble bien que toute référence aux bougies 0 et 1 ou à la fonction ArrayCopyRates n'accède qu'aux informations déjà chargées dans les graphiques, donc ArrayCopyRates semble renvoyer un nombre valide d'éléments copiés et iTime(..., 0) et iTime(..., 1) renvoient un prix valide pour les 2 dernières bougies stockées lors de la fermeture de la plateforme le jour précédent.

Cela signifie que l'indicateur a été tracé comme si c'était hier (PERIOD_D1 [0] = (2017.02.08 00:00)).

L'indicateur est construit de telle sorte que les lignes haute, 50% et basse sont toujours tracées sur le jour actuel, même si l'utilisateur déplace le fib (ce sont les 3 lignes de tendance montrées dans le log ci-dessus). Par conséquent, j'ai un morceau de code dans OnCalculate() qui teste si la ligne de tendance moyenne est tracée le jour en cours (l'utilisateur a une option d'entrée pour désactiver les lignes supérieure et inférieure, donc la seule ligne qui sera toujours tracée est la ligne moyenne).

OnCalculate( ... )
:

      if(ObjectFind(Trend2Name) != -1)                // Check whether mid range line exists
        {
            
         if((TimeDay(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeDay(TimeCurrent()))
           && (TimeMonth(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeMonth(TimeCurrent()))
           && (TimeYear(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeYear(TimeCurrent()))) // Indicator has already been ploted today        
           {
            return(rates_total);
           }
         else     // Indicator exists but in a past date, so delete it and plot it on current day
           {
            if(DebugLog)
               Print("Indicator in a past date! Deleting it and creating it today!");
              
            if(ObjectFind(FibName) != -1)
              FiboLevelsDelete(0,FibName);              
            // Indicator will be created by the OnChartEvent() when it detects the fib was deleted.
           }
        }
      else        // Indicator doesn't exist, so create it
        {
         if(DebugLog)
            Print("Indicator doesn't exist! Creating it.");
         CreateIndicator();
        }
:

Après quelques ticks, les données sont partiellement chargées et le morceau de code ci-dessus détectera que les lignes ont été tracées sur un jour précédent, supprimera la fib et déclenchera un recalcul des plages et un redessin des objets (c'est-à-dire fib, lignes de tendance, etc).


2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Indicateur dans une date passée ! Le supprimer et le créer aujourd'hui !
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDRFibo 131296489639296384 supprimé !
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Suppression de PDRRectangle 131296489639296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Suppression de PDRTrend1 131296489639296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Suppression de PDRTrend2 131296489639296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Suppression de PDRTrend3 131296489639296384

Et nous en revenons au problème que j'évoquais au début de ce message. Le test que j'ai mis en place ci-dessus ne fait pas attendre à l'indicateur le chargement complet de l'historique et donc les fourchettes sont mal calculées sur la base de données partielles.

Voici une version plus complète du log montré au début du message qui montre que non seulement PrevDayEnd est mal calculé car la 2ème bougie (index 1) dans le graphique 1h est (2017.02.07 21:00) mais aussi CurrDayBegin qui est supposé être la 1ère bougie du jour courant dans le graphique 1h est approximé par iBarShift à (2017.02.08 06:00).

CurrDayBegin = iTime(NULL, PERIOD_D1, 0);
      
while(TimeDayOfWeek(iTime(NULL, PERIOD_H1, iBarShift(NULL, PERIOD_H1, CurrDayBegin))) != TimeDayOfWeek(TimeCurrent()))

     // If iBarShift can't find the 0am candle and returns the 11pm candle of prev day.

  CurrDayBegin = CurrDayBegin + 3600;        // Move 1h until you find the 1st candle of today.                                        

2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : == AUTRE JOUR DE LA SEMAINE ==
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR PrevDayEnd = 1 (2017.02.07 21:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR PrevDayBegin = 22 (2017.02.07 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR CurrDayBegin = (2017.02.08 06:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR PERIOD_D1 [0] = (2017.02.08 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR PERIOD_D1 [1] = (2017.02.07 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR PERIOD_D1 [2] = (2017.02.06 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR Jour de la semaine = 3
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR iHighest (Candle = 8) (Price = 2299.33) (Time = 2017.02.07 14:00:001)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : PDR iLowest (Candle = 19) (Price = 2288.57) (Time = 2017.02.07 03:00:001)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Fib de Time1=2017.02.07 03:00 Prix1=2288.57 à Time2=2017.02.07 14:00 Prix2=2299.33
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Ligne de tendance 'PDRTrend1 131296489639296384' de Time1=2017.02.08 06:00 Price1=2288.57 à Time2=2017.02.09 06:00 Price2=2288.57
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Ligne de tendance 'PDRTrend2 131296489639296384' de Time1=2017.02.08 06:00 Price1=2293.95 à Time2=2017.02.09 06:00 Price2=2293.95
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1 : Ligne de tendance 'PDRTrend3 131296489639296384' de Time1=2017.02.08 06:00 Price1=2299.33 à Time2=2017.02.09 06:00 Price2=2299.33

Donc, en résumé, existe-t-il un moyen de tester si tout l'historique a été chargé sur un graphique ? Ou est-ce que je rate quelque chose dans mon code ?

Merci de votre compréhension pour ce très long message.

S'il vous plaît laissez-moi savoir si vous souhaitez voir l'ensemble du code et le journal. Je préfère ne pas joindre le code ici, mais je serais heureux de l'envoyer en privé.

Voici des captures d'écran de l'indicateur :

(1) Calculé en utilisant un historique incomplet (remarquez que les lignes horizontales ne commencent pas au début de la journée).

Indicateur calculé avec un historique incomplet

(2) Recalculé en utilisant l'historique complet (les lignes horizontales commencent au début de la journée)

Indicateur recalculé en utilisant l'historique complet

Problems with ERR_HISTORY_WILL_UPDATED (4066 ) & weekends
Problems with ERR_HISTORY_WILL_UPDATED (4066 ) & weekends
  • www.mql5.com
Hi i m building a custom indicator and got problems with the 4066 Error...