Caractéristiques du langage mql5, subtilités et techniques - page 30

 

Je ne comprends pas du tout...

Je crée une poignée d'un AO standard dans l'indicateur, mais avec une période de temps définie. Lorsque je reçois des données d'AO avec une période qui ne correspond pas à la période actuelle, j'obtiens ... Je n'obtiens rien - erreur 4806.

Question : Quelle est la bonne façon d'obtenir des données à partir d'indicateurs standards dont les délais ne coïncident pas avec le délai actuel ?

//+------------------------------------------------------------------+
//|                                                      iMTF_AO.mq5 |
//|              Copyright 2017, Artem A. Trishkin, Skype artmedia70 |
//|                       https://login.mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Artem A. Trishkin, Skype artmedia70"
#property link      "https://login.mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot Label1
#property  indicator_label1  "AO"
#property  indicator_type1   DRAW_LINE
#property  indicator_color1  clrRed
#property  indicator_style1  STYLE_SOLID
#property  indicator_width1  1
//--- input parameters
sinput   ENUM_TIMEFRAMES   PeriodForWork  =  PERIOD_H4;  // Таймфрейм, с которого берём данные AO
//--- indicator buffers
double         Buffer[];
int   handle, error=ERR_SUCCESS;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,Buffer,INDICATOR_DATA);
   IndicatorSetInteger(INDICATOR_DIGITS,Digits());
   handle=iAO(NULL,PeriodForWork);
   if(handle==INVALID_HANDLE) return(INIT_FAILED);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   ArraySetAsSeries(Buffer,true);
   if(rates_total<1) return(0);
   int limit=rates_total-prev_calculated;
   if(limit>1) {
      limit=rates_total-1;
      }
   //---
   static string txt="";
   for(int i=limit; i>=0; i--) {
      Buffer[i]=AO(i);
      if(i<11 && i>0) {
         string ao=(Buffer[i]==EMPTY_VALUE?"EMPTY_VALUE":DoubleToString(AO(i),Digits()));
         txt+="\nAO("+(string)i+")="+ao;
         }
      }
   Comment("handle AO: ",handle,", TIMEFRAME AO: ",GetNameTF(PeriodForWork),", error: ",error,"\n-----------",txt,"\n-----------");
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
double AO(int shift){
   double array[1];
   error=ERR_SUCCESS;
   ResetLastError();
   if(CopyBuffer(handle,0,shift,1,array)==1) return(array[0]);
   else error=GetLastError();
   return(EMPTY_VALUE);
}
//+------------------------------------------------------------------+
string GetNameTF(int timeframe=PERIOD_CURRENT) {
   if(timeframe==PERIOD_CURRENT) timeframe=Period();
   switch(timeframe) {
      //--- MQL4
      case 1: return("M1");
      case 5: return("M5");
      case 15: return("M15");
      case 30: return("M30");
      case 60: return("H1");
      case 240: return("H4");
      case 1440: return("D1");
      case 10080: return("W1");
      case 43200: return("MN");
      //--- MQL5
      case 2: return("M2");
      case 3: return("M3");
      case 4: return("M4");      
      case 6: return("M6");
      case 10: return("M10");
      case 12: return("M12");
      case 16385: return("H1");
      case 16386: return("H2");
      case 16387: return("H3");
      case 16388: return("H4");
      case 16390: return("H6");
      case 16392: return("H8");
      case 16396: return("H12");
      case 16408: return("D1");
      case 32769: return("W1");
      case 49153: return("MN");      
      default: return("UnknownPeriod");
   }
}
//+------------------------------------------------------------------+
Dossiers :
iMTF_AO.mq5  9 kb
 
Artyom Trishkin:

Je ne comprends pas du tout...

Je crée une poignée d'un AO standard dans l'indicateur, mais avec une période de temps définie. Lorsque je reçois des données d'AO avec une période qui ne correspond pas à la période actuelle, j'obtiens ... Je n'obtiens rien - erreur 4806.

La question est la suivante : quelle est la bonne façon d'obtenir les données des indicateurs standard avec des délais qui ne coïncident pas avec le délai actuel ?


A propos de l'obtention des valeurs de l'INDICATEUR dans l'INDICATEUR :

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégie

Comment prendre les données d'un autre Indicateur dans un Indicateur

Vladimir Karputov, 2016.12.27 08:41

En gardant à l'esprit que dans les indicateurs MQL5, la barre avec l'index "0" est par défaut la barre de GAUCHE sur le graphique, essayons d'obtenir des données dans notre indicateur à partir de deux autres indicateurs - MA et Alligator(cet exemple dans l'indicateur "IndicatorFromIndicators.mql5").

Essayons de recevoir des données de MA et Alligator sur la barre avec l'index "0", "1" et "2" :

  {
//---
   Comment("Проверка: time[0]=",time[0],"\n",
           "rates_total-1: ",rates_total,"\n",
           "BarsCalculated(iMA): ",BarsCalculated(handle_iMA),"\n",
           "BarsCalculated(iAlligator): ",BarsCalculated(handle_iAlligator),"\n",
           "MA[",0,"]=",StringFormat("%."+IntegerToString(Digits()+1)+"f",iMAGet(0)),"\n",
           "MA[",1,"]=",StringFormat("%."+IntegerToString(Digits()+1)+"f",iMAGet(1)),"\n",
           "MA[",2,"]=",StringFormat("%."+IntegerToString(Digits()+1)+"f",iMAGet(2)),"\n",
           "Jaws[",0,"]=",StringFormat("%."+IntegerToString(Digits())+"f",iAlligatorGet(GATORJAW_LINE,0)),"\n",
           "Jaws[",1,"]=",StringFormat("%."+IntegerToString(Digits())+"f",iAlligatorGet(GATORJAW_LINE,1)),"\n",
           "Jaws[",2,"]=",StringFormat("%."+IntegerToString(Digits())+"f",iAlligatorGet(GATORJAW_LINE,2)));
//--- return value of prev_calculated for next call
   return(rates_total);
  }

Attachons l'indicateur de test"IndicatorFromIndicators.mql5" au graphique et réglons le réticule sur la barre la PLUS DROITE - c'est-à-dire qu'il ne s'agit pas d'une barre zéro. Voilà à quoi ça ressemble :

IndicatorFromIndicators

Bien que le réticule soit réglé sur la barre la plus à droite - c'est-à-dire certainement pas une barre avec un indice "0", lorsque vous utilisezCopyBuffer, vous devez savoir queCopyBuffer copiera les données du présent vers le passé, c'est-à-dire que la barre avec un indice "0" signifie la barre actuelle.


CopyBuffer : Les éléments de données à copier (tampon indicateur avec un index buffer_num) sont comptés à partir de la position de départ du présent vers le passé, c'est-à-dire que la position de départ de 0 signifie la barre actuelle (valeur de l'indicateur pour la barre actuelle).


C'est-à-dire que dans l'indicateur MQL5, s'il utilise l'opération CopyBuffer, vous devez retourner le tableau (ArraySetAsSeries), de sorte que la barre la plus à droite du graphique corresponde à l'indice "0" dans le tampon de l'indicateur (maintenant dans l'exemple "iMTF_AO.mq5", la barre la plus à droite du graphique correspond à rates_total-1).

 
Vladimir Karputov:


A propos de l'obtention des valeurs INDICATOR dans INDICATOR :


CopyBuffer : Les éléments des données copiées (tampon indicateur avec un index buffer_num) sont comptés à partir de la position de départ du présent vers le passé, c'est-à-dire que la position de départ égale à 0 signifie la barre actuelle (valeur de l'indicateur pour la barre actuelle).


C'est-à-dire que dans l'indicateur MQL5, s'il utilise l'opération CopyBuffer, vous devez retourner le tableau (ArraySetAsSeries), de sorte que la barre la plus à droite du graphique corresponde à l'indice "0" dans le tampon de l'indicateur (maintenant dans l'exemple "iMTF_AO.mq5", la barre la plus à droite du graphique correspond à rates_total-1).

Je ne reçois qu'une seule barre. Et l'indicateur sur le cadre temporel "natif" affiche les données normalement. Sur le "non-natif" - valeur vierge. J'ai constaté empiriquement qu'une valeur vide sera renvoyée jusqu'à ce que l'historique complet soit chargé pour la période pour laquelle je reçois des données de l'AO.

//+------------------------------------------------------------------+
//|                                                      iMTF_AO.mq5 |
//|              Copyright 2017, Artem A. Trishkin, Skype artmedia70 |
//|                       https://login.mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Artem A. Trishkin, Skype artmedia70"
#property link      "https://login.mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot Label1
#property  indicator_label1  "AO"
#property  indicator_type1   DRAW_LINE
#property  indicator_color1  clrRed
#property  indicator_style1  STYLE_SOLID
#property  indicator_width1  1
//--- input parameters
sinput   ENUM_TIMEFRAMES   PeriodForWork  =  PERIOD_H4;  // Таймфрейм, с которого берём данные AO
//--- indicator buffers
double         Buffer[];
int   handle, error=ERR_SUCCESS;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,Buffer,INDICATOR_DATA);
   IndicatorSetInteger(INDICATOR_DIGITS,Digits());
   handle=iAO(NULL,PeriodForWork);
   if(handle==INVALID_HANDLE) return(INIT_FAILED);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   ArraySetAsSeries(Buffer,true);
   int bars=Bars(NULL,PeriodForWork);
   datetime time_limit=GetTime(Symbol(),PeriodForWork,bars-1);
   int limit_p=GetBarShift(Symbol(),Period(),time_limit);
   if(rates_total<1) return(0);
   int limit=(PeriodForWork==Period()?rates_total-prev_calculated:limit_p);
   if(limit>1) {
      limit=rates_total-1;
      }
   //---
   static string txt="";
   for(int i=limit; i>=0; i--) {
      Buffer[i]=AO(i);
      if(i<6 && i>0) {
         string ao=(Buffer[i]==EMPTY_VALUE?"EMPTY_VALUE":DoubleToString(AO(i),Digits()));
         txt+="\nAO("+(string)i+")="+ao;
         }
      }
   Comment("handle AO: ",handle,", TIMEFRAME AO: ",GetNameTF(PeriodForWork),", error: ",error,"\n-----------",(error>0?"\nLoading history":txt),
           "\n-----------",
           "\nAO(1)=",DoubleToString(AO(1),Digits()),
           "\nAO(",limit_p,")=",DoubleToString(AO(limit_p),Digits())
          );
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
double AO(int shift){
   double array[];
   ArrayResize(array,1);
   ArrayInitialize(array,EMPTY_VALUE);
   error=ERR_SUCCESS;
   ResetLastError();
   if(CopyBuffer(handle,0,shift,1,array)==1) {
      ArraySetAsSeries(array,false);
      return(array[0]);
      }
   else error=GetLastError();
   return(EMPTY_VALUE);
}
//+------------------------------------------------------------------+
datetime GetTime(const string symbol_name, const ENUM_TIMEFRAMES timeframe, const int shift) {
   datetime array[1];
   ResetLastError();
   if(CopyTime(symbol_name,timeframe,shift,1,array)==1) return(array[0]);
   Print(__FUNCTION__," > Ошибка получения времени бара ",shift,": ",GetLastError());
   return(0);
}
//+------------------------------------------------------------------+
int GetBarShift(const string symbol_name, const ENUM_TIMEFRAMES timeframe, const datetime time) {
   int res=WRONG_VALUE;
   datetime last_bar;
   if(SeriesInfoInteger(symbol_name,timeframe,SERIES_LASTBAR_DATE,last_bar)) {
      if(time>last_bar) res=0;
      else {
         const int shift=Bars(symbol_name,timeframe,time,last_bar);
         if(shift>0) res=shift-1;
         }
      }
   return(res);
}
//+------------------------------------------------------------------+
string GetNameTF(int timeframe=PERIOD_CURRENT) {
   if(timeframe==PERIOD_CURRENT) timeframe=Period();
   switch(timeframe) {
      //--- MQL4
      case 1: return("M1");
      case 5: return("M5");
      case 15: return("M15");
      case 30: return("M30");
      case 60: return("H1");
      case 240: return("H4");
      case 1440: return("D1");
      case 10080: return("W1");
      case 43200: return("MN");
      //--- MQL5
      case 2: return("M2");
      case 3: return("M3");
      case 4: return("M4");      
      case 6: return("M6");
      case 10: return("M10");
      case 12: return("M12");
      case 16385: return("H1");
      case 16386: return("H2");
      case 16387: return("H3");
      case 16388: return("H4");
      case 16390: return("H6");
      case 16392: return("H8");
      case 16396: return("H12");
      case 16408: return("D1");
      case 32769: return("W1");
      case 49153: return("MN");      
      default: return("UnknownPeriod");
   }
}
//+------------------------------------------------------------------+

La question qui se pose alors est la suivante : comment éviter d'entrer dans la boucle pendant que l'historique est chargé pour la période considérée ? C'est juste un test, en général l'indicateur effectue des calculs en fonction de l'historique de la période spécifiée et il n'est pas nécessaire d'essayer de les effectuer lorsque l'historique n'est pas présent.

Dossiers :
iMTF_AO.mq5  12 kb
 
Artyom Trishkin:

Je n'ai droit qu'à une barre. Et l'indicateur sur l'horizon temporel "natif" affiche les données normalement. Sur le modèle "non-natif", il affiche une valeur vide. J'ai découvert empiriquement qu'une valeur vide sera renvoyée jusqu'à ce que tout l'historique soit chargé pour la période de temps, à partir de laquelle je reçois des données de l'AO.

La question se posera alors différemment : comment ne pas entrer dans la boucle, alors que l'historique de la période est en train de se charger ? Il s'agit juste d'un test. En général, l'indicateur effectue les calculs en fonction de l'historique d'une période spécifiée et il n'est pas nécessaire d'essayer de les effectuer tant qu'il n'y a pas d'historique.

Avez-vous essayé la synchronisation ? De plus, les développeurs conseillent de maintenir à jour les données du TF/symbole requis grâce à la minuterie.
 
Ici :
      Buffer[i]=AO(i);

Le "i" n'est pas "0", mais une valeur exorbitante. En résumé, disons que nous exécutons l'exemple sur M15 - nous avons 5000 barres sur cette période. Nous demandons les données de H4 - nous n'avons que 400 barres dessus. Ensuite, nous essayons de demander "AO(4999)".

C'est-à-dire que pour la période H4, nous essayons de demander la barre avec l'index "4999" - mais il n'y a pas du tout de barre sur H4, il n'y a que 400 barres, mais nous demandons la barre "0", et si l'indicateur utilise l'opération CopyBuffer, nous devons inverser le tableau (ArraySetAsSeries), de sorte que la barre la plus à droite sur le graphique correspond à l'index "0" dans le tampon de l'indicateur (maintenant dans l'exemple "iMTF_AO.mq5" la barre la plus à droite sur le graphique correspond à rates_total-1).

 

Forum sur le trading, les systèmes de trading automatisé et les tests de stratégies de trading

Bugs, bugs, questions

fxsaber, 2017.04.12 08:38

Un petit coup de chapeau. Contournement de l'opérateur d'affectation
template <typename T>
struct STRUCT_COPY
{
  T Value;
  
  STRUCT_COPY( const T& tValue)
  {
    this = (STRUCT_COPY)tValue;
  }  
};

struct STRUCT
{
  int i;
  
  void operator =( const STRUCT& )
  {
    this.i = 5;
  }
};

#define  PRINT(A) ::Print(#A + " = " + (string)(A));

void OnStart()
{
  STRUCT Struct;  
  Struct.i = 1;  
  PRINT(Struct.i);
  
  STRUCT StructCopy1 = Struct;
  PRINT(StructCopy1.i);
  
  // Обходим void STRUCT::operator=(const STRUCT&)
  STRUCT_COPY<STRUCT> StructCopy2(Struct);
  PRINT(StructCopy2.Value.i);  
}

Résultat

Struct.i = 1
StructCopy1.i = 5
StructCopy2.Value.i = 1
 
Vladimir Karputov:
Ici.. :

Le "i" n'est pas "0", mais une valeur exorbitante. En résumé, disons que nous exécutons l'exemple sur M15 - nous avons 5000 barres sur cette période. Nous demandons les données de H4 - nous n'avons que 400 barres dessus. Ensuite, nous essayons de demander "AO(4999)".

Par exemple, à partir de la période H4, nous essayons de demander la barre avec l'index "4999" - mais il n'y a pas une telle barre sur H4, il y a seulement 400 barres là, mais nous voulons la barre "0", et si l'indicateur utilise l'opération "CopyBuffer", nous devrions inverser le tableau (ArraySetAsSeries), de sorte que la barre la plus à droite dans le graphique correspond à l'index "0" dans le tampon de l'indicateur (par exemple "iMTF_AO.mq5" maintenant la barre la plus à droite dans le graphique correspond à rates_total-1).

Non, bien sûr, j'ai essayé de calculer la limite:

   int bars=Bars(NULL,PeriodForWork);                         
   datetime time_limit=GetTime(Symbol(),PeriodForWork,bars-1);
   int limit_p=GetBarShift(Symbol(),Period(),time_limit);     
   if(rates_total<1) return(0);
   int limit=(PeriodForWork==Period()?rates_total-prev_calculated:limit_p);
   if(limit>1) {          
      limit=rates_total-1;
      }                   

... Mais je vois que j'ai merdé dans la précipitation - elle ne convient qu'à la période actuelle

 
Artyom Trishkin:

Non, bien sûr, j'ai essayé de calculer la limite:

... Mais je vois, j'ai merdé dans la précipitation - c'est approprié pour la période actuelle seulement.


  1. Inverser le tableau du tampon (ArraySetAsSeries) - ceci est obligatoire si l'indicateur utilise le CopyBuffer
  2. Gardez à l'esprit que le CopyBuffer : éléments des données copiées(tampon indicateur avec un index buffer_num) est compté à partir de la position de départ du présent vers le passé, c'est-à-dire que la position de départ de 0 signifie la barre actuelle (la valeur de l'indicateur pour la barre actuelle).
Après cela, en AO (le début "0" signifie la barre la PLUS DROITE), pas une valeur exorbitante.
 
Vladimir Karputov:

  1. Inverser le tableau du tampon (ArraySetAsSeries) - ceci est obligatoire si l'indicateur utilise le CopyBuffer
  2. Rappelez-vous que les éléments CopyBuffer : des données copiées(tampon indicateur avec un index buffer_num) sont comptés à partir de la position de départ du présent vers le passé, c'est-à-dire que la position de départ égale à 0 signifie la barre actuelle (valeur de l'indicateur pour la barre actuelle).
Après cela en AO(run "0" signifie la barre la PLUS DROITE), pas une valeur exorbitante.

As-tu au moins regardé le code que je t'ai montré ? Ou l'avez-vous exécuté ?

Je n'ai pas demandé comment remplir le tampon de l'indicateur, mais pourquoi si je prends des valeurs d'AO qui ne proviennent pas de la barre actuelle, elles renvoient des valeurs vides.
J'ai compris - il n'y a pas d'historique, il est en train d'être chargé et pendant qu'il est chargé, AO d'une période non native renvoie l'erreur "pas de données".

La question qui se pose maintenant est la suivante : comment savoir si l'historique pour l'horizon temporel requis est entièrement chargé, afin de ne pas entrer dans le cycle des indicateurs ?

 
Les commentaires non liés à ce sujet ont été déplacés vers "Questions des débutants de MQL5 MT5 MetaTrader 5".
Raison: