Methode der Flächeninhalte

Vladimir Karputov | 13 April, 2016

Gliederung


Einleitung

Wie man die Indikatoren und Expert Advisors aus den Zip-Dateien am Ende des Artikels richtig installiert: die Zip-Dateien "Indicators.zip" und "Experts.zip" müssen im <Dateiordner>\MQL5\ entpackt werden

2004 erschien die Beschreibung der Methode zum ersten Mal [1]. Die Methode zeichnet sich dadurch aus, dass sie die Daten des RSI-Indikators aus einer ungewöhnlichen Perspektive betrachtet: es wird vorgeschlagen, den Flächeninhalt abzuschätzen, den der Oszillator über/unter der Linie 50 seit dem letzten Moment zeichnet, wo diese durchgekreuzt wurde. Seit 2004 haben sich die Märkte stark verändert, die MQL5-Sprache wurde entwickelt, und dies bedeutet, es ist höchste Zeit, die Strategie in der MQL5-Sprache auf dem aktuellen Markt zu überprüfen.


1. Allgemeine Auswertungsmethode für Werte des RSI-Indikators

Die gewöhnliche Methode des Handels nach den Signalen des RSI-Indikators beinhaltet die Auswertung der Werte des Indikators im Hinblick auf das überkaufte/überverkaufte Niveau, die Suche nach der Divergenz zwischen den Werten des Indikators und dem Preis, Umkehrung nachdem der Indikator in den überkauften/überverkauften Bereichen war, und das Muster Failure Swing. Auf diese Weise werden für die technische Analyse des RSI-Oszillators mindestens vier Signale verwendet, was das Enscheidungssystem erschwert.

Aber wir wissen Bescheid, dass der RSI-Indikator sich nicht in der überkauften (über der Linie 70)/überverkauften Zone (unter der Linie 30) lange befinden kann – er  kehrt unter allen Umständen zurück und durchkreuzt die Linie 50:

RSI

Abb. 1. Der RSI-Oszillator kehrt immer aus der überkauften/überverkauften Zone zurück

Auf der Abbildung 1 sieht man, dass die Zeit, die der Oszillator in den überkauften/überverkauften Zonen verbringt im Vergleich zur restlichen Zeit sehr kurz ist. Nachdem der RSI in den überkauften/überverkauften Zonen gewesen ist, durchkreuzt er die Linie 50. Gerade das Wissen darüber, dass der RSI-Oszillator immer zurückkehrt und die Linie 50 durchkreuzt, sowie die Notwendigkeit, die technische Analyse von Werten des RSI-Oszillators zu vereinfachen, bildeten die Grundlage für die Entwicklung der Methode der Flächeninhalte.


2. Methode der Flächeninhalte

Nach der Methode der Flächeninhalte werden die Werte des RSI-Oszillators nach einer Größe ausgewertet nämlich nach dem Flächeninhalt, den der Oszillator über/unter der Linie 50 bildet. Dieser Wert beschreibt das überkaufte/überverkaufte Niveau:

area_figure

Abb. 2. Die Methode der Flächeninhalte — Abschätzung der Fläche über/unter der Linie 50

Als Signal zur Eröffnung einer Position dient in diesem Fall die Größe des Inhalts über/unter der Linie 50 seit dem letzten Moment, als sie und der RSI-Indikator sich gekreuzt haben.   

Verkaufssignal 

Abb. 3. Signal zur Eröffnung einer SELL-Position, wenn der Bereich gleich 300 ist

Das Signal zum Schließen einer Position wird in dem Moment generiert, wenn der RSI-Oszillator die Linie 50 durchkreuzt, mit anschließender Bildung des lokalen Maximums/Minimums und dem Rollback von 4 %.

Close SELL signal 

Abb. 4. Signal zum Schließen einer SELL-Position nach der Bildung des lokalen Minimums und dem anschließenden Rollback von 4%

Bei der Veranschaulichung des Flächeninhalts über/unter der Linie 50 hilft uns der RSIAreaIndicator Indikator.  


3. Indikator RSIAreaIndicator_v1

Der RSIAreaIndicator Indikator basiert auf dem RSI Oszillator. Der grundlegende Unterschied besteht darin, dass der RSIAreaIndicator zwei Puffer hat. Ein Puffer hat den Stil DRAW_HISTOGRAM und der zweite DRAW_LINE. Die Werte der Puffer werden nach der folgenden Formel berechnet:

formula RSIAreaIndicaor

So sieht der Indikator RSIAreaIndicator Version 1.00 aus:

RSIAreaIndicator 

Abb. 5. RSIAreaIndicator _v1 Indikator

 


3.1. Erstellung eines Entwurfs des Indikators 

Ich empfehle, die von Ihnen erstellen Kundenindikatoren in einem separaten Ordner abzulegen. In meinem Fall heißt dieser Ordner "MyInd". Vor dem Schreiben des Indikators ist es notwendig, einen Entwurf für ihn im MetaEditor unter Verwendung von MQL5 Wizard zu erstellen. Die ersten Schritte der Erstellung eines Entwurfs finden Sie in diesem Video: 


 

Den Entwurf können Sie sich am Ende des Beitrag anschauen, der Indikator wurde unter dem Namen "RSIAreaIndicatorStep1.mq5" gespeichert. 

3.2. Ausfüllung der Kopfzeile des Indikators

Der nächste Schritt ist das Hinzufügen der Beschreibung des Indikators. Später kann man die Beschreibung immer im Allgemeines-Tab in den Einstellungen des Indikators sehen. Der ganze hinzugefügte Code wird für die visuelle Wahrnehmung gefärbt:

#property version   "1.00"
#property description   "The indicator displays area RSI over/under line 50"
#property indicator_separate_window

Wir wissen, dass RSIAreaIndicator über zwei Puffer verfügt. Neben diesen zwei brauchen wir einen zusätzlichen Hilfspuffer. Somit beläuft sich die Zahl der Puffer, die im Indikator verwendet werden, auf drei. Fangen wir mit der Bearbeitung der Kopfzeile des Codes des Indikators an:

#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   2
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_type2   DRAW_LINE
#property indicator_color1  clrGray
#property indicator_color2  clrGray
//--- input parameters
input int      ExtRSIPeriod=13;

Nun müssen wir drei Arrays deklarieren, in denen die Werte der Indikator-Puffer und des Hilfspuffers gespeichert werden:

//--- input parameters
input int      ExtRSIPeriod=13;
//---- buffers
double ExtMapBuffer1[];
double ExtMapBuffer2[];
double ExtMapBuffer3[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |

Da unser Indikator RSIAreaIndicator anhand des standardmäßigen RSI-Indikators berechnet wird, und wir die Werte des Indikators erhalten müssen, wird eine Variable benötigt, in der der Bezeichner (Handle) des Relative Strength Index Indikators gespeichert wird:

double ExtMapBuffer3[];
//--- variable for storing the handle of the iRSI indicator 
int    handle;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |

Nun müssen drei Variablen in der Kopfzeile deklariert werden. In der Variablen name wird der Name des Symbols gespeichert, auf dem der Indikator gestartet wurde, in der Variablen short_name — der Kurzname des Indikators und in der Variablen bars_calculated — die Anzahl berechneter Balken im RSI-Indikator:

int    handle;
//--- variable for storing 
string name=Symbol();
//--- name of the indicator on a chart 
string short_name;
//--- we will keep the number of values in the Relative Strength Index indicator 
int    bars_calculated=0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |

Die Kopfzeile des Indikators ist ausgefüllt, nun können wir die OnInit() Funktion bearbeiten.

3.3. Bearbeitung der OnInit() Funktion des Indikators 

Da wir einen Indikator schreiben, müssen wir die Indikatorpuffer mit den früher deklariereten dynamischen Arrays vom Typ double verbinden:

int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,ExtMapBuffer1,INDICATOR_DATA);
   SetIndexBuffer(1,ExtMapBuffer2,INDICATOR_DATA);
   SetIndexBuffer(2,ExtMapBuffer3,INDICATOR_CALCULATIONS);
//---
   return(INIT_SUCCEEDED);

Nachdem wir die Puffer mit den Arrays verbunden haben, setzen wir die Indexierung der Elemente des Arrays wie in Timeserien (empfehlenswert ist, sich das Beispiel in der Dokumentation über ArraySetAsSeries anzuschauen). Das ganz rechte Element der Arrays hat den Index "0":

   SetIndexBuffer(1,ExtMapBuffer2,INDICATOR_DATA);
   SetIndexBuffer(2,ExtMapBuffer3,INDICATOR_CALCULATIONS);
   ArraySetAsSeries(ExtMapBuffer1,true);
   ArraySetAsSeries(ExtMapBuffer2,true);
   ArraySetAsSeries(ExtMapBuffer3,true);
//---
   return(INIT_SUCCEEDED);

Setzen wir die Genauigkeit der Wiedergabe — der Indikator wird mit zwei Zeichen nach dem Komma angezeigt:

   ArraySetAsSeries(ExtMapBuffer3,true);
//--- set accuracy 
   IndicatorSetInteger(INDICATOR_DIGITS,2);
//---
   return(INIT_SUCCEEDED);

 In der OnInit() Funktion müssen wir noch den Bezeichner (Handle) des RSIndex Indikators erhalten, die Variable short_name ausfüllen und dem Indikator einen Kurznamen zuweisen:

   ArraySetAsSeries(ExtMapBuffer2,true);
   ArraySetAsSeries(ExtMapBuffer3,true);
//--- set accuracy 
   IndicatorSetInteger(INDICATOR_DIGITS,2);
   handle=iRSI(name,0,ExtRSIPeriod,PRICE_CLOSE);
//--- if the handle is not created 
   if(handle==INVALID_HANDLE)
     {
      //--- notify about failure and output error code 
      PrintFormat("Failed to create handle of the iRSI indicator for the symbol %s/%s, error code %d",
                  name,
                  EnumToString(PERIOD_CURRENT),
                  GetLastError());
      //--- the indicator is stopped early 
      return(INIT_FAILED);
     }
//--- show the symbol/timeframe the RSI Area Indicator is calculated for 
   short_name=StringFormat("RSIArea(%d)",ExtRSIPeriod);
   IndicatorSetString(INDICATOR_SHORTNAME,short_name);
//--- normal initialization of the indicator 
   return(INIT_SUCCEEDED);

Die Kopfzeile des Indikators und die OnInit() Funktion sind nun ausgefüllt. Sie können den bearbeiteten Code am Ende des Beitrags finden: der Indikator wurde unter dem Namen "RSIAreaIndicatorStep2.mq5" gespeichert.  

3.4. Erstellung einer Hilfsfunktion des Indikators 

Für die Arbeit des Indikators RSIAreaIndicator muss man bei jeder Eingabe der OnCalculate() Funktion Daten des RSI-Indikators erhalten. Genauso wichtig ist es, die Bedingungen für ein einfaches Lesen des Codes zu sichern, und die Funktionen des Programms zu teilen. Der Hilfscode für das Erhalten von RSI-Werten und das Kopieren dieser Werte in einen der Puffer von RSIAreaIndicator wurden aus diesem Grund in eine separate Funktion FillArrayFromBuffer() verschoben. Wir platzieren diese nach der OnCalculate() Funktion. Die Werte werden mit der Funktion CopyBuffer kopiert.

//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+ 
//| Filling indicator buffers from the iRSI indicator                | 
//+------------------------------------------------------------------+ 
bool FillArrayFromBuffer(double &rsi_buffer[],  // indicator buffer of Relative Strength Index values 
                         int ind_handle,        // handle of the iRSI indicator 
                         int amount             // number of copied values 
                         )
  {
//--- reset error code 
   ResetLastError();
//--- fill a part of the iRSIBuffer array with values from the indicator buffer that has 0 index 
   if(CopyBuffer(ind_handle,0,0,amount,rsi_buffer)<0)
     {
      //--- output error code if copying fails 
      PrintFormat("Failed to copy data from the iRSI indicator, error code %d",GetLastError());
      //--- quit with zero result - it means that the indicator is considered as not calculated 
      return(false);
     }
//--- all in order 
   return(true);
  }
//+------------------------------------------------------------------+

3.5. Erstellung des Hauptcodes des Indikators 

Der Hauptcode (oder Logik) des RSIAreaIndicator Indikators befindet sich in der OnCalculate() Funktion. Hier wird die Hauptvariable values_to_copy deklariert. Später wird die Variable values_to_copy die Anzahl der Werte speichern, die aus dem RSI-Indikator kopiert werden muss.

                const int &spread[])
  {
//--- number of values copied from the iRSI indicator 
   int values_to_copy;
//--- determine the number of values calculated in the indicator 
   int calculated=BarsCalculated(handle);
   if(calculated<=0)
     {
      PrintFormat("BarsCalculated() returned %d, error code %d",calculated,GetLastError());
      return(0);
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }

Berechnung des Wertes values_to_copy:

      PrintFormat("BarsCalculated() returned %d, error code %d",calculated,GetLastError());
      return(0);
     }
//--- if it is the first calculation of the indicator or if the number of values in the iRSI indicator changed 
//---or if it is necessary to calculate the indicator for two or more bars (it means something has changed in the price history) 
   if(prev_calculated==0 || calculated!=bars_calculated || rates_total>prev_calculated+1)
     {
      //--- if the iRSIBuffer array is greater than the number of values in the iRSI indicator for symbol/period, then we don't copy everything  
      //--- otherwise, we copy less than the size of indicator buffers 
      if(calculated>rates_total) values_to_copy=rates_total;
      else                       values_to_copy=calculated;
     }
   else
     {
      //--- it means that the indicator is calculated not for the first time, but since the last call of OnCalculate() 
      //--- not more than one bar is added for calculation 
      values_to_copy=(rates_total-prev_calculated)+1;
     }
//--- return value of prev_calculated for next call
   return(rates_total);

Warum wird die Variable values_to_copy auf solche Weise berechnet? Die Elemente der Arrays (time[], open[], high[], low[], close[], tick_volume[], volume[] und spread[]), die an die OnCalculate() Funktion übergeben werden, werden in einem MQL5-Indikator vom Anfang des Arrays zum Ende indexiert. So sieht das auf dem Beispiel aus:

Array Not Series

Abb. 6. Indexierung der Elemente des Arrays, wenn Array keine Timeserie ist 

D.h. im Array, der nicht als Timeserie gilt, hat das Element ganz rechts den höchsten Index. Dies muss bei mathematischen Berechnungen berücksichtigt werden.

Nun wenn der Wert der Variablen values_to_copy berechnet ist, kann man die Hilfsfunktion FillArrayFromBuffer() aufrufen und die Indikatorpuffer ExtMapBuffer1[] und ExtMapBuffer2[] ausfüllen:

     

      //--- not more than one bar is added for calculation 
      values_to_copy=(rates_total-prev_calculated)+1;
     }
//--- fill the array with values of the iRSI indicator 
//--- if FillArrayFromBuffer returns false, it means the information is not ready yet, quit operation 
   if(!FillArrayFromBuffer(ExtMapBuffer3,handle,values_to_copy)) return(0);
//---
   for(int i=0;i<values_to_copy;i++)
     {
      ExtMapBuffer1[i]=ExtMapBuffer2[i]=ExtMapBuffer3[i]-50.0;
     }
//--- memorize the number of values in the Relative Strength Index indicator 
   bars_calculated=calculated;
//--- return value of prev_calculated for next call
   return(rates_total);

Der Indikator RSIAreaIndicator version 1.00 ist fertig. Man kann ihn am Ende des Artikels unter dem Namen "RSIAreaIndicatorv1.mq5" herunterladen. Nun kann man mit dem Schreiben des Expert Advisors RSIAreaEA version 1.00 anfangen, der nach der Methode der Flächeninhalte handeln wird.


4. Expert Advisor RSIAreaExpert version 1.00

Auch wie bei der Arbeit mit Indikatoren empfehle ich die erstellten Expert Advisors in einem separaten Ordner abzulegen. Mein Ordner für Expert Advisors heißt z.B. "MyExp". Analog zum Indikator erstellen wir einen Entwurf für den RSIAreaExpert_v1 Expert Advisor. Eine wichtige Anmerkung: auf einem der Schritte muss man alle Häkchen entfernen:

Setting Expert 

 Abb. 7. Einstellungen für die Erstellung des Expert Advisors

Den Entwurf können Sie am Ende des Beitrags finden, der Expert Advisor wurde unter dem Namen "RSIAreaExpert_v1_Step1.mq5" gespeichert. 

4.1. Bearbeitung der Kopfzeile des Expert Advisors

Fügen wir die Beschreibung des Expert Advisors hinzu. Sie ist im Allgemeines-Tab des Expert Advisors zu sehen:

#property version   "1.00"
#property description "EA trades on \"Method areas\""
//+------------------------------------------------------------------+
//| Expert initialization function                                   |

Man hat nicht immer die Lust, die Beschreibung direkt ausfüllen, aber später wird es uns helfen, wenn wir uns an die eiserne Regel halten werden: "Bei der Erstellung eines Programms muss man als allererste eine Beschreibung verfassen". 

Der Expert Advisor verwendet die Standardbibliothek (die CTrade Klasse) für die Ausführung von Trades. Dafür müssen wir die CTrade Klasse einfügen und die my_trade Variable deklarieren:

#property description "EA trades on \"Method areas\""
#include <Trade\Trade.mqh>
//--- global variables
CTrade      my_trade;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |

Fügen wir drei Variablen hinzu (um den Handle des RSI-Indikators, den aktuellen berechneten Flächeninhalt und eine Hilfsvareable zu speichern):

//--- global variables
CTrade      my_trade;
int         handle;     // variable for storing the handle of the iRSI indicator 
double      RSIArea;    // the calculated area
double      RSIOpen;    // the auxiliary variable
//+------------------------------------------------------------------+
//| Expert initialization function                                   |

Der letzte Schritt in der Bearbeitung der Kopfzeile des EAs ist die Input-Parameter hinzuzufügen:

double      RSIOpen;    // the auxiliary variable
//--- input parametres
input int   ExtRSIPeriod=13;    // period of RSI
input int   AreaCondition=300;  // area
input ENUM_TIMEFRAMES period=PERIOD_M15;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |

Die Variable period wurde nur für ein einfaches Testen im Strategietester eingeführt. So kann man unterschiedliche Testperioden setzen:

variable period

Abb. 8. Die period Variable erlaubt den Expert Advisor in unterschiedlichen Perioden zu testen 

Die Kopfzeile des Expert Advisors ist ausgefüllt, nun ist die OnInit() Funktion an der Reihe. Die OnInit() Funktion enthält eine einzige Operation, und zwar das Erhalten des Handles des Indikators auf dem laufenden Symbol und in der vorgegebenen Periode (period):

int OnInit()
  {
//---
   handle=iRSI(Symbol(),period,ExtRSIPeriod,PRICE_CLOSE);
//--- if the handle is not created 
   if(handle==INVALID_HANDLE)
     {
      //--- notify about failure and output error code 
      PrintFormat("Failed to create handle of the iRSI indicator for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(period),
                  GetLastError());
      //--- the indicator is stopped early 
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }

Diese Änderungen im Prozess der Bearbeitung des Expert Advisors sind in der Datei "RSIAreaExpert_v1_Step2.mq5" zu sehen.

4.2. Hilfsfunktion RSIAreaFunc 

Die Funktion der Bestimmung des Flächeninhalts RSIAreaFunc() besteht aus mehreren Teilen. Wir werden das Funktional Schritt für Schritt hinzufügen. Der erste Block (Erläuterungen nach dem Code):

void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+
//| Area calculation                                                 |
//+------------------------------------------------------------------+
double RSIAreaFunc(int &RSIAreaShift,int BeginShift)
  {
   int    shift,limit;
   double rsivalue,result;
//--- get current RSI 
   limit=Bars(Symbol(),period)-ExtRSIPeriod;
   if(limit>100)
      limit=100;
   double   arr_rsi[];
   ArrayResize(arr_rsi,limit);
   ArraySetAsSeries(arr_rsi,true);
   if(CopyBuffer(handle,0,0,limit,arr_rsi)==-1)
     {
      Print("CopyBuffer from iRSI failed, no data");
      return(0);
     }
   return(result);
  }

Die limit Variable ist dafür zuständig, wie viele Werte des iRSI Indikators wir ins arr_rsi[] Array mithilfe von CopyBuffer kopieren werden. Begrenzen wir die limit Variable durch "100", d.h. wir werden immer die letzten 100 Werte des iRSI-Indikators kopieren. Diese Änderungen des Expert Advisors sind in der Datei "RSIAreaExpert_v1_Step3.mq5" zu sehen.

4.3 Code für das Testen der CopyBuffer Funktion 

Wenn es Ihnen nicht ganz klar ist, wie die CopyBuffer Funktion funktioniert und welche Werte das Array mit dem Index "0" enthält, dann kann man einen einfachen Code zur Überprüfung schreiben: schreiben wir den Aufruf der Hilfsfunktion RSIAreaFunc() in OnTick() Funktion.

void OnTick()
  {
//---
   static int RSIAreaShift=0;
   RSIAreaFunc(RSIAreaShift,0);
  }
//+------------------------------------------------------------------+
//| Area calculation                                                 |
//+------------------------------------------------------------------+
double RSIAreaFunc(int &RSIAreaShift,int BeginShift)

Am Ende des ersten Blocks der RSIAreaFunc() Funktion schreiben wir die Ausgabe des Kommentars — des ersten und des letzten Wertes des arr_rsi[] Arrays:

   if(CopyBuffer(handle,0,0,limit,arr_rsi)==-1)
     {
      Print("CopyBuffer from iRSI failed, no data");
      return(0);
     }
//---
   Comment("arr_rsi[",limit-1,"]=",DoubleToString(arr_rsi[limit-1],2),
           "; arr_rsi[0]=",DoubleToString(arr_rsi[0],2));
   return(result);
  }

Das ist ein Prüfcode, er ist nur in der Datei RSIAreaExpert_v1_Step3_check.mq5, enthalten und im Hauptexperten nicht vorhanden. Für die Überprüfung machen wir das folgende:

Auf dem Chart sieht man sofort, dass der Wert des Elemets mit dem Index "0" im arr_rsi Array dem Wert des RSI-Indikators auf dem Balken ganz rechts entspricht:

  check function CopyBuffer 

Abb. 9. Überprüfung der CopyBuffer Funktion  

4.4. Weitere Bearbeitung der Hilfsfunktion

Der nächste Block der RSIAreaFunc() Funktion:  

   if(CopyBuffer(handle,0,0,limit,arr_rsi)==-1)
     {
      Print("CopyBuffer from iRSI failed, no data");
      return(0);
     }

   result=arr_rsi[0]-50.0; // values from the bar that has 0 index

   for(shift=BeginShift+1;shift<limit;shift++)
     {
      rsivalue=arr_rsi[shift]-50;
      if((result>0 && rsivalue<-3) || (result<0 && rsivalue>3))
        {
         RSIAreaShift=shift;
         break;
        }
      result+=rsivalue;
     }
   return(result);
  }

Zuerst wird der result Variablen der Wert des RSI-Indikators auf dem ganz rechten Balken minus 50 zugewiesen. Dann folgt der Loop des arr_rsi Arrays, vom Element mit dem Index "1" bis zum Element mit dem Index limit-1. In diesem Loop wird die Bedingung geprüft: "Ob die Nulllinie gekreuzt wurde". Wenn sie sich gekreuzt haben, wird der Index des Balkens (von rechts nach links) in der RSIAreaShift Variablen gespeichert.

4.5. Funktion OnTick() des Expert Advisors

Wir sind mit der Bearbeitung der Hilfsfunktion RSIAreaFunc() fertig. Nun ist die Hauptfunktion OnTick() an der Reihe. Fügen wir der OnTick() den folgenden Code hinzu: 

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   static int RSIAreaShift=0;
   int      shift;
   double   RSICurrent,RSILocalMin,RSILocalMax,value;
   double   arr_rsi[1],rsi;
   MqlTick  last_tick;
//---
   if(CopyBuffer(handle,0,0,1,arr_rsi)==-1)
     {
      Print("CopyBuffer from iRSI failed, no data");
      return;
     }
   rsi=arr_rsi[0];
//--- 
   if(!SymbolInfoTick(Symbol(),last_tick))
      Print("SymbolInfoTick() failed, error = ",GetLastError());
//---
  }

Mithilfe der bereits bekannten Funktion CopyBuffer erhalten wir den Wert des RSI-Indikators auf dem Balken ganz rechts und weisen diesen Wert der rsi Variablen zu. Ferner werden wir häufig auf diese Variable im Code Bezug nehmen. Dann erhalten wir die laufenden Preise für dieses Symbol und speichern diese in der last_tick Variable.

Der nächste Block des Codes wird unter der Voraussetzung bearbeitet, dass eine offene Position für dieses Symbol vorhanden ist:

 

   if(!SymbolInfoTick(Symbol(),last_tick))
      Print("SymbolInfoTick() failed, error = ",GetLastError());
//--- check the conditions for opening a position
   if(!PositionSelect(Symbol()))
     {
      RSIArea=RSIAreaFunc(RSIAreaShift,0);
      //--- check for a chance to take a long position
      if(RSIArea<-AreaCondition)
        {
         my_trade.Buy(1.0,NULL,last_tick.ask,0.0,0.0,NULL);
         RSIOpen=rsi;
         return;
        }
      //--- check for a chance to take a short position
      if(RSIArea>AreaCondition)
        {
         my_trade.Sell(1.0,NULL,last_tick.bid,0.0,0.0,NULL);
         RSIOpen=rsi;
         return;
        }
      RSIAreaShift=0;
     }
//---
  }
//+------------------------------------------------------------------+
//| Area calculation                                                 |

Die Bedingungen für das Eröffnen einer Position werden im Code übergeprüft: wenn der zum jetzigen Zeitpunkt berechnete Flächeninhalt (Variable RSIArea) kleiner/größer als der Input-Parameter (AreaCondition) ist, dann wird eine Buy/Sell Position eröffnete.

Weiter wird der RSICurrent Variablen der Wert der rsi Variablen zugewiesen (Hinweis: in der Variable wurde der Werte des RSI-Indikators auf dem ganz rechten Balken gespeichert) und die Bedingung für die Beendigung der OnTick() Funktion:

 

      RSIAreaShift=0;
     }
   RSICurrent=rsi;
   if(RSIOpen>50 && RSICurrent>50) return;
   if(RSIOpen<50 && RSICurrent<50) return;

   RSILocalMin = RSICurrent;
   RSILocalMax = RSICurrent;

//---
  }
//+------------------------------------------------------------------+
//| Area calculation                                                 |

Der nächste Block des Codes findet lokale Minima und Maxima und weist diese Werte den Variablen RSILocalMin und RSILocalMax zu:

 

  RSILocalMin = RSICurrent;
   RSILocalMax = RSICurrent;
   
//--- search local minimum/maximum
   if(RSIAreaShift>1)
     {
      double   arr_rsi_1[];
      ArrayResize(arr_rsi_1,RSIAreaShift);
      ArraySetAsSeries(arr_rsi_1,true);
      if(CopyBuffer(handle,0,0,RSIAreaShift,arr_rsi_1)==-1)
        {
         Print("CopyBuffer from iRSI failed, no data");
         return;
        }
      for(shift=1; shift<RSIAreaShift; shift++)
        {
         value=arr_rsi_1[shift];
         if(value<RSILocalMin && RSIArea>0) RSILocalMin=value;
         if(value>RSILocalMax && RSIArea<0) RSILocalMax=value;
        }
     }
//---
  }
//+------------------------------------------------------------------+
//| Area calculation                                                 |

Und schließlich der letzte Block des Codes:

 

         if(value>RSILocalMax && RSIArea<0) RSILocalMax=value;
        }
     }

//--- check for rollback
   if(PositionSelect(Symbol()))
     {
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
        {
         //--- check if it is time for closing
         if(RSILocalMax>=RSICurrent+4 && RSILocalMax>50)
            my_trade.PositionClose(Symbol(),20);
        }
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
        {
         //--- check if it is time for closing
         if(RSILocalMin<=RSICurrent-4 && RSILocalMin<50)
            my_trade.PositionClose(Symbol(),20);
        }
     }
//---
   return;
  }
//+------------------------------------------------------------------+
//| Area calculation                                                 |

Hier (wenn eine offene Position vorhanden ist) wird die Bedingung für die Schließung nach der folgenden Regel überprüft:

Der RSI-Oszillator durchkreuzt die Linie 50 mit der anschließenden Bildung des lokalen Maximums/Minimums und dem Rollback von 4% der Skala.
Z.B. wenn sich der RSI lange über der Linie 50 befindet, haben wir zu einem Zeitpunkt eine offene SELL-Position. Dann nimmt der Wert des Indikators ab und erreicht, z.B. die Linie 40, dann beginnt der Wert des Indikators zuzunehmen (d.h. das lokale Minimum wird gebildet). Als Signal zum Schließen der Position dient der Moment, in dem der Wert des Indikators die Linie 44 erreicht.

Damit ist die Erstellung von RSIAreaExpert_v1 abgeschlossen. Die Datei "RSIAreaExpert_v1.mq5" kann man am Ende des Beitrags herunterladen.


5. Testen des Expert Advisors RSIAreaExpert version 1.00 für verschiedene Perioden und Symbole

Der RSIAreaExpert Expert Advisor wurde ursprünglich im H1-Chart [1] getestet, aber seit 2004 haben sich Finanzmärkte stark verändert und sind volatiler geworden, aus diesem Grund haben wir uns entschieden, die Funktionsfähigkeit der Methode der Flächeninhalte anhand einer größeren Anzahl an Zeitrahmen - von M10 bis H6 - zu testen. Der Bereich der Flächeninhalte wurde für das Testen erheblich erweitert: von 100 bis 800. Testperiode — von 2015.01.05 bis 2016.01.05.

Testergebnisse des Expert Advisors RSIAreaExpert version 1 für AUDCAD:

  RSIAreaExpert version 1 AreaCondition to Profit AUDCAD

Abb. 10. Testergebnisse des Expert Advisors RSIAreaExpert version 1. Symbol AUDCAD. Intervall der Flächeninhalte 100-800. Perioden M10-H6 

In der H2-Periode ist eine gute Dichte der Ergebnisse zu sehen. Die H3-Periode kann auch in Betracht gezogen werden. Nun schauen wir uns die Grafik unten an und evaluieren, wie viele Trades auf AUDCAD pro Jahr beim Testen von RSIAreaExpert version 1 ausgeführt wurden:

RSIAreaExpert version 1 Trades to Profit AUDCAD

Abb. 11.  Testergebnisse von RSIAreaExpert version 1. Symbol AUDCAD. Intervall der Flächeninhalte 100-800. Perioden M10-H6 

Die Anzahl der Trades in den Perioden H2 und H3 schwankt und beläuft sich auf ca.50 Trades. Das ist nicht viel, und die Abweichung ist groß. Daraus ziehen wir die Schlußfolgerung, dass die Methode der Flächeninhalte auf AUDCAD schlecht funktioniert.

Testergebnisse des Expert Advisors RSIAreaExpert version 1 für AUDUSD

RSIAreaExpert version 1 AreaCondition to Profit AUDUSD 

 Abb. 12.  Testergebnisse von RSIAreaExpert version 1. AUDUSD Symbol. Intervall der Flächeninhalte 100-800. Perioden M10-H6 

Wenn es um die Profitabilität der Strategie auf dem AUDUSD Symbol geht, kann man den Handel in H2 und H3 analysieren. In diesen Perioden schwankt der Parameter AreaCondition von 250 bis 400. Um die Zweckmäßigkeit des Handels mit H2 und H3 zu begründen, muss man sich die Anzahl der Trades in diesen Perioden pro Jahr anschauen:

RSIAreaExpert version 1 Trades to Profit AUDUSD 

 Abb. 13.  Testergebnisse von RSIAreaExpert version 1. AUDUSD Symbol. Intervall der Flächeninhalte 100-800. Perioden M10-H6 

Wie Sie sehen können, ist ihre Zahl extrem klein. Dies bedeutet, dass es nicht empfehlenswert ist, auf AUDUSD mithilfe der Methode der Flächeninhalte zu handeln.

Testergebnisse von RSIAreaExpert version 1 für EURUSD:

RSIAreaExpert version 1 AreaCondition to Profit EURUSD

 Abb. 14. Testergebnisse des RSIAreaExpert Expert Advisors. Intervall der Flächeninhalte 100-800. Perioden M10-H6  

Auf der Abbildung 4 sieht man, dass für die M10-Periode eine 'gute' Dichte der Profit-Ergebnisse beim Schwanken der Flächeninhalte von 400 bis 550, für M12 — von 300 bis 400 und für M15 — von 300 bis 400 zu verzeichnen ist. Höhere Perioden werden nicht in Betracht gezogen, denn die Anzahl an Trades auf diesen Perioden pro Jahr zu klein ist (sieh Abb. 5).

Auf der Abbildung 5 ist ein Diagramm zu sehen, das die Abhängigkeit zwischen der Anzahl an Trades und dem Profit für EURUSD darstellt:

RSIAreaExpert version 1 Trades to Profit EURUSD

Abb. 15. Testergebnisse des RSIAreaExpert Expert Advisors. Intervall der Flächeninhalte 100-800. Perioden M10-H6 

Hier sieht man, dass die Anzahl an Trades auf höheren Perioden (von H1 bis H6) sehr klein ist, und somit die Anwendung der Methode auf solchen Perioden in Frage stellt. Die Anzahl an Trades in M10, M12 und M15 spricht hingegen für die Anwendung der Methode der Flächeninhalte in diesen Zeitrahmen. Das Symbol EURUSD passt ganz sicher für den Handel nach der Methode der Flächeninhalte.

Testergebnisse des Expert Advisors RSIAreaExpert version 1 für GBPUSD:

RSIAreaExpert version 1 AreaCondition to Profit GBPUSD 

 Abb. 16.  Testergebnisse von RSIAreaExpert version 1. GBPUSD Symbol. Intervall der Flächeninhalte 100-800. Perioden M10-H6 

GBPUSD weist eine gute Dichte der profitablen Trades in M20 auf. Der AreaCondition Parameter variiert von 300 bis 500.

RSIAreaExpert version 1 Trades to Profit GBPUSD 

Abb. 17.  Testergebnisse von RSIAreaExpert version 1. GBPUSD Symbol. Intervall der Flächeninhalte 100-800. Perioden M10-H6  

Für GBPUSD mit der Periode M20 beläuft sich die Anzahl an Trades von 140 bis 250 für das ganze Jahr. Das ist natürlich kein fantastischer Wert, man kann ihn sich trotzdem merken. Mit anderen Worten ist der Handel mithilfe der Methode der Flächeninhalte auf GBPUSD nicht für jedermann. 

Testergebnisse des Expert Advisors RSIAreaExpert version 1 für USDCAD:

 

Abb. 18.  Testergebnisse von RSIAreaExpert version 1. USDCAD Symbol. Intervall der Flächeninhalte 100-800. Perioden M10-H6  

Für USDCAD würde ich nur M30 in Betracht ziehen, denn nur diese Periode weist Profite auf. Dabei ändert sich der AreaCondition Parameter von 280 bis 550.

RSIAreaExpert version 1 Trades to Profit USDCAD 

 Abb. 19.  Testergebnisse von RSIAreaExpert version 1. USDCAD Symbol. Intervall der Flächeninhalte 100-800. Perioden M10-H6  

Die Anzahl an Trades variiert auf diesem Währungspaar mit dem Zeitrahmen M30 pro Jahr von 90 bis 200. Das ist nicht viel, aus diesem Grund würde ich die Methode der Flächeninhalte für USDCAD nicht empfehlen.

Testergebnisse des Expert Advisors RSIAreaExpert version 1 für USDJPY:

RSIAreaExpert version 1 AreaCondition to Profit USDJPY 

Abb. 20.  Testergebnisse von RSIAreaExpert version 1. USDJPY Symbol. Intervall der Flächeninhalte 100-800. Perioden M10-H6  

Zwei Perioden auf dem USDJPY Symbol: M10 und M30. Der AreaCondition Parameter für M10 liegt zwischen 320 und 650, für M30 — zwischen 550 und 600.

RSIAreaExpert version 1 Trades to Profit USDJPY 

Abb. 21.  Testergebnisse von RSIAreaExpert version 1. USDJPY Symbol. Intervall der Flächeninhalte 100-800. Perioden M10-H6  

Für USDJPY variiert die Anzahl der Trades für die M10 Periode nach der Methode der Flächeninhalte pro Jahr von 150 bis 200, und für die Periode M30 von 50 bis 150. Wir sehen, dass die Empfehlungen für das Trading auch ziemlich unklar sind.


Fazit

Es ist noch nicht die Zeit, den Handel nach der Methode der Flächeninhalte zu außer Acht zu lassen. Unter aktuellen Bedingungen auf dem Markt zeigte das System Verluste im Zeitrahmen H1, obwohl früher [1] der Hauptprofit gerade in diesem Zeitrahmen erzielt wurde. Der Handel nach der Methode der Flächeninhalte hat sich auf dem Symbol EURUSD in den Zeitrahmen M10, M12 und M15 als besonders erfolgreich erwiesen. Das Testen gerade auf diesem Währungspaar und in diesen Zeitrahmen hat eine ausreichende Anzahl an Trades pro Jahr gezeigt.

 

Literaturverzeichnis

  1. I.V. Morosov., R.R. Fatkhullin. FOREX: from simple to compex. New opportunities of MetaTrader client terminal. - M: Teletrade Ltd, 2004. - 448 S.
Wie man die Indikatoren und Expert Advisors aus den Zip-Dateien am Ende des Artikels richtig installiert: die Zip-Dateien "Indicators.zip" und "Experts.zip" müssen im <Dateiordner>\MQL5\ entpackt werden