iCustom(Indikator) werte vom Indikator richtig auslesen

Joosy
140

Sehr geehrte Community,
ich frage mit iCustom individuell einen Fractalindikator ab. Das funktioniert auch soweit. Nun benötige ich die Werte des Indikators in einer von mir erstellen Klasse. Darin frage ich die Daten über die Instanz mit CopyBuffer ab. Die Daten bekomme ich auch. Jedoch auch die Daten zwischen den Fractals.
Das ganze sieht so aus:

void CIndicators::OnTick(){
   CIndicators::FractalsOnTick();
}

void CIndicators::FractalsOnTick(void){
   //bars = Bars(mySymbol, myPeriod)-1;
   bars = 30;
   
   if(CopyBuffer(FractalHandle,0,1,bars,FractalUp) <= 0 || CopyBuffer(FractalHandle,1,1,bars,FractalDown) <= 0){
      PrintFormat("%s. Failed to load FractalUp or FractalDown, Error code: %d", __FUNCTION__, GetLastError());
      return;
   }

   FractArraySizeUp     = ArraySize(FractalUp);
   FractArraySizeDown   = ArraySize(FractalDown);
   
   for(i=0; i<FractArraySizeUp; i++){
      if(FractalUp[i] > 0.0)
         LastFractUp = NormalizeDouble(FractalUp[i],_Digits); //FractalUp[i];
   }

   for(i=0; i<FractArraySizeDown; i++){
      if(FractalDown[i] > 0.0)
         LastFractDown = NormalizeDouble(FractalDown[i],_Digits); //FractalDown[i];
   }

   ArrayPrint(FractalUp);
} 
ArrayPrint liefert folgendes Ergebnis:
[ 0] 2E+308 2E+308 1.18296 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 1.18428 2E+308 2E+308
[15] 2E+308 2E+308 2E+308 2E+308 2E+308 1.18739 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 1.18766

Ich brauche nur die fettmarkierten Werte. Wie kann ich alles andere in der Schleife Ausschließen?
Carl Schreiber
Moderator
12290
Carl Schreiber  

Ich denke Du darfst nicht nach > 0 abfragen sondern nach EMPTY_VALUE.

Aber Du kannst selber nachschauen in \Indicators\Examples\Fractals.mq5.

Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Other Constants
Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Other Constants
  • www.mql5.com
The CLR_NONE constant is used to outline the absence of color, it means that the graphical object or graphical series of an indicator will not be plotted. This constant was not included into the Web-color constants list, but it can be applied everywhere where the color arguments are required. The EMPTY_VALUE constant usually corresponds to the...
Joosy
140
Joosy  

Funktioniert leider nur eingeschränkt. Zunächst kommen die korrekten Werte, gehen aber dann auf 0 und werden dann auch nicht mehr aktualisiert. Ich weiß nicht an was es liegt?

Muss aber noch hinzufügen, dass ich grad ausschließlich mit dem Strategietester fahre. Keine Ahnung, was der für Macken hat?

Ich finde auch nirgends eine Anwendung, wie ich in MQL5, Datentypen bedingungsgemäß abfragen kann?

Trotzdem Danke für die Hilfe:-)

Wie teste ich einen Handelsroboter vor dem Kauf
Wie teste ich einen Handelsroboter vor dem Kauf
  • www.mql5.com
Der Kauf eines Handelsroboters am MQL5 Markt hat bestimmte Vorzüge gegenüber ähnlichen Möglichkeiten - ein automatisiertes System kann direkt im MetaTrader5-Terminal getestet werden. Vor dem Kauf kann und soll ein Expert Advisor sorgfältig in allen ungünstigen Modi im eingebauten Strategietester ausgeführt werden, um das System komplett zu...
pennyhunter
442
pennyhunter  
Joosy:

Funktioniert leider nur eingeschränkt. Zunächst kommen die korrekten Werte, gehen aber dann auf 0 und werden dann auch nicht mehr aktualisiert. Ich weiß nicht an was es liegt?

Muss aber noch hinzufügen, dass ich grad ausschließlich mit dem Strategietester fahre. Keine Ahnung, was der für Macken hat?

Ich finde auch nirgends eine Anwendung, wie ich in MQL5, Datentypen bedingungsgemäß abfragen kann?

Trotzdem Danke für die Hilfe:-)

Du könntest möglicherweise ein Integer Array verwenden, der sich die Indizes der Bars merkt, wo die Extrema sich befinden. Man würde dann die damit abrufbaren double Werte mit einer Schleife in ein Ergebnisarray buffern.
Bei ArraySetAsSeries=true müsste man die int Werte bei jedem neuen Bar um eins vergrößern glaube ich weil sich diese ja in die Vergangenheit verschieben.

Ist vielleicht nicht elegant, aber wäre gespannt ob Dir das was bringt.
pennyhunter
442
pennyhunter  
Joosy:

Sehr geehrte Community,
ich frage mit iCustom individuell einen Fractalindikator ab. Das funktioniert auch soweit. Nun benötige ich die Werte des Indikators in einer von mir erstellen Klasse. Darin frage ich die Daten über die Instanz mit CopyBuffer ab. Die Daten bekomme ich auch. Jedoch auch die Daten zwischen den Fractals.
Das ganze sieht so aus:

ArrayPrint liefert folgendes Ergebnis:
[ 0] 2E+308 2E+308 1.18296 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 1.18428 2E+308 2E+308
[15] 2E+308 2E+308 2E+308 2E+308 2E+308 1.18739 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 1.18766

Ich brauche nur die fettmarkierten Werte. Wie kann ich alles andere in der Schleife Ausschließen?

                //|----------------------|***
                //|ZIGZAG EXTREMA PRINTER|***
                //|----------------------|***


int zigzag_handle ,InpDepth=20 ,InpBackStep=15 ,InpDeviation=20, ind_num=100, bar_num=500;
int UpIndex[100], DownIndex[100];

double ZigZagPlot[], ZigZagUp[], ZigZagDown[], UpResult[], DownResult[];
string signal = "Kein Extremum im Buffer";
MqlRates rates[];
//+------------------------------------------------------------------+
//| OnInit()                                                         |
//+------------------------------------------------------------------+

int OnInit()
  {                                      //wie man indikatoren aufruft / Dokumentation iCustom
   zigzag_handle=iCustom(_Symbol,_Period,"Examples\\ZigZag.ex5",InpDepth,InpBackStep,InpDeviation);
   
   ArraySetAsSeries(ZigZagPlot,true);
   ArraySetAsSeries(ZigZagUp,true);
   ArraySetAsSeries(ZigZagDown,true);
   ArraySetAsSeries(rates,true);
   
   ChartIndicatorAdd(0,0,zigzag_handle);
   
   
   return(INIT_SUCCEEDED);
   }
//+------------------------------------------------------------------+
//|  OnDeinit()                                                      |
//+------------------------------------------------------------------+

void OnDeinit(const int reason)
  {
   IndicatorRelease(zigzag_handle);
   
   }
//+------------------------------------------------------------------+
//|  OnTick()                                                        |
//+------------------------------------------------------------------+

void OnTick()
  {
   CopyBuffer(zigzag_handle,0,0,bar_num,ZigZagPlot);
   CopyBuffer(zigzag_handle,1,0,bar_num,ZigZagUp);
   CopyBuffer(zigzag_handle,2,0,bar_num,ZigZagDown);
   CopyRates(_Symbol,_Period,0,bar_num,rates);
       

     ValueExtraction();
     CommentFunction();
     PrintFunction();
   
   }

        
//+------------------------------------------------------------------+
//|  Werte holen                                                     |
//+------------------------------------------------------------------+

void ValueExtraction()       //merkt sich die Indizes der Extremwerte in Hilfsarrays
{
   for(int i=bar_num-1; i>=0; i--)              
         
     {
      if (ZigZagUp[i]!=0.0)
      {
           
          for(int j=99; j>0; j--)
             {
              UpIndex[j]=UpIndex[j-1];
              }
               UpIndex[0]=i;
               
                
       }

//----         
 else if (ZigZagDown[i]!=0.0)
      {
        
          for(int k=99; k>0; k--)
             {
              DownIndex[k]=DownIndex[k-1];
              }
               DownIndex[0]=i;
                
       }
      }
     } 
     
     
//+------------------------------------------------------------------+
//|Print Funktion                                                    |
//+------------------------------------------------------------------+
     
void PrintFunction()        //holt sich die highs und lows mit Hilfe der Indizes aus den MqlRates
     {                      //wieder undschreibt diese in bereinigter Form (ohne Nullen) in der 
     for(int j=0; j<99; j++)//richtigen Reihenfolge in ein Ergebnisarray der richtigen Größe und
                            //druckt dieses aus.
     
       {ArrayResize(UpResult,j+1,1); 
        UpResult[j]=rates[UpIndex[j]].high;
        
        if(UpIndex[j+1]<UpIndex[j])
        {break;}
         
         
        }
          ArrayReverse(UpResult,0,WHOLE_ARRAY);
          Print("ZigZagUp:");
          ArrayPrint(UpResult,_Digits,"|+++|",0,WHOLE_ARRAY,ARRAYPRINT_ALIGN);
        


     for(int k=0; k<99; k++)
     
       {ArrayResize(DownResult,k+1,1); 
        DownResult[k]=rates[DownIndex[k]].low;
        
        if(DownIndex[k+1]<DownIndex[k])
        {break;}
         
         
        }
          ArrayReverse(DownResult,0,WHOLE_ARRAY);
          Print("ZigZagDown of last ", bar_num,":");
          ArrayPrint(DownResult,_Digits,"|---|",0,WHOLE_ARRAY,ARRAYPRINT_ALIGN);
                 
        
      }

                
//+------------------------------------------------------------------+
//|    Kommentar (zur Kontrolle)                                     |
//+------------------------------------------------------------------+
         
void CommentFunction()    //Damit man sieht, was in welchem Hilfsarray passiertt
     {      
      Comment(
              UpIndex[0],"         ",DownIndex[0],"\n",
              UpIndex[1],"         ",DownIndex[1],"\n",
              UpIndex[2],"         ",DownIndex[2],"\n",
              
              UpIndex[3],"         ",DownIndex[3],"\n",
              UpIndex[4],"         ",DownIndex[4],"\n",
              UpIndex[5],"         ",DownIndex[5],"\n",
              UpIndex[6],"         ",DownIndex[6],"\n",
             
              UpIndex[7],"         ",DownIndex[7],"\n",
              UpIndex[8],"         ",DownIndex[8],"\n",
              UpIndex[9],"         ",DownIndex[9],"\n",
              UpIndex[10],"        ",DownIndex[10],"\n",
              
              UpIndex[11],"        ",DownIndex[11],"\n",
              UpIndex[12],"        ",DownIndex[12],"\n",
              UpIndex[13],"        ",DownIndex[13],"\n",
              UpIndex[14],"        ",DownIndex[14]);
     
      }   
      

Wird das Teil noch benötigt?

Habe zwischenzeitlich festgestellt, wie sehr ich das Thema ZigZag unterschätzt hatte und dass man damit gerade was Trend/Flat-Bestimmung angeht, sehr nützliche Sachen anstellen kann.

Außerdem möchte ich auch wissen, ob man das so machen würde. Er tut zwar was er verspricht, aber kann sein dass man das Eine oder Andere besser machen könnte um Rechenleistung zu sparen. Außerdem bin ich ziemlich stolz auf das Programm. Ist zwar nicht objektorientiert, doch für mich als Anfänger ist das ein Meilenstein und vielleicht kannst Du die eine oder andere Methode adaptieren.

Würde mich freuen, Eure Meinung zu hören.

Dominik Egert
1167
Dominik Egert  
Also der Code schaut auf den ersten Blick schon ordentlich aus.

Ich habe ein paar Tipps.

If-Abfragen sind langsam. Besonders in Schleifen führen sie zu Conditional-Break Situationen in der Ausführungseinheit der CPU.

Häufig lassen sich Schleifen so bauen, dass die Bedingung im "Kopf" der Schleife ist.

Auswertungen können arithmetisch gelöst werden.

Ein boolscher Vergleich ist wie eine 1 oder 0 und kann mittels Multiplikation und Addition zu einem Ergebnis gebracht werden.

Also der Art:

value = (value * (cond == Null)) + (value * (cond != Null));

In einer Schleife ist das ca 10 Mal schneller als eine If-Abfrage.

Ein weiterer Hinweis:

unsigned int ist schneller als signed int.

Variablen, die keine Änderung erfahren, sollten als const deklariert werden. Diese sind auch schneller als änderbare Variablen.

Rückgabewerte von Funktionen sollten immer const deklariert werden (können).

Und als Besonderheit für MQL, die for Schleifen sollten so definiert werden:

for(uint x = NULL; (x < y) && !_StopFlag; x++)

Nach dem Stopflag können weitere Bedingungen eingefügt werden.


Christian
3231
Christian  
Joosy:

Sehr geehrte Community,
ich frage mit iCustom individuell einen Fractalindikator ab. Das funktioniert auch soweit. Nun benötige ich die Werte des Indikators in einer von mir erstellen Klasse. Darin frage ich die Daten über die Instanz mit CopyBuffer ab. Die Daten bekomme ich auch. Jedoch auch die Daten zwischen den Fractals.
Das ganze sieht so aus:

ArrayPrint liefert folgendes Ergebnis:
[ 0] 2E+308 2E+308 1.18296 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 1.18428 2E+308 2E+308
[15] 2E+308 2E+308 2E+308 2E+308 2E+308 1.18739 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 2E+308 1.18766

Ich brauche nur die fettmarkierten Werte. Wie kann ich alles andere in der Schleife Ausschließen?



Parameterwerte mit Format 2e-308 deuten fast immer auf uninitialisierte oder nie gefüllte Variablen hin.

Sprich, du liest irgendwo irgendwas im Speicher deines Rechenknechtes.

pennyhunter
442
pennyhunter  
Dominik Egert:
Also der Code schaut auf den ersten Blick schon ordentlich aus.

Ich habe ein paar Tipps.

If-Abfragen sind langsam. Besonders in Schleifen führen sie zu Conditional-Break Situationen in der Ausführungseinheit der CPU.

Häufig lassen sich Schleifen so bauen, dass die Bedingung im "Kopf" der Schleife ist.

Auswertungen können arithmetisch gelöst werden.

Ein boolscher Vergleich ist wie eine 1 oder 0 und kann mittels Multiplikation und Addition zu einem Ergebnis gebracht werden.

Also der Art:

value = (value * (cond == Null)) + (value * (cond != Null));

In einer Schleife ist das ca 10 Mal schneller als eine If-Abfrage.

Ein weiterer Hinweis:

unsigned int ist schneller als signed int.

Variablen, die keine Änderung erfahren, sollten als const deklariert werden. Diese sind auch schneller als änderbare Variablen.

Rückgabewerte von Funktionen sollten immer const deklariert werden (können).

Und als Besonderheit für MQL, die for Schleifen sollten so definiert werden:

for(uint x = NULL; (x < y) && !_StopFlag; x++)

Nach dem Stopflag können weitere Bedingungen eingefügt werden.


Sehr interessante Anmerkung, danke! Wie Du vielleicht siehst komme ich nicht vom Programmieren. Wo lernt man das? Gruß

Dominik Egert
1167
Dominik Egert  
pennyhunter:

Sehr interessante Anmerkung, danke! Wie Du vielleicht siehst komme ich nicht vom Programmieren. Wo lernt man das? Gruß

Dominik Egert
1167
Dominik Egert  
Im Grunde sind höhere Programmiersprachen eine Abstraktion der zugrundeliegenden Architektur.
Sprachen, die  durch einen Compiler erstellt werden C, C++, C#, Basic usw. werden von dieser höheren Sprache in eine Niedrigere übersetzt. Die Compiler nutzen dafür Methoden um Basisbefehle der CPU zu gruppieren.

Das heißt, die eigentliche Sprache oder besser, der Befehlssatz der Systemarchitektur ist das, was am Ende in Binärcode ausgeführt werden wird.

Die Binärsprache der CPU ist repräsentiert durch Assembler und stellt die grundlegende Funktionalität bereit, repräsentiert diese.

Einen guten Einblick erhält man zB beim Studium der ISA, dokumentiert hier:

https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html

Dazu hilft es zu verstehen wie ein Compiler von der höheren Sprache in die niedrigere Sprache übersetzt.

Leider ist der MQL Compiler nicht genauer dokumentiert, ich nehme daher einen relativ Gängigen als Beispiel:

https://gcc.gnu.org/onlinedocs/

Besonders Kapitel 6 und folgende geben einen Ansatz darüber, wie es im Grunde funktioniert.


Aber es gibt auch YouTube Videos zu diesem Themen.

Auch der Vergleich von verschiedenen Compiler zeigt, es ist eine Frage der Interpretation und das machen manche anders als andere. Daher ist es schwierig für MQL eine definierte Aussage zu treffen.

Es gibt jedoch allgemeine Ansätze, wie zB das Vermeiden von Conditional Breaks. Dieses Beispiel zeigt zB dass hier die Prefetch-Unit der CPU, welche im Code versucht zu erraten welche Daten/ welcher Code schon vorab in den Cache der CPU geladen werden wird, mit der Art des geschriebenen Codes beeinflusst werden kann.

So lassen sich bestimmte, wiederholende Situationen vermeiden.

In diesem Beispiel muss die CPU ihren Cache komplett neu aufbauen, wenn die Vorhersage nicht richtig war. Das wiederum kostet deutlich mehr Zeit als ein paar Additionen, welche bei voller Geschwindigkeit durchgeführt werden können. Additionen und Multiplikationen zählen zu den schnellsten Befehlen. (Eine Addition braucht 4 Takte und das kann man zB in dem ISA Handbuch nachlesen).

Des Weiteren ist zB das ? Als Operator genau eine Assembly Anweisung und diese braucht (ich glaube) 2 Takte der CPU.

Hier ein Beispiel:

const uint x = (a>b) ? c : NULL;

Insgesamt sind hier nur wenige Anweisungen in Gebrauch. Ein Vergleich, eine Auswahl, eine Zuweisung. Also weniger als 10 Takte der CPU.

Eine 4 GHz CPU hat entsprechend 4 Milliarden Takte pro Sekunde zur Verfügung.

Diese Beschreibung ist als Schema zu verstehen und nicht als Absolut, da dies von CPU und Compiler entsprechend abhängt.

Beste Grüße



pennyhunter
442
pennyhunter  
Dominik Egert:
Im Grunde sind höhere Programmiersprachen eine Abstraktion der zugrundeliegenden Architektur.
Sprachen, die  durch einen Compiler erstellt werden C, C++, C#, Basic usw. werden von dieser höheren Sprache in eine Niedrigere übersetzt. Die Compiler nutzen dafür Methoden um Basisbefehle der CPU zu gruppieren.

Das heißt, die eigentliche Sprache oder besser, der Befehlssatz der Systemarchitektur ist das, was am Ende in Binärcode ausgeführt werden wird.

Die Binärsprache der CPU ist repräsentiert durch Assembler und stellt die grundlegende Funktionalität bereit, repräsentiert diese.

Einen guten Einblick erhält man zB beim Studium der ISA, dokumentiert hier:

https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html

Dazu hilft es zu verstehen wie ein Compiler von der höheren Sprache in die niedrigere Sprache übersetzt.

Leider ist der MQL Compiler nicht genauer dokumentiert, ich nehme daher einen relativ Gängigen als Beispiel:

https://gcc.gnu.org/onlinedocs/

Besonders Kapitel 6 und folgende geben einen Ansatz darüber, wie es im Grunde funktioniert.


Aber es gibt auch YouTube Videos zu diesem Themen.

Auch der Vergleich von verschiedenen Compiler zeigt, es ist eine Frage der Interpretation und das machen manche anders als andere. Daher ist es schwierig für MQL eine definierte Aussage zu treffen.

Es gibt jedoch allgemeine Ansätze, wie zB das Vermeiden von Conditional Breaks. Dieses Beispiel zeigt zB dass hier die Prefetch-Unit der CPU, welche im Code versucht zu erraten welche Daten/ welcher Code schon vorab in den Cache der CPU geladen werden wird, mit der Art des geschriebenen Codes beeinflusst werden kann.

So lassen sich bestimmte, wiederholende Situationen vermeiden.

In diesem Beispiel muss die CPU ihren Cache komplett neu aufbauen, wenn die Vorhersage nicht richtig war. Das wiederum kostet deutlich mehr Zeit als ein paar Additionen, welche bei voller Geschwindigkeit durchgeführt werden können. Additionen und Multiplikationen zählen zu den schnellsten Befehlen. (Eine Addition braucht 4 Takte und das kann man zB in dem ISA Handbuch nachlesen).

Des Weiteren ist zB das ? Als Operator genau eine Assembly Anweisung und diese braucht (ich glaube) 2 Takte der CPU.

const uint x = (a>b) ? c : NULL;

Insgesamt sind hier nur wenige Anweisungen in Gebrauch. Ein Vergleich, eine Auswahl, eine Zuweisung. Also weniger als 10 Takte der CPU.

Eine 4 GHz CPU hat entsprechend 4 Milliarden Takte pro Sekunde zur Verfügung.

Diese Beschreibung ist als Schema zu verstehen und nicht als Absolut, da dies von CPU und Compiler entsprechend abhängt.

Beste Grüße



Danke für die Erklärung mit den Takten.

Leider muss ich zugeben, dass mir das GNU Zeug zu hoch ist. Mein Ziel ist auch, MQL5 einigermaßen zu lernen und nicht unbedingt andere Sprachen. In der Gnu Doku weiß ich gar nicht wo ich anfangen soll. Die Information mit den Takten habe ich da nicht so auf Anhieb gefunden.

Also gut. Dass der Compiler die Befehle der höheren Sprache in Binärcode umsetzt ist so ziemlich klar. Wo ich Probleme habe sind die konkreten kleinen Vor- und Nachteile von bestimmten ungewohnten Schreibweisen.

Die Konstanten, gut das kann man dann auch mit Eingabeparametern machen, oder nicht? Gibt es was zu beachten bezüglich & Zeichen bei der Übergabe von Variableln?

Das hier ist nicht so einfach zu verstehen:

value = (value * (cond == Null)) + (value * (cond != Null));   

Zunächst mal sieht es von der Formel her aus wie Quantenmechanik: Der eine Term mit der Bedingung die nicht zutrifft wird gleich null während der andere wo sie zutrifft einen Wert annimmt bzw der Wert wird mit eins multipliziert (Schrödingergleichung?). Es irritiert mich aber, dass es ebenso umgekehrt funktioniert... wie kann es ein if Statement ersetzen, wenn das Ergebnis immer gleich ist? Was wir brauchen sind doch entweder oder? Welcher Wert ist mit value eigentlich gemeint?

Muss es nicht eher so heißen:   result = (value1 * (cond == Null)) + (value2 * (cond != Null));      ? 

Ich sage jetzt mal konkreter:

if(Ask>MA[0]) {Trade.Buy(...);}  wie würde man das umsetzen? Es gibt ja hier mehrere Werte Ask und MA[0] bzw. man könnte sagen Ask-MA[0] ist ein Wert, der positiv sein muss wenn ein Kaufkontrakt eröffnet werden soll. Nur wie verknüpfe ich das dann mit dem Kaufbefehl?


Oder warte...Beispiel:
(Trade.Buy()*(Ask>MA[0])
(Trade.Sell()*(Bid<MA[0])              Würde das so gehen?


Oder vielleicht so:

void CheckTradingConditions(const int& bid, const int& ask)
{
(Trade.Buy()*(Ask>MA[0]))+((Trade.Sell()*(Bid<MA[0]))+(return;)
}


oder mit

const uint x = Ask>MA[0] ? Trade.Buy(...) : Null 

Wäre das so richtig?