Caratteristiche del linguaggio mql5, sottigliezze e tecniche - pagina 30

 

Non lo capisco affatto...

Creo un handle di un AO standard nell'indicatore, ma con un timeframe impostato. Quando ricevo dati da AO con un timeframe che non corrisponde a quello attuale, ottengo ... Non ottengo nulla - errore 4806.

Domanda: Qual è il modo corretto per ottenere dati da indicatori standard con tempi che non coincidono con quello attuale?

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

Non lo capisco affatto...

Creo un handle di un AO standard nell'indicatore, ma con un timeframe impostato. Quando ricevo dati da AO con un timeframe che non corrisponde a quello attuale, ottengo ... Non ottengo nulla - errore 4806.

Qual è la domanda, qual è il modo corretto per ottenere i dati da indicatori standard con timeframes che non coincidono con quello attuale?


Su come ottenere i valori dell'INDICATORE nell'INDICATORE:

Forum sul trading, sistemi di trading automatico e test di strategia

Come prendere dati da un altro indicatore in un indicatore

Vladimir Karputov, 2016.12.27 08:41

Tenendo presente che negli indicatori MQL5, la barra con indice "0" è di default la barra di SINISTRA del grafico, proviamo ad ottenere i dati nel nostro indicatore da altri due indicatori - MA e Alligator(questo esempio nell'indicatore "IndicatorFromIndicators.mql5").

Proviamo a ricevere dati da MA e Alligator sulla barra con indice "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);
  }

Colleghiamo l'indicatore di prova"IndicatorFromIndicators.mql5" al grafico e impostiamo il mirino sulla barra più a destra - cioè non è la barra zero. Questo è quello che sembra:

IndicatoreFromIndicators

Anche se il mirino è impostato sulla barra più a destra - cioè sicuramente non una barra con indice "0", quando si usaCopyBuffer si deve essere consapevoli cheCopyBuffer copierà i dati dal presente al passato, cioè la barra con indice "0" significa la barra corrente.


CopyBuffer: gli elementi di dati da copiare (buffer di indicatori con un indice buffer_num) sono contati dalla posizione iniziale dal presente al passato, cioè la posizione iniziale di 0 significa la barra attuale (valore dell'indicatore per la barra attuale).


Cioè, nell'indicatore MQL5, se usa l'operazione CopyBuffer, bisogna capovolgere l'array (ArraySetAsSeries), in modo che la barra più a destra nel grafico corrisponda all'indice "0" nel buffer dell'indicatore (ora nell'esempio "iMTF_AO.mq5", la barra più a destra nel grafico corrisponde a rates_total-1).

 
Vladimir Karputov:


Per ottenere i valori di INDICATOR in INDICATOR:


CopyBuffer: gli elementi dei dati copiati (buffer indicatore con un indice buffer_num) sono contati dalla posizione di partenza dal presente al passato, cioè la posizione di partenza uguale a 0 significa la barra corrente (valore dell'indicatore per la barra corrente).


Cioè, nell'indicatore MQL5, se usa l'operazione CopyBuffer, bisogna capovolgere l'array (ArraySetAsSeries), in modo che la barra più a destra nel grafico corrisponda all'indice "0" nel buffer dell'indicatore (ora nell'esempio "iMTF_AO.mq5", la barra più a destra nel grafico corrisponde a rates_total-1).

Ottengo solo una barra. E l'indicatore sul timeframe "nativo" visualizza i dati normalmente. Sul valore "non nativo" - vuoto. Ho capito empiricamente che viene restituito un valore vuoto fino a quando non viene caricata l'intera cronologia per il lasso di tempo in cui ricevo i dati 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");
   }
}
//+------------------------------------------------------------------+

La domanda sarebbe allora: come evitare di entrare nel ciclo mentre la storia viene caricata per il timeframe? È solo un test, in generale l'indicatore esegue i calcoli in base alla storia del timeframe specificato e non c'è bisogno di provare a eseguirli mentre la storia non è presente.

File:
iMTF_AO.mq5  12 kb
 
Artyom Trishkin:

Ho solo una barra. E l'indicatore sul timeframe "nativo" visualizza i dati normalmente. Su quello "non nativo" mostra un valore vuoto. Ho capito empiricamente che un valore vuoto sarà restituito fino a quando tutta la storia è caricata per il timeframe, da cui ricevo i dati da AO.

Allora la domanda suonerà in modo diverso: come non entrare nel loop, mentre la storia per il timeframe è in caricamento? Questo è solo un test. In generale, l'indicatore esegue i calcoli in base alla storia di un determinato timeframe e non c'è bisogno di provare ad eseguirli finché non c'è storia.

Avete provato la sincronizzazione? Inoltre, gli sviluppatori consigliano di mantenere aggiornati i dati del TF/simbolo richiesto attraverso il timer.
 
Qui:
      Buffer[i]=AO(i);

La "i" non è "0", ma qualche valore esorbitante. In conclusione: diciamo che eseguiamo l'esempio su M15 - abbiamo 5000 barre su questo periodo. Richiediamo i dati di H4 - abbiamo solo 400 barre su di esso. Poi proviamo a richiedere "AO(4999)".

Cioè, dal periodo H4 cerchiamo di richiedere la barra con l'indice "4999" - ma non c'è nessuna barra del genere su H4, ci sono solo 400 barre, ma richiediamo la barra "0", e se l'indicatore usa l'operazione CopyBuffer, dovremmo invertire l'array (ArraySetAsSeries), in modo che la barra più a destra nel grafico corrisponda all'indice "0" nel buffer dell'indicatore (ora nell'esempio "iMTF_AO.mq5" la barra più a destra sul grafico corrisponde a rates_total-1).

 

Forum sul trading, sistemi di trading automatico e test di strategie di trading

Bug, bug, domande

fxsaber, 2017.04.12 08:38

Una piccola punta di cappello. Bypassare l'operatore di assegnazione
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);  
}

Risultato

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

La "i" non è "0", ma qualche valore esorbitante. In conclusione: diciamo che eseguiamo l'esempio su M15 - abbiamo 5000 barre su questo periodo. Richiediamo i dati di H4 - abbiamo solo 400 barre su di esso. Poi proviamo a richiedere "AO(4999)".

Per esempio, dal periodo H4, cerchiamo di richiedere la barra con indice "4999" - ma non c'è una tale barra su H4, ci sono solo 400 barre lì, ma vogliamo la barra "0", e se l'indicatore usa l'operazione "CopyBuffer", dovremmo invertire l'array (ArraySetAsSeries), in modo che la barra più a destra nel grafico corrisponde all'indice "0" nel buffer dell'indicatore (per esempio "iMTF_AO.mq5" ora la barra più a destra nel grafico corrisponde a rates_total-1).

No, naturalmente ho cercato di calcolare il 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;
      }                   

... Ma vedo che ho sbagliato in fretta - è appropriato solo per il periodo attuale

 
Artyom Trishkin:

No, naturalmente ho cercato di calcolare il limite:

... Ma vedo, ho fatto un casino nella fretta - è appropriato solo per il periodo attuale


  1. Invertire l'array di buffer (ArraySetAsSeries) - questo è obbligatorio se l'indicatore usa il CopyBuffer
  2. Tenete presente che il CopyBuffer: elementi dei dati copiati(buffer di indicatori con un indice buffer_num) è contato dalla posizione iniziale dal presente al passato, cioè la posizione iniziale di 0 significa la barra attuale (il valore dell'indicatore per la barra attuale).
Dopo di che in AO (inizio "0" significa la barra più a destra), non qualche valore esorbitante.
 
Vladimir Karputov:

  1. Invertire l'array di buffer (ArraySetAsSeries) - questo è obbligatorio se l'indicatore usa il CopyBuffer
  2. Ricordate che il CopyBuffer: gli elementi dei dati copiati(buffer di indicatori con un indice buffer_num) sono contati dalla posizione di partenza dal presente al passato, cioè, la posizione di partenza uguale a 0 significa la barra attuale (valore dell'indicatore per la barra attuale).
Dopo di che in AO (eseguire "0" significa la barra più giusta), non qualche valore esorbitante.

Hai almeno guardato il codice che ti ho mostrato? O l'hai eseguito?

Non ho chiesto come riempire il buffer dell'indicatore, ma perché se prendo valori da AO non dalla barra corrente, restituiscono valori vuoti.
Ho capito - non c'è storia, viene caricata e mentre viene caricata AO da un timeframe non nativo restituisce l'errore "no data".

Ora la domanda è: come sapere che la storia per il timeframe necessario è completamente caricata, in modo da non entrare nel ciclo dell'indicatore?

 
I commenti non relativi a questo argomento sono stati spostati in "Domande dai principianti di MQL5 MT5 MetaTrader 5".
Motivazione: