Características del lenguaje mql5, sutilezas y técnicas - página 30

 

No lo entiendo en absoluto...

Creo una manija de un AO estándar en el indicador, pero con un marco de tiempo establecido. Cuando recibo datos de AO con un marco temporal que no coincide con el actual, obtengo ... No obtengo nada - error 4806.

Pregunta: ¿Cuál es la forma correcta de obtener datos de indicadores estándar con plazos que no coinciden con el actual?

//+------------------------------------------------------------------+
//|                                                      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");
   }
}
//+------------------------------------------------------------------+
Archivos adjuntos:
iMTF_AO.mq5  9 kb
 
Artyom Trishkin:

No lo entiendo en absoluto...

Creo una manija de un AO estándar en el indicador, pero con un marco de tiempo establecido. Cuando recibo datos de AO con un marco temporal que no coincide con el actual, obtengo ... No obtengo nada - error 4806.

¿Cuál es la pregunta, cuál es la forma correcta de obtener los datos de los indicadores estándar con plazos que no coinciden con el actual?


Sobre la obtención de los valores del INDICADOR en el INDICADOR:

Foro sobre comercio, sistemas de comercio automatizados y pruebas de estrategias

Cómo tomar datos de otro indicador en un indicador

Vladimir Karputov, 2016.12.27 08:41

Teniendo en cuenta que en los indicadores MQL5, la barra con índice "0" es por defecto la barra IZQUIERDA del gráfico, vamos a intentar obtener datos en nuestro indicador desde otros dos indicadores - MA y Alligator(este ejemplo en el indicador "IndicatorFromIndicators.mql5").

Intentemos recibir datos de MA y Alligator en la barra con índice "0", "1" y "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);
  }

Adjuntemos el indicador de prueba"IndicatorFromIndicators.mql5" al gráfico y pongamos la retícula en la barra MÁS CORRECTA, es decir, que no sea la barra cero. Esto es lo que parece:

IndicadorDeIndicadores

Aunque el retículo se fija en la barra más correcta - es decir, definitivamente no en una barra con índice "0", cuando se utilizaCopyBuffer se debe tener en cuenta queCopyBuffer copiará los datos del presente al pasado, es decir, la barra con índice "0" significa la barra actual.


CopyBuffer: Los elementos de datos a copiar (buffer de indicadores con un índice buffer_num) se cuentan desde la posición de inicio del presente al pasado, es decir, la posición de inicio de 0 significa la barra actual (valor del indicador para la barra actual).


Es decir, en el indicador MQL5, si se utiliza la operación CopyBuffer, hay que voltear el array (ArraySetAsSeries), de forma que la barra más a la derecha del gráfico corresponda al índice "0" del buffer del indicador (ahora en el ejemplo "iMTF_AO.mq5", la barra más a la derecha del gráfico corresponde a rates_total-1).

 
Vladimir Karputov:


Sobre la obtención de los valores de INDICATOR en INDICATOR:


CopyBuffer: Los elementos de los datos copiados (buffer indicador con un índice buffer_num) se cuentan desde la posición inicial del presente al pasado, es decir, la posición inicial igual a 0 significa la barra actual (valor del indicador para la barra actual).


Es decir, en el indicador MQL5, si utiliza la operación CopyBuffer, debe voltear el array (ArraySetAsSeries), de manera que la barra más a la derecha del gráfico corresponda al índice "0" del buffer del indicador (ahora en el ejemplo "iMTF_AO.mq5", la barra más a la derecha del gráfico corresponde a rates_total-1).

Sólo consigo una barra. Y el indicador en el marco temporal "nativo" muestra los datos normalmente. En el valor "no nativo" - en blanco. He averiguado empíricamente que se devolverá un valor vacío hasta que se cargue todo el historial para el periodo de tiempo del que recibo los datos de 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 pregunta sería entonces: ¿Cómo evitar entrar en el bucle mientras se carga el historial para el marco temporal? Es sólo una prueba, mientras que en general el indicador realiza los cálculos de acuerdo con el historial de un marco de tiempo especificado y no hay necesidad de tratar de realizarlos hasta que no haya historial.

Archivos adjuntos:
iMTF_AO.mq5  12 kb
 
Artyom Trishkin:

Sólo tengo una barra. Y el indicador en el marco temporal "nativo" muestra los datos normalmente. En el "no nativo" muestra un valor en blanco. He averiguado empíricamente que se devolverá un valor vacío hasta que se cargue todo el historial para el marco temporal, del que recibo datos de AO.

La pregunta entonces sonará de otra manera: ¿cómo no entrar en el bucle, mientras que la historia para el marco de tiempo se está cargando? Esto es sólo una prueba. En general, el indicador realiza los cálculos de acuerdo con la historia de un marco de tiempo especificado y no hay necesidad de tratar de realizarlos hasta que no haya historia.

¿Has probado la sincronización? Además, los desarrolladores aconsejan mantener actualizados los datos del TF/símbolo requerido a través del temporizador.
 
Aquí:
      Buffer[i]=AO(i);

La "i" no es "0", sino algún valor exorbitante. En resumen: digamos que ejecutamos el ejemplo en M15 - tenemos 5000 barras en este periodo. Solicitamos datos de H4 - sólo tenemos 400 barras en él. Entonces intentamos solicitar "AO(4999)".

Es decir, desde el periodo H4 intentamos solicitar la barra con índice "4999" - pero no hay tal barra en H4 en absoluto, sólo hay 400 barras allí, pero solicitamos la barra "0", y si el indicador utiliza la operación CopyBuffer, deberíamos girar el array (ArraySetAsSeries) para que la barra más a la derecha en el gráfico corresponda al índice "0" en el buffer del indicador (ahora en el ejemplo "iMTF_AO.mq5" la barra más a la derecha en el gráfico corresponde a rates_total-1).

 

Foro sobre trading, sistemas de trading automatizados y pruebas de estrategias de trading

Bichos, errores, preguntas

fxsaber, 2017.04.12 08:38

Un poco de sombrero. Evitar el operador de asignación
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);  
}

Resultado

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

La "i" no es "0", sino algún valor exorbitante. En resumen: digamos que ejecutamos el ejemplo en M15 - tenemos 5000 barras en este periodo. Solicitamos datos de H4 - sólo tenemos 400 barras en él. Entonces intentamos solicitar "AO(4999)".

Por ejemplo, del periodo H4, intentamos solicitar la barra con índice "4999" - pero no hay tal barra en H4, sólo hay 400 barras allí, pero queremos la barra "0", y si el indicador utiliza la operación CopyBuffer, deberíamos invertir el array (ArraySetAsSeries), de modo que la barra más a la derecha en el gráfico corresponde al índice "0" en el buffer del indicador (por ejemplo "iMTF_AO.mq5" ahora la barra más a la derecha en el gráfico corresponde a rates_total-1).

No, por supuesto que intenté calcular el límite:

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

... Pero veo que he me tido la pata a toda prisa: sólo es apropiado para el marco temporal actual

 
Artyom Trishkin:

No, por supuesto que intenté calcular el límite:

... Pero ya veo, metí la p ata deprisa - es apropiado sólo para el marco temporal actual


  1. Invertir la matriz del buffer (ArraySetAsSeries) - esto es obligatorio si el indicador utiliza el CopyBuffer
  2. Hay que tener en cuenta que el CopyBuffer: elementos de los datos copiados(buffer del indicador con un índice buffer_num) se cuenta desde la posición inicial del presente al pasado, es decir, la posición inicial igual a 0 significa la barra actual (el valor del indicador para la barra actual).
Después de eso en AO(inicio "0" significa la barra más correcta), no un valor exorbitante.
 
Vladimir Karputov:

  1. Invertir la matriz del buffer (ArraySetAsSeries) - esto es obligatorio si el indicador utiliza el CopyBuffer
  2. Recuerde que el CopyBuffer: elementos de los datos copiados(buffer de indicadores con un índice buffer_num) se cuenta desde la posición inicial del presente al pasado, es decir, la posición inicial igual a 0 significa la barra actual (valor del indicador para la barra actual).
Después de eso en AO(run "0" significa la barra más correcta), no un valor exorbitante.

¿Acaso miraste el código que te mostré? ¿O lo has hecho tú?

No pregunté cómo llenar el buffer del indicador, sino por qué si tomo valores de AO no de la barra actual, devuelven valores vacíos.
Lo tengo - no hay historial, se está cargando y mientras se carga AO desde un marco temporal no nativo devuelve el error "no hay datos".

Ahora la pregunta es: ¿cómo saber que el historial para el marco temporal necesario está completamente cargado, para no entrar en el ciclo del indicador?

 
Los comentarios no relacionados con este tema han sido trasladados a "Preguntas de los principiantes de MQL5 MT5 MetaTrader 5".