Cross-Plattform Expert Advisor: Geldmanagement

Enrico Lambino | 26 Juli, 2017


Inhaltsverzeichnis

  1. Einführung
  2. Ziele
  3. Basisklasse
  4. Klassen und Typen des Geldmanagements
  5. Container der Objekte für das Geldmanagement
  6. Beispiel
  7. Schlussfolgerung

Einführung

Das Geldmanagement ist ein gemeinsames Merkmal aller Expert Advisor. Es erlaubt dem Expert Advisor dynamisch die Lotgröße der nächsten Position zu bestimmen. In diesem Artikel stellen wir mehrere Klassen für das Geldmanagement vor, die uns den ganzen Prozess der Berechnung der Lotgröße eines Cross-Plattform Expert Advisors automatisieren.

Ziele

  • Verstehen und anwenden der gängigsten Methoden des Geldmanagements im Handel
  • Dem Expert Advisor ermöglichen aus eine Liste verfügbarer Methoden des Geldmanagement auszuwählen
  • Kompatibilität mit MQL4 und MQL5

Basisklasse

Alle Klassen des Geldmanagements dieses Artikels habe eine bestimmte Basisklasse mit den Namen CMoney, abgeleitet von der Klasse CMoneyBase. Die Klasse CMoneyBase wird durch den folgenden Codeausschnitt definiert:

class CMoneyBase : public CObject
  {
protected:
   bool              m_active;
   double            m_volume;
   double            m_balance;
   double            m_balance_inc;
   int               m_period;
   bool              m_equity;
   string            m_name;
   CSymbolManager   *m_symbol_man;
   CSymbolInfo      *m_symbol;
   CAccountInfo     *m_account;
   CEventAggregator *m_event_man;
   CObject          *m_container;
public:
                     CMoneyBase(void);
                    ~CMoneyBase(void);
   virtual int       Type(void) const {return CLASS_TYPE_MONEY;}
   //--- Initialisierung
   virtual bool      Init(CSymbolManager*,CAccountInfo*,CEventAggregator*);
   bool              InitAccount(CAccountInfo*);
   bool              InitSymbol(CSymbolManager*);
   CObject          *GetContainer(void);
   void              SetContainer(CObject*);
   virtual bool      Validate(void);
   //--- Abfragen und Ändern
   bool              Active(void) const;
   void              Active(const bool);
   void              Equity(const bool);
   bool              Equity(void) const;
   void              LastUpdate(const datetime);
   datetime          LastUpdate(void) const;
   void              Name(const string);
   string            Name(void) const;
   double            Volume(const string,const double,const ENUM_ORDER_TYPE,const double);
   void              Volume(const double);
   double            Volume(void) const;
protected:
   virtual void      OnLotSizeUpdated(void);
   virtual bool      UpdateLotSize(const string,const double,const ENUM_ORDER_TYPE,const double);
  };

Die meisten Methoden dieser Klasse ändern oder erfragen verschiedene Klassenmitglieder und sind daher selbsterklärend. Für die praktische Anwendung sind aber nur drei Methoden wirklich wichtig UpdateLotSize, OnLotSizeUpdated, und Volume.

Die Methode UpdateLotSize berechnet das aktuelle Handelsvolumen. Sie ist auch, abgeleitet aus der Basisklasse, die Hauptmethode, und daher finden sich die meisten Unterschiede zwischen den verschiedenen Klassen für das Geldmanagement innerhalb dieser Methode. In der Basisklasse sind das quasi virtuelle Methoden, da sie nur einen Wert zurückgegeben:

bool CMoneyBase::UpdateLotSize(const string,const double,const ENUM_ORDER_TYPE,const double)
  {
   return true;
  }

Manchmal müssen nach dem Berechnen der Handelsvolumens bestimmte Variablen für eine weitere Berechnung aktualisiert werden. In diesem Fall wird die Methode OnLotSizeUpdated verwendet. Diese Methode wird automatisch innerhalb der Methode UpdateLotSize aufgerufen. Der folgende Code zeigt die erwähnte Methode:

void CMoneyBase::OnLotSizeUpdated(void)
  {
   m_symbol=m_symbol_man.Get();
   double maxvol=m_symbol.LotsMax();
   double minvol=m_symbol.LotsMin();
   if(m_volume<minvol)
      m_volume=minvol;
   if(m_volume>maxvol)
      m_volume=maxvol;
  }

Um das aktuelle, von dem Objekt des Geldmanagements berechnete Handelsvolumen abzufragen, muss der Expert Advisor aber nicht UpdateLotSize oder OnLotSizeUpdated aufrufen. Es muss nur die Methode Volume der Klasse aufgerufen werden. Diese Methode selbst ruft automatisch die beiden anderen Methoden auf:

double CMoneyBase::Volume(const string symbol,const double price,const ENUM_ORDER_TYPE type,const double sl=0)
  {
   if(!Active())
      return 0;
   if(UpdateLotSize(symbol,price,type,sl))
      OnLotSizeUpdated();
   return m_volume;
  }

Klassen und Typen des Geldmanagements

Feste Lotgröße

Das ist die wohl gängigste Methode der Bestimmung der Lotgröße und die, mit der die meisten Händler gut vertraut sind. Durch eine feste Lotgröße haben alle Positionen dieselbe Lotgröße, egal, ob der Kontostand steigt oder fällt.

Für diese Form des Geldmanagements benötigt man nur diese feste Lotgröße. Daher kann der größte Unterschied zwischen CMoney/CMoneyBase im Konstruktor gefunden werden, wo die feste Lotgröße bestimmt wird:

CMoneyFixedLotBase::CMoneyFixedLotBase(double volume)
  {
   Volume(volume);
  }
Falls wir jetzt eine dynamische Veränderung des Ergebnisses dieser Methode des Geldmanagements wünschen, müssen wir nur das Klassenmitglied m_volume durch Aufruf der Methode Volume neu festsetzen.


Fixes Risiko (fixer Anteil)

Die Methode des fixen Risikos oder fixen Anteils des Geldmanagements reserviert eine festen Prozentsatz des Kontostandes oder des Eigenkapital je Position. Das ist Teil der Standardbibliothek durch CmoneyFixedRisk. Führt eine Position zu einem Verlust, entspricht dieser Verlust prozentual dem Kontostand zum Zeitpunkt der Eröffnung der Position. Dieser Verlust ist nicht einfach nur irgendein Verlust sondern der maximale Verlust, wenn z.B. der Markt den StopLoss der Position trifft. Diese Methode verlangt einen StopLoss größer als Null, damit sie funktioniert.

Die Berechnung des prozentualen Risikos einer Position berechnet sich nach folgender Formel:

Volume = (balance * account_percentage / ticks) / tick_value

wobei:

  • balance – Kontostand oder Eigenkapital
  • account_percentage – der zu riskierende Prozentsatz des Kontos (Bereich: 0,0-1,0)
  • ticks – der Wert des StopLoss, ausgedrückt in Ticks
  • tick_value – der Tick-Wert ist der Wert einer Bewegung um einen Tick des Symbols oder Handelsinstrumentes in der Kontowährung (basierend auf 1.0 Lot)

Ein Tick ist definiert als die kleinste Preisbewegung eines Währungspaars oder Handelsinstrumentes. Zum Beispiel hat der EURUSD (bei einem Broker mit 5 Dezimalen oder Digits) eine Tick-Größe (tick-size) von 0,00001, und das ist die kleinst mögliche Preisbewegung dieses Währungspaars. Wenn der Wert des StopLoss' in Points oder Pips ausgedrückt wird, ist das Ergebnis die Differenz zwischen den Preisen der Eröffnung und dem StopLoss einer Position in Points oder Pips.

Für dasselbe Währungspaar ist der Tick-Wert einer Währung eines 4-Digits-Broker anders als der eines 5-Digits-Broker. Das rührt daher, dass 1 Tick eines 4-Digits-Broker gleich einem Point (oder Pip), wohingegen der Pip einen 5-Digits-Broker 10 Points entspricht.

Als Beispiel eines Geldmanagements mit fixem Risiko, gehen wir von einem Kontostand von 1.000 USD und einem Risiko von 5% für eine neue Position aus. Nehmen wir Tick-Wert von 0,1 und einen StopLoss von 200 Points (20 Pips) einen 5-Digits-Broker:

Volume = (1000 * 0,05 / 200) / 0,1 = 2,5 Lot

Die errechnete Lotgröße steigt mit dem Prozentsatz des Risikos und dem Kontostand und fällt bei steigendem Abstand des StopLoss' oder des Tick-Werts. Der Kontostand, das Risiko und der Tick-Wert sind meistens konstant, sich ändernde StopLoss' (dynamisch berechnet) aber nicht. Dieser Ansatz ist aber in der Regel für Strategien ohne eine Begrenzung des Abstandes der Preise von Eröffnung und dem StopLoss ungeeignet, da das zu sehr kleinen (und vom Broker zurückgewiesenen) Lotgrößen führen würde. Andererseits führen zu kleine Differenzen des StopLoss' zu sehr großen Lotgrößen, eventuell auch zu Problemen mit dem Broker und dessen maximal erlaubter Lotgröße. Das Problem wurde durch den MetaTrader 5 dadurch gelöst, dass er Aufträge, wenn die Größen zu groß sind, in mehrere "Deals" aufteilt. Der MetaTrader 4 jedoch verfügt nicht über diese Fähigkeit – ein großes Handelsvolumen muss vorbereitet werden (aufgeteilt in mehrere kleinere Positionen) oder es wird einfach vermieden, die maximal erlaubte Lotgröße zu überschreiten.

Die Formel der Berechnung findet sich in der Methode UpdateLotSize:

bool CMoneyFixedFractionalBase::UpdateLotSize(const string symbol,const double price,const ENUM_ORDER_TYPE type,const double sl)
  {
   m_symbol=m_symbol_man.Get(symbol);
   double last_volume=m_volume;
   if(CheckPointer(m_symbol))
     {
      double balance=m_equity==false?m_account.Balance():m_account.Equity();
      double ticks=0;
      if(price==0.0)
        {
         if(type==ORDER_TYPE_BUY)
            ticks=MathAbs(m_symbol.Bid()-sl)/m_symbol.TickSize();
         else if(type==ORDER_TYPE_SELL)
            ticks=MathAbs(m_symbol.Ask()-sl)/m_symbol.TickSize();
        }
      else ticks=MathAbs(price-sl)/m_symbol.TickSize();
      m_volume=((balance*(m_risk/100))/ticks)/m_symbol.TickValue();
     }
   return NormalizeDouble(last_volume-m_volume,2)==0;
  }
Zuerst holen wir uns den StopLoss in Ticks. Danach verwenden wir die obige Formel, um m_volume, das Mitglied der Klasse, zu aktualisieren, und verwenden das für den Rückgabewert.


Fixer Anteil

Ein Geldmanagement auf Basis eines fixen Anteils berechnet das Handelsvolumen als Anteil des verfügbaren Kontostandes. Das kann als ein Sonderfall des Geldmanagements mittels einer fixen Lotgröße betrachtet werden, mit dem Unterschied, dass die Lotgröße automatisch und nicht, durch den Händler, manuell angepasst wird. Steigt der Kontostand, erhöht sich die Lotgröße nach Überschreiten eines Schwellenwertes. Fällt der Kontostand, sinkt die Lotgröße entsprechend.

Anders als das Geldmanagement durch ein fixes Risiko, benötigt das eines fixen Anteils keinen StopLoss größer Null. Damit ist er ideal für Positionen ohne StopLoss und die, die in anderer Form (erreichter Gewinn/Verlust in Kontowährung etc.) beendet werden.

Die Berechnung des Positionsvolumens über einen fixen Anteil erfolgt in der Regel nach dieser Formel:

Volume = base_volume + (balance / balance_increase) * volume_increment

wobei:

  • base_volume – Volumen, das dem Gesamtvolumen hinzugefügt wird, unabhängig vom Kontostand
  • balance – aktueller Kontostand
  • balance_increase – Erhöhung des Kontostandes, um die Erhöhung der Lotgröße auszulösen
  • volume_increment – Volumen, um das das Gesamtvolumen erhöht/erniedrigt wird, wenn sich der Kontostand um "balance_increase" ändert

Als Beispiel nehmen wir ein Basisvolumen von 0,0 Lot an, und das Volumen soll sich um 0,1 je $1,000 auf dem Konto ändern. Der Kontostand betrage aktuell $2.500. Das Gesamtvolumen berechnet sich daher wie folgt:

Volume = 0 + (2500 / 1000) * 0,1 = 0,25 Lot

Diese Methode verfügt über viele Varianten. Eine von ihnen ändert die Lotgröße nur beim Erreichen festgelegter Level (dies ist das oben erwähnte Geldmanagement über einen fixen Anteil). Im obigen Beispiel errechneten wir ein Volumen von 0,25 Lots, aber es hätte auch bei 0,2 verbleiben können und sich erst ab einem Kontostand von $3.000 auf 0,3 Lot erhöht.

Diese Methode UpdateLotSize kann wie folgt implementiert werden:

bool CMoneyFixedRatioBase::UpdateLotSize(const string symbol,const double price,const ENUM_ORDER_TYPE type,const double sl=0)
  {
   m_symbol=m_symbol_man.Get(symbol);
   double last_volume=m_volume;
   if(CheckPointer(m_symbol))
     {
      double balance=m_equity==false?m_account.Balance():m_account.Equity();      
      m_volume=m_volume_base+((int)(balance/m_balance_inc))*m_volume_inc;
      m_balance=balance;
     }
   return NormalizeDouble(last_volume-m_volume,2)==0;
  }


Fixes Risiko Pro Point (Fixe Marge)

Fixes Risiko Pro Point weist jedem Point des StopLoss einen bestimmten Wert in der Kontowährung zu. Der Algorithmus berechnet die Lotgröße auf Basis des gewünschten Tick-Werts des Händlers. Ist die Kontowährung beispielsweise USD und das fixe Risiko per Point bei 2,0, dann hat jeder Point des StopLoss' einen Wert von $2. Falls der StopLoss der Position 200 Points beträgt, dann beträgt das maximale Risiko der gesamten Position $400 ($400 wenn die Marktpreise den StopLoss der Position auslösen).

Für einen normalen Händler ist diese Form des Geldmanagements einfacher, da das Risiko der Position in einer dem Händler vertrauten Weise, z.B. der Kontowährung, dargestellt werden. Der Händler muss nur den gewünschten Tick-Wert des Vermögenswertes festlegen und dann wird das Handelsvolumen automatisch berechnet. Der Tick-Wert oder die Änderung von Gewinn/Verlust pro kleinster Preisbewegung bleiben gleich, aber das Gesamtrisiko hängt von der Größe des StopLoss' einer Position ab.

Unter Verwendung dieser Formel kann diese Methode des Geldmanagements in folgender Weise in der Methode UpdateLotSize implementiert werden:

bool CMoneyFixedRiskPerPointBase::UpdateLotSize(const string symbol,const double price,const ENUM_ORDER_TYPE type,const double sl=0)
  {
   m_symbol=m_symbol_man.Get(symbol);
   double last_volume=m_volume;
   if(CheckPointer(m_symbol))
     {
      double balance=m_equity==false?m_account.Balance():m_account.Equity();
      m_volume=(m_risk/m_symbol.TickValue());
     }
   return NormalizeDouble(last_volume-m_volume,2)==0;
  }


Fixes Risiko (Fixe Marge)

Das fixe Risiko per Marge (margin) ist äquivalent zur Klasse CMoneyFixedMargin aus der Standardbibliothek von MQL5. Dies ist ein Sonderfall der Methode des fixen Risikos pro Point des Geldmanagements. Anders aber als das fixe Risiko pro Point berücksichtigt diese Methode den gesamten StopLoss in der Berechnung des Handelsvolumens, so dass das Risiko, unabhängig vom Größe des StopLoss', gleich bleibt. Im vorherigen Beispiel hatten wir einen StopLoss von 200 Points und $400 als maximales Risiko. Würde der StopLoss auf 100 Points reduziert werden, würde sich das maximale Risiko einer Position nach dem fixen Risiko pro Point halbieren ($200), wobei allerdings bei einem Geldmanagement mit fixen Margen das maximale Risiko konstant ($400) bleiben würde.

Mit dieser Formel können wir die Methode UpdateLotSize wie folgt implementieren:

bool CMoneyFixedRiskBase::UpdateLotSize(const string symbol,const double price,const ENUM_ORDER_TYPE type,const double sl)
  {
   m_symbol=m_symbol_man.Get(symbol);
   double last_volume=m_volume;
   if(CheckPointer(m_symbol))
     {
      double balance=m_equity==false?m_account.Balance():m_account.Equity();
      double ticks=0;
      if(price==0.0)
        {
         if(type==ORDER_TYPE_BUY)
            ticks=MathAbs(m_symbol.Bid()-sl)/m_symbol.TickSize();
         else if(type==ORDER_TYPE_SELL)
            ticks=MathAbs(m_symbol.Ask()-sl)/m_symbol.TickSize();
        }
      else ticks=MathAbs(price-sl)/m_symbol.TickSize();
      m_volume=(m_risk/m_symbol.TickValue())/ticks;
     }
   return NormalizeDouble(last_volume-m_volume,2)==0;
  }
Diese Formel ist ziemlich ähnlich der der fixen Risikos pro Point, außer, dass wir den Tick-Wert benötigen, um das Ergebnis der vorherigen Formel durch diesen Wert zu teilen.


Container der Objekte für das Geldmanagement

Ähnlich den besprochenen Signalklassen früherer Artikel erhält auch das Objekt für das Geldmanagement einen Container. Das erlaubt einem Expert Advisor dynamisch zwischen verschiedenen, verfügbaren Objekten des Geldmanagements aus einer Liste auszuwählen. Idealerweise agiert der Container als Mediator zwischen den Klassen des Geldmanagements und dem anderen Code des Expert Advisors. Die Basisklasse dieser Objekte ist CMoneysBase, die wie folgt definiert ist:

class CMoneysBase : public CArrayObj
  {
protected:
   bool              m_active;
   int               m_selected;
   CEventAggregator *m_event_man;
   CObject          *m_container;
public:
                     CMoneysBase(void);
                    ~CMoneysBase(void);
   virtual int       Type(void) const {return CLASS_TYPE_MONEYS;}
   //--- Initialisierung
   virtual bool      Init(CSymbolManager*,CAccountInfo*,CEventAggregator*);
   CObject          *GetContainer(void);
   void              SetContainer(CObject*);
   virtual bool      Validate(void) const;
   //--- setters and getters
   virtual bool      Active(void) const;
   virtual void      Active(const bool);
   virtual int       Selected(void) const;
   virtual void      Selected(const int);
   virtual bool      Selected(const string);
   //--- volume calculation
   virtual double    Volume(const string,const double,const ENUM_ORDER_TYPE,const double);
  };

Da das Objekt mehrere Objekte des Geldmanagements aufnehmen soll, benötigt es zur Verwendung durch einen Expert Advisor zumindest zwei Methoden:

  1. Entweder auswählen oder zwischen den Methoden des Geldmanagements dynamische wechseln
  2. Verwenden des Objektes des Geldmanagements und Abfrage des berechneten Handelsvolumens


Die Auswahl geschieht auf zwei Wegen: durch die Zuweisung eines Index des Arrays der Objekte des Geldmanagements (CMoneysBase extends CArrayObj), oder durch das Finden des Objektes auf Grund des Namens (Methode Name aus CMoneyBase/CMoney). Das Folgende zeigt die überladene Methode Selected, die als Argument eine Ganzzahl (oder Index) erwartet:

CMoneysBase::Selected(const int value)
  {
   m_selected=value;
  }

Das Folgende zeigt die überladene Methode Selected, die als Argument eine Zeichenkette (oder Namen des Objektes des Geldmanagements) erwartet: Beachten Sie, dass der Name des Objektes des Geldmanagements nicht 'leer' sein darf.

bool CMoneysBase::Selected(const string select)
  {
   for(int i=0;i<Total();i++)
     {
      CMoney *money=At(i);
      if(!CheckPointer(money))
         continue;
      if(StringCompare(money.Name(),select))
        {
         Selected(i);
         return true;
        }
     }
   return false;
  }

Die dritte Form der überladenen Methode erwartet kein Argument. Sie liefert einfach den Index des gewählten Objektes des Geldmanagements, das dann nützlich sein kann, wenn der Expert Advisor wissen will, welche Methode des Geldmanagements gerade ausgewählt ist:

int CMoneysBase::Selected(void) const
  {
   return m_selected;
  }
Das aktuelle Volumen wird von der Methode Volumen dieses Objekts berechnet. Die Methode holt sich zuerst den Zeiger auf das Objekt der gewählten Methode des Geldmanagements und ruft dann deren Methode Volumen auf. Der Code der Methode Volumen von CMoneysBase folgt:
double CMoneysBase::Volume(const string symbol,const double price,const ENUM_ORDER_TYPE type,const double sl=0)
  {
   CMoney *money=At(m_selected);
   if(CheckPointer(money))
      return money.Volume(symbol,price,type,sl);
   return 0;
  }

Hier wird greift die Methode auf das Objekt aus der Liste der Objekte zu und sichert den Zugang in einem Zeiger. Um Fehler zu vermeiden, muss man sicherstellen, dass das aktuelle Objekt in der Objektliste an der Stelle des Index existiert.


Beispiel

Als Beispiel verwenden wir das letzte Beispiel aus dem vorherigen Artikel. Wir verändern es so, dass wir in diesem Artikel die Klassen des Geldmanagements einfügen und platzieren sie in einem einzelnen Container und fügen das dem Order-Manager hinzu. Das Meiste wurde in der Funktion OnInit des EAs ergänzt, wie man unten sieht:

int OnInit()
  {
//---
   order_manager=new COrderManager();
   money_manager = new CMoneys();
   CMoney *money_fixed= new CMoneyFixedLot(0.05);
   //CMoney *money_ff= new CMoneyFixedFractional(5);
   CMoney *money_ratio= new CMoneyFixedRatio(0,0.1,1000);
   //CMoney *money_riskperpoint= new CMoneyFixedRiskPerPoint(0.1);
   //CMoney *money_risk= new CMoneyFixedRisk(100);
   
   money_manager.Add(money_fixed);
   //money_manager.Add(money_ff);
   money_manager.Add(money_ratio);
   //money_manager.Add(money_riskperpoint);
   //money_manager.Add(money_risk);
   order_manager.AddMoneys(money_manager);
   //order_manager.Account(money_manager);
   symbol_manager=new CSymbolManager();
   symbol_info=new CSymbolInfo();
   if(!symbol_info.Name(Symbol()))
      Print("symbol not set");
   symbol_manager.Add(GetPointer(symbol_info));
   order_manager.Init(symbol_manager,new CAccountInfo());

   MqlParam params[1];
   params[0].type=TYPE_STRING;
#ifdef __MQL5__
   params[0].string_value="Examples\\Heiken_Ashi";
#else
   params[0].string_value="Heiken Ashi";
#endif
   SignalHA *signal_ha=new SignalHA(Symbol(),0,1,params,signal_bar);
   SignalMA *signal_ma=new SignalMA(Symbol(),(ENUM_TIMEFRAMES) Period(),maperiod,0,mamethod,maapplied,signal_bar);
   signals=new CSignals();
   signals.Add(GetPointer(signal_ha));
   signals.Add(GetPointer(signal_ma));
   signals.Init(GetPointer(symbol_manager),NULL);
//---
   return(INIT_SUCCEEDED);
  }

Wir haben die Zeilen für die Methoden des Geldmanagements des fixen Anteil, des fixen Risikos und des fixen Risikos pro Point eingefügt. Da die Methoden jedoch einen StopLoss größer als Null benötigen und unser EA diesbezüglich keine StopLoss erstellt, werden wir diese Methoden erst einmal übergehen. In der Zwischenzeit verwenden wir nur die Methoden des Geldmanagement der fixen Lotgröße und des fixen Anteils. Falls diese Objekte einen ungültigen StopLoss (kleiner Null) zurückgeben, wird die standardmäßige Lotgröße des Order-Managers verwendet (Standard ist 0,1 Lot des Mitglieds m_lotsize von ofCorderManager/COrderManagerBase) .

COrderManager hat ein eigenes Klassenmitglied, der ein Zeiger auf den Container (CMoney) des Geldmanagements ist. Die Verwendung des COrderManager bedeutet also, dass die Headerdatei des Geldmanagements in den Quellcode inkludiert werden müssen. Falls ein Experte den COrderManager nicht verwendet, dann muss die Direktive #include der Klassen des Geldmanagements im Quellcode angegeben werden.

In der Funktion OnTick ändern wir den EA dahingehend, dass er für Kaufpositionen fixe Lotgrößen und für Verkaufspositionen fixe Anteile für die Lotgrößen verwendet. Beides wird erreicht durch eine Änderung des gewählten Typs des Geldmanagements vor dem Aufruf der Methode TradeOpen des Order-Managers über die Methode Selected aus CMoneys:

void OnTick()
  {
//---
   if(symbol_info.RefreshRates())
     {
      signals.Check();
      if(signals.CheckOpenLong())
        {
         close_last();
         //Print("Entering buy trade..");
         money_manager.Selected(0);
         order_manager.TradeOpen(Symbol(),ORDER_TYPE_BUY,symbol_info.Ask());
        }
      else if(signals.CheckOpenShort())
        {
         close_last();
         //Print("Entering sell trade..");
         money_manager.Selected(1);
         order_manager.TradeOpen(Symbol(),ORDER_TYPE_SELL,symbol_info.Bid());
        }
     }
  }

Da das Geldmanagement im Grunde reine Mathematik ist, ist zu erwarten, dass die berechnete Lotgrößen im MetaTrader 4 und MetaTrader 5 gleich sind. Das Folgende zeigt die Testergebnisse des EAs im MetaTrader 4 (die ersten 10 Positionen):

# Zeit Typ Order Größe Preis S / L T / P Gewinn Kontostand
1 2017.01.02 00:00 sell 1 1.00 1.05100 0.00000 0.00000
2 2017.01.03 03:00 close 1 1.00 1.04679 0.00000 0.00000 419.96 10419.96
3 2017.01.03 03:00 buy 2 0.05 1.04679 0.00000 0.00000
4 2017.01.03 10:00 close 2 0.05 1.04597 0.00000 0.00000 -4.10 10415.86
5 2017.01.03 10:00 sell 3 1.00 1.04597 0.00000 0.00000
6 2017.01.03 20:00 close 3 1.00 1.04285 0.00000 0.00000 312.00 10727.86
7 2017.01.03 20:00 buy 4 0.05 1.04285 0.00000 0.00000
8 2017.01.03 22:00 close 4 0.05 1.04102 0.00000 0.00000 -9.15 10718.71
9 2017.01.03 22:00 sell 5 1.00 1.04102 0.00000 0.00000
10 2017.01.04 02:00 close 5 1.00 1.04190 0.00000 0.00000 -89.04 10629.67
11 2017.01.04 02:00 buy 6 0.05 1.04190 0.00000 0.00000
12 2017.01.04 03:00 close 6 0.05 1.03942 0.00000 0.00000 -12.40 10617.27
13 2017.01.04 03:00 sell 7 1.00 1.03942 0.00000 0.00000
14 2017.01.04 06:00 close 7 1.00 1.04069 0.00000 0.00000 -127.00 10490.27
15 2017.01.04 06:00 buy 8 0.05 1.04069 0.00000 0.00000
16 2017.01.05 11:00 close 8 0.05 1.05149 0.00000 0.00000 54.05 10544.32
17 2017.01.05 11:00 sell 9 1.00 1.05149 0.00000 0.00000
18 2017.01.05 16:00 close 9 1.00 1.05319 0.00000 0.00000 -170.00 10374.32
19 2017.01.05 16:00 buy 10 0.05 1.05319 0.00000 0.00000
20 2017.01.06 05:00 close 10 0.05 1.05869 0.00000 0.00000 27.52 10401.84

Im MetaTrader 5 sehen wir folgende Ergebnisse ("Hedging-Mode", die ersten 10 Positionen):

Orders
Eröffnungszeit Order Symbol Typ Volumen Preis S / L T / P Zeit Status Kommentar
2017.01.02 00:00:00 2 EURUSD sell 1.00 / 1.00 1.05100 2017.01.02 00:00:00 filled
2017.01.03 03:00:00 3 EURUSD buy 1.00 / 1.00 1.04669 2017.01.03 03:00:00 filled
2017.01.03 03:00:00 4 EURUSD buy 0.05 / 0.05 1.04669 2017.01.03 03:00:00 filled
2017.01.03 10:00:00 5 EURUSD sell 0.05 / 0.05 1.04597 2017.01.03 10:00:00 filled
2017.01.03 10:00:00 6 EURUSD sell 1.00 / 1.00 1.04597 2017.01.03 10:00:00 filled
2017.01.03 20:00:00 7 EURUSD buy 1.00 / 1.00 1.04273 2017.01.03 20:00:00 filled
2017.01.03 20:00:00 8 EURUSD buy 0.05 / 0.05 1.04273 2017.01.03 20:00:00 filled
2017.01.03 22:00:00 9 EURUSD sell 0.05 / 0.05 1.04102 2017.01.03 22:00:00 filled
2017.01.03 22:00:00 10 EURUSD sell 1.00 / 1.00 1.04102 2017.01.03 22:00:00 filled
2017.01.04 02:00:00 11 EURUSD buy 1.00 / 1.00 1.04180 2017.01.04 02:00:00 filled
2017.01.04 02:00:00 12 EURUSD buy 0.05 / 0.05 1.04180 2017.01.04 02:00:00 filled
2017.01.04 03:00:00 13 EURUSD sell 0.05 / 0.05 1.03942 2017.01.04 03:00:00 filled
2017.01.04 03:00:00 14 EURUSD sell 1.00 / 1.00 1.03942 2017.01.04 03:00:00 filled
2017.01.04 06:00:00 15 EURUSD buy 1.00 / 1.00 1.04058 2017.01.04 06:00:00 filled
2017.01.04 06:00:00 16 EURUSD buy 0.05 / 0.05 1.04058 2017.01.04 06:00:00 filled
2017.01.05 11:00:00 17 EURUSD sell 0.05 / 0.05 1.05149 2017.01.05 11:00:00 filled
2017.01.05 11:00:00 18 EURUSD sell 1.00 / 1.00 1.05149 2017.01.05 11:00:00 filled
2017.01.05 16:00:00 19 EURUSD buy 1.00 / 1.00 1.05307 2017.01.05 16:00:00 filled
2017.01.05 16:00:00 20 EURUSD buy 0.05 / 0.05 1.05307 2017.01.05 16:00:00 filled
2017.01.06 05:00:00 21 EURUSD sell 0.05 / 0.05 1.05869 2017.01.06 05:00:00 filled


Da der Order-Manager bereits die Unterschiede zwischen den beiden Plattformen (und Sprachen) berücksichtigt, sollten die Methoden und die Ergebnisse der Berechnung der Lotgrößen gleich sein und irgendwelche Unterschiede, die entstehen könnten, müssten dem Order-Manager selbst zuzuordnen sein.

Schlussfolgerung

Dieser Artikel zeigt wie das Geldmanagement in einem Cross-Plattform Expert Advisor integriert werden kann. Er bespricht 5 verschiedene Methoden des Geldmanagement. Er beschreibt auch einen eigenen Container von Objekten für die Zeiger auf diese Objekte, um dynamisch die Methode des Geldmanagements auszuwählen.