English Русский 中文 Español 日本語 Português
Besonderheiten von Kundenindikatoren

Besonderheiten von Kundenindikatoren

MetaTrader 4Beispiele | 5 November 2015, 13:32
1 283 0
MetaQuotes
MetaQuotes

Das Schreiben von Kundenindikatoren im Handelssystem MetaTrader hat auch einige Besonderheiten.

  • Damit man ein Programm als Kundenindikator bezeichnen könnte, muss es einer der zwei Definitionen entsprechen:

    #property indicator_chart_window      // der Indikator wird im Hauptfenster des Charts gezeichnet

    oder

    #property indicator_separate_window   // der Indikator wird in einem separaten Fenster gezeichnet
  • Um dem Maßstab des separaten Fensters zu fixieren, werden folgende Definitionen genutzt:

    #property indicator_minimum Min_Value
    #property indicator_maximum Max_Value
    

    dabei sind "Min_Value" und "Max_Value" entsprechende Zahlen. z.B.: für den Kundenindikator RSI müssen diese Werte 0 und 100 betragen.

  • Die Anzahl der Indikatorarrays, die notwendig sind, um einen Indikator zu zeichnen, wird mit der folgenden Definition eingestellt:

    #property indicator_buffer N

    wo der N-Wert von 1 bis 8 liegen kann.

  • Die Farbe der Indikatorlinie wird mit der folgenden Definition eingestellt:

    #property indicator_color1 Blue
    #property indicator_color2 Red
    ...
    #property indicator_colorN <SomeColor>
    

    wo N die Anzahl der Indikatorarrays beträgt, die mit der "#property indicator_buffer" definiert wurde.

  • Es gibt eine Reihe von Funktionen, anhand derer man die Berechnung und die Visualisierung des Indikators steuern kann. Als Beispiel wird der Kundenindikator Ichimoku Kinko Hyo verwendet:

    //+------------------------------------------------------------------+
    //|                                                     Ichimoku.mq4 |
    //|                      Copyright © 2004, MetaQuotes Software Corp. |
    //|                                       https://www.metaquotes.net/ |
    //+------------------------------------------------------------------+
    #property copyright "Copyright © 2004, MetaQuotes Software Corp."
    #property link      "https://www.metaquotes.net/"
     
    #property indicator_chart_window
    #property indicator_buffers 7
    #property indicator_color1 Red
    #property indicator_color2 Blue
    #property indicator_color3 SandyBrown
    #property indicator_color4 Thistle
    #property indicator_color5 Lime
    #property indicator_color6 SandyBrown
    #property indicator_color7 Thistle
    //---- input parameters
    extern int Tenkan=9;
    extern int Kijun=26;
    extern int Senkou=52;
    //---- indicator buffers
    double Tenkan_Buffer[];
    double Kijun_Buffer[];
    double SpanA_Buffer[];
    double SpanB_Buffer[];
    double Chinkou_Buffer[];
    double SpanA2_Buffer[];
    double SpanB2_Buffer[];
    //---- span_a drawing begin
    int a_begin;
    //+------------------------------------------------------------------+
    //| Custom indicator initialization function                         |
    //+------------------------------------------------------------------+
    int init()
      {
    //----
       SetIndexStyle(0,DRAW_LINE);
       SetIndexBuffer(0,Tenkan_Buffer);
       SetIndexDrawBegin(0,Tenkan-1);
       SetIndexLabel(0,"Tenkan Sen");
    //----
       SetIndexStyle(1,DRAW_LINE);
       SetIndexBuffer(1,Kijun_Buffer);
       SetIndexDrawBegin(1,Kijun-1);
       SetIndexLabel(1,"Kijun Sen");
    //----
       a_begin=Kijun; if(a_begin<Tenkan) a_begin=Tenkan;
       SetIndexStyle(2,DRAW_HISTOGRAM,STYLE_DOT);
       SetIndexBuffer(2,SpanA_Buffer);
       SetIndexDrawBegin(2,Kijun+a_begin-1);
       SetIndexShift(2,Kijun);
       SetIndexLabel(2,NULL);
       SetIndexStyle(5,DRAW_LINE,STYLE_DOT);
       SetIndexBuffer(5,SpanA2_Buffer);
       SetIndexDrawBegin(5,Kijun+a_begin-1);
       SetIndexShift(5,Kijun);
       SetIndexLabel(5,"Senkou Span A");
    //----
       SetIndexStyle(3,DRAW_HISTOGRAM,STYLE_DOT);
       SetIndexBuffer(3,SpanB_Buffer);
       SetIndexDrawBegin(3,Kijun+Senkou-1);
       SetIndexShift(3,Kijun);
       SetIndexLabel(3,NULL);
       SetIndexStyle(6,DRAW_LINE,STYLE_DOT);
       SetIndexBuffer(6,SpanB2_Buffer);
       SetIndexDrawBegin(6,Kijun+Senkou-1);
       SetIndexShift(6,Kijun);
       SetIndexLabel(6,"Senkou Span B");
    //----
       SetIndexStyle(4,DRAW_LINE);
       SetIndexBuffer(4,Chinkou_Buffer);
       SetIndexShift(4,-Kijun);
       SetIndexLabel(4,"Chinkou Span");
    //----
       return(0);
      }
    //+------------------------------------------------------------------+
    //| Ichimoku Kinko Hyo                                               |
    //+------------------------------------------------------------------+
    int start()
      {
       int    i,k;
       int    counted_bars=IndicatorCounted();
       double high,low,price;
    //----
       if(Bars<=Tenkan || Bars<=Kijun || Bars<=Senkou) return(0);
    //---- initial zero
       if(counted_bars<1)
         {
          for(i=1;i<=Tenkan;i++)    Tenkan_Buffer[Bars-i]=0;
          for(i=1;i<=Kijun;i++)     Kijun_Buffer[Bars-i]=0;
          for(i=1;i<=a_begin;i++) { SpanA_Buffer[Bars-i]=0; SpanA2_Buffer[Bars-i]=0; }
          for(i=1;i<=Senkou;i++)  { SpanB_Buffer[Bars-i]=0; SpanB2_Buffer[Bars-i]=0; }
         }
    //---- Tenkan Sen
       i=Bars-Tenkan;
       if(counted_bars>Tenkan) i=Bars-counted_bars-1;
       while(i>=0)
         {
          high=High[i]; low=Low[i]; k=i-1+Tenkan;
          while(k>=i)
            {
             price=High[k];
             if(high<price) high=price;
             price=Low[k];
             if(low>price)  low=price;
             k--;
            }
          Tenkan_Buffer[i]=(high+low)/2;
          i--;
         }
    //---- Kijun Sen
       i=Bars-Kijun;
       if(counted_bars>Kijun) i=Bars-counted_bars-1;
       while(i>=0)
         {
          high=High[i]; low=Low[i]; k=i-1+Kijun;
          while(k>=i)
            {
             price=High[k];
             if(high<price) high=price;
             price=Low[k];
             if(low>price)  low=price;
             k--;
            }
          Kijun_Buffer[i]=(high+low)/2;
          i--;
         }
    //---- Senkou Span A
       i=Bars-a_begin+1;
       if(counted_bars>a_begin-1) i=Bars-counted_bars-1;
       while(i>=0)
         {
          price=(Kijun_Buffer[i]+Tenkan_Buffer[i])/2;
          SpanA_Buffer[i]=price;
          SpanA2_Buffer[i]=price;
          i--;
         }
    //---- Senkou Span B
       i=Bars-Senkou;
       if(counted_bars>Senkou) i=Bars-counted_bars-1;
       while(i>=0)
         {
          high=High[i]; low=Low[i]; k=i-1+Senkou;
          while(k>=i)
            {
             price=High[k];
             if(high<price) high=price;
             price=Low[k];
             if(low>price)  low=price;
             k--;
            }
          price=(high+low)/2;
          SpanB_Buffer[i]=price;
          SpanB2_Buffer[i]=price;
          i--;
         }
    //---- Chinkou Span
       i=Bars-1;
       if(counted_bars>1) i=Bars-counted_bars-1;
       while(i>=0) { Chinkou_Buffer[i]=Close[i]; i--; }
    //----
       return(0);
      }
    //+------------------------------------------------------------------+
    

  • Die Funktion "SetIndexStyle" steuert die Zeichnungsparameter eines Indikatorarrays. Im Zeichnungsmodus DRAW_LINE werden Linien zwischen den Werten gezeichnet, die im entsprechenden Indikatorarray definiert wurden. Der Modus DRAW_HISTOGRAM, angewandt zum Indikator des Hauptfensters, hat seine eigenen Besonderheiten. Das Histogramm wird zwischen den entsprechenden Werten der zwei Indexarrays gezeichnet: einem geraden (in unserem Fall - SpanA_Buffer) und einem ungeraden (SpanB_Buffer). Dabei wird die Farbe desjenigen Indexarrays verwendet, dessen Wert höher ist.

  • Die Funktion "SetIndexDrawBegin" zeigt, von welchem Element die wichtigen Daten des Indikatorarrays beginnen.

  • Die Funktion "SetIndexBuffer" erklärt jedes eindimensionale "double" Array zum Indexarray. Dabei werden die Indexarrays durch das System gesteuert. Gerade aus diesem Grund braucht man die Größe dieser Arrays nicht anzugeben.

    //---- indicator buffers
    double Tenkan_Buffer[];
    double Kijun_Buffer[];
    double SpanA_Buffer[];
    double SpanB_Buffer[];
    double Chinkou_Buffer[];
    double SpanA2_Buffer[];
    double SpanB2_Buffer[];
    

    Zu den Indikatorarrays darf man nicht die Funktion ArrayResize anwenden - das macht keinen Sinn. Unnötig ist auch die Anwendung der Funktion ArrayInitialize zu den Indikatorarrays, insbesondere als "init", wenn die Inidkatorarrays noch nicht verteilt sind. Die Indikatorarrays werden bei der Zu-und Neuordnung des Speichers automatisch initialisiert. Als Initialisierungswert wird EMPTY_VALUE oder der durch die Funktion SetIndexEmptyValue angegebener Wert verwendet. Die "leeren" Werte werden nicht angezeigt.

  • Die Funktion "SetIndexLabel" setzt den Namen, der in Tool-Tips und im Datenfenster neben dem entsprechenden Wert angezeigt wird (voreingestellt ist der Name "ValueN", wo N die Nummer des Indexarrays ist). Wenn statt des Namens Null anzugeben, wird der entsprechende Wert weder in den Tool-Tips noch im Datenfenster angezeigt. Im gegebenen Fall werden Wolken mit einem Histogramm schraffiert und mit einer Linie begrenzt. Dabei sind die Werte der "Linie-" und der "Histogrammarrays" gleich und man kann nur einen der beiden anzeigen.

  • Die Funktion "IndicatorCounted" lässt den Indikator sparsam berechnen. Diese Funktion liefert die Anzahl der Balken, die zum Zeitpunkt des vorherigen Starts des Indikator vorhanden sind, d.h. die Anzahl der bereits kalkulierten Balken (wenn dabei kein Fehler aufgetreten ist und das Programm nicht vorzeitig beendet wurde), die nicht mehr umgerechnet werden müssen. Wenn der Kundenindikator reinitialisiert wird oder wenn historische Daten weitgehend aktualisiert werden, wird diese Anzahl automatisch auf Null gestellt.

  • Betrachten wir noch ein Beispiel. Kundenindikator - Accelerator/Decelerator Oscillator:

    //+------------------------------------------------------------------+
    //|                                                  Accelerator.mq4 |
    //|                      Copyright © 2005, MetaQuotes Software Corp. |
    //|                                       https://www.metaquotes.net/ |
    //+------------------------------------------------------------------+
    #property  copyright "Copyright © 2005, MetaQuotes Software Corp."
    #property  link      "https://www.metaquotes.net/"
    //---- indicator settings
    #property  indicator_separate_window
    #property  indicator_buffers 3
    #property  indicator_color1  Black
    #property  indicator_color2  Green
    #property  indicator_color3  Red
    //---- indicator buffers
    double     ExtBuffer0[];
    double     ExtBuffer1[];
    double     ExtBuffer2[];
    double     ExtBuffer3[];
    double     ExtBuffer4[];
    //+------------------------------------------------------------------+
    //| Custom indicator initialization function                         |
    //+------------------------------------------------------------------+
    int init()
      {
    //---- 2 additional buffers are used for counting.
       IndicatorBuffers(5);
    //---- drawing settings
       SetIndexStyle(0,DRAW_NONE);
       SetIndexStyle(1,DRAW_HISTOGRAM);
       SetIndexStyle(2,DRAW_HISTOGRAM);
       IndicatorDigits(Digits+2);
       SetIndexDrawBegin(0,38);
       SetIndexDrawBegin(1,38);
       SetIndexDrawBegin(2,38);
    //---- 4 indicator buffers mapping
       SetIndexBuffer(0,ExtBuffer0);
       SetIndexBuffer(1,ExtBuffer1);
       SetIndexBuffer(2,ExtBuffer2);
       SetIndexBuffer(3,ExtBuffer3);
       SetIndexBuffer(4,ExtBuffer4);
    //---- name for DataWindow and indicator subwindow label
       IndicatorShortName("AC");
       SetIndexLabel(1,NULL);
       SetIndexLabel(2,NULL);
    //---- initialization done
       return(0);
      }
    //+------------------------------------------------------------------+
    //| Accelerator/Decelerator Oscillator                               |
    //+------------------------------------------------------------------+
    int start()
      {
       int    limit;
       int    counted_bars=IndicatorCounted();
       double prev,current;
    //---- last counted bar will be recounted
       if(counted_bars>0) counted_bars--;
       limit=Bars-counted_bars;
    //---- macd counted in the 1-st additional buffer
       for(int i=0; i<limit; i++)
          ExtBuffer3[i]=iMA(NULL,0,5,0,MODE_SMA,PRICE_MEDIAN,i)-
                        iMA(NULL,0,34,0,MODE_SMA,PRICE_MEDIAN,i);
    //---- signal line counted in the 2-nd additional buffer
       for(i=0; i<limit; i++)
          ExtBuffer4[i]=iMAOnArray(ExtBuffer3,Bars,5,0,MODE_SMA,i);
    //---- dispatch values between 2 buffers
       bool up=true;
       for(i=limit-1; i>=0; i--)
         {
          current=ExtBuffer3[i]-ExtBuffer4[i];
          prev=ExtBuffer3[i+1]-ExtBuffer4[i+1];
          if(current>prev) up=true;
          if(current<prev) up=false;
          if(!up)
            {
             ExtBuffer2[i]=current;
             ExtBuffer1[i]=0.0;
            }
          else
            {
             ExtBuffer1[i]=current;
             ExtBuffer2[i]=0.0;
            }
           ExtBuffer0[i]=current;
         }
    //---- done
       return(0);
      }
    //+------------------------------------------------------------------+
    

  • Die Funktion "IndicatorBuffers" setzt die Anzahl der Puffer, anhand derer der Indikator berechnet wird. In der Regel wird diese Funktion aufgerufen, wenn mehr Indexarrays genutzt werden als es nötig ist, um einen Indikator zu zeichnen. Die zusätzlichen Arrays werden durch das System gesteuert.

  • Die Funktion "SetIndexDigits" steuert die Genauigkeit der Informationsausgabe. In diesem Fall ist die übliche Genauigkeit von vier Zeichen nach dem Komma nicht ausreichend, um den Unterschied zwischen zwei gleitenden Durchschnitten und den weiteren Unterschied zwischen dem Ergebnis und einer Signallinie zu berechnen.

  • Die Funktion "SetIndexDrawBegin" zeigt, von welchem Element die wichtigen Daten des Indikatorarrays beginnen. Im gegebenen Fall wird die Signallinie als einfacher gleitender Durchschnitt vom anderen einfachen gleitenden Durchschnitt berechnet. Aus diesem Grund sind die ersten 38 Werte des Indikators leer und werden nicht gezeichnet.

  • Die Funktion "IndicatorShortName" setzt den so genannten Kurznamen des Indikators, der in der oberen linken Ecke des Indikatorfensters sowie im Fenster "DataWindow" angezeigt wird. Wenn nichts anderes angegeben wurde, wird der Name des Kundenindikators als Kurzname benutzt. Im gegebenen Beispiel braucht man die Funktion SetIndexLabel nicht, weil nur ein Wert ausgegeben wird. Für die Ausgabe eines einzigen Wertes ist der Name des Indikators ausreichend.

  • Die Funktion "SetIndexStyle" steuert die Zeichnungsparameter eines Indikatorarrays. Der Modus DRAW_NONE bedeutet, dass diese Linie nicht gezeichnet werden muss. Es geht darum, dass das Histogramm im vorgestellten Indikator in zwei Farben gezeichnet werden muss. Die Daten aus dem ExtBuffer0 werden in zwei anderen Arrays verteilt - ExtBuffer1 und ExtBuffer2. Die Funktion SetIndexLabel mit dem Parameter NULL wird genutzt, um doppelte Daten in den Tool-Tips und im Datenfenster nicht auszugeben. Der Zeichnungsmodus DRAW_HISTOGRAM, angewandt zum Indikator eines separaten Fensters, lässt das Histogramm zwischen dem Nullwert und dem Wert des entsprechenden Arrays zeichnen (vgl. wie das Histogramm im Hauptfenster gezeichnet wird, siehe oben).

  • Die Eingangsparameter, die Indikatoren und Funktionen für Berechnungen verwenden, müssen als "extern" definiert werden und können jeglichen Typs sein.

  • Wenn die Eingangsparameter nicht angegeben sind, wird der entsprechende Kundenindikator am einfachsten aufgerufen.

    double current_AC = iCustom( NULL, 0, "Accelerator", 0, 0 );

    Die Übergabe der ersten Werte "NULL" und "0" bedeutet, dass der laufende Chart benutzt wird. Als Name des Kundenindikators wird der entsprechende Dateiname ohne Dateierweiterung mq4 genutzt. Wenn der vorletzte Parameter Null beträgt, bedeutet dies, dass die Daten aus dem allerersten Indikatorarray benötigt werden. Wenn der letzte Parameter Null beträgt, bedeutet dies, dass der Wert des allerletzten Elements des aufgerufenen Indikatorarrays benötigt wird (d.h. der neuste und aktuellste Wert).

  • Die Parameter werden in die Berechnungsfunktion des Kundenindikators in der Reihenfolge übergeben, in der sie beschrieben sind. Der Aufruf des Kundenindikators "Ichimoku" mit den Parametern (9,26,52) wird z.B. folgendermaßen aussehen:

    iCustom( NULL, 0, "Ichimoku", 9, 26, 52, 0, shift );

    Im Grunde genommen kann man die Parameter des Indikators nicht in die Funktion übergeben. Wenn im Programm keine einzige externe Variable definiert wurde, dann ist es sinnlos, Parameter zu übergeben. Man kann auch die Ausgangswerte verwenden, die bei der Beschreibung der Parameter genutzt werden. Der Aufruf desselben Kundenindikators ohne Parameter wird z.B. folgendermaßen aussehen:

    iCustom( NULL, 0, "Ichimoku", 0, shift );

    D.h. es werden diejenigen Werte verwendet, die die Variablen "Tenkan", "Kijun" und "Senkou" initialisieren nämlich 9, 26 und 52. Wenn aber in einem Expert Advisor ein Kundenindikator mit unterschiedlichen Parametersätzen aufgerufen werden, ist die Nutzung von Standardeinstellungen überhaupt nicht zu empfehlen.

Es ist zu bemerken, dass eine überflüssige Anzahl von Kundenindikatoren sowie inkorrekt geschriebene Indikatoren die Arbeit des Kundenterminals wesentlich verlangsamen können.

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/1497

MagicNumber – "magischer" Identifikator der Order MagicNumber – "magischer" Identifikator der Order
In diesem Artikel geht es um einen konfliktfreien Handel mehrerer Experten in einem МТ 4 Terminal. Er bringt dem Experten bei, nur "eigene" Order zu steuern, ohne "fremde" (die von Hand oder von anderen Experten eröffneten) Positionen zu modifizieren und zu schließen. Die Zielgruppe des Artikels bilden die Nutzer, die bereits Grundkenntnisse über das Terminal und Programmieren in MQL4 haben.
Was Zahlen im Bericht über den Expertentest bedeuten Was Zahlen im Bericht über den Expertentest bedeuten
Anhand von Berichten kann man sowohl unterschiedliche Expert Advisors als auch Arbeitsergebnisse eines und denselben Experten mit verschiedenen Parametern miteinander vergleichen. Dieser Artikel erläutert, wie man solche Berichte liest und ihre Ergebnisse interpretiert.
Ereignisse im МetaТrader 4 Ereignisse im МetaТrader 4
In diesem Artikel geht es darum, wie man solche Ereignisse wie Eröffnung, Schließung und Modifizierung von Orders im Terminal МetaТrader 4 verfolgen kann. Der Artikel setzt Grundkenntnisse über das Terminal und Programmieren in MQL4 voraus.
Pause zwischen Trades Pause zwischen Trades
In diesem Artikel geht es darum, wie man eine Pause zwischen Trades einlegt, wenn mehrere Expert Advisors in einem MT 4 Terminal arbeiten. Die Zielgruppe des Artikels bilden Nutzer, die bereits Grundkenntnisse über das Terminal und Programmieren in MQL4 haben.