Weiß jemand, wie man einen Multicurrency-Indikator entwickelt? - Seite 4

 

Nun Jungs, der erste Teil ist getan (Lesen aller Paare Kurse).

Nun muss ich die Kurse aller Paare, die mit der Funktion ArrayCopyRates kopiert wurden, verwenden, um einige grafische Indikatoren wie einen RSI zu erstellen... wie ich im Bild unten zeige:

In meiner ursprünglichen Frage beabsichtige ich wissen, wie dies zu tun... und nicht über das Lesen von Kursen. Ich glaube nicht, dass ich brauchen, um Raten zu kopieren, bevor es zu zeichnen, aber war gut zu wissen, wie zu tun... jetzt muss ich nur einen Weg zu entdecken, um den Indikator Bereich zu plotten alle Paare zu teilen...

 
Verstehen Sie. Dann müssen alle Elemente als Objekte gezeichnet werden.
 

Dies ist ein Indikator, den ich irgendwo aufgeschnappt habe, ich habe nie versucht, ihn zu entziffern. Er zeigt eine Darstellung von 3 Zeitrahmen des aktuellen Charts. Das Verrückte daran ist, dass die Kerzen mit Histogrammen gezeichnet werden. Ziemlich nett, aber nicht das, was ich im Moment mache.

Beste Wünsche

Dateien:
 
Ok, danke. Ich bin auf der Arbeit unterwegs und wenn ich zurückkomme, werde ich es testen.
 
Fernando Carreiro:

Ein Update für alle, die diesen Thread verfolgen!

Ich habe dem OP per PM geholfen, seinen Code zu korrigieren, da er Schwierigkeiten mit Englisch hat und wir beide Portugiesisch sprechen. Bei unseren Tests sind wir auf ein weiteres "komisches" Problem gestoßen, das mit der Funktion"ArrayCopyRates()" auftritt. Wenn man ein MqlRates-Array mit"ArrayCopyRates()" in einem EA verwendet, ist das Daten-Array ein virtuelles Array, das immer den aktuellen Stand der Dinge meldet, so dass die Daten immer frisch sind.

In einem Indicator scheint dies jedoch nicht der Fall zu sein. Das Array ist keine virtuelle Kopie, sondern eine statische Kopie, die zum Zeitpunkt des Aufrufs von"ArrayCopyRates()" festgelegt wurde. Die Daten werden nicht aktualisiert, wenn das Symbol nicht mit dem Diagrammsymbol übereinstimmt. Wenn es sich um dasselbe Symbol wie das Diagramm handelt, dann sind die Array-Daten "live" und werden wie erwartet aktualisiert, aber wenn es sich um ein anderes Symbol handelt, ist es eine statische Kopie.

Damit dies in einem Indikator funktioniert, muss die Funktion "ArrayCopyRates()" bei jedem Aufruf des Ereignisses OnCalculate() aufgerufen werden, wenn neue Daten benötigt werden.

Nur um Ihre Erkenntnisse zu erweitern Fernando - auch wenn Symbol ist das gleiche wie Chart-Symbol, wenn der Zeitrahmen ist anders, dann das Array ist statisch.

Um also eine virtuelle Kopie in einem Indikator zu haben, muss es das gleiche Symbol UND der gleiche Zeitrahmen sein. Alles andere ist statisch.

 
honest_knave: Nur um Ihre Erkenntnisse Fernando erweitern - auch wenn Symbol ist das gleiche wie Chart-Symbol, wenn der Zeitrahmen ist anders, dann das Array ist statisch. Also, um eine virtuelle Kopie zu haben, in einem Indikator, muss es das gleiche Symbol UND den gleichen Zeitrahmen sein. Alles andere ist statisch.
Vielen Dank für das Update!
 
Hallo,

Ich habe überall nach einer Lösung für dieses Problem gesucht und möchte mich bei allen in diesem Thread für diese Diskussion bedanken.

Das ist meine erste Nachricht im Forum, also lassen Sie mich bitte wissen, wenn ich irgendein Protokoll verpasst habe und ich würde gerne in der nächsten Nachricht korrigieren.

Ich versuche, einen sehr einfachen Indikator zu entwickeln, aber meine Logik scheint empfindlich darauf zu reagieren, dass der Chart ganz aktuell ist, deshalb bin ich so an dieser Diskussion interessiert.

Mein Indikator zeichnet ein Fib auf die Spanne des Vortages (Tageshoch zu Tagestief oder Tagestief zu Tageshoch) und zieht am aktuellen Tag Linien am Hoch, Tief und 50% des Fib. Wenn der Indikator bei einem GMT-Broker (Tageskerze am Sonntag) verwendet wird, kann der Benutzer einen Eingabeparameter festlegen, um zu wählen, ob er am Montag nur die Freitag- oder Sonntagsspanne oder Freitag + Sonntag verwendet. Bei einem NY-Close-Broker (GMT+2) macht das keinen Unterschied, da es keine Sonntagskerzen gibt.

Eine weitere Funktion dieses Indikators besteht darin, dass der Benutzer den Fib verschieben kann und die Linien (Hoch, 50% und Tief) am aktuellen Tag an den neuen, durch den Fib festgelegten Bereich angepasst werden. So kann der Benutzer den Bereich anpassen, falls er sich verkleinert.

Der Indikator wird hauptsächlich auf mehreren 1-Stunden-Charts verwendet, aber der Benutzer sollte in der Lage sein, den Zeitrahmen zu wechseln, ohne dass die Änderungen der Fib verloren gehen.

Um die Fib zu zeichnen, muss ich nicht nur das Hoch und das Tief des Vortages finden, sondern auch die Zeit für diese Punkte.

Die Idee ist einfach, aber ich stehe vor ein paar Herausforderungen.

Angenommen, es ist Mitte der Woche, um den Höchst- und Tiefststand des Vortages zu finden, verwende ich einfach:

       Hi = iHigh(NULL, PERIOD_D1, 1);
       Lo = iLow(NULL, PERIOD_D1, 1);

Das ist gut, aber jetzt muss ich herausfinden, wann am Vortag der Höchst- und Tiefststand war. Ich beschloss, die Zeit der 1-Stunden-Kerze für Hoch und Tief mit iHighest und iLowest zu schätzen. Und damit begannen die Probleme.


Um iHighest und iLowest zu verwenden, muss ich die erste 1-Stunden-Kerze und die Größe des Bereichs angeben, in meinem Fall also die erste und die letzte 1-Stunden-Kerze des Vortags. Ich habe also die Eröffnung der vorherigen Tageskerze für den Beginn des Vortages und die Eröffnung der Tageskerze des aktuellen Tages -1 verwendet, um das Ende des Vortages zu finden:

       PrevDayBegin = iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 1));                
       PrevDayEnd = iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 0)-1);

Und das funktioniert hervorragend, wenn Sie den Indikator nur für Währungen verwenden (wiederum unter der Annahme, dass es sich um die Wochenmitte handelt), denn PrevDayBegin ist der Index der 0:00 Uhr-Kerze und PrevDayEnd ist der Index der 23:00 Uhr-Kerze des Vortags. Das Problem liegt bei Futures (Indizes, Gold, Rohöl, etc.). Die tägliche Kerzeneröffnung ist immer um 0:00 Uhr, aber die erste Kerze bei Futures ist um 1 Uhr morgens (GMT+2). Daher gibt die obige Codezeile, die PrevDayBegin berechnet, die 1-Stunden-Kerze für 23:00 Uhr am Vortag zurück.

Ich habe dann beschlossen, einen Code einzufügen, um dieser Situation Rechnung zu tragen und den PrevDayBegin zu verschieben, bis er auf denselben Wochentag fällt wie PrevDayEnd:

       if(TimeDayOfWeek(iTime(NULL, PERIOD_H1, PrevDayBegin)) != TimeDayOfWeek(iTime(NULL, PERIOD_H1, PrevDayEnd)))
         PrevDayBegin--;  

Und all diese Logik funktioniert großartig, wenn Sie alle 1h-Kerzen aktuell haben, aber werfen Sie einen Blick auf das Protokoll unten zeigt einige Drucke von dem, was heute passiert ist. Als Referenz habe ich MT4 am Abend des Vortages geschlossen und heute Morgen (gegen 7 Uhr UK) wieder geöffnet, daher fehlten nur wenige Stunden an Daten in den Charts.

2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == ANDERER TAG DER WOCHE ==
2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 1 (2017.02.08 19:00)
2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 20 (2017.02.08 00:00)

Ein Blick auf das Log zeigt, dass die aktuellste Kerze auf dem 1h-Chart am 2017.02.08 20:00 (Index 0) war, daher approximiert iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 0)-1) dies auf (Index 1) 2017.02.08 19:00. Folglich geraten alle Berechnungen für den Indikator durcheinander, weil iHighest und iLowest den falschen Bereich verwenden.

Basierend auf den vorherigen Diskussionen habe ich versucht und verwendet einige der Lösungen vorgeschlagen, um zu warten, bis alle Kerzen geladen werden, bevor die Berechnungen zu tun, aber aparently ist immer noch nicht funktioniert.

So habe ich beispielsweise in OnInit() die folgenden Codezeilen eingefügt, um die Aktualisierung der Charts auf dem 1-Stunden-, dem Tages- und dem aktuellen Zeitrahmen auszulösen (nur für den Fall, dass die Plattform geschlossen war, als der Chart auf einem anderen Zeitrahmen geöffnet war):

   // Triggers history update
   MqlRates mqlrates_array_d1[];
   MqlRates mqlrates_array_h1[];
   MqlRates mqlrates_array[];
  
   ArrayCopyRates(mqlrates_array_d1,NULL,PERIOD_D1);
   ArrayCopyRates(mqlrates_array_h1,NULL,PERIOD_H1);
   ArrayCopyRates(mqlrates_array,NULL,0);  
Eine andere Sache, die ich bemerkt habe, ist, dass es scheint, dass MT4 die jüngste Kerze Time[0] auf dem Zeitrahmen aktualisiert, der im Chart geöffnet ist, bevor er die gesamte fehlende Historie lädt. Daher beschloss ich zu testen, ob Time[1] auch ein gültiger Preis war.

Dieser Code wurde in OnCalculate() eingefügt und basiert auf den Codes von @whroeder1(hier) und @Fernando Carreiro& @Wemerson Guimaraes(hier):

bool isHistoryLoading;

OnInit();
:
isHistoryLoading = true;
:

OnCalculate( ... )
:
      MqlRates mqlrates_array_d1[];
      MqlRates mqlrates_array_h1[];
      MqlRates mqlrates_array[];
      
      if(isHistoryLoading)
        {      
         ResetLastError();        
        
         if(ArrayCopyRates(mqlrates_array_d1,NULL,PERIOD_D1)>0)
           {
            if(GetLastError() == 0)
              {
               if((iTime(NULL,PERIOD_D1,0) > 0) && (iTime(NULL,PERIOD_D1,1) > 0))
                 {
                  ResetLastError();
  
                  if(ArrayCopyRates(mqlrates_array_h1,NULL,PERIOD_H1)>0)
                    {
                     if(GetLastError() == 0)
                       {
                        if((iTime(NULL,PERIOD_H1,0) > 0) && (iTime(NULL,PERIOD_H1,1) > 0))
                          {
                           ResetLastError();
      
                           if(ArrayCopyRates(mqlrates_array,NULL,0)>0)
                             {
                              if(GetLastError() == 0)
                                {
                                 if((iTime(NULL,0,0) > 0) && (iTime(NULL,0,1) > 0))                            
                                   {
                                    isHistoryLoading = false;
                                
                                    if(DebugLog)
                                      Print("Chart up-to-date!");        
                                    }
                                }
                             }
                          }
                       }
                    }                      
                 }
              }
           }
        }
        
      if(isHistoryLoading)
        {
         if(DebugLog)
           Print("Waiting for chart to update!");
         return(rates_total);
        }    

:

Und dies ist das Log, als die Plattform geöffnet wurde und der Indikator zum ersten Mal geladen wurde:

2017.02.09 06:56:18.492 Custom indicator Prev_Day_Range_LRT_50_v0.6 SPX500,H1: erfolgreich geladen
2017.02.09 06:56:18.630 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: initialisiert
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Chart aktuell!
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Indikator ist nicht vorhanden! Er wird erstellt.
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == ANDERER WOCHENTAG ==
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 20 (2017.02.07 23:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 42 (2017.02.07 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR CurrDayBegin = (2017.02.08 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [0] = (2017.02.08 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [1] = (2017.02.07 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [2] = (2017.02.06 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR Tag der Woche = 3
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iHighest (Kerze = 28) (Preis = 2299.33) (Zeit = 2017.02.07 14:00:001)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iLowest (Kerze = 20) (Preis = 2287.88) (Uhrzeit = 2017.02.07 23:00:001)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Fib von Zeit1=2017.02.07 14:00 Preis1=2299.33 bis Zeit2=2017.02.07 23:00 Preis2=2287.88
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendlinie 'PDRTrend1 131296489639296384' von Time1=2017.02.08 00:00 Price1=2299.33 bis Time2=2017.02.09 00:00 Price2=2299.33
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendlinie 'PDRTrend2 131296489639296384' von Time1=2017.02.08 00:00 Price1=2293.605 bis Time2=2017.02.09 00:00 Price2=2293.605
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendlinie 'PDRTrend3 131296489639296384' von Time1=2017.02.08 00:00 Price1=2287.88 bis Time2=2017.02.09 00:00 Price2=2287.88

Es scheint, dass jeder Verweis auf die Kerzen 0 und 1 oder die Funktion ArrayCopyRates nur auf die Informationen zugreift, die bereits in den Charts geladen sind. Daher scheint ArrayCopyRates eine gültige Anzahl von kopierten Elementen zurückzugeben und iTime(..., 0) und iTime(..., 1) geben einen gültigen Preis für die letzten 2 Kerzen zurück, die gespeichert wurden, als die Plattform am Vortag geschlossen wurde.

Das bedeutet, dass der Indikator so gezeichnet wurde, als wäre es gestern gewesen (PERIOD_D1 [0] = (2017.02.08 00:00)).

Der Indikator ist so aufgebaut, dass die Hoch-, 50%- und Tiefstkurse immer am aktuellen Tag gezeichnet werden, auch wenn der Benutzer den Fib verschiebt (dies sind die 3 Trendlinien, die im obigen Protokoll angezeigt werden). Daher habe ich ein Stück Code auf OnCalculate(), das testet, ob die mittlere Trendlinie am aktuellen Tag gezeichnet wird (der Benutzer hat eine Eingabeoption, um die obere und untere Linie zu deaktivieren, so dass die einzige Linie, die immer gezeichnet wird, die mittlere ist).

OnCalculate( ... )
:

      if(ObjectFind(Trend2Name) != -1)                // Check whether mid range line exists
        {
            
         if((TimeDay(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeDay(TimeCurrent()))
           && (TimeMonth(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeMonth(TimeCurrent()))
           && (TimeYear(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeYear(TimeCurrent()))) // Indicator has already been ploted today        
           {
            return(rates_total);
           }
         else     // Indicator exists but in a past date, so delete it and plot it on current day
           {
            if(DebugLog)
               Print("Indicator in a past date! Deleting it and creating it today!");
              
            if(ObjectFind(FibName) != -1)
              FiboLevelsDelete(0,FibName);              
            // Indicator will be created by the OnChartEvent() when it detects the fib was deleted.
           }
        }
      else        // Indicator doesn't exist, so create it
        {
         if(DebugLog)
            Print("Indicator doesn't exist! Creating it.");
         CreateIndicator();
        }
:

Nach ein paar Ticks werden die Daten teilweise geladen, und der obige Code erkennt, dass die Linien an einem früheren Tag gezeichnet wurden, löscht die Fib und löst eine Neuberechnung der Bereiche und ein erneutes Zeichnen der Objekte aus (d. h. Fib, Trendlinien usw.).


2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Indikator in einem vergangenen Datum! Löschen Sie ihn und erstellen Sie ihn heute!
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDRFibo 131296489639296384 gelöscht!
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDRRectangle 131296489639296384 gelöscht
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Löschen von PDRTrend1 131296489639296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Löschen von PDRTrend2 131296489639296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Löschen von PDRTrend3 131296489639296384

Und dann kommen wir zurück zu dem Problem, das ich am Anfang dieser Nachricht erwähnt habe. Der Test, den ich oben implementiert habe, lässt den Indikator nicht warten, bis die Historie vollständig geladen ist, und daher werden die Bereiche auf der Grundlage von Teildaten falsch berechnet.

Dies ist eine vollständigere Version des Logs, das am Anfang der Nachricht gezeigt wurde. Es zeigt, dass nicht nur PrevDayEnd falsch berechnet wird, da die zweite Kerze (Index 1) im 1-Stunden-Chart (2017.02.07 21:00) ist, sondern auch CurrDayBegin, das die erste Kerze des aktuellen Tages im 1-Stunden-Chart sein soll, wird von iBarShift auf (2017.02.08 06:00) geschätzt.

CurrDayBegin = iTime(NULL, PERIOD_D1, 0);
      
while(TimeDayOfWeek(iTime(NULL, PERIOD_H1, iBarShift(NULL, PERIOD_H1, CurrDayBegin))) != TimeDayOfWeek(TimeCurrent()))

     // If iBarShift can't find the 0am candle and returns the 11pm candle of prev day.

  CurrDayBegin = CurrDayBegin + 3600;        // Move 1h until you find the 1st candle of today.                                        

2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == ANDERER WOCHENTAG ==
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 1 (2017.02.07 21:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 22 (2017.02.07 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR CurrDayBegin = (2017.02.08 06:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [0] = (2017.02.08 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [1] = (2017.02.07 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [2] = (2017.02.06 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR Tag der Woche = 3
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iHighest (Kerze = 8) (Preis = 2299.33) (Zeit = 2017.02.07 14:00:001)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iLowest (Kerze = 19) (Preis = 2288.57) (Uhrzeit = 2017.02.07 03:00:001)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Fib von Zeit1=2017.02.07 03:00 Preis1=2288.57 bis Zeit2=2017.02.07 14:00 Preis2=2299.33
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendlinie 'PDRTrend1 131296489639296384' von Time1=2017.02.08 06:00 Price1=2288.57 bis Time2=2017.02.09 06:00 Price2=2288.57
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendlinie 'PDRTrend2 131296489639296384' von Time1=2017.02.08 06:00 Price1=2293.95 bis Time2=2017.02.09 06:00 Price2=2293.95
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendlinie 'PDRTrend3 131296489639296384' von Time1=2017.02.08 06:00 Price1=2299.33 bis Time2=2017.02.09 06:00 Price2=2299.33

Gibt es also, kurz gesagt, eine Möglichkeit zu testen, ob alle Daten in ein Diagramm geladen wurden? Oder übersehe ich irgendetwas in meinem Code?

Vielen Dank für das Verständnis dieser sehr langen Nachricht.

Bitte lassen Sie mich wissen, wenn Sie den gesamten Code und das Protokoll sehen möchten. Ich würde den Code lieber nicht hier anhängen, aber ich kann ihn Ihnen gerne privat schicken.

Dies sind Bildschirmfotos des Indikators:

(1) Berechnet mit einer unvollständigen Historie (bitte beachten Sie, dass die horizontalen Linien nicht am Anfang des Tages beginnen)

Indikator mit unvollständiger Historie berechnet

(2) Neu berechnet mit der vollständigen Historie (die horizontalen Linien beginnen am Anfang des Tages)

Indikator unter Verwendung der gesamten Historie neu berechnet

Problems with ERR_HISTORY_WILL_UPDATED (4066 ) & weekends
Problems with ERR_HISTORY_WILL_UPDATED (4066 ) & weekends
  • www.mql5.com
Hi i m building a custom indicator and got problems with the 4066 Error...