Home Systeemhandel Bericht

Moving Average EA voor MetaTrader 5: Optimaliseer je Handelsstrategie

Bijlage
1921.zip (1.81 KB, Downloaden 0 keer)

De Moving Average EA is opgenomen in het standaardpakket van de MetaTrader 5 client terminal en is een mooi voorbeeld van een EA die handelt met behulp van de Moving Average indicator.

Het EA-bestand, Moving Average.mq5, vind je in de map "terminal_data_folder\MQL5\Experts\Examples\Moving Average\. Deze EA laat zien hoe je technische indicatoren, handelsgeschiedenis functies en handelsklassen van de Standaard Bibliotheek kunt gebruiken. Daarnaast bevat de EA een geldbeheersysteem dat is gebaseerd op handelsresultaten.

Laten we de structuur van de Expert Advisor bekijken en hoe deze werkt.

1. EA Eigenschappen

//+------------------------------------------------------------------+
//|            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"

De eerste 5 rijen bevatten een opmerking, de volgende drie regels stellen de eigenschappen van het MQL5-programma (auteursrecht, link, versie) in met behulp van de preprocessor-directieven #property.

Wanneer je de Expert Advisor uitvoert, worden ze weergegeven in het tabblad "Algemeen":


Figuur 1. Algemene Parameters van de Moving Average EA


1.2. Inbegrepen Bestanden

Vervolgens vertelt de #include directieve de compiler om het bestand "Trade.mqh" op te nemen.

Dit bestand maakt deel uit van de Standaard Bibliotheek en bevat de CTrade klasse voor gemakkelijke toegang tot handelsfuncties.

#include <Trade\Trade.mqh>

De naam van het inbegrepen bestand wordt in haakjes "<>;" weergegeven, zodat het pad relatief is ten opzichte van de directory: "terminal_data_folder\Include\."

1.3 Invoerparameters

Daarna komen het type, de naam, de standaardwaarden en een opmerking. Hun rol wordt weergegeven in fig. 2.

input double MaximumRisk = 0.02; // Maximale Risico in percentage
input double DecreaseFactor = 3; // Afnamefactor
input int MovingPeriod = 12; // Moving Average periode
input int MovingShift = 6; // Moving Average verschuiving

De parameters MaximumRisk en DecreaseFactor zullen worden gebruikt voor geldbeheer, MovingPeriod en MovingShift stellen de periode en verschuiving van de Moving Average technische indicator in die zal worden gebruikt om handelsvoorwaarden te controleren.

De tekst in de opmerking in de invoerparameterregel, samen met de standaardwaarden, worden weergegeven in het tabblad "Opties" in plaats van de naam van de invoerparameter:


Fig. 2. Invoerparameters van de Moving Average EA

1.4. Global Variabelen

Vervolgens wordt de globale variabele ExtHandle gedeclareerd. Deze zal worden gebruikt voor het opslaan van de handle van de Moving Average indicator.

//---
int ExtHandle = 0;

Daarna volgen 6 functies. Het doel van elk van hen wordt beschreven in de opmerking vóór de functie-inhoud:

  • TradeSizeOptimized() - Bereken de optimale lotgrootte;
  • CheckForOpen() - Controleer op open positievoorwaarden;
  • CheckForClose() - Controleer op sluitpositievoorwaarden;
  • OnInit() - Initialisatiefunctie van de Expert;
  • OnTick() - Tick-functie van de Expert;
  • OnDeinit() - Deinitialisatiefunctie van de Expert;

De laatste drie functies zijn evenementafhandelingsfuncties; de eerste drie servicefuncties worden in hun code aangeroepen.

2. Evenementafhandelingsfuncties

2.1. De OnInit() initialisatiefunctie

De OnInit() functie wordt één keer aangeroepen bij de eerste start van de Expert Advisor. Gewoonlijk wordt in de OnInit() gebeurtenis handler de EA voorbereid op gebruik: invoerparameters worden gecontroleerd, indicatoren en parameters worden geïnitialiseerd, enz. In het geval van kritieke fouten, wanneer verder werken zinloos is, verlaat de functie met een retourcode INIT_FAILED.

//+------------------------------------------------------------------+
//| Expert initialisatiefunctie                                      |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//---
   ExtHandle = iMA(_Symbol,_Period, MovingPeriod, MovingShift,MODE_SMA,PRICE_CLOSE);
   if(ExtHandle == INVALID_HANDLE)
     {
      printf("Fout bij het aanmaken van MA-indicator");
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }

Aangezien de EA-handel is gebaseerd op de indicator Moving Average, wordt de iMA() aangeroepen om de Moving Average indicator te creëren en de handle op te slaan in de globale variabele ExtHandle.

In geval van een fout, wordt OnInit() verlaten met een retourcode INIT_FAILED - dit is een correcte manier om de werking van de EA/indicator te beëindigen in het geval van een mislukte initialisatie.


2.2. De OnTick() functie

De OnTick() functie wordt elke keer aangeroepen wanneer een nieuwe quote wordt ontvangen voor het symbool van de grafiek waarop de EA draait.

//+------------------------------------------------------------------+
//| Expert tick functie                                             |
//+------------------------------------------------------------------+
void OnTick(void)
  {
//---
   if(PositionSelect(_Symbol))
      CheckForClose();
   else
      CheckForOpen();
//---
  }

De PositionSelect() functie wordt gebruikt om te bepalen of er een open positie is voor het huidige symbool.

Als er open posities zijn, wordt de CheckForClose() functie aangeroepen, die de huidige marktsituatie analyseert en de open positie sluit. Anders wordt CheckForOpen() aangeroepen, die de voorwaarden voor markttoetreding controleert en een nieuwe positie opent als dergelijke voorwaarden zich voordoen.


2.3. De OnDeInit() deinitialisatiefunctie

OnDeInit() wordt aangeroepen wanneer een EA van de grafiek wordt verwijderd. Als een programma grafische objecten plaatst tijdens de werking, kunnen deze van de grafiek worden verwijderd.

//+------------------------------------------------------------------+
//| Expert deinitialisatiefunctie                                    |
//+------------------------------------------------------------------+
void OnDeinit(const int reden)
  {
  }
//+------------------------------------------------------------------+

In dit geval worden er geen acties uitgevoerd tijdens de deinitialisatie van de Expert Advisor.


3. Servicefuncties

3.1. Functie TradeSizeOptimized()

Deze functie berekent en retourneert de waarde van de optimale lotgrootte voor het openen van een positie met het opgegeven risiconiveau en handelsresultaten.

//+------------------------------------------------------------------+
//| Bereken optimale lotgrootte                                     |
//+------------------------------------------------------------------+
double TradeSizeOptimized(void)
  {
   double prijs=0.0;
   double marge=0.0;
//--- Bereken de lotgrootte
   if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,prijs))
      return(0.0);
   if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,prijs,marge))
      return(0.0);
   if(marge <= 0.0)
      return(0.0);

   double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_FREEMARGIN)*MaximumRisk/marge,2);
//--- berekenen van de lengte van de reeks opeenvolgende verlieshandel
   if(DecreaseFactor > 0)
     {
      //--- vraag de volledige handelsgeschiedenis aan
      HistorySelect(0,TimeCurrent());
      //--
      int orders=HistoryDealsTotal(); // het totale aantal deals
      int verliezen=0; // het aantal verliesdeals in de reeks

      for(int i=orders-1; i >= 0; i--)
      {
        ulong ticket=HistoryDealGetTicket(i);
        if(ticket==0)
           {
            Print("HistoryDealGetTicket mislukt, geen handelsgeschiedenis");
            break;
           }
        //--- controleer het deal symbool
        if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol)
            continue;
        //--- controleer de winst
        double winst=HistoryDealGetDouble(ticket,DEAL_PROFIT);
        if(winst > 0.0)
            break;
        if(winst < 0.0)
            verliezen++;
        }
      //---
      if(verliezen > 1)
         lot=NormalizeDouble(lot-lot*verliezen/DecreaseFactor,1);
    }
//--- normaliseren en controleren van de toegestane waarden van het handelsvolume
   double stapvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   lot=stapvol*NormalizeDouble(lot/stapvol,0);

   double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   if(lotdouble maxvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
   if(lot>maxvol)
      lot=maxvol;
//--- retourneer de waarde van het handelsvolume
   return(lot);
  }

De SymbolInfoDouble() functie wordt gebruikt om te controleren of prijzen beschikbaar zijn voor het huidige symbool. Vervolgens wordt de OrderCalcMargin() functie gebruikt om de marge op te vragen die nodig is om een bestelling te plaatsen (in dit geval een kooporder). De initiële lotgrootte wordt bepaald uit de waarde van de marge die nodig is voor het plaatsen van een order, de beschikbare marge van de rekening (AccountInfoDouble(ACCOUNT_FREEMARGIN)) en de maximaal toegestane waarde van risico die is opgegeven in de invoerparameter MaximumRisk.

Als de waarde van de invoerparameter DecreaseFactor positief is, worden de deals in de geschiedenis geanalyseerd en wordt de grootte van de lot aangepast rekening houdend met informatie over de maximale reeks verlieshandel: de initiële lotgrootte wordt vermenigvuldigd met de grootte (1-verliezen/DecreaseFactor).

Daarna wordt het handelsvolume "afgerond" op de waarde die een veelvoud is van de minimum toegestane stap van volume (stapvol) voor het huidige symbool. Ook worden de minimum (minvol) en maximum mogelijke waarden (maxvol) van het handelsvolume opgevraagd, en als de lotwaarde buiten de toegestane limieten valt, wordt deze aangepast. Het resultaat is dat de functie de berekende waarde van het handelsvolume retourneert.


3.2. Functie CheckForOpen()

CheckForOpen() wordt gebruikt om de voorwaarden voor het openen van posities te controleren en opent deze wanneer de handelsvoorwaarden zich voordoen (in dit geval wanneer de prijs de moving average kruist).

//+------------------------------------------------------------------+
//| Controleer op open positievoorwaarden                             |
//+------------------------------------------------------------------+
void CheckForOpen(void)
  {
   MqlRates rt[2];
//--- kopieer de prijswaarden
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("CopyRates van ",_Symbol," mislukt, geen geschiedenis");
      return;
    }
//--- Handel alleen op de eerste tick van de nieuwe balk
   if(rt[1].tick_volume > 1)
      return;
//--- Verkrijg de huidige waarde van de Moving Average indicator
   double ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer van iMA mislukt, geen data");
      return;
    }
//--- controleer de signalen
   ENUM_ORDER_TYPE signal=WRONG_VALUE;

   if(rt[0].open > ma[0] && rt[0].close < ma[0])
      signal=ORDER_TYPE_SELL; // verkoopvoorwaarde
   else
      {
      if(rt[0].open < ma[0] && rt[0].close > ma[0])
         signal=ORDER_TYPE_BUY; // koopvoorwaarde
    }
//--- aanvullende controles
   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);
          }
//---
  }

Bij het handelen met de moving average moet je controleren of de prijs de moving average kruist. Met behulp van de CopyRates() functie worden twee waarden van de huidige prijzen gekopieerd naar de array van structuren rt[], rt[1] komt overeen met de huidige balk, rt[0] - voltooide balk.

Een nieuwe balk wordt gestart door het tickvolume van de huidige balk te controleren. Als dit gelijk is aan 1, is er een nieuwe balk gestart. Het moet worden opgemerkt dat deze methode om een nieuwe balk te detecteren in sommige gevallen kan mislukken (wanneer quotes in pakketten binnenkomen), dus het feit van de start van de vorming van een nieuwe balk moet worden gedaan door de tijd van de huidige quote op te slaan en te vergelijken (zie IsNewBar).

De huidige waarde van de Moving Average indicator wordt opgevraagd met de CopyBuffer() functie en opgeslagen in de ma[] array die slechts één waarde bevat. Vervolgens controleert het programma of de prijs de moving average heeft gekruist en maakt het aanvullende controles (of handelen met de EA mogelijk is en of er balken in de geschiedenis zijn). Als dit succesvol is, wordt een geschikte positie voor het symbool geopend door de PositionOpen() methode van het handelsobject (een instantie van CTrade) aan te roepen.

De openingsprijs van de positie wordt ingesteld met de SymbolInfoDouble() functie die de Bid of Ask prijs retourneert, afhankelijk van de waarde van de signal variabele. Het volume van de positie wordt bepaald door de TradeSizeOptimized() functie die hierboven is beschreven.


3.3. Functie CheckForClose()

CheckForClose() controleert de voorwaarden voor het sluiten van posities en sluit deze als de voorwaarden om deze te sluiten zich voordoen.

//+------------------------------------------------------------------+
//| Controleer op sluitpositievoorwaarden                             |
//+------------------------------------------------------------------+
void CheckForClose(void)
  {
   MqlRates rt[2];
//--- Kopieer prijswaarden
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("CopyRates van ",_Symbol," mislukt, geen geschiedenis");
      return;
    }
//--- Handel alleen op de eerste tick van de nieuwe balk
   if(rt[1].tick_volume > 1)
      return;
//--- Verkrijg de huidige waarde van de Moving Average indicator
   double ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer van iMA mislukt, geen data");
      return;
    }
//--- Verkrijg het type van de positie die eerder is geselecteerd met PositionSelect()
   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[0].open < ma[0] && rt[0].close > ma[0])
      signal=true;
//--- aanvullende controles
   if(signal)
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
        if(Bars(_Symbol,_Period) > 100)
           {
            CTrade trade;
            trade.PositionClose(_Symbol,3);
          }
//---
  }

Het algoritme van de CheckForClose() functie is vergelijkbaar met het algoritme van CheckForOpen(). Afhankelijk van de richting van de huidige open posities, worden de sluitingsvoorwaarden gecontroleerd (prijs die de MA naar beneden kruist om te kopen of omhoog om te verkopen). Een open positie wordt gesloten door de PositionClose() methode van het handelsobject (een instantie van CTrade) aan te roepen.


4. Backtesting

De beste waarden van de parameters kunnen worden gevonden met behulp van de Strategietester van de MetaTrader 5 terminal.

Bijvoorbeeld, bij het optimaliseren van de MovingPeriod parameter in de periode van 2012.01.01-2013.08.01, worden de beste resultaten behaald met MovingPeriod=45:

Backtesting Resultaten van de Moving Average Expert Advisor

Backtesting Resultaten van de Moving Average Expert Advisor

Conclusies:

De Moving Average Expert Advisor die is opgenomen in het standaardpakket van de MetaTrader 5 terminal, is een voorbeeld van het gebruik van technische indicatoren, handelsgeschiedenis functies en handelsklassen van de Standaard Bibliotheek. Daarnaast bevat de EA een geldbeheersysteem dat is gebaseerd op handelsresultaten.


Gerelateerde berichten

Reactie (0)