Características da linguagem mql5, subtilezas e técnicas - página 30

 

Eu não percebo nada...

Eu crio um cabo de um AO padrão no indicador, mas com um período de tempo definido. Quando recebo dados da AO com um prazo que não coincide com o actual, recebo ... Eu não recebo nada - erro 4806.

Pergunta: Qual é a forma correcta de obter dados de indicadores padrão com prazos que não coincidem com o 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");
   }
}
//+------------------------------------------------------------------+
Arquivos anexados:
iMTF_AO.mq5  9 kb
 
Artyom Trishkin:

Eu não percebo nada...

Eu crio um cabo de um AO padrão no indicador, mas com um período de tempo definido. Quando recebo dados da AO com um prazo que não coincide com o actual, recebo ... Eu não recebo nada - erro 4806.

Qual é a pergunta, qual é a forma correcta de obter os dados dos indicadores padrão com prazos que não coincidem com o actual?


Sobre a obtenção dos valores do INDICADOR no INDICADOR:

Fórum sobre negociação, sistemas de negociação automatizados e testes estratégicos

Como obter dados de outro Indicador em um Indicador

Vladimir Karputov, 2016.12.27 08:41

Tendo em conta que nos indicadores MQL5, a barra com índice "0" é por defeito a barra ESQUERDA no gráfico, vamos tentar obter dados no nosso indicador a partir de outros dois indicadores - MA e Alligator(este exemplo no indicador "IndicatorFromIndicators.mql5").

Vamos tentar receber dados de MA e Alligator na barra com índices "0", "1" e "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);
  }

Vamos anexar o indicador de teste"IndicatorFromIndicators.mql5" ao gráfico e definir o retículo para a barra mais direita - ou seja, não é barra zero. Isto é o que parece:

IndicadorDeIndicadores

Embora a mira esteja definida para a barra DIREITA - ou seja, definitivamente não uma barra com índice "0", ao utilizaro CopyBuffer deve estar ciente de queo CopyBuffer irá copiar dados do presente para o passado, ou seja, barra com índice "0" significa a barra actual.


CopyBuffer: Os elementos de dados a serem copiados (buffer de código com um buffer_num de índice) são contados a partir da posição inicial do presente para o passado, ou seja, a posição inicial 0 significa a barra atual (valor do código para a barra atual).


Ou seja, no código MQL5, se ele utiliza a operação CopyBuffer, é necessário inverter a matriz (ArraySetAsSeries), para que a barra mais à direita no gráfico corresponda ao índice "0" no buffer do código (agora no exemplo "iMTF_AO.mq5", a barra mais à direita no gráfico corresponde a rates_total-1).

 
Vladimir Karputov:


Sobre obter valores INDICADORES no INDICADOR:


CopyBuffer: Os elementos dos dados copiados (buffer de código com um buffer_num de índice) são contados da posição inicial do presente para o passado, ou seja, a posição inicial igual a 0 significa a barra atual (valor do código para a barra atual).


Ou seja, no código MQL5, se ele utiliza a operação CopyBuffer, deve-se inverter a matriz (ArraySetAsSeries), para que a barra mais à direita no gráfico corresponda ao índice "0" no buffer do indicador (agora no exemplo "iMTF_AO.mq5", a barra mais à direita no gráfico corresponde a rates_total-1).

Eu só tenho um bar. E o indicador no período de tempo "nativo" exibe os dados normalmente. Sobre o "não-nativo" - valor em branco. Descobri empiricamente que um valor vazio será devolvido até que todo o histórico seja carregado durante o período de tempo a partir do qual recebo os dados da 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");
   }
}
//+------------------------------------------------------------------+

A questão seria então: Como evitar entrar no laço enquanto o histórico está sendo carregado durante o período de tempo? É apenas um teste, enquanto em geral o indicador realiza cálculos de acordo com o histórico de um determinado período de tempo e não há necessidade de tentar realizá-los até que não haja histórico.

Arquivos anexados:
iMTF_AO.mq5  12 kb
 
Artyom Trishkin:

Só tenho direito a um bar. E o indicador no período de tempo "nativo" exibe os dados normalmente. No "não-nativo", mostra um valor em branco. Descobri empiricamente que um valor vazio será devolvido até que todo o histórico seja carregado durante o período de tempo, a partir do qual recebo dados da AO.

Então a questão soará diferente: como não entrar no laço, enquanto o histórico para o período de tempo está carregando? Isto é apenas um teste. Em geral, o indicador executa os cálculos de acordo com o histórico de um determinado período de tempo e não há necessidade de tentar realizá-los até que não haja histórico.

Você já tentou a sincronização? Além disso, os desenvolvedores aconselham a manter os dados do TF/símbolo necessários atualizados através do temporizador.
 
Toma:
      Buffer[i]=AO(i);

O "i" não é um "0", mas um valor exorbitante. Resumindo: digamos que corremos o exemplo na M15 - temos 5000 barras neste período. Pedimos dados ao H4 - temos apenas 400 barras. Depois tentamos pedir "AO(4999)".

Ou seja, a partir do período H4 tentamos solicitar a barra com índice "4999" - mas não existe nenhuma barra desse tipo no H4, existem apenas 400 barras, mas solicitamos a barra "0", e se o indicador utilizar a operação CopyBuffer, devemos girar o array (ArraySetAsSeries) para que a barra mais à direita no gráfico corresponda ao índice "0" no buffer do indicador (agora no exemplo "iMTF_AO.mq5" a barra mais à direita no gráfico corresponde a rates_total-1).

 

Fórum sobre negociação, sistemas de negociação automatizados e testes de estratégia de negociação

Bugs, bugs, perguntas

fxsaber, 2017.04.12 08:38

Uma pequena ponta do chapéu. Contornar o operador de atribuição
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:
Aqui..:

O "i" não é um "0", mas um valor exorbitante. Resumindo: digamos que corremos o exemplo na M15 - temos 5000 barras neste período. Pedimos dados ao H4 - temos apenas 400 barras. Depois tentamos pedir "AO(4999)".

Por exemplo, a partir do período H4, tentamos solicitar a barra com índice "4999" - mas não existe tal barra no H4, existem apenas 400 barras, mas queremos a barra "0", e se o indicador utiliza a operação CopyBuffer, devemos inverter o array (ArraySetAsSeries), para que a barra mais à direita no gráfico corresponda ao índice "0" no buffer do indicador (por exemplo "iMTF_AO.mq5" agora a barra mais à direita no gráfico corresponde a rates_total-1).

Não, claro que tentei calcular o 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;
      }                   

... Mas vejo que estraguei tudo à pressa - é apropriado apenas para o actual período de tempo

 
Artyom Trishkin:

Não, claro que tentei calcular o limite:

... Mas vejo que estraguei tudo à pressa - é apropriado apenas para o período de tempo actual.


  1. Reverter a matriz de buffer (ArraySetAsSeries) - isto é obrigatório se o indicador usar o CopyBuffer
  2. Tenha em mente que o CopyBuffer: elementos dos dados copiados(buffer indicador com um buffer_num índice) é contado a partir da posição inicial do presente para o passado, ou seja, a posição inicial de 0 significa a barra atual (o valor do indicador para a barra atual).
Depois disso, em AO(start "0" significa a barra ORIENTE), e não algum valor exorbitante.
 
Vladimir Karputov:

  1. Reverter a matriz de buffer (ArraySetAsSeries) - isto é obrigatório se o indicador usar o CopyBuffer
  2. Lembre-se de que o CopyBuffer: elementos dos dados copiados(buffer indicador com um buffer_num índice) é contado a partir da posição inicial do presente para o passado, ou seja, a posição inicial igual a 0 significa a barra atual (valor do indicador para a barra atual).
Depois disso, em AO(run "0" significa a barra ORIENTE), e não algum valor exorbitante.

Olhaste sequer para o código que te mostrei? Ou você a dirigiu?

Eu não perguntei como preencher o buffer indicador, mas porque é que se eu tirar valores de AO não da barra actual, eles devolvem valores vazios.
Eu recebi - não há histórico, ele está sendo carregado e enquanto ele está sendo carregado AO de um período de tempo não nativo retorna o erro "sem dados".

Agora a questão é: como saber se o histórico para o período de tempo necessário está totalmente carregado, de modo a não entrar no ciclo indicador?

 
Comentários não relacionados a este tópico foram movidos para "Perguntas dos iniciantes do MQL5 MT5 MetaTrader 5".