Startseite Systemhandel Beitrag

Der Moving Average EA für MetaTrader 5: Ein Leitfaden für Trader

Anhang
1921.zip (1.81 KB, Herunterladen 0 mal)

Der Moving Average EA ist im Standardpaket des MetaTrader 5 enthalten und ein gutes Beispiel dafür, wie man mit dem Moving Average-Indikator handelt.

Die EA-Datei Moving Average.mq5 befindet sich im Ordner "terminal_data_folder\MQL5\Experts\Examples\Moving Average". Diese EA demonstriert den Einsatz von technischen Indikatoren, Handelsverlauf-Funktionen und Handelsklassen der Standardbibliothek. Darüber hinaus enthält der EA ein Geldmanagementsystem, das auf den Handelsergebnissen basiert.

Schauen wir uns die Struktur des Expert Advisors und seine Funktionsweise an.

1. Eigenschaften des EA

//+------------------------------------------------------------------+
//|                                              Moving Averages.mq5 |
//|                                               Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2009-2013, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

Die ersten 5 Zeilen enthalten einen Kommentar, die folgenden drei Zeilen setzen die Eigenschaften des MQL5-Programms (Urheberrecht, Link, Version) mit Hilfe von Präprozessor-Direktiven #property.

Wenn Sie den Expert Advisor ausführen, werden diese im Tab "Allgemein" angezeigt:


Abbildung 1. Allgemeine Parameter des Moving Average EA


1.2. Include-Dateien

Als Nächstes gibt die #include-Direktive dem Compiler an, die Datei "Trade.mqh" einzuschließen.

Diese Datei ist Teil der Standardbibliothek und enthält die CTrade-Klasse für einen einfachen Zugriff auf Handelsfunktionen.

#include <Trade\Trade.mqh>

Der Name der Include-Datei wird in spitzen Klammern "<>;" angezeigt, sodass der Pfad relativ zum Verzeichnis "terminal_data_folder\Include\" festgelegt ist.

1.3 Eingaben

Es folgen Typ, Name, Standardwerte und ein Kommentar. Ihre Rolle ist in Abbildung 2 dargestellt.

input double MaximumRisk        = 0.02;    // Maximales Risiko in Prozent
input double DecreaseFactor     = 3;       // Reduktionsfaktor
input int    MovingPeriod       = 12;      // Moving Average Periode
input int    MovingShift        = 6;       // Verschiebung des Moving Averages

Die Parameter MaximumRisk und DecreaseFactor werden für das Geldmanagement verwendet, MovingPeriod und MovingShift legen die Periode und die Verschiebung des Moving Average-technischen Indikators fest, die zur Überprüfung der Handelsbedingungen verwendet werden.

Der Kommentar im Eingabeparameter wird zusammen mit den Standardwerten im Tab "Optionen" anstelle des Namens des Eingabeparameters angezeigt:


Abbildung 2. Eingabeparameter des Moving Average EA

1.4. Globale Variablen

Dann wird die globale Variable ExtHandle deklariert. Sie wird verwendet, um den Handle des Moving Average-Indikators zu speichern.

//---
int   ExtHandle=0;

Es folgen 6 Funktionen. Der Zweck jeder von ihnen wird im Kommentar vor dem Funktionskörper beschrieben:

  • TradeSizeOptimized() - Berechnet die optimale Lotgröße;
  • CheckForOpen() - Überprüft die Bedingungen für offene Positionen;
  • CheckForClose() - Überprüft die Bedingungen für das Schließen von Positionen;
  • OnInit() - Initialisierungsfunktion des Expert Advisors;
  • OnTick() - Tick-Funktion des Expert Advisors;
  • OnDeinit() - Deinitialisierungsfunktion des Expert Advisors;

Die letzten drei Funktionen sind Ereignisbehandlungsfunktionen; die ersten drei Dienstfunktionen werden in ihrem Code aufgerufen.

2. Ereignisbehandlungsfunktionen

2.1. Die OnInit() Initialisierungsfunktion

Die OnInit()-Funktion wird einmal beim ersten Start des Expert Advisors aufgerufen. Normalerweise wird im OnInit()-Ereignisbehandler der EA für den Betrieb vorbereitet: Eingabeparameter werden überprüft, Indikatoren und Parameter werden initialisiert usw. Im Falle kritischer Fehler, wenn die weitere Arbeit sinnlos ist, wird die Funktion mit dem Rückgabewert INIT_FAILED beendet.

//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Expert Advisors                                   |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//---
   ExtHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE);
   if(ExtHandle==INVALID_HANDLE)
     {
      printf("Fehler beim Erstellen des MA-Indikators");
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }

Da der Handel des EA auf dem Indikator Moving Average basiert, wird durch den Aufruf von iMA() der Moving Average-Indikator erstellt und sein Handle in der globalen Variable ExtHandle gespeichert.

Im Falle eines Fehlers wird OnInit() mit dem Rückgabewert INIT_FAILED beendet - das ist der richtige Weg, um den Betrieb des EA/Indikators im Falle einer misslungenen Initialisierung abzuschließen.

2.2. Die OnTick() Funktion

Die OnTick()-Funktion wird jedes Mal aufgerufen, wenn ein neues Angebot für das Symbol empfangen wird, auf dem der EA läuft.

//+------------------------------------------------------------------+
//| Tickfunktion des Expert Advisors                                             |
//+------------------------------------------------------------------+
void OnTick(void)
  {
//---
   if(PositionSelect(_Symbol))
      CheckForClose();
   else
      CheckForOpen();
//---
  }

Die PositionSelect()-Funktion wird verwendet, um zu bestimmen, ob es eine offene Position für das aktuelle Symbol gibt.

Wenn offene Positionen vorhanden sind, wird die CheckForClose()-Funktion aufgerufen, die den aktuellen Zustand des Marktes analysiert und die offene Position schließt. Andernfalls wird CheckForOpen() aufgerufen, die die Bedingungen für den Markteintritt überprüft und eine neue Position eröffnet, wenn solche Bedingungen eintreten.

2.3. Die OnDeInit() Deinitialisierungsfunktion

OnDeInit() wird aufgerufen, wenn ein EA vom Chart entfernt wird. Wenn ein Programm während des Betriebs grafische Objekte platziert, können diese vom Chart entfernt werden.

//+------------------------------------------------------------------+
//| Deinitialisierungsfunktion des Expert Advisors                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+

In diesem Fall werden während der Deinitialisierung des Expert Advisors keine Aktionen durchgeführt.

3. Dienstfunktionen

3.1. Funktion TradeSizeOptimized()

Diese Funktion berechnet und gibt den Wert der optimalen Lotgröße für die Eröffnung einer Position mit dem angegebenen Risikolevel und den Handelsergebnissen zurück.

//+------------------------------------------------------------------+
//| Berechnung der optimalen Lotgröße                                       |
//+------------------------------------------------------------------+
double TradeSizeOptimized(void)
  {
   double price=0.0;
   double margin=0.0;
//--- Berechnung der Lotgröße
   if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price))
      return(0.0);
   if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin))
      return(0.0);
   if(margin<=0.0)
      return(0.0);
   double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_FREEMARGIN)*MaximumRisk/margin,2);
//--- Berechnung der Länge der Serie von aufeinanderfolgenden Verlustgeschäften
   if(DecreaseFactor>0)
     {
      //--- Anfrage für die gesamte Handelshistorie
      HistorySelect(0,TimeCurrent());
      //--
      int    orders=HistoryDealsTotal();  // die Gesamtanzahl der Deals
      int    losses=0                    // die Anzahl der Verlustgeschäfte in der Serie
      for(int i=orders-1;i>=0;i--)
        {
         ulong ticket=HistoryDealGetTicket(i);
         if(ticket==0)
           {
            Print("HistoryDealGetTicket fehlgeschlagen, keine Handelshistorie");
            break;
           }
         //--- Überprüfung des Handelssymbols
         if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol)
            continue;
         //--- Überprüfung des Gewinns
         double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);
         if(profit>0.0)
            break;
         if(profit<0.0)
            losses++;
    }
      //---
      if(losses>1)
         lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
    }
//--- Normalisieren und Überprüfen der erlaubten Werte des Handelsvolumens
   double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   lot=stepvol*NormalizeDouble(lot/stepvol,0);
   double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   if(lot<minvol)
      lot=minvol;
   double maxvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
   if(lot>maxvol)
      lot=maxvol;
//--- Rückgabe des Wertes des Handelsvolumens
   return(lot);
  }

Die SymbolInfoDouble()-Funktion wird verwendet, um die Verfügbarkeit von Preisen für das aktuelle Symbol zu überprüfen. Anschließend wird die OrderCalcMargin()-Funktion verwendet, um die für eine Order erforderliche Margin anzufordern (in diesem Fall eine Kauforder). Die anfängliche Lotgröße wird aus dem Wert der für die Erteilung einer Order erforderlichen Margin, der freien Margin des Kontos (AccountInfoDouble(ACCOUNT_FREEMARGIN)) und dem maximalen Risikowert, der im Eingabeparameter MaximumRisk angegeben ist, ermittelt.

Wenn der Wert des Eingabeparameters DecreaseFactor positiv ist, werden die Deals in der Historie analysiert und die Größe des Lots unter Berücksichtigung der Informationen über die maximale Serie von Verlustgeschäften angepasst: die anfängliche Lotgröße wird mit der Größe (1-losses/DecreaseFactor) multipliziert.

Anschließend wird das Handelsvolumen auf den Wert gerundet, der dem minimal zulässigen Volumenschritt (stepvol) für das aktuelle Symbol multipliziert wird. Auch die minimalen (minvol) und maximalen möglichen Werte (maxvol) des Handelsvolumens werden angefordert, und wenn der Lotwert die erlaubten Grenzen überschreitet, wird er angepasst. Das Ergebnis der Funktion ist der berechnete Wert des Handelsvolumens.

3.2. Funktion CheckForOpen()

CheckForOpen() wird verwendet, um die Bedingungen für die Eröffnung von Positionen zu überprüfen und öffnet sie, wenn Handelsbedingungen eintreten (in diesem Fall, wenn der Preis den gleitenden Durchschnitt überschreitet).

//+------------------------------------------------------------------+
//| Überprüfung auf Bedingungen zur Eröffnung von Positionen                               |
//+------------------------------------------------------------------+
void CheckForOpen(void)
  {
   MqlRates rt[2];
//--- Kopieren der Preiswerte
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("CopyRates von ",_Symbol," fehlgeschlagen, keine Historie");
      return;
     }
//--- Handel nur beim ersten Tick der neuen Kerze
   if(rt[1].tick_volume>1)
      return;
//--- Aktuellen Wert des Moving Average-Indikators abrufen 
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer von iMA fehlgeschlagen, keine Daten");
      return;
     }
//--- Überprüfung der Signale
   ENUM_ORDER_TYPE signal=WRONG_VALUE;
   if(rt[0].open>ma[0] && rt[0].close<ma[0])
      signal=ORDER_TYPE_SELL    // Verkaufsbedingung
   else
      {
         if(rt[0].open<ma[0] && rt[0].close>ma[0])
           signal=ORDER_TYPE_BUY  // Kaufbedingung
    }
//--- Zusätzliche Überprüfungen
   if(signal!=WRONG_VALUE)
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         if(Bars(_Symbol,_Period)>100)
           {
            CTrade trade;
            trade.PositionOpen(_Symbol,signal,TradeSizeOptimized(),
                               SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ? SYMBOL_BID:SYMBOL_ASK),
                               0,0);
          }
//---
  }

Bei Handelsstrategien mit dem Moving Average müssen Sie überprüfen, ob der Preis den gleitenden Durchschnitt überschreitet. Mit der CopyRates()-Funktion werden zwei Werte der aktuellen Preise in das Array von Strukturen rt[] kopiert, wobei rt[1] der aktuellen Kerze und rt[0] der abgeschlossenen Kerze entspricht.

Eine neue Kerze wird durch Überprüfung des Tickvolumens der aktuellen Kerze gestartet. Wenn es gleich 1 ist, hat eine neue Kerze begonnen. Es sollte beachtet werden, dass diese Methode zur Erkennung einer neuen Kerze in einigen Fällen fehlschlagen kann (wenn Angebote in Paketen kommen), sodass der Beginn der Bildung einer neuen Kerze durch Speichern und Vergleichen der Zeit des aktuellen Angebots (siehe IsNewBar) erfolgen sollte.

Der aktuelle Wert des Moving Average-Indikators wird mit der CopyBuffer()-Funktion angefordert und im ma[]-Array gespeichert, das nur einen Wert enthält. Das Programm überprüft dann, ob der Preis den gleitenden Durchschnitt überschreitet, und führt zusätzliche Überprüfungen durch (ob der Handel mit dem EA möglich ist und die Anzahl der Kerzen in der Historie). Bei Erfolg wird durch den Aufruf der PositionOpen()-Methode des Handelsobjekts (eine Instanz von CTrade) eine entsprechende Position für das Symbol eröffnet.

Der Eröffnungspreis der Position wird mit der SymbolInfoDouble()-Funktion festgelegt, die den Bid- oder Ask-Preis zurückgibt, abhängig vom Wert der Variablen signal. Das Positionsvolumen wird durch den Aufruf von TradeSizeOptimized() bestimmt, wie oben beschrieben.

3.3. Funktion CheckForClose()

CheckForClose() überprüft die Bedingungen für das Schließen von Positionen und schließt sie, wenn Bedingungen zum Schließen auftreten.

//+------------------------------------------------------------------+
//| Überprüfung auf Bedingungen zum Schließen von Positionen                              |
//+------------------------------------------------------------------+
void CheckForClose(void)
  {
   MqlRates rt[2];
//--- Preiswerte kopieren
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("CopyRates von ",_Symbol," fehlgeschlagen, keine Historie");
      return;
     }
//--- Handel nur beim ersten Tick der neuen Kerze
   if(rt[1].tick_volume>1)
      return;
//--- Aktuellen Wert des Moving Average-Indikators abrufen
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer von iMA fehlgeschlagen, keine Daten");
      return;
     }
//--- Typ der zuvor ausgewählten Position mit PositionSelect() abrufen
   bool signal=false;
   long type=PositionGetInteger(POSITION_TYPE);
   if(type==(long)POSITION_TYPE_BUY   && rt[0].open>ma[0] && rt[0].close<ma[0])
      signal=true;
   if(type==(long)POSITION_TYPE_SELL  && rt[00] && rt[0].close>ma[0])
      signal=true;
//--- Zusätzliche Überprüfungen
   if(signal)
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         if(Bars(_Symbol,_Period)>100)
           {
            CTrade trade;
            trade.PositionClose(_Symbol,3);
           }
//---
  }

Der Algorithmus der Funktion CheckForClose() ähnelt dem Algorithmus von CheckForOpen(). Je nach Richtung der aktuellen offenen Positionen werden die Bedingungen für deren Schließung überprüft (Preisüberschreitung des MA nach unten für Kauf- oder nach oben für Verkaufspositionen). Eine offene Position wird durch den Aufruf der PositionClose()-Methode des Handelsobjekts (Instanz von CTrade) geschlossen.

4. Backtesting

Die besten Werte der Parameter können mit dem Strategietester des MetaTrader 5-Terminals gefunden werden.

Zum Beispiel, wenn man den Parameter MovingPeriod im Zeitraum 2012.01.01-2013.08.01 optimiert, erhält man die besten Ergebnisse mit MovingPeriod=45:

Backtesting Ergebnisse des Moving Average Expert Advisors

Backtesting Ergebnisse des Moving Average Expert Advisors

Fazit:

Der im Standardpaket des MetaTrader 5 enthaltene Moving Average Expert Advisor ist ein Beispiel für den Einsatz von technischen Indikatoren, Handelsgeschichten-Funktionen und Handelsklassen der Standardbibliothek. Darüber hinaus enthält der EA ein Geldmanagementsystem, das auf den Handelsergebnissen basiert.


Verwandte Beiträge

Kommentar (0)