Merkmale der Sprache mql5, Feinheiten und Techniken - Seite 30

 

Ich verstehe das überhaupt nicht...

Ich erstelle einen Handle eines Standard-AOs im Indikator, aber mit einem festgelegten Zeitrahmen. Wenn ich Daten von AO mit einem Zeitrahmen erhalte, der nicht mit dem aktuellen übereinstimmt, erhalte ich ... Ich bekomme nichts - Fehler 4806.

Frage: Wie kann man Daten von Standardindikatoren abrufen, deren Zeitrahmen nicht mit dem aktuellen übereinstimmt?

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

Ich verstehe das überhaupt nicht...

Ich erstelle einen Handle eines Standard-AOs im Indikator, aber mit einem festgelegten Zeitrahmen. Wenn ich Daten von AO mit einem Zeitrahmen erhalte, der nicht mit dem aktuellen übereinstimmt, erhalte ich ... Ich bekomme nichts - Fehler 4806.

Was ist die Frage, was ist der richtige Weg, um die Daten von Standardindikatoren mit Zeitrahmen, die nicht mit dem aktuellen übereinstimmen, zu erhalten?


Über das Abrufen der INDICATOR-Werte im INDICATOR:

Forum für Handel, automatisierte Handelssysteme und Strategietests

Wie man Daten aus einem anderen Indikator in einen Indikator übernimmt

Wladimir Karputow, 2016.12.27 08:41

Da bei MQL5-Indikatoren der Balken mit dem Index "0" standardmäßig der LINKE Balken im Diagramm ist, versuchen wir, Daten von zwei anderen Indikatoren - MA und Alligator - in unseren Indikator zu übernehmen(dieses Beispiel im Indikator "IndicatorFromIndicators.mql5").

Versuchen wir, Daten von MA und Alligator auf dem Balken mit dem Index "0", "1" und "2" zu erhalten:

  {
//---
   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);
  }

Fügen wir den Testindikator"IndicatorFromIndicators.mql5" in den Chart ein und setzen das Fadenkreuz auf den RECHTESTEN Balken, d.h. nicht auf den Nullbalken. So sieht es aus:

IndicatorFromIndicators

Obwohl das Fadenkreuz auf den RECHTESTEN Takt eingestellt ist - also definitiv nicht auf einen Takt mit dem Index "0", sollten Sie bei der Verwendung vonCopyBuffer beachten, dassCopyBuffer Daten von der Gegenwart in die Vergangenheit kopiert, d.h. Takt mit Index "0" bedeutet den aktuellen Takt.


CopyBuffer: Die zu kopierenden Datenelemente (Indikatorpuffer mit einem Index buffer_num) werden von der Startposition aus von der Gegenwart in die Vergangenheit gezählt, d.h. die Startposition 0 bedeutet den aktuellen Takt (Indikatorwert für den aktuellen Takt).


Das heißt, im MQL5-Indikator, wenn er die Operation CopyBuffer verwendet, müssen Sie das Array umdrehen (ArraySetAsSeries), so dass der äußerste rechte Balken im Diagramm dem Index "0" im Indikatorpuffer entspricht (im Beispiel "iMTF_AO.mq5" entspricht der äußerste rechte Balken im Diagramm nun rates_total-1).

 
Wladimir Karputow:


Über den Erhalt von INDICATOR-Werten in INDICATOR:


CopyBuffer: Die Elemente der kopierten Daten (Indikatorpuffer mit einem Index buffer_num) werden von der Startposition aus von der Gegenwart in die Vergangenheit gezählt, d.h. die Startposition gleich 0 bedeutet den aktuellen Takt (Indikatorwert für den aktuellen Takt).


Das heißt, im MQL5-Indikator, wenn er die Operation CopyBuffer verwendet, müssen Sie das Array umdrehen (ArraySetAsSeries), so dass der äußerste rechte Balken im Diagramm dem Index "0" im Indikatorpuffer entspricht (im Beispiel "iMTF_AO.mq5" entspricht der äußerste rechte Balken im Diagramm nun rates_total-1).

Ich bekomme nur einen Balken. Und der Indikator für den "nativen" Zeitrahmen zeigt die Daten normal an. Auf den "nicht-nativen" - leeren Wert. Ich habe empirisch herausgefunden, dass ein leerer Wert zurückgegeben wird, bis der gesamte Verlauf für den Zeitraum geladen ist, für den ich Daten von AO erhalte.

//+------------------------------------------------------------------+
//|                                                      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");
   }
}
//+------------------------------------------------------------------+

Die Frage wäre dann: Wie kann man vermeiden, in die Schleife einzutreten, während die Historie für den Zeitrahmen geladen wird? Es handelt sich nur um einen Test, während der Indikator im Allgemeinen Berechnungen auf der Grundlage des Verlaufs eines bestimmten Zeitrahmens durchführt und nicht versucht werden muss, sie durchzuführen, solange kein Verlauf vorhanden ist.

Dateien:
iMTF_AO.mq5  12 kb
 
Artyom Trishkin:

Ich bekomme nur einen Balken. Und der Indikator für den "nativen" Zeitrahmen zeigt die Daten normal an. Auf der "nicht-nativen" Seite wird ein leerer Wert angezeigt. Ich habe empirisch herausgefunden, dass ein leerer Wert zurückgegeben wird, bis der gesamte Verlauf für den Zeitraum geladen ist, für den ich Daten von AO erhalte.

Dann wird die Frage anders klingen: Wie kommt man nicht in die Schleife, während der Verlauf für den Zeitrahmen geladen wird? Dies ist nur ein Test. Im Allgemeinen führt der Indikator Berechnungen auf der Grundlage des Verlaufs eines bestimmten Zeitrahmens durch, und es besteht keine Notwendigkeit, diese Berechnungen durchzuführen, bis es keinen Verlauf mehr gibt.

Haben Sie die Synchronisierung ausprobiert? Außerdem raten die Entwickler, die Daten des gewünschten TF/Symbols durch den Timer auf dem neuesten Stand zu halten.
 
Hier:
      Buffer[i]=AO(i);

Das "i" ist nicht "0", sondern ein exorbitanter Wert. Fazit: Nehmen wir an, wir lassen das Beispiel auf M15 laufen - wir haben 5000 Balken in diesem Zeitraum. Wir fordern Daten von H4 an - wir haben nur 400 Balken darauf. Dann versuchen wir, "AO(4999)" anzufordern.

Das heißt, von der Periode H4 versuchen wir, den Balken mit dem Index "4999" anzufordern - aber es gibt überhaupt keinen solchen Balken auf H4, es gibt dort nur 400 Balken, aber wir fordern den Balken "0" an, und wenn der Indikator die Operation CopyBuffer verwendet, sollten wir das Array umkehren (ArraySetAsSeries), so dass der ganz rechte Balken im Diagramm dem Index "0" im Indikatorpuffer entspricht (jetzt im Beispiel "iMTF_AO.mq5" entspricht der ganz rechte Balken im Diagramm rates_total-1).

 

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

Wanzen, Wanzen, Fragen

fxsaber, 2017.04.12 08:38

Ein kleiner Hinweis auf den Hut. Umgehung des Zuweisungsoperators
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);  
}

Ergebnis

Struct.i = 1
StructCopy1.i = 5
StructCopy2.Value.i = 1
 
Wladimir Karputow:
Hier..:

Das "i" ist nicht "0", sondern ein exorbitanter Wert. Fazit: Nehmen wir an, wir lassen das Beispiel auf M15 laufen - wir haben 5000 Balken in diesem Zeitraum. Wir fordern Daten von H4 an - wir haben nur 400 Balken darauf. Dann versuchen wir, "AO(4999)" anzufordern.

Zum Beispiel, von der Periode H4, versuchen wir, die Bar mit dem Index "4999" - aber es gibt nicht eine solche Bar auf H4, gibt es nur 400 Bars gibt, aber wir wollen Bar "0", und wenn der Indikator verwendet die Operation CopyBuffer, sollten wir das Array (ArraySetAsSeries), so dass die ganz rechts im Chart entspricht Index "0" in der Indikator-Puffer (zum Beispiel "iMTF_AO.mq5" jetzt die ganz rechts im Chart entspricht rates_total-1).

Nein, natürlich habe ich versucht, den Grenzwert zu berechnen:

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

... Aber ich sehe, dass ich es in der Eile vermasselt habe - es ist nur für den aktuellen Zeitrahmen geeignet

 
Artyom Trishkin:

Nein, natürlich habe ich versucht, den Grenzwert zu berechnen:

... Aber ich sehe, ich habe es in der Eile vermasselt - es ist nur für den aktuellen Zeitrahmen geeignet


  1. Umkehrung des Puffer-Arrays (ArraySetAsSeries) - dies ist obligatorisch, wenn der Indikator die CopyBuffer-Funktion verwendet
  2. Beachten Sie, dass die CopyBuffer: Elemente der kopierten Daten(Indikatorpuffer mit einem Index buffer_num) von der Startposition aus von der Gegenwart in die Vergangenheit gezählt werden , d.h. die Startposition 0 bedeutet den aktuellen Takt (den Indikatorwert für den aktuellen Takt).
Danach in AO (Start "0" bedeutet den RECHTESTEN Balken), nicht irgendeinen exorbitanten Wert.
 
Wladimir Karputow:

  1. Umkehrung des Pufferarrays (ArraySetAsSeries) - dies ist obligatorisch, wenn der Indikator die CopyBuffer-Funktion verwendet
  2. Denken Sie daran, dass die CopyBuffer: Elemente der kopierten Daten(Indikatorpuffer mit einem Index buffer_num) von der Startposition aus der Gegenwart in die Vergangenheit gezählt werden, d.h. die Startposition gleich 0 bedeutet den aktuellen Takt (Indikatorwert für den aktuellen Takt).
Danach in AO(run "0" bedeutet den RECHTESTEN Balken), nicht irgendeinen exorbitanten Wert.

Haben Sie sich den Code, den ich Ihnen gezeigt habe, überhaupt angesehen? Oder haben Sie es durchgeführt?

Ich habe nicht gefragt, wie man den Indikatorpuffer füllt, sondern warum, wenn ich Werte von AO nicht aus dem aktuellen Balken nehme, sie leere Werte zurückgeben.
Ich habe es - es gibt keine Historie, sie wird geladen und während sie geladen wird, gibt AO aus einem nicht nativen Zeitrahmen den Fehler "keine Daten" zurück.

Nun stellt sich die Frage: Wie kann man wissen, dass die Historie für den benötigten Zeitrahmen vollständig geladen ist, um nicht in den Indikatorzyklus einzutreten?

 
Kommentare, die sich nicht auf dieses Thema beziehen, wurden nach "Fragen von MQL5 MT5 MetaTrader 5 Anfängern" verschoben.
Grund der Beschwerde: