English Русский 日本語
preview
Wie man einen einfachen Multi-Currency Expert Advisor mit MQL5 erstellt (Teil 5):  Die Bollinger Bänder mit dem Keltner-Kanal — Indikatoren Signal

Wie man einen einfachen Multi-Currency Expert Advisor mit MQL5 erstellt (Teil 5): Die Bollinger Bänder mit dem Keltner-Kanal — Indikatoren Signal

MetaTrader 5Handel | 26 Februar 2024, 13:10
199 13
Roberto Jacobs
Roberto Jacobs

Einführung

Die Definition eines Multiwährungs-Expert Advisors in diesem Artikel ist ein Expert Advisor oder Handelsroboter, der handeln kann (z.B. Aufträge eröffnen, schließen und verwalten, Trailing Stop Loss und Trailing Profit) für mehr als 1 Symbolpaar aus nur einem Symbolchart, wobei in diesem Artikel Expert Advisor für 30 Paare handeln wird.

In diesem Artikel werden wir Signale von zwei Indikatoren verwenden, in diesem Fall Bollinger Bänder® und dem Keltner Kanal.

Auf der alten Plattform (MetaTrader 4) war die Verwendung von Signalen dieser Art als iBandsOnArray-Funktion bekannt.

In der Erklärung der Funktion iBandsOnArray in der MQL4-Referenz heißt es, dass: Anmerkung: Im Gegensatz zu iBands(...) nimmt die Funktion iBandsOnArray() keine Daten nach Symbolname, Zeitrahmen oder angewandtem Preis entgegen. Die Preisdaten müssen vorher aufbereitet werden...

In der Diskussion im MQL5-Forum habe ich gelesen, dass es sogar Händler oder Nutzer gibt, die sagen, dass iBandOnArray() in MQL5 nicht existiert.
In der Tat ist iBandOnArray() nicht in der MQL5-Funktionsliste enthalten, aber durch die Verwendung des Indikator.Handles von iBands() können wir iBandOnArray() in MQL5 tatsächlich leicht erstellen. Meiner Meinung nach ist die Verwendung des Indikator-Handles in MQL5 sogar einfacher und bequemer als die Verwendung der Funktion iBandsOnArray() in MetaTrader 4.

Wie in den vorangegangenen Artikeln bewiesen, wissen wir alle, dass der Handel mit mehreren Währungen, sowohl auf dem Handelsterminal als auch auf dem Strategietester, mit der Leistung, den Fähigkeiten und den Möglichkeiten von MQL5 möglich ist.

Daher ist das Ziel, die wesentlichen Bedürfnisse der Händler, die effiziente und effektive Handelsroboter wollen zu befriedigen, sodass durch den Rückgriff auf die Stärken, Fähigkeiten und Einrichtungen von der sehr zuverlässigen MQL5 zur Verfügung gestellt, können wir eine einfache Multi-Currency Expert Advisor, die in diesem Artikel verwendet 2 Indikator-Signale für die Auftragserteilung erstellen: die Bollinger Bänder® mit dem Keltner-Kanal, wobei die Bollinger Bänder die Kursdaten des Keltner Kanal verwenden. In der Zwischenzeit werden wir für Trailing Stops weiterhin den Parabolic SAR (iSAR) Indikator verwenden.

Pläne und Eigenschaften

1. Handel mit Währungspaaren.

Dieser Multi-Currency Expert Advisor ist für den Handel mit einem Symbol oder Paar wie folgt konzipiert:

EURUSD,GBPUSD,AUDUSD,NZDUSD,USDCAD,USDCHF,USDJPY,EURGBP,EURAUD, EURNZD, EURCAD, EURCHF, EURJPY, GBPAUD, GBPNZD, GBPCAD,GBPCHF,GBPJPY,AUDNZD,AUDCAD,AUDCHF,AUDJPY,NZDCAD,NZDCHF,NZDJPY, CADCHF, CADJPY, CHFJPY = 28 Paare.

Plus 2 Metallpaare: XAUUSD (Gold) und XAGUSD (Silber),

insgesamt sind es 30 Paare.

Wie im vorigen Artikel machen wir es uns auch in diesem Artikel einfach, indem wir spezielle Eingabeeigenschaften für das Präfix und das Suffix des Paarnamens hinzufügen. Dann werden wir mit einer einfachen Funktion das Präfix und/oder Suffix des Paarnamens in Kombination mit den 30 registrierten Paarnamen behandeln, sodass bei der Verwendung eines EA auf MetaTrader 5 von einem Broker mit solchen speziellen Symbolnamen alles reibungslos funktioniert.

Die Schwäche der Funktion zur Erkennung von Symbolnamen mit Präfixen und Suffixen ist, dass diese Funktion nur für Forex- und Metallsymbolpaare oder -namen im MT5 funktioniert, nicht aber für spezielle Symbole und Indizes. Eine weitere Schwäche dieser Methode besteht darin, dass sich der Händler beim Namen des Präfixes und/oder Suffixes des Paares vertippen kann (Groß- und Kleinschreibung muss beachtet werden). Daher erwarten wir von Händlern, die den Expert Advisor in diesem Artikel verwenden, Präzision und Genauigkeit bei der Eingabe des Präfixes und/oder Suffixes des Paarnamens.

Wie im vorherigen Artikel haben wir auch in diesem Expert Advisor 10 Optionen für die Paare hinzugefügt, die zu diesem Zeitpunkt gehandelt werden. Eines der 10 Optionspaare, die gehandelt werden, ist „Des Händlers Wunschpaare“, wobei die zu handelnden Paare manuell vom Händler in der Eigenschaft Expert Input eingegeben werden müssen. Sie müssen jedoch immer darauf achten, dass der Name des Paares, das Sie eingeben, bereits in der Liste der 30 Paare enthalten ist.

In dieser Version des Expert Advisors haben wir auch eine Option für die Handelssitzung (Zeitzone) hinzugefügt, sodass die Paare, die gehandelt werden, der Zeit der Handelssitzung entsprechen können.

2. Indikatoren.

In dieser Version des Expert Advisors werden wir die Signale von zwei Indikatoren verwenden, in diesem Fall die Bollinger Bänder® mit dem Keltner Kanal. Als Preisdaten für die Bollinger Bänder® verwenden wir den Keltner Kanal.

2.1. Keltner-Kanal-Indikator.

Der Keltner-Kanal wurde erstmals in den 1960er Jahren von Chester Keltner eingeführt. Die ursprüngliche Formel verwendete einfache gleitende Durchschnitte (SMAs) und die Höchst-/Tiefstkurs-Spanne zur Berechnung der Bandbreiten.  In den 1980er Jahren wurde eine neue Formel eingeführt, die die Average True Range (ATR) verwendet. Die ATR-Methode ist heute weit verbreitet.

Der Keltner-Kanal-Indikator, der in diesem Artikel für Expert Advisor s verwendet wird, wurde von mir speziell mit einer Methode erstellt, die heute sehr beliebt ist, nämlich dem Exponential Moving Average (EMA) Periode 20 mit oberen und unteren Bändern unter Verwendung des ATR-Indikators Periode 20.

Die Eingangseigenschaften des Keltner-Kanalanzeigers sind wie folgt:

BBOnKC_Keltner-Kanal-Indikator-cr

2.2. Der Indikator Bollinger Bänder®.

Die Bollinger Bänder® wurden von John Bollinger in den 80er Jahren entwickelt und wurden schnell zu einem der am häufigsten verwendeten Indikatoren im Bereich der technischen Analyse. Die Bollinger Bänder® bestehen aus drei Bändern - dem oberen, dem mittleren und dem unteren Band - die dazu dienen, kurzfristige Preisextreme auf dem Markt hervorzuheben. Das obere Band ist ein Zeichen für überkaufte Bedingungen, während das untere Band ein Zeichen für überverkaufte Bedingungen ist. Die meisten Finanzanalysten verwenden Bollinger Bänder® und kombinieren sie mit anderen Indikatoren, um ein besseres analytisches Bild der Marktlage zu erhalten.

Im Expert Advisor dieses Artikels verwenden wir die Bollinger Bänder® mit einer Periodenlänge 38, der die Preisdaten des Keltner Kanals nutzt.

Die Eingabeeigenschaften des Bollinger Bänder® sind wie folgt:

BBOnKC_Bollinger Bänder Indikator-cr

Eine Veranschaulichung des Keltner-Kanal als Preisdaten für die Bollinger Bänder® für KAUF- oder VERKAUFSSIGNALE ist in den Abbildungen 1 und 2 zu sehen.

BBOnKC_BUY-Signal

Abbildung 1. Kaufsignal


BBOnKC_SELL-Signal

Abbildung 2. Verkaufssignal

In der obigen Abbildung wird nur dann ein Signal gegeben, wenn die mittlere Linie des Keltner-Kanals die obere Linie der Bollinger Bänder® oder die untere Linie der Bollinger Bänder® über- oder unterschreitet. Aber für den Expert Advisor in diesem Artikel ist das Indikatorsignal tatsächlich eine Kreuzung zwischen der mittleren Linie des Keltner-Kanals und der oberen, mittleren und unteren Linie der Bollinger Bänder®.

  • Bei Kaufsignalen:

  1. Erstes Signal: Wenn die mittlere Linie des Keltner Kanal-Indikators die untere Linie des Bollinger Bänder® nach oben kreuzt oder
  2. Zweites Signal: Wenn die Mittellinie des Keltner Kanal-Indikators die Mittellinie der Bollinger Bänder® nach oben kreuzt oder
  3. Drittes Signal: Wenn die mittlere Linie des Keltner-Kanals die obere Linie der Bollinger Bänder® nach oben kreuzt.

  • Bei Verkaufssignalen:

  1. Erstes Signal: Wenn die mittlere Linie des Keltner Kanal Indikators die obere Linie des Bollinger Bänder® Indikators nach unten kreuzt oder
  2. Zweites Signal: Wenn die Mittellinie des Keltner Kanal-Indikators die Mittellinie der Bollinger Bänder® nach unten kreuzt oder
  3. Drittes Signal: Wenn die mittlere Linie des Keltner-Kanals die untere Linie der Bollinger Bänder® nach unten kreuzt.

3. Handels- & Auftragsmanagement

Dieser Multi-Currency Expert Advisor bietet Ihnen mehrere Optionen für die Verwaltung Ihrer Handels:

3.1. Stop-Loss-Aufträge

Optionen: Use Order Stop Loss (Yes) or (No) (Stop-Loss-Auftrag verwenden, Ja oder Nein)

  • Wenn die Option (No) für Use Stop-Loss für Aufträge verwenden ausgewählt ist, werden alle Aufträge ohne Stop-Loss eröffnet.

  • Wenn die Option Stop-Loss für Aufträge verwenden (Yes): Auch hier haben Sie die Wahl: Use Automatic Calculation Stop Loss (Yes) or (No) (Autom. Berechnung des Stop Loss verwenden, Ja oder Nein)
  • Wenn die Option Automatische Berechnung Stop Loss (Yes), dann wird die Stop-Loss-Berechnung automatisch durch den Experten durchgeführt.
  • Wenn die Option Automatische Berechnung des Stop Loss (No) gewählt wurde, muss der Händler den Stop-Loss-Wert in Pips eingeben.

  • Wenn die Option Use Order Stop Loss (No): Dann prüft der Experte für jede eröffnete Order, ob die Signalbedingung noch gut ist und die Order mit Gewinn aufrechterhalten werden kann oder ob sich das Signal abgeschwächt hat und die Order geschlossen werden muss, um den Gewinn zu sichern oder ob sich die Signalbedingung umgekehrt hat und die Order mit Verlust geschlossen werden muss.

Anmerkung: Speziell um Positionen zu schließen (Close Trade) und den Gewinn zu sichern (Save Profit), wird aufgrund eines schwachen Signals eine Option angeboten, ob diese aktiviert werden soll oder nicht.

Wenn sie nicht aktiviert ist (No), wird der Auftrag trotz des schwächeren Signals aufrechterhalten oder nicht geschlossen, um den Gewinn zu sichern.

Wenn aktiviert (Yes), sind die Bedingungen für die Indikatoren Keltner Kanal und Bollinger Bänder®:

  • Für das Schließen von Kaufpositionen: Wenn die untere Linie des Keltner-Kanals die obere Linie der Bollinger Bänder® nach unten kreuzt, wird die Kaufposition geschlossen.
  • Für das Schließen von Verkaufspositionen: Wenn die obere Linie des Keltner Kanals die untere Linie der Bollinger Bänder® nach oben kreuzt, wird die Verkaufsposition geschlossen.

Der Code zum Setzen eines Stop-Loss-Auftrags lautet wie folgt:

double MCEA::OrderSLSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice)
  {
//---
    slv=0.0;
    int x=PairsIdxArray(xsymb);
    Pips(xsymb);
    RefreshTick(xsymb);
    //--
    switch(type) 
      { 
       case (ORDER_TYPE_BUY):
         {
           if(use_sl==Yes && autosl==Yes) slv=mc_symbol.NormalizePrice(atprice-38*pip);
           else
           if(use_sl==Yes && autosl==No)  slv=mc_symbol.NormalizePrice(atprice-SLval*pip);
           else slv=0.0;
           //--
           break;
         }
       case (ORDER_TYPE_SELL):
         {
           if(use_sl==Yes && autosl==Yes) slv=mc_symbol.NormalizePrice(atprice+38*pip);
           else
           if(use_sl==Yes && autosl==No)  slv=mc_symbol.NormalizePrice(atprice+SLval*pip);
           else slv=0.0;
         }
      }
    //---
    return(slv);
//---
  } //-end OrderSLSet()
//---------//

Der Code für „Close Trade“ and „Save Profit“ auf der Signalbasis lautet wie folgt:

int MCEA::GetCloseInWeakSignal(const string symbol,int exis) // Signal Indicator Position Close in profit
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    //--
    int br=3;
    Pips(symbol);
    double difud=mc_symbol.NormalizePrice(1.5*pip);
    //--
    double KCub[],
           KClb[];
    double BBub[],
           BBlb[];
    //--
    ArrayResize(KCub,br,br);
    ArrayResize(KClb,br,br);
    ArrayResize(BBub,br,br);
    ArrayResize(BBlb,br,br);
    ArraySetAsSeries(KCub,true);
    ArraySetAsSeries(KClb,true);
    ArraySetAsSeries(BBub,true);
    ArraySetAsSeries(BBlb,true);
    //--
    int xx=PairsIdxArray(symbol);
    //--
    CopyBuffer(hKC[xx],1,0,br,KCub);
    CopyBuffer(hKC[xx],2,0,br,KClb);
    CopyBuffer(hBB[xx],1,0,br,BBub);
    CopyBuffer(hBB[xx],2,0,br,BBlb);
    //--
    int dirmove=DirectionMove(symbol,TFt);
    bool closebuy=(KClb[1]>=BBub[1] && KClb[0]<BBub[0]-difud);
    bool closesel=(KCub[1]<=BBlb[1] && KCub[0]>BBlb[0]+difud);
    //--
    if(exis==down && closesel && dirmove==rise) ret=rise;
    if(exis==rise && closebuy && dirmove==down) ret=down;
    //--
    return(ret);
//---
  } //-end GetCloseInWeakSignal()
//---------//

3.2. Take-Profit

Optionen: Take-Profit verwenden, Ja (Yes) oder Nein No)

  • Wenn die Option Use Order Take Profit (No) ausgewählt ist, werden alle Aufträge ohne Take Profit eröffnet.

  • Bei der Option Use Order Take Profit (Yes): Auch hier haben Sie die Wahl: Use Automatic Calculation Order Take Profit (Yes) oder (No) (Take-Profit automatisch berechnen, Ja oder Nein).

  • Bei der Option Automatic Calculation Order Take Profit (Yes), dann wird die Berechnung der Take Profit Order automatisch vom Experten durchgeführt.

  • Wenn die Option Automatic Calculation Order Take Profit (No), gewählt wurde, muss der Händler den Order-Take-Profit-Wert in Pips eingeben.

Der Code für das Setzen von Take-Profit lautet wie folgt:

double MCEA::OrderTPSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice)
  {
//---
    tpv=0.0;
    int x=PairsIdxArray(xsymb);
    Pips(xsymb);
    RefreshTick(xsymb);
    //--
    switch(type) 
      { 
       case (ORDER_TYPE_BUY):
         {
           if(use_tp==Yes && autotp==Yes) tpv=mc_symbol.NormalizePrice(atprice+50*pip);
           else
           if(use_tp==Yes && autotp==No)  tpv=mc_symbol.NormalizePrice(atprice+TPval*pip);
           else tpv=0.0;
           //--
           break;
         }
       case (ORDER_TYPE_SELL):
         {
           if(use_tp==Yes && autotp==Yes) tpv=mc_symbol.NormalizePrice(atprice-50*pip);
           else
           if(use_tp==Yes && autotp==No)  tpv=mc_symbol.NormalizePrice(atprice-TPval*pip);
           else tpv=0.0;
         }
      }
    //---
    return(tpv);
//---
  } //-end OrderTPSet()
//---------//

3.3. Trailing Stop und Trailing Take-Profit

Optionen: Use Trailing SL/TP (Yes) or (No) (Nachlaufende SL/TP verwenden, Ja oder Nein)

  • Wenn die Option Use Trailing SL/TP (No) gewählt wurde, wird der Experte keinen Trailing-Stop-Loss und keinen Trailing-Take-Profit durchführen.

  • Bei der Option Use Trailing SL/TP (Yes): Auch hier haben Sie die Wahl: Use Automatic Trailing (Yes) oder (No) (Automatisches Nachziehen verwenden, Ja oder Nein). 

  • Wenn die Option Automatisches Trailing verwenden (Yes) aktiviert ist, wird der Trailing-Stop vom Experten unter Verwendung des Parabolic SAR (iSAR)-Wertes auf demselben Zeitrahmen wie die Signalberechnungen ausgeführt, wobei gleichzeitig ein Trailing-Profit auf der Grundlage des variablen Wertes TPmin (minimaler Trailing-Profit-Wert) erzielt wird.
  • Wenn die Option Automatisches Trailing verwenden (No) aktiviert ist, wird der Trailing-Stop vom Experten anhand des Wertes in der Eingabeeigenschaft ausgeführt.

Anmerkung: Der Experte führt einen Trailing-Take-Profit gleichzeitig mit einem Trailing-Stop aus.

Funktion „Trailing Stop Price“:

double MCEA::TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type)
  {
//---
    int br=2;
    double pval=0.0;
    int x=PairsIdxArray(xsymb);
    Pips(xsymb);
    //--
    switch(TS_type)
      {
        case 0:
          {
            RefreshTick(xsymb);
            if(ptype==POSITION_TYPE_BUY)  pval=mc_symbol.NormalizePrice(mc_symbol.Bid()-TSval*pip);
            if(ptype==POSITION_TYPE_SELL) pval=mc_symbol.NormalizePrice(mc_symbol.Ask()+TSval*pip);
            break;
          }
        case 1:
          {
            double PSAR[];
            ArrayResize(PSAR,br,br);
            ArraySetAsSeries(PSAR,true);
            CopyBuffer(hParIU[x],0,0,br,PSAR);
            RefreshPrice(xsymb,TFt,br);
            //--
            if(ptype==POSITION_TYPE_BUY  && (PSAR[0]<iLow(xsymb,TFt,0)))
               pval=PSAR[0];
            if(ptype==POSITION_TYPE_SELL && (PSAR[0]>iHigh(xsymb,TFt,0)))
               pval=PSAR[0];
            break;
          }
      }
    //--
    return(pval);
//---
  } //-end TSPrice()
//---------//

SL/TP-Funktion modifizieren:

bool MCEA::ModifySLTP(const string symbx,int TS_type)
  {
//---
   ResetLastError();
   MqlTradeRequest req={};
   MqlTradeResult  res={};
   MqlTradeCheckResult check={};
   //--
   int TRSP=TS_type;
   bool modist=false;
   int x=PairsIdxArray(symbx);
   Pips(symbx);
   //--
   int total=PositionsTotal();
   //--        
   for(int i=total-1; i>=0; i--) 
     {
       string symbol=PositionGetSymbol(i);
       if(symbol==symbx && mc_position.Magic()==magicEA)
         {
           ENUM_POSITION_TYPE opstype = mc_position.PositionType();
           if(opstype==POSITION_TYPE_BUY) 
             {
               RefreshTick(symbol);
               double price = mc_position.PriceCurrent();
               double vtrsb = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP));
               double pos_open   = mc_position.PriceOpen();
               double pos_stop   = mc_position.StopLoss();
               double pos_profit = mc_position.Profit();
               double pos_swap   = mc_position.Swap();
               double pos_comm   = mc_position.Commission();
               double netp=pos_profit+pos_swap+pos_comm;
               double modstart=mc_symbol.NormalizePrice(pos_open+TSmin*pip);
               double modminsl=mc_symbol.NormalizePrice(vtrsb+TSmin*pip);
               double modbuysl=vtrsb;
               double modbuytp=mc_symbol.NormalizePrice(price+TPmin*pip);
               bool modbuy = (price>modminsl && modbuysl>modstart && (pos_stop==0.0||modbuysl>pos_stop));
               //--
               if(modbuy && netp>0.05)
                 {
                   modist=mc_trade.PositionModify(symbol,modbuysl,modbuytp);
                 }  
             }
           if(opstype==POSITION_TYPE_SELL) 
             {
               RefreshTick(symbol);
               double price = mc_position.PriceCurrent();
               double vtrss = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP));
               double pos_open   = mc_position.PriceOpen();
               double pos_stop   = mc_position.StopLoss();
               double pos_profit = mc_position.Profit();
               double pos_swap   = mc_position.Swap();
               double pos_comm   = mc_position.Commission();
               double netp=pos_profit+pos_swap+pos_comm;
               double modstart=mc_symbol.NormalizePrice(pos_open-TSmin*pip);
               double modminsl=mc_symbol.NormalizePrice(vtrss-TSmin*pip);
               double modselsl=vtrss;
               double modseltp=mc_symbol.NormalizePrice(price-TPmin*pip);
               bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==0.0||modselsl<pos_stop)); 
               //--
               if(modsel && netp>0.05)
                 {
                   modist=mc_trade.PositionModify(symbol,modselsl,modseltp);
                 }  
             }
         }
     }
    //--
    return(modist);
//---
  } //-end ModifySLTP()
//---------//

4. Manuelle Auftragsverwaltung.

Um die Effizienz in diesem Mehr-Währungs-EA zu unterstützen, werden mehrere manuelle Klick-Buttons hinzugefügt.

4.1. Set SL / TP All Orders (Setzen von SL / TP bei allen Aufträgen)

Wenn der Händler-Eingabeparameter Use Order Stop Loss (No) und/oder Use Order Take Profit (No) einstellt,
aber der Händler beabsichtigt, Stop Loss oder Take Profit für alle Aufträge zu verwenden, dann genügt ein einziger Klick auf die Schaltfläche

„Set SL / TP All Orders“ (SL/TP für alle Aufträge setzen) werden alle Aufträge geändert und ein Stop-Loss und/oder Take-Profits angewendet.

4.2. „Close All Orders“ (Alle Aufträge schließen). Wenn ein Händler alle Aufträge schließen möchte, dann werden mit einem einzigen Klick auf die Schaltfläche „Close All Orders“ alle offenen Aufträge geschlossen.

4.3. „Close All Orders Profit“ (Schließen aller Positionen im Gewinn). Wenn ein Händler alle Positionen, die bereits profitabel sind, mit einem einzigen Klick schließen möchte, genügt ein Klick auf die Schaltfläche „Close All Orders Profit“

5. Management-Befehle und Chartsymbole.

Für Multi-Currency Expert Advisors, die 30 Paare von nur einem Symbolchart aus handeln, ist es sehr effektiv und effizient, eine Schalttafel für alle Symbole zur Verfügung zu stellen, sodass Händler Charts oder Symbole mit nur einem Klick wechseln können, um die Genauigkeit des Indikatorsignals zu sehen, wenn der Experte eine Order öffnet oder schließt.

Umsetzung der Planung im Programm MQL5

1. Programmkopf und Eingabeeigenschaften

Header-Datei MQL5 einbinden:

//+------------------------------------------------------------------+
//|                             Include                              |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\AccountInfo.mqh>
//--
CTrade              mc_trade;
CSymbolInfo         mc_symbol;
CPositionInfo       mc_position; 
CAccountInfo        mc_account;
//---

Enumeration zur Verwendung der Zeitzone:

//--
enum tm_zone
 {
   Cus_Session,        // Trading on Custom Session
   New_Zealand,        // Trading on New Zealand Session
   Australia,          // Trading on Australia Sydney Session
   Asia_Tokyo,         // Trading on Asia Tokyo Session
   Europe_London,      // Trading on Europe London Session
   US_New_York         // Trading on US New York Session
 };
//--

Enumeration zur Auswahl der Zeitstunde:

//--
enum swhour
  {
    hr_00=0,   // 00:00
    hr_01=1,   // 01:00
    hr_02=2,   // 02:00
    hr_03=3,   // 03:00
    hr_04=4,   // 04:00
    hr_05=5,   // 05:00
    hr_06=6,   // 06:00
    hr_07=7,   // 07:00
    hr_08=8,   // 08:00
    hr_09=9,   // 09:00
    hr_10=10,  // 10:00
    hr_11=11,  // 11:00
    hr_12=12,  // 12:00
    hr_13=13,  // 13:00
    hr_14=14,  // 14:00
    hr_15=15,  // 15:00
    hr_16=16,  // 16:00
    hr_17=17,  // 17:00
    hr_18=18,  // 18:00
    hr_19=19,  // 19:00
    hr_20=20,  // 20:00
    hr_21=21,  // 21:00
    hr_22=22,  // 22:00
    hr_23=23   // 23:00
  };
//--

Enumeration zur Auswahl von Zeitminuten:

//--
enum inmnt
  {
    mn_00=0,   // Minute 0
    mn_05=5,   // Minute 5
    mn_10=10,  // Minute 10
    mn_15=15,  // Minute 15
    mn_20=20,  // Minute 20
    mn_25=25,  // Minute 25
    mn_30=30,  // Minute 30
    mn_35=35,  // Minute 35
    mn_40=40,  // Minute 40
    mn_45=45,  // Minute 45
    mn_50=50,  // Minute 50
    mn_55=55   // Minute 55
  };
//--

Enumeration zur Auswahl von Optionspaaren, die gehandelt werden sollen:

//--
enum PairsTrade
 {
   All30,  // All Forex 30 Pairs
   TrdWi,  // Trader Wishes Pairs 
   Usds,   // Forex USD Pairs
   Eurs,   // Forex EUR Pairs
   Gbps,   // Forex GBP Pairs
   Auds,   // Forex AUD Pairs
   Nzds,   // Forex NZD Pairs
   Cads,   // Forex CDD Pairs
   Chfs,   // Forex CHF Pairs
   Jpys    // Forex JPY Pairs
 };   
//--

Enumeration YN wird für die Optionen (Yes) oder (No) in der Experteneingabeeigenschaft verwendet.

Die Enumeration zur Bestimmung der Losgröße.

//--
enum YN
  {
   No,
   Yes
  };
//--

Die Enumeration zur Auswahl des Zeitrahmens, der für die Berechnung der Signalindikatoren verwendet werden soll:

//--
enum TFUSE
  {
   TFM5,     // PERIOD_M5
   TFM15,    // PERIOD_M15
   TFM30,    // PERIOD_M30
   TFH1,     // PERIOD_H1
   TFH2,     // PERIOD_H2
   TFH3,     // PERIOD_H3
   TFH4,     // PERIOD_H4
   TFH6,     // PERIOD_H6
   TFH8,     // PERIOD_H8
   TFH12,    // PERIOD_H12
   TFD1      // PERIOD_D1
  };
//--

Anmerkung: Bei der TFUSE-Aufzählung beschränken wir die Verwendung von Zeitrahmenberechnungen für Experten nur auf die Bereiche TF-M5 bis TF-D1

Eingabeeigenschaften des Experten:

//---
input group               "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter
input TFUSE               tfinuse = TFH1;             // Select Expert TimeFrame, default PERIOD_H1
input int                KCPeriod = 20;               // Input Keltner Channel Period, default 20
input ENUM_MA_METHOD     KCMethod = MODE_EMA;         // Select Keltner Channel MA Method, default EMA
input ENUM_APPLIED_PRICE   KCMAAP = PRICE_TYPICAL;    // Select Keltner Channel MA Applied Price, default Price Typical
input int                KCATRPer = 20;               // Input Keltner Channel ATR Period, default 20
input double      KCATRBandsMulti = 1.0;              // Input Keltner Channel ATR bands multiplier
input int                BBPeriod = 38;               // Input Bollinger Bands® Indicator period, default 38
input double               BBDevi = 1.0;              // Input Bollinger Bands® Indicator Deviations, default 1.00
//---
input group               "=== Select Pairs to Trade ===";  // Selected Pairs to trading
input PairsTrade         usepairs = All30;           // Select Pairs to Use
input string         traderwishes = "eg. eurusd,usdchf"; // If Use Trader Wishes Pairs, input pair name here, separate by comma
input string           sym_prefix = "";              // Input the symbol prefix in case sensitive (if any)
input string           sym_suffix = "";              // Input the symbol suffix in case sensitive (if any)
//--
input group               "=== Money Management Lot Size Parameter ==="; // Money Management Lot Size Parameter
input mmt                  mmlot = DynamLot;         // Money Management Type
input double                Risk = 10.0;             // Percent Equity Risk per Trade (Min=1.0% / Max=10.0%)
input double                Lots = 0.01;             // Input Manual Lot Size FixedLot
//--Trade on Specific Time
input group               "=== Trade on Specific Time ==="; // Trade on Specific Time
input YN           trd_time_zone = Yes;              // Select If You Like to Trade on Specific Time Zone
input tm_zone            session = Cus_Session;      // Select Trading Time Zone
input swhour            stsescuh = hr_00;            // Time Hour to Start Trading Custom Session (0-23)
input inmnt             stsescum = mn_15;            // Time Minute to Start Trading Custom Session (0-55)
input swhour            clsescuh = hr_23;            // Time Hour to Stop Trading Custom Session (0-23)
input inmnt             clsescum = mn_55;            // Time Minute to Stop Trading Custom Session (0-55)
//--Day Trading On/Off
input group               "=== Day Trading On/Off ==="; // Day Trading On/Off
input YN                    ttd0 = No;               // Select Trading on Sunday (Yes) or (No)
input YN                    ttd1 = Yes;              // Select Trading on Monday (Yes) or (No)
input YN                    ttd2 = Yes;              // Select Trading on Tuesday (Yes) or (No)
input YN                    ttd3 = Yes;              // Select Trading on Wednesday (Yes) or (No)
input YN                    ttd4 = Yes;              // Select Trading on Thursday (Yes) or (No)
input YN                    ttd5 = Yes;              // Select Trading on Friday (Yes) or (No)
input YN                    ttd6 = No;               // Select Trading on Saturday (Yes) or (No)
//--Trade & Order management Parameter
input group               "=== Trade & Order management Parameter ==="; // Trade & Order management Parameter
input YN                  use_sl = No;               // Use Order Stop Loss (Yes) or (No)
input YN                  autosl = Yes;              // Use Automatic Calculation Stop Loss (Yes) or (No)
input double               SLval = 30;               // If Not Use Automatic SL - Input SL value in Pips
input YN                  use_tp = Yes;              // Use Order Take Profit (Yes) or (No)
input YN                  autotp = Yes;              // Use Automatic Calculation Take Profit (Yes) or (No)
input double               TPval = 100;              // If Not Use Automatic TP - Input TP value in Pips
input YN            TrailingSLTP = Yes;              // Use Trailing SL/TP (Yes) or (No)
input YN                 autotrl = Yes;              // Use Automatic Trailing (Yes) or (No)
input double               TSval = 5;                // If Not Use Automatic Trailing Input Trailing value in Pips
input double               TSmin = 5;                // Minimum Pips to start Trailing Stop
input double               TPmin = 25;               // Input Trailing Profit Value in Pips
input YN           Close_by_Opps = Yes;              // Close Trade By Opposite Signal (Yes) or (No)
input YN               SaveOnRev = Yes;              // Close Trade and Save profit due to weak signal (Yes) or (No)
//--Others Expert Advisor Parameter
input group               "=== Others Expert Advisor Parameter ==="; // Others EA Parameter
input YN                  alerts = Yes;              // Display Alerts / Messages (Yes) or (No)
input YN           UseEmailAlert = No;               // Email Alert (Yes) or (No)
input YN           UseSendnotify = No;               // Send Notification (Yes) or (No)
input YN      trade_info_display = Yes;              // Select Display Trading Info on Chart (Yes) or (No)
input ulong              magicEA = 20231204;         // Expert ID (Magic Number)
//---

Anmerkung: Wenn die Eingabeeigenschaft der Experten-ID (Magic Number) leer gelassen wird, kann der Expert Advisor manuell eröffnete Aufträge verwalten.

In der Experteneigenschaftsgruppe Globale Strategie-EA-Parameter werden Händler angewiesen, den Expertenzeitrahmen für Indikatorsignalberechnungen auszuwählen und Parameter für die Indikatoren Keltner Kanal und Bollinger Bänder® einzugeben.

Bei der Erstellung des Expert Advisors in diesem Artikel werden die Eingabeeigenschaften für den Keltner-Kanal-Indikator im Expert Advisor genau die gleichen Eingabeeigenschaften wie im Indikator verwenden.

//--
input int                period_kc = 20;             // Input Keltner Channel Period 
input ENUM_MA_METHOD     ma_method = MODE_EMA;       // Select MA Type of smoothing
input ENUM_APPLIED_PRICE  ma_price = PRICE_TYPICAL;  // Select MA Applied Price
input int               atr_period = 20;             // Input ATR Period (typically over 10 or 20)
input double            band_multi = 1.00;           // Input the Band Multiplier ATR Desired
//--

In der Eigenschaftsgruppe Select Pairs to Trade (Zu handelnde Paare auswählen) müssen die Händler das zu handelnde Paar aus den 10 zur Verfügung stehenden Optionen auswählen; standardmäßig ist All Forex 30 Pairs festgelegt.

Um das zu handelnde Paar zu konfigurieren, rufen wir die Funktion HandlingSymbolArrays() auf. Mit der Funktion HandlingSymbolArrays() werden wir alle Paare behandeln, die gehandelt werden sollen.

void MCEA::HandlingSymbolArrays(void)
  {
//---
    string All30[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY","EURGBP",
                    "EURAUD","EURNZD","EURCAD","EURCHF","EURJPY","GBPAUD","GBPNZD","GBPCAD",
                    "GBPCHF","GBPJPY","AUDNZD","AUDCAD","AUDCHF","AUDJPY","NZDCAD","NZDCHF",
                    "NZDJPY","CADCHF","CADJPY","CHFJPY","XAUUSD","XAGUSD"}; // 30 pairs
    string USDs[]={"USDCAD","USDCHF","USDJPY","AUDUSD","EURUSD","GBPUSD","NZDUSD","XAUUSD","XAGUSD"}; // USD pairs
    string EURs[]={"EURAUD","EURCAD","EURCHF","EURGBP","EURJPY","EURNZD","EURUSD"}; // EUR pairs
    string GBPs[]={"GBPAUD","GBPCAD","GBPCHF","EURGBP","GBPJPY","GBPNZD","GBPUSD"}; // GBP pairs
    string AUDs[]={"AUDCAD","AUDCHF","EURAUD","GBPAUD","AUDJPY","AUDNZD","AUDUSD"}; // AUD pairs
    string NZDs[]={"AUDNZD","NZDCAD","NZDCHF","EURNZD","GBPNZD","NZDJPY","NZDUSD"}; // NZD pairs
    string CADs[]={"AUDCAD","CADCHF","EURCAD","GBPCAD","CADJPY","NZDCAD","USDCAD"}; // CAD pairs
    string CHFs[]={"AUDCHF","CADCHF","EURCHF","GBPCHF","NZDCHF","CHFJPY","USDCHF"}; // CHF pairs
    string JPYs[]={"AUDJPY","CADJPY","CHFJPY","EURJPY","GBPJPY","NZDJPY","USDJPY"}; // JPY pairs
    //--
    sall=ArraySize(All30);
    arusd=ArraySize(USDs);
    aretc=ArraySize(EURs);
    ArrayResize(VSym,sall,sall);
    ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY);
    //--
    if(usepairs==TrdWi && StringFind(traderwishes,"eg.",0)<0)
      {
        string to_split=traderwishes; // A string to split into substrings pairs name
        string sep=",";               // A separator as a character 
        ushort u_sep;                 // The code of the separator character 
        //--- Get the separator code 
        u_sep=StringGetCharacter(sep,0);
        //--- Split the string to substrings 
        int p=StringSplit(to_split,u_sep,SPC); 
        if(p>0)
          {
            for(int i=0; i<p; i++) StringToUpper(SPC[i]);
            //--
            for(int i=0; i<p; i++)
              {
                if(ValidatePairs(SPC[i])<0) ArrayRemove(SPC,i,1);
              }
          }
        arspc=ArraySize(SPC);
      }
    //--
    SetSymbolNamePS();      // With this function we will detect whether the Symbol Name has a prefix and/or suffix
    //--
    if(inpre>0 || insuf>0)
      {
        if(usepairs==TrdWi && arspc>0)
          {
            for(int t=0; t<arspc; t++)
              {
                SPC[t]=pre+SPC[t]+suf;
              }
          }
        //--
        for(int t=0; t<sall; t++)
          {
            All30[t]=pre+All30[t]+suf;
          }
        for(int t=0; t<arusd; t++)
          {
            USDs[t]=pre+USDs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            EURs[t]=pre+EURs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            GBPs[t]=pre+GBPs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            AUDs[t]=pre+AUDs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            NZDs[t]=pre+NZDs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            CADs[t]=pre+CADs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            CHFs[t]=pre+CHFs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            JPYs[t]=pre+JPYs[t]+suf;
          }
      }
    //--
    ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY);
    ArrayResize(AS30,sall,sall);
    ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY);
    for(int x=0; x<sall; x++) {SymbolSelect(AS30[x],true);}
    if(ValidatePairs(Symbol())>=0) symbfix=true;
    if(!symbfix) 
      {
        Alert("Expert Advisors will not trade on pairs "+Symbol());
        Alert("-- "+expname+" -- ",Symbol()," -- Expert Advisor will be Remove from the chart.");
        ExpertRemove();
      }
    //--
    switch(usepairs)
      {
        case 0: // All Forex 30 Pairs
          {
            ArrayResize(DIRI,sall,sall);
            arrsymbx=sall;
            ArraySymbolResize();
            ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY);
            pairs="Multi Currency 30 Pairs";
            //--
            break;
          }
        case 1: // Trader wishes pairs
          {
            ArrayResize(DIRI,arspc,arspc);
            arrsymbx=arspc;
            ArraySymbolResize();
            ArrayCopy(DIRI,SPC,0,0,WHOLE_ARRAY);
            pairs="("+string(arspc)+") Trader Wishes Pairs";
            //--
            break;
          }
        case 2: // USD pairs
          {
            ArrayResize(DIRI,arusd,arusd);
            arrsymbx=arusd;
            ArraySymbolResize();
            ArrayCopy(DIRI,USDs,0,0,WHOLE_ARRAY);
            pairs="("+string(arusd)+") Multi Currency USD Pairs";
            //--
            break;
          }
        case 3: // EUR pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,EURs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex EUR Pairs";
            //--
            break;
          }
        case 4: // GBP pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,GBPs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex GBP Pairs";
            //--
            break;
          }
        case 5: // AUD pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,AUDs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex AUD Pairs";
            //--
            break;
          }
        case 6: // NZD pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,NZDs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex NZD Pairs";
            //--
            break;
          }
        case 7: // CAD pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,CADs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex CAD Pairs";
            //--
            break;
          }
        case 8: // CHF pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,CHFs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex CHF Pairs";
            //--
            break;
          }
        case 9: // JPY pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,JPYs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex JPY Pairs";
            //--
            break;
          }
      }
    //--
    return;
//---
  } //-end HandlingSymbolArrays()
//---------//

Innerhalb der Funktion HandlingSymbolArrays() rufen wir die Funktion SetSymbolNamePS() auf. Mit SetSymbolNamePS() können wir Symbolnamen mit Präfixen und/oder Suffixen behandeln.

void MCEA::SetSymbolNamePS(void)
  {
//---
   symbfix=false;
   int ptriml;
   int ptrimr;
   string insymbol=Symbol();
   int sym_Lenpre=StringLen(prefix);
   int sym_Lensuf=StringLen(suffix);
   if(sym_Lenpre>0)
     {
       ptriml=StringTrimLeft(suffix);
       ptriml=StringTrimRight(suffix);
     }
   if(sym_Lensuf>0)
     {
       ptrimr=StringTrimLeft(suffix);
       ptrimr=StringTrimRight(suffix);
     }
   string sym_pre=prefix;
   string sym_suf=suffix;
   //--
   pre=sym_pre;
   suf=sym_suf;
   inpre=StringLen(pre);
   insuf=StringLen(suf);
   posCur1=inpre;
   posCur2=posCur1+3;
   //--
   return;
//---
  } //-end SetSymbolNamePS()
//---------//

Anmerkung: Der Experte wird die Paare validieren. Wenn der Händler einen Fehler bei der Eingabe des Paar-Namens oder des Paar-Präfix-Namens und/oder des Paar-Suffix-Namens (Tippfehler) macht, oder wenn die Paar-Validierung fehlschlägt, erhält der Experte eine Warnung und der Expert Advisor wird aus dem Chart entfernt.

In der Experten-Eingabeeigenschaftsgruppe Trade on Specific Time (Handel zu einer bestimmten Zeit) wählt der Händler aus, ob er in einer bestimmten Zeitzone handeln möchte (Ja) oder (Nein), und wenn Ja, wählen Sie die Aufzählungsoptionen:

  • Handel während einer nutzerdefinierten Sitzung (Custom Session)
  • Handel während der neuseeländischen Sitzung
  • Handel während der Australien Sydney Session
  • Handel während der Asien Tokyo Session
  • Handel während der Europa London Session
  • Handel während der Amerika New York Session

Handel während der Custom Session: In dieser Sitzung müssen die Händler die Zeit oder die Stunden und Minuten für den Handelsbeginn und die Stunden und Minuten für den Handelsschluss festlegen. Das bedeutet, dass die EA nur während des angegebenen Zeitraums vom Beginn bis zum Ende Aktivitäten durchführen wird.

Beim Handel zwischen der New Zealand Session und der New York US Session wird die Zeit vom Beginn des Handels bis zum Abschluss des Handels vom EA berechnet.

Klasse für funktionierenden Expert Advisor

Um den Aufbau und die Konfiguration des Expert Advisor-Workflows zu bestimmen, erstellen wir eine Klasse, die alle Variablen, Objekte und Funktionen deklariert, die für diesen Multi-Currency Expert Advisor erforderlich sind.

//+------------------------------------------------------------------+
//| Class for working Expert Advisor                                 |
//+------------------------------------------------------------------+
class MCEA
  {
//---
    private:
    //---- 
    int              x_year;       // Year 
    int              x_mon;        // Month 
    int              x_day;        // Day of the month 
    int              x_hour;       // Hour in a day 
    int              x_min;        // Minutes 
    int              x_sec;        // Seconds
    //--
    int              oBm,
                     oSm,
                     ldig;
    //--- Variables used in prefix and suffix symbols
    int              posCur1,
                     posCur2;
    int              inpre,
                     insuf;
    bool             symbfix;
    string           pre,suf;
    string           prefix,suffix;       
    //--- Variables are used in Trading Time Zone
    int              ishour,
                     onhour;
    int              tftrlst,
                     tfcinws;
    datetime         rem,
                     znop,
                     zncl,
                     zntm;
    datetime         SesCuOp,
                     SesCuCl,
                     Ses01Op,
                     Ses01Cl,
                     Ses02Op,
                     Ses02Cl,
                     Ses03Op,
                     Ses03Cl,
                     Ses04Op,
                     Ses04Cl,
                     Ses05Op,
                     Ses05Cl,
                     SesNoOp,
                     SesNoCl;
    //--
    string           tz_ses,
                     tz_opn,
                     tz_cls;
    //--
    string           tmopcu,
                     tmclcu,
                     tmop01,
                     tmcl01,
                     tmop02,
                     tmcl02,
                     tmop03,
                     tmcl03,
                     tmop04,
                     tmcl04,
                     tmop05,
                     tmcl05,
                     tmopno,
                     tmclno;      
    //----------------------    
    //--
    double           LotPS;
    double           slv,
                     tpv,
                     pip,
                     xpip;
   double            SARstep,
                     SARmaxi;
    double           floatprofit,
                     fixclprofit;
    //--
    string           pairs,
                     hariini,
                     daytrade,
                     trade_mode;
    //--
    double           OPEN[],
                     HIGH[],
                     LOW[],
                     CLOSE[];
    datetime         TIME[];
    datetime         closetime;
    //--
    //------------
     
    //------------
    void             SetSymbolNamePS(void);
    void             HandlingSymbolArrays(void);
    void             Set_Time_Zone(void);
    void             Time_Zone(void);
    bool             Trade_session(void);
    string           PosTimeZone(void);
    int              ThisTime(const int reqmode);
    int              ReqTime(datetime reqtime,const int reqmode);
    //--
    int              DirectionMove(const string symbol,const ENUM_TIMEFRAMES stf);
    int              BBOnKeltnerChannel(const string symbol);
    int              PARSAR05(const string symbol);
    int              LotDig(const string symbol);
    //--
    double           MLots(const string symbx);
    double           NonZeroDiv(double val1,double val2);
    double           OrderSLSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice);
    double           OrderTPSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice);
    double           SetOrderSL(const string xsymb,ENUM_POSITION_TYPE type,double atprice);
    double           SetOrderTP(const string xsymb,ENUM_POSITION_TYPE type,double atprice);
    double           TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type);
    //--
    string           ReqDate(int d,int h,int m);
    string           TF2Str(ENUM_TIMEFRAMES period);
    string           timehr(int hr,int mn);
    string           TradingDay(void);
    string           AccountMode();
    string           GetCommentForOrder(void)             { return(expname); }
    //------------

    public:
    //---
    
    //-- BBOnKeltnerChannel_MCEA Config --
    string           DIRI[],
                     AS30[],
                     VSym[];
    string           SPC[];
    string           USD[];
    string           EUR[];
    string           GBP[];
    string           AUD[];
    string           NZD[];
    string           CAD[];
    string           CHF[];
    string           JPY[];             
    //--                 
    string           expname;
    string           indiname;
    //--
    int              hKC[];
    int              hBB[];
    int              hParIU[],
                     hPar05[];
    int              ALO,
                     dgts,
                     arrsar,
                     arrsymbx;
    int              sall,
                     arusd,
                     aretc,
                     arspc,
                     arper;
    ulong            slip;        
    //--
    double           profitb[],
                     profits[];
    //--
    int              Buy,
                     Sell;
    int              ccur,
                     psec,
                     xtto,
                     checktml;
    int              OpOr[],xob[],xos[];         
    //--
    int              year,  // Year 
                     mon,   // Month 
                     day,   // Day 
                     hour,  // Hour 
                     min,   // Minutes 
                     sec,   // Seconds 
                     dow,   // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) 
                     doy;   // Day number of the year (January 1st is assigned the number value of zero)
    //--
    ENUM_TIMEFRAMES  TFt,
                     TFT05;
    //--
    bool             PanelExtra;
    //------------
                     MCEA(void);
                     ~MCEA(void);            
    //------------
    //--
    virtual void     BBOnKeltnerChannel_MCEA_Config(void);
    virtual void     ExpertActionTrade(void);
    //--
    void             ArraySymbolResize(void);
    void             CurrentSymbolSet(const string symbol);
    void             Pips(const string symbol);
    void             TradeInfo(void);
    void             Do_Alerts(const string symbx,string msgText);
    void             CheckOpenPMx(const string symbx);
    void             SetSLTPOrders(void);
    void             CloseBuyPositions(const string symbol);
    void             CloseSellPositions(const string symbol);
    void             CloseAllOrders(void);
    void             CheckClose(const string symbx);
    void             TodayOrders(void);
    void             UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf);
    void             RefreshPrice(const string symbx,ENUM_TIMEFRAMES xtf,int bars);
    //--
    bool             RefreshTick(const string symbx);  
    bool             TradingToday(void);
    bool             OpenBuy(const string symbol);
    bool             OpenSell(const string symbol);
    bool             ModifyOrderSLTP(double mStop,double ordtp);
    bool             ModifySLTP(const string symbx,int TS_type);          
    bool             CloseAllProfit(void);
    bool             ManualCloseAllProfit(void);
    //--
    int              PairsIdxArray(const string symbol);
    int              ValidatePairs(const string symbol);
    int              GetOpenPosition(const string symbol);
    int              GetCloseInWeakSignal(const string symbol,int exis);
    //--
    string           getUninitReasonText(int reasonCode);
    //--
    //------------
//---
  }; //-end class MCEA
//---------//

Die allererste und wichtigste Funktion im Arbeitsprozess des Multi-Currency Expert Advisor, die von OnInit() aufgerufen wird, ist BBOnKeltnerChannel_MCEA_Config().

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//---
   mc.BBOnKeltnerChannel_MCEA_Config();
   //--
   return(INIT_SUCCEEDED);
//---
  } //-end OnInit()
//---------//

Die Funktion BBOnKeltnerChannel_MCEA_Config() konfiguriert alle zu verwendenden Symbole, alle Handles der verwendeten Indikatoren und einige wichtige Funktionen des Headers der Include-Datei für den Expert Advisor Workflow.

In den Funktionszeilen 468 bis 484 wird erklärt, wie der Zeitrahmen zu handhaben ist und wie man Indikator-Handles für alle verwendeten Indikatoren erstellt.

//+------------------------------------------------------------------+
//| Expert Configuration                                             |
//+------------------------------------------------------------------+
void MCEA::BBOnKeltnerChannel_MCEA_Config(void) 
  {
//---
    //--
    HandlingSymbolArrays(); // With this function we will handle all pairs that will be traded
    //--
    TFT05=PERIOD_M5;
    ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1};
    int arTFs=ArraySize(TFs);
    //--
    for(int x=0; x<arTFs; x++) if(tfinuse==x) TFt=TFs[x]; // TF for calculation signal
    //--
    //-- Keltner Channel and Bollinger Bands® Indicators handle for all symbol
    for(int x=0; x<arrsymbx; x++) 
      {
        hKC[x]=iCustom(DIRI[x],TFt,indiname,KCPeriod,KCMethod,KCMAAP,KCATRPer,KCATRBandsMulti); //-- Handle for the Keltner Channel indicator
        hParIU[x]=iSAR(DIRI[x],TFt,SARstep,SARmaxi);         //-- Handle for the iSAR indicator according to the selected Timeframe
        hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi);       //-- Handle for the iSAR indicator for M5 Timeframe
        //--
      }
    //--
    for(int x=0; x<arrsymbx; x++) 
      hBB[x]=iBands(DIRI[x],TFt,BBPeriod,0,BBDevi,hKC[x]); //-- Handle for the iBands On Keltner Channel Indicator handle
    //--
    ALO=(int)mc_account.LimitOrders()>sall ? sall : (int)mc_account.LimitOrders();
    //--
    LotPS=(double)ALO;
    //--
    mc_trade.SetExpertMagicNumber(magicEA);
    mc_trade.SetDeviationInPoints(slip);
    mc_trade.SetMarginMode();
    Set_Time_Zone();
    //--
    return;
//---
  } //-end BBOnKeltnerChannel_MCEA_Config()
//---------//

2. Experten-Tick-Funktion

Innerhalb der Expert Tick Funktion OnTick() werden wir eine der wichtigsten Funktionen in einem Multi-Currency Expert Advisor aufrufen, nämlich die ExpertActionTrade() Funktion.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(void)
  {
//---
    mc.ExpertActionTrade();
    //--
    return;
//---
  } //-end OnTick()
//---------//

Dies ist der Ablauf des EA-Arbeitsprozesses innerhalb dieser Funktion.

Die Funktion ExpertActionTrade() führt alle Aktivitäten durch und verwaltet den automatischen Handel, angefangen von Eröffnungs- und Schließaufträgen, den Trailing-Stops oder -Profits und anderen zusätzlichen Aktivitäten.

void MCEA::ExpertActionTrade(void)
  {
//---
    //--Check Trading Terminal
    ResetLastError();
    //--
    if(!MQLInfoInteger(MQL_TRADE_ALLOWED) && mc.checktml==0) //-- Check whether MT5 Algorithmic trading is Allow or Prohibit
      {
        mc.Do_Alerts(Symbol(),"Trading Expert at "+Symbol()+" are NOT Allowed by Setting.");
        mc.checktml=1;  //-- Variable checktml is given a value of 1, so that the alert is only done once.
        return;
      }
    //--
    if(!DisplayManualButton("M","C","R")) DisplayManualButton(); //-- Show the expert manual button panel
    //--
    if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart
    //---
    //--
    int mcsec=mc.ThisTime(mc.sec); 
    //--
    if(fmod((double)mcsec,5.0)==0) mc.ccur=mcsec;
    //--
    if(mc.ccur!=mc.psec)
      {
        string symbol;
        //-- Here we start with the rotation of the name of all symbol or pairs to be traded
        for(int x=0; x<mc.arrsymbx && !IsStopped(); x++) 
          {
            //-- 
            if(mc.DIRI[x]==Symbol()) symbol=Symbol();
            else symbol=mc.DIRI[x];
            //--
            mc.CurrentSymbolSet(symbol);
            //--
            if(mc.TradingToday() && mc.Trade_session())
              {
                //--
                mc.OpOr[x]=mc.GetOpenPosition(symbol); //-- Get trading signals to open positions
                //--                                   //-- and store in the variable OpOr[x]
                if(mc.OpOr[x]==mc.Buy) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Buy" (value=1)
                  {
                    //--
                    mc.CheckOpenPMx(symbol);
                    //--
                    if(Close_by_Opps==Yes && mc.xos[x]>0) mc.CloseSellPositions(symbol);
                    //--
                    if(mc.xob[x]==0 && mc.xtto<mc.ALO) mc.OpenBuy(symbol);
                    else
                    if(mc.xtto>=mc.ALO)
                      {
                        //--
                        mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+
                                            "\n the limit = "+string(mc.ALO)+" Orders ");
                        //--
                        mc.CheckOpenPMx(symbol);
                        //--
                        if(mc.xos[x]>0 && mc.profits[x]<-1.02 && mc.xob[x]==0) {mc.CloseSellPositions(symbol); mc.OpenBuy(symbol);}
                        else
                        if(SaveOnRev==Yes) mc.CloseAllProfit();
                      }
                  }
                if(mc.OpOr[x]==mc.Sell) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Sell" (value=-1)
                  {
                    //--
                    mc.CheckOpenPMx(symbol);
                    //--
                    if(Close_by_Opps==Yes && mc.xob[x]>0) mc.CloseBuyPositions(symbol);
                    //--
                    if(mc.xos[x]==0 && mc.xtto<mc.ALO) mc.OpenSell(symbol);
                    else
                    if(mc.xtto>=mc.ALO)
                      {
                        //--
                        mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+
                                            "\n the limit = "+string(mc.ALO)+" Orders ");
                        //--
                        mc.CheckOpenPMx(symbol);
                        //--
                        if(mc.xob[x]>0 && mc.profitb[x]<-1.02 && mc.xos[x]==0) {mc.CloseBuyPositions(symbol); mc.OpenSell(symbol);}
                        else
                        if(SaveOnRev==Yes) mc.CloseAllProfit();
                      }
                  }
              }
            //--
            mc.CheckOpenPMx(symbol);
            //--
            if(mc.xtto>0)
              {
                //--
                if(SaveOnRev==Yes) //-- Close Trade and Save profit due to weak signal (Yes)
                  {
                    mc.CheckOpenPMx(symbol);
                    if(mc.profitb[x]>0.02 && mc.xob[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) 
                      {
                        mc.CloseBuyPositions(symbol); 
                        mc.Do_Alerts(symbol,"Close BUY order "+symbol+" to save profit due to weak signal.");
                      }
                    if(mc.profits[x]>0.02 && mc.xos[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Sell)==mc.Buy)
                      {
                        mc.CloseSellPositions(symbol); 
                        mc.Do_Alerts(symbol,"Close SELL order "+symbol+" to save profit due to weak signal.");
                      }
                  }
                //--
                if(TrailingSLTP==Yes) //-- Use Trailing SL/TP (Yes)
                  {
                    if(autotrl==Yes) mc.ModifySLTP(symbol,1); //-- If Use Automatic Trailing (Yes)
                    if(autotrl==No)  mc.ModifySLTP(symbol,0); //-- Use Automatic Trailing (No)
                  }
              }
            //--
            mc.CheckClose(symbol);
          }
        //--
        mc.psec=mc.ccur;
      }
    //--
    return;
//---
  } //-end ExpertActionTrade()
//---------//

Die Eigenschaftsgruppe „Day Trading On/Off“ (Taghandel ein/aus) gibt Händlern die Möglichkeit, an den angegebenen Tagen von Sonntag bis Samstag zu handeln. Auf diese Weise können die Händler die Experten für den Handel an dem angegebenen Tag aktivieren oder deaktivieren, indem sie die Option (Ja) oder (Nein) verwenden.

//--Day Trading On/Off
input group               "=== Day Trading On/Off ==="; // Day Trading On/Off
input YN                    ttd0 = No;               // Select Trading on Sunday (Yes) or (No)
input YN                    ttd1 = Yes;              // Select Trading on Monday (Yes) or (No)
input YN                    ttd2 = Yes;              // Select Trading on Tuesday (Yes) or (No)
input YN                    ttd3 = Yes;              // Select Trading on Wednesday (Yes) or (No)
input YN                    ttd4 = Yes;              // Select Trading on Thursday (Yes) or (No)
input YN                    ttd5 = Yes;              // Select Trading on Friday (Yes) or (No)
input YN                    ttd6 = No;               // Select Trading on Saturday (Yes) or (No)

Die Ausführung für Day Trading On/Off ist wie folgt:

bool MCEA::TradingToday(void)
  {
//---
    bool tradetoday=false;
    int trdday=ThisTime(dow);
    hariini="No";
    //--
    int ttd[];
    ArrayResize(ttd,7);
    ttd[0]=ttd0;
    ttd[1]=ttd1;
    ttd[2]=ttd2;
    ttd[3]=ttd3;
    ttd[4]=ttd4;
    ttd[5]=ttd5;
    ttd[6]=ttd6;
    //--
    if(ttd[trdday]==Yes) {tradetoday=true; hariini="Yes";}
   //--
   return(tradetoday);
//---
  } //-end TradingToday()
//---------//

Anmerkungen: Die Bedingungen für den Tageshandel (Day Trading On/Off) werden in der Handelsinfo im Chart angezeigt.

In der Eigenschaftsgruppe „Trade on Specific Time“ (Handel zu bestimmten Zeiten) des Expert Advisors haben Händler die Möglichkeit, nach Zeitzonen zu handeln.

input group               "=== Trade on Specific Time ==="; // Trade on Specific Time
input YN           trd_time_zone = Yes;              // Select If You Like to Trade on Specific Time Zone
input tm_zone            session = Cus_Session;      // Select Trading Time Zone
input swhour            stsescuh = hr_00;            // Time Hour to Start Trading Custom Session (0-23)
input inmnt             stsescum = mn_15;            // Time Minute to Start Trading Custom Session (0-55)
input swhour            clsescuh = hr_23;            // Time Hour to Stop Trading Custom Session (0-23)
input inmnt             clsescum = mn_55;            // Time Minute to Stop Trading Custom Session (0-55)

Anmerkungen: Wie oben erläutert, wird im Falle des Handels an der New Zealand Session zum Handel an der US New York Session die Zeit vom Beginn des Handels bis zum Handelsschluss vom EA berechnet. In den Eigenschaften des Experteneintrags müssen Händler also nur die Uhrzeit für die Stunde und Minute des Handelsbeginns und die Uhrzeit für die Stunde und Minute des Handelsendes für die nutzerdefinierte Sitzung festlegen.

Speziell für den Zeitzonenhandel wird ein Aufruf der booleschen Funktion Trade_session() zur Funktion ExpertActionTrade() hinzugefügt.

Wenn Trade_session() true ist, dann wird der EA-Arbeitsprozess fortgesetzt, bis er beendet ist, aber wenn er false ist, dann wird der EA nur die Aufgaben „Close Trade and Save Profit due to Weak Signal if it is (Yes)“ (Schließen der Position und Sichern des Gewinns aufgrund schwachen Signals, wenn es (Ja) ist) und „Trailing Stop if it is (Yes)“ (Trailing Stop, wenn ja (Ja)) ausführen.

bool MCEA::Trade_session(void)
  {
//---
   bool trd_ses=false;
   ishour=ThisTime(hour);
   if(ishour!=onhour) Set_Time_Zone();
   datetime tcurr=TimeCurrent(); // Server Time
   //--
   switch(session)
     {
       case Cus_Session:
         {
           if(tcurr>=SesCuOp && tcurr<=SesCuCl) trd_ses=true;
           break;
         }
       case New_Zealand:
         {
           if(tcurr>=Ses01Op && tcurr<=Ses01Cl) trd_ses=true;
           break;
         }
       case Australia:
         {
           if(tcurr>=Ses02Op && tcurr<=Ses02Cl) trd_ses=true;
           break;
         }
       case Asia_Tokyo:
         {
           if(tcurr>=Ses03Op && tcurr<=Ses03Cl) trd_ses=true;
           break;
         }
       case Europe_London:
         {
           if(tcurr>=Ses04Op && tcurr<=Ses04Cl) trd_ses=true;
           break;
         }
       case US_New_York:
         {
           if(tcurr>=Ses05Op && tcurr<=Ses05Cl) trd_ses=true;
           break;
         }
     }
   //--
   if(trd_time_zone==No) 
     {
      if(tcurr>=SesNoOp && tcurr<=SesNoCl) trd_ses=true;
     }
   //--
   onhour=ishour;
   //--
   return(trd_ses);
//---  
  } //-end Trade_session()
//---------//

3. Wie kann ich Handelssignale für offene Positionen erhalten?

Um ein Signal zu erhalten, ruft die Funktion ExpertActionTrade() die Funktion GetOpenPosition() auf.

int MCEA::GetOpenPosition(const string symbol) // Signal Open Position 
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    //--
    int BBOnKC=BBOnKeltnerChannel(symbol);
    //--
    if(BBOnKC==rise) ret=rise;
    if(BBOnKC==down) ret=down;
    //--
    return(ret);
//---
  } //-end GetOpenPosition()
//---------//

Die Funktion GetOpenPosition() ruft BBOnKeltnerChannel() Funktionen auf, die die Signalberechnungen durchführt.

int MCEA::BBOnKeltnerChannel(const string symbol) // Fungction of Bollinger Bands® On Keltner Channel Indicator
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    int br=3;
    Pips(symbol);
    double difud=mc_symbol.NormalizePrice(1.5*pip);
    //--
    double KCmb[], // Destination array for Keltner Channel Middle Line buffer
           KCub[], // Destination array for Keltner Channel Upper Band buffer
           KClb[]; // Destination array for Keltner Channel Lower Band buffer
    double BBmb[], // Destination array for Bollinger Bands® BASE_LINE buffer
           BBub[], // Destination array for Bollinger Bands® UPPER_BAND buffer
           BBlb[]; // Destination array for Bollinger Bands® LOWER_BAND buffer
    //--
    ArrayResize(KCmb,br,br);
    ArrayResize(KCub,br,br);
    ArrayResize(KClb,br,br);
    ArrayResize(BBmb,br,br);
    ArrayResize(BBub,br,br);
    ArrayResize(BBlb,br,br);
    ArraySetAsSeries(KCmb,true);
    ArraySetAsSeries(KCub,true);
    ArraySetAsSeries(KClb,true);
    ArraySetAsSeries(BBmb,true);
    ArraySetAsSeries(BBub,true);
    ArraySetAsSeries(BBlb,true);
    //--
    int xx=PairsIdxArray(symbol);
    //--
    CopyBuffer(hKC[xx],0,0,br,KCmb);
    CopyBuffer(hKC[xx],1,0,br,KCub);
    CopyBuffer(hKC[xx],2,0,br,KClb);
    CopyBuffer(hBB[xx],0,0,br,BBmb);
    CopyBuffer(hBB[xx],1,0,br,BBub);
    CopyBuffer(hBB[xx],2,0,br,BBlb);
    //--
    bool BBKCrise1=(KCmb[1]<=BBlb[1] && KCmb[0]>BBlb[0]+difud);
    bool BBKCrise2=(KCmb[1]<=BBmb[1] && KCmb[0]>BBmb[0]+difud);
    bool BBKCrise3=(KCmb[1]<=BBub[1] && KCmb[0]>BBub[0]+difud);
    //--
    bool BBKCdown1=(KCmb[1]>=BBub[1] && KCmb[0]<BBub[0]-difud);
    bool BBKCdown2=(KCmb[1]>=BBmb[1] && KCmb[0]<BBmb[0]-difud);
    bool BBKCdown3=(KCmb[1]>=BBlb[1] && KCmb[0]<BBlb[0]-difud);
    //--
    if(BBKCrise1 || BBKCrise2 || BBKCrise3) ret=rise;
    if(BBKCdown1 || BBKCdown2 || BBKCdown3) ret=down;
    //--
    return(ret);
//---
  } //-end BBOnKeltnerChannel()
//---------//

Wie Sie sehen können, wird innerhalb der Funktion BBOnKeltnerChannel() eine Funktion verwendet und aufgerufen, nämlich die Funktion PairsIdxArray().

int xx=PairsIdxArray(symbol);
int MCEA::PairsIdxArray(const string symbol)
  {
//---
    int pidx=-1;
    //--
    for(int x=0; x<arrsymbx; x++)
      {
        if(DIRI[x]==symbol)
          {
            pidx=x;
            break;
          }
      } 
    //--
    return(pidx);
//---
  } //-end PairsIdxArray()
//---------//

Die Funktion PairsIdxArray() wird verwendet, um den Namen des gewünschten Symbols und die Handles seiner Indikatoren zu erhalten. Dann wird das entsprechende Indikator-Handle aufgerufen, um den Pufferwerte der Signale vom Keltner Kanal und den Bollinger Bänder® aus diesem Zeitrahmen abzurufen.

Als Nächstes müssen wir die Puffernummer des Keltner-Kanals kennen. Beim Keltner-Kanal wissen wir in der Funktion OnInit(), dass die Puffernummern wie folgt sind: 0 - Mittlere Linie, 1 - Oberes Band, 2 - Unteres Band

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   //-- assignment of array to indicator buffer 
   SetIndexBuffer(0,KC_Middle,INDICATOR_DATA);
   SetIndexBuffer(1,KC_UpperB,INDICATOR_DATA);
   SetIndexBuffer(2,KC_LowerB,INDICATOR_DATA);
   SetIndexBuffer(3,KC_ATRtemp,INDICATOR_CALCULATIONS);
   //--
   handleMA=iMA(Symbol(),Period(),period_kc,0,MODE_EMA,ma_price);
   //--
   if(handleMA==INVALID_HANDLE) 
     { 
      //--- tell about the failure and output the error code 
      PrintFormat("Failed to create handle of the Moving Average indicator for the symbol %s/%s, error code %d", 
                  Symbol(), 
                  EnumToString(Period()), 
                  GetLastError()); 
      //--- the indicator is stopped early 
      return(INIT_FAILED); 
     } 
   //--
   handleATR=iATR(Symbol(),Period(),atr_period);
   //--
   if(handleATR==INVALID_HANDLE) 
     { 
      //--- tell about the failure and output the error code 
      PrintFormat("Failed to create handle of the ATR indicator for the symbol %s/%s, error code %d", 
                  Symbol(), 
                  EnumToString(Period()), 
                  GetLastError()); 
      //--- the indicator is stopped early 
      return(INIT_FAILED); 
     } 
   //--
   short_name=StringFormat("Keltner Channel(%d, %s, %.2f)",period_kc,EnumToString(ma_method),band_multi);
   IndicatorSetString(INDICATOR_SHORTNAME,short_name);
   IndicatorSetInteger(INDICATOR_DIGITS,Digits());
   //--
   return(INIT_SUCCEEDED);
//---
  }
//---------//

In diesem Fall müssen wir auch die Anzahl der Puffer des Bollinger Bänder® Indikators kennen.

Die Erklärung dazu ist in der Funktion iBands® angegeben:

„Hinweis Puffernummern: 0 - BASE_LINE, 1 - UPPER_BAND, 2 - LOWER_BAND“

applied_price

[in] Der verwendete Preis. Kann eine der Preiskonstanten ENUM_APPLIED_PRICE oder ein Handle eines anderen Indikators sein.

In diesem Artikel werden Expert Advisors den angewandten Preis für Bollinger Bänder® aus dem Keltner Kanal Indikator Handle verwenden.

Um also den Pufferwert für jede Zeile der Indikatoren Keltner Kanal und Bollinger Bänder® zu erhalten, kopieren wir jeden Puffer aus dem Indikatoren-Handle.

Kopieren des Puffers der Mittellinie (Puffer 0) vom Handle des Keltner-Kanals in das Ziel-Array:

CopyBuffer(hKC[xx],0,0,br,KCmb);

Kopieren des Puffers des oberen Bandes (Puffer 1) vom Handle des Keltner-Kanals in das Ziel-Array:

CopyBuffer(hKC[xx],1,0,br,KCub);

Kopieren des Puffers des unteren Bandes (Puffer 2) vom Handle des Keltner-Kanals in das Ziel-Array:

CopyBuffer(hKC[xx],2,0,br,KClb);

Kopieren des BASE_LINE Puffers (Puffer 0) der Bollinger Bänder® in das Ziel-Array:

CopyBuffer(hBB[xx],0,0,br,BBmb);

Kopieren des UPPER_BAND Puffers (Puffer 1) der Bollinger Bänder® in das Ziel-Array:

CopyBuffer(hBB[xx],1,0,br,BBub);

Kopieren des LOWER_BAND Puffers (Puffer 2) der Bollinger Bänder® in das Ziel-Array:

CopyBuffer(hBB[xx],2,0,br,BBlb);

Als Nächstes werden die folgenden Ergebnisse von der Funktion GetOpenPosition() zurückgegeben:

  • Wert 0, Signal unbekannt.
  • Der Wert 1 ist ein Signal für einen Kaufauftrag.
  • Der Wert -1 ist ein Signal für einen Verkaufsauftrag.

Der Expert Advisor ruft die Funktion OpenBuy() auf, wenn die Funktion GetOpenPosition() den Wert 1 zurückgibt.

bool MCEA::OpenBuy(const string symbol) 
  {
//---
    ResetLastError();
    //--
    bool buyopen      = false;
    string ldComm     = GetCommentForOrder()+"_Buy";
    double ldLot      = MLots(symbol);
    ENUM_ORDER_TYPE type_req = ORDER_TYPE_BUY;
    //--
    MqlTradeRequest req={};
    MqlTradeResult  res={};
    MqlTradeCheckResult check={};
    //-- structure is set to zero
    ZeroMemory(req);
    ZeroMemory(res);
    ZeroMemory(check);
    //--
    CurrentSymbolSet(symbol);
    double SL=OrderSLSet(symbol,type_req,mc_symbol.Bid());
    double TP=OrderTPSet(symbol,type_req,mc_symbol.Ask());
    //--
    if(RefreshTick(symbol))
       buyopen=mc_trade.Buy(ldLot,symbol,mc_symbol.Ask(),SL,TP,ldComm);
    //--
    int error=GetLastError();
    if(buyopen||error==0)
      {
        string bsopen="Open BUY Order for "+symbol+" ~ Ticket= ["+(string)mc_trade.ResultOrder()+"] successfully..!";
        Do_Alerts(symbol,bsopen);
      }
    else
      {
        mc_trade.CheckResult(check);
        Do_Alerts(Symbol(),"Open BUY order for "+symbol+" FAILED!!. Return code= "+
                 (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]");
        return(false);   
      }
    //--
    return(buyopen);
    //--
//---
  } //-end OpenBuy
//---------//

In der Zwischenzeit ruft der Expert Advisor die Funktion OpenSell() auf, wenn die Funktion GetOpenPosition() einen Wert von -1 zurückgibt.

bool MCEA::OpenSell(const string symbol) 
  {
//---
    ResetLastError();
    //--
    bool selopen      = false;
    string sdComm     = GetCommentForOrder()+"_Sell";
    double sdLot      = MLots(symbol);
    ENUM_ORDER_TYPE type_req = ORDER_TYPE_SELL;
    //--
    MqlTradeRequest req={};
    MqlTradeResult  res={};
    MqlTradeCheckResult check={};
    //-- structure is set to zero
    ZeroMemory(req);
    ZeroMemory(res);
    ZeroMemory(check);
    //--
    CurrentSymbolSet(symbol);
    double SL=OrderSLSet(symbol,type_req,mc_symbol.Ask());
    double TP=OrderTPSet(symbol,type_req,mc_symbol.Bid());
    //--
    if(RefreshTick(symbol))
       selopen=mc_trade.Sell(sdLot,symbol,mc_symbol.Bid(),SL,TP,sdComm);
    //--
    int error=GetLastError();
    if(selopen||error==0)
      {
        string bsopen="Open SELL Order for "+symbol+" ~ Ticket= ["+(string)mc_trade.ResultOrder()+"] successfully..!";
        Do_Alerts(symbol,bsopen);
      }
    else
      {
        mc_trade.CheckResult(check);
        Do_Alerts(Symbol(),"Open SELL order for "+symbol+" FAILED!!. Return code= "+
                 (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]");
        return(false);   
      }
    //--
    return(selopen);
    //--
//---
  } //-end OpenSell
//---------//

4. ChartEvent Funktion.

Um die Effektivität und Effizienz bei der Verwendung von Multi-Currency Expert Advisors zu unterstützen, wird es als notwendig erachtet, eine oder mehrere manuelle Schaltflächen für die Verwaltung von Aufträgen und die Änderung von Charts oder Symbolen zu erstellen.

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
//--- handling CHARTEVENT_CLICK event ("Clicking the chart")
   ResetLastError();
   //--
   ENUM_TIMEFRAMES CCS=mc.TFt;
   //--
   if(id==CHARTEVENT_OBJECT_CLICK) 
     {
       int lensymbol=StringLen(Symbol());
       int lensparam=StringLen(sparam);
       //--
       //--- if "Set SL All Orders" button is click
       if(sparam=="Set SL/TP All Orders") 
         { 
           mc.SetSLTPOrders();
           Alert("-- "+mc.expname+" -- ",Symbol()," -- Set SL/TP All Orders");
           //--- unpress the button 
           ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_STATE,false);
           ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_ZORDER,0);
           CreateManualPanel();
         }
       //--- if "Close All Order" button is click
       if(sparam=="Close All Order") 
         { 
           mc.CloseAllOrders();
           Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Orders");
           //--- unpress the button 
           ObjectSetInteger(0,"Close All Order",OBJPROP_STATE,false);
           ObjectSetInteger(0,"Close All Order",OBJPROP_ZORDER,0);
           CreateManualPanel();
         }
       //--- if "Close All Profit" button is click
       if(sparam=="Close All Profit") 
         { 
           mc.ManualCloseAllProfit();
           Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Profit");
           //--- unpress the button 
           ObjectSetInteger(0,"Close All Profit",OBJPROP_STATE,false);
           ObjectSetInteger(0,"Close All Profit",OBJPROP_ZORDER,0);
           CreateManualPanel();
         }
       //--- if "X" button is click
       if(sparam=="X") 
         { 
           ObjectsDeleteAll(0,0,OBJ_BUTTON);
           ObjectsDeleteAll(0,0,OBJ_LABEL);
           ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL);
           //--- unpress the button 
           ObjectSetInteger(0,"X",OBJPROP_STATE,false);
           ObjectSetInteger(0,"X",OBJPROP_ZORDER,0);
           //--
           DeleteButtonX();
           mc.PanelExtra=false;
           DisplayManualButton();
         }
       //--- if "M" button is click
       if(sparam=="M") 
         { 
           //--- unpress the button 
           ObjectSetInteger(0,"M",OBJPROP_STATE,false);
           ObjectSetInteger(0,"M",OBJPROP_ZORDER,0);
           mc.PanelExtra=true;
           CreateManualPanel();
         }
       //--- if "C" button is click
       if(sparam=="C") 
         { 
           //--- unpress the button 
           ObjectSetInteger(0,"C",OBJPROP_STATE,false);
           ObjectSetInteger(0,"C",OBJPROP_ZORDER,0);
           mc.PanelExtra=true;
           CreateSymbolPanel();
         }
       //--- if "R" button is click
       if(sparam=="R") 
         { 
           Alert("-- "+mc.expname+" -- ",Symbol()," -- Expert Advisor will be Remove from the chart.");
           ExpertRemove();
           //--- unpress the button 
           ObjectSetInteger(0,"R",OBJPROP_STATE,false);
           ObjectSetInteger(0,"R",OBJPROP_ZORDER,0);
           if(!ChartSetSymbolPeriod(0,Symbol(),Period()))
             ChartSetSymbolPeriod(0,Symbol(),Period());
           DeletePanelButton();
           ChartRedraw(0);
         }
       //--- if Symbol button is click
       if(lensparam==lensymbol)
         {
           int sx=mc.ValidatePairs(sparam);
           ChangeChartSymbol(mc.AS30[sx],CCS);
           mc.PanelExtra=false;
         }
       //--
     }
    //--
    return;
//---
  } //-end OnChartEvent()
//---------//

In der anderen Parametergruppe der Eingabeeigenschaften des Expert Advisors kann der Händler auswählen, ob Handelsinformationen auf dem Chart angezeigt werden sollen (Yes) oder (No).

Wenn diese Option ausgewählt ist (Yes), werden die Handelsinformationen auf dem Chart angezeigt, an das der Expert Advisor durch Aufruf der Funktion TradeInfo() angehängt ist.

Als Teil der Funktion TradeInfo() haben wir auch eine Funktion hinzugefügt, die die Zeit entsprechend den Bedingungen der Handelszeitzone beschreibt.

string MCEA::PosTimeZone(void)
  {
//---
    string tzpos="";
    //--
    if(ReqTime(zntm,day)>ThisTime(day))
     {
       tzpos=tz_opn+ " Next day to " +tz_cls + " Next day";
     }
    else
    if(TimeCurrent()<znop)
      {
        if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)==ReqTime(zncl,day))
          tzpos=tz_opn+" to " +tz_cls+ " Today";
        //else
        if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)<ReqTime(zncl,day))
          tzpos=tz_opn+ " Today to " +tz_cls+ " Next day";
      }
    else
    if(TimeCurrent()>=znop && TimeCurrent()<zncl)
      {
        if(ThisTime(day)<ReqTime(zncl,day))
          tzpos=tz_opn+ " Today to " +tz_cls+ " Next day";
        else
        if(ThisTime(day)==ReqTime(zncl,day))
          tzpos=tz_opn+" to " +tz_cls+ " Today";
      }
    else
    if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)<ReqTime(zncl,day))
      {
        tzpos=tz_opn+" Today to " +tz_cls+ " Next day";
      }
    //--
    return(tzpos);
//----
  } //-end PosTimeZone()
//---------//
void MCEA::TradeInfo(void) // function: write comments on the chart
  {
//----
   Pips(Symbol());
   double spread=SymbolInfoInteger(Symbol(),SYMBOL_SPREAD)/xpip;
   rem=zntm-TimeCurrent();
   string postime=PosTimeZone();
   string eawait=" - Waiting for active time..!";
   //--
   string comm="";
   TodayOrders();
   //--
   comm="\n     :: Server Date Time : "+string(ThisTime(year))+"."+string(ThisTime(mon))+"."+string(ThisTime(day))+ "   "+TimeToString(TimeCurrent(),TIME_SECONDS)+
        "\n     ------------------------------------------------------------"+
        "\n      :: Broker               :  "+ TerminalInfoString(TERMINAL_COMPANY)+
        "\n      :: Expert Name      :  "+ expname+
        "\n      :: Acc. Name         :  "+ mc_account.Name()+
        "\n      :: Acc. Number      :  "+ (string)mc_account.Login()+
        "\n      :: Acc. TradeMode :  "+ AccountMode()+
        "\n      :: Acc. Leverage    :  1 : "+ (string)mc_account.Leverage()+
        "\n      :: Acc. Equity       :  "+ DoubleToString(mc_account.Equity(),2)+
        "\n      :: Margin Mode     :  "+ (string)mc_account.MarginModeDescription()+
        "\n      :: Magic Number   :  "+ string(magicEA)+
        "\n      :: Trade on TF      :  "+ EnumToString(TFt)+
        "\n      :: Today Trading   :  "+ TradingDay()+" : "+hariini+
        "\n      :: Trading Session :  "+ tz_ses+
        "\n      :: Trading Time    :  "+ postime;
        if(TimeCurrent()<zntm)
          {
            comm=comm+
            "\n      :: Time Remaining :  "+(string)ReqTime(rem,hour)+":"+(string)ReqTime(rem,min)+":"+(string)ReqTime(rem,sec) + eawait;
          }
        comm=comm+
        "\n     ------------------------------------------------------------"+
        "\n      :: Trading Pairs     :  "+pairs+
        "\n      :: BUY Market      :  "+string(oBm)+
        "\n      :: SELL Market     :  "+string(oSm)+
        "\n      :: Total Order       :  "+string(oBm+oSm)+
        "\n      :: Order Profit      :  "+DoubleToString(floatprofit,2)+
        "\n      :: Fixed Profit       :  "+DoubleToString(fixclprofit,2)+
        "\n      :: Float Money     :  "+DoubleToString(floatprofit,2)+
        "\n      :: Nett Profit        :  "+DoubleToString(floatprofit+fixclprofit,2);
   //--
   Comment(comm);
   ChartRedraw(0);
   return;
//----
  } //-end TradeInfo()  
//---------//

Die Schnittstelle des Multi-Currency Expert Advisor BBOnKeltnerChannel_MCEA sieht ähnlich aus wie in der folgenden Abbildung.

Aussehen des EA

Unter dem Namen des Expert Advisors BBOnKeltnerChannel_MCEA finden Sie die Schaltflächen „M“, „C“ und „R“.

Wenn Sie auf die Schaltfläche M klicken, wird ein Feld mit Schaltflächen für manuelle Klicks angezeigt, wie in der folgenden Abbildung dargestellt.

Experte_Handbuch_Schaltfläche_01

Der Händler kann Aufträge manuell verwalten, wenn die Schaltfläche für manuelle Klicks angezeigt wird:

1. Wie oben erläutert, kann der Händler, wenn er die Parameter „Use Order Stop Loss (No) and/or Use Order Take Profit (No)“ (Stop Loss verwenden (Nein) und/oder Take Profit verwenden (Nein)) eingibt, dann aber beabsichtigt, Stop Loss oder Take Profit für alle Aufträge zu verwenden, mit einem einzigen Klick auf die Schaltfläche „Set SL / TP All Orders“ (SL/TP für alle Aufträge setzen) alle Aufträge ändern und Stop Loss und/oder Take Profit anwenden.

void MCEA::SetSLTPOrders(void) 
  {
//---
   ResetLastError();
   MqlTradeRequest req={};
   MqlTradeResult  res={};
   MqlTradeCheckResult check={};
   //--
   double modbuysl=0;
   double modselsl=0;
   double modbuytp=0;
   double modseltp=0;
   string position_symbol;
   int totalorder=PositionsTotal();
   //--    
   for(int i=totalorder-1; i>=0; i--) 
     {
       string symbol=PositionGetSymbol(i);
       position_symbol=symbol;
       if(mc_position.Magic()==magicEA)
         {
           ENUM_POSITION_TYPE opstype = mc_position.PositionType();
           if(opstype==POSITION_TYPE_BUY) 
             {
               Pips(symbol);
               RefreshTick(symbol);
               double price    = mc_position.PriceCurrent();
               double pos_open = mc_position.PriceOpen();
               double pos_stop = mc_position.StopLoss();
               double pos_take = mc_position.TakeProfit();
               modbuysl=SetOrderSL(symbol,opstype,pos_open);
               if(price<modbuysl) modbuysl=mc_symbol.NormalizePrice(price-slip*pip);
               modbuytp=SetOrderTP(symbol,opstype,pos_open);
               if(price>modbuytp) modbuytp=mc_symbol.NormalizePrice(price+slip*pip);
               //--
               if(pos_stop==0.0 || pos_take==0.0)
                 {
                   if(!mc_trade.PositionModify(position_symbol,modbuysl,modbuytp))
                     {
                       mc_trade.CheckResult(check);
                       Do_Alerts(symbol,"Set SL and TP for "+EnumToString(opstype)+" on "+symbol+" FAILED!!. Return code= "+
                                (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]");
                     }
                 }
             }
           if(opstype==POSITION_TYPE_SELL) 
             {
               Pips(symbol);
               RefreshTick(symbol);
               double price    = mc_position.PriceCurrent();
               double pos_open = mc_position.PriceOpen();
               double pos_stop = mc_position.StopLoss();
               double pos_take = mc_position.TakeProfit();
               modselsl=SetOrderSL(symbol,opstype,pos_open);
               if(price>modselsl) modselsl=mc_symbol.NormalizePrice(price+slip*pip);
               modseltp=SetOrderTP(symbol,opstype,pos_open);
               if(price<modseltp) modseltp=mc_symbol.NormalizePrice(price-slip*pip);
               //--
               if(pos_stop==0.0 || pos_take==0.0)
                 {
                   if(!mc_trade.PositionModify(position_symbol,modselsl,modseltp))
                     {
                       mc_trade.CheckResult(check);
                       Do_Alerts(symbol,"Set SL and TP for "+EnumToString(opstype)+" on "+symbol+" FAILED!!. Return code= "+
                                (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]");
                     }
                 }
             }
         }
     }
    //--
    return;
//---
  } //-end SetSLTPOrders
//---------//

2. Alle Aufträge schließen: Wenn ein Händler alle Aufträge schließen möchte, reicht ein einziger Klick auf die Schaltfläche „Close All Orders“ (Alle Aufträge schließen), um alle offenen Aufträge zu schließen.

void MCEA::CloseAllOrders(void) //-- function: close all order
   {
//----
    ResetLastError();
    //--
    MqlTradeRequest req={};
    MqlTradeResult  res={};
    MqlTradeCheckResult check={};
    //--
    int total=PositionsTotal(); // number of open positions
    //--- iterate over all open positions
    for(int i=total-1; i>=0; i--)
      {
        //--- if the MagicNumber matches
        if(mc_position.Magic()==magicEA)
          { 
            //--
            string position_Symbol   = PositionGetSymbol(i);  // symbol of the position
            ulong  position_ticket   = PositionGetTicket(i);  // ticket of the the opposite position
            ENUM_POSITION_TYPE  type = mc_position.PositionType();
            RefreshTick(position_Symbol);
            bool closepos = mc_trade.PositionClose(position_Symbol,slip);
            //--- output information about the closure
            PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type));
            //---
          }
      }
   //---
   return;
//----
   } //-end CloseAllOrders()
//---------//

3. Schließen der Positionen im Gewinn: Wenn ein Händler alle bereits profitablen Positionen schließen möchte, genügt ein einziger Klick auf die Schaltfläche „Close All Profitable Orders“, um alle offenen, bereits profitablen Positionen zu schließen.

bool MCEA::ManualCloseAllProfit(void)
   {
//----
    ResetLastError();
    //--
    bool orclose=false;
    //--
    MqlTradeRequest req={};
    MqlTradeResult  res={};
    MqlTradeCheckResult check={};
    //--
    int ttlorder=PositionsTotal(); // number of open positions
    //--
    for(int x=0; x<arrsymbx; x++)
       {
         string symbol=DIRI[x];
         orclose=false;
         //--
         for(int i=ttlorder-1; i>=0; i--)
            {
              string position_Symbol   = PositionGetSymbol(i);
              ENUM_POSITION_TYPE  type = mc_position.PositionType();
              if((position_Symbol==symbol) && (mc_position.Magic()==magicEA))
                {
                  double pos_profit = mc_position.Profit();
                  double pos_swap   = mc_position.Swap();
                  double pos_comm   = mc_position.Commission();
                  double cur_profit = NormalizeDouble(pos_profit+pos_swap+pos_comm,2);
                  ulong  position_ticket = PositionGetTicket(i);
                  //---
                  if(type==POSITION_TYPE_BUY && cur_profit>0.02)
                    {
                      RefreshTick(position_Symbol);
                      orclose = mc_trade.PositionClose(position_Symbol,slip);
                      //--- output information about the closure
                      PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type));
                    }
                  if(type==POSITION_TYPE_SELL && cur_profit>0.02)
                    {
                      RefreshTick(position_Symbol);
                      orclose = mc_trade.PositionClose(position_Symbol,slip);
                      //--- output information about the closure
                      PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type));
                    }
                }
            }
       }
     //--
     return(orclose);
//----
   } //-end ManualCloseAllProfit()
//---------//

Wenn die Schaltfläche C angeklickt wird, wird eine Schaltfläche mit 30 Symbolnamen oder -paaren angezeigt, und die Händler können auf einen der Paar- oder Symbolnamen klicken. Wenn Sie auf einen der Paarnamen oder ein Symbol klicken, wird das Chartsymbol sofort durch das Symbol ersetzt, auf dessen Namen Sie geklickt haben.

Expert, manuelle Schaltfläche 02

In diesem Fall wird in der Funktion OnChartEvent() der Befehl ChangeChartSymbol() aufgerufen, wenn einer der Symbolnamen angeklickt wird.

       //--- if Symbol button is click
       if(lensparam==lensymbol)
         {
           int sx=mc.ValidatePairs(sparam);
           ChangeChartSymbol(mc.AS30[sx],CCS);
           mc.PanelExtra=false;
         }
       //--
void ChangeChartSymbol(string c_symbol,ENUM_TIMEFRAMES cstf)
  {
//---
   //--- unpress the button 
   ObjectSetInteger(0,c_symbol,OBJPROP_STATE,false);
   ObjectSetInteger(0,c_symbol,OBJPROP_ZORDER,0);
   ObjectsDeleteAll(0,0,OBJ_BUTTON);
   ObjectsDeleteAll(0,0,OBJ_LABEL);
   ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL);
   //--
   ChartSetSymbolPeriod(0,c_symbol,cstf);
   //--
   ChartRedraw(0);
   //--
   return;
//---
  } //-end ChangeChartSymbol()
//---------//

Wenn Sie auf die Schaltfläche R klicken, wird der Multi-Currency Expert Advisor BBOnKeltnerChannel_MCEA aus dem Chart entfernt, sodass der Händler die Experten nicht manuell trennen muss.

   if(id==CHARTEVENT_OBJECT_CLICK) 
     {
       //--
       //--- if "R" button is click
       if(sparam=="R") 
         { 
           Alert("-- "+mc.expname+" -- ",Symbol()," -- Expert Advisor will be Remove from the chart.");
           ExpertRemove();
           //--- unpress the button 
           ObjectSetInteger(0,"R",OBJPROP_STATE,false);
           ObjectSetInteger(0,"R",OBJPROP_ZORDER,0);
           if(!ChartSetSymbolPeriod(0,Symbol(),Period()))
             ChartSetSymbolPeriod(0,Symbol(),Period());
           DeletePanelButton();
           ChartRedraw(0);
         }
       //---
     }

Strategietester

Wie Sie wissen, unterstützt das MetaTrader 5-Terminal Strategy Tester und ermöglicht es uns, Strategien zu testen, auf mehreren Symbolen zu handeln oder den automatischen Handel für alle verfügbaren Symbole und auf allen verfügbaren Zeitrahmen zu testen. Daher werden wir auf der MetaTrader 5 Strategy Tester Plattform einen BBOnKeltnerChannel_MCEA als Multi-Currency Expert Advisor testen.

In diesem Test haben wir den BBOnKeltnerChannel_MCEA auf das Paar XAGUSD und den Zeitrahmen H1 gelegt, mit einer nutzerdefinierten Zeitspanne von 2023.09.04 bis 2023.12.02.

ST Test--Zeitraum

Der Test wurde mit zwei verschiedenen Eingabeeigenschaften durchgeführt, und zwar in der Parametergruppe Trade & Order Management.

1. Standard-Eingabeeigenschaften.

ST_Standard-Eingabe 1

ST_Standard-Eingabe-Ergebnis

2. Nutzerdefinierte Eingabeeigenschaften.

ST_Custom-Input1

ST_Custom-Input-Ergebnis

Schlussfolgerung

Die Schlussfolgerung bei der Erstellung eines Multi-Currency Expert Advisors mit Signalen der Bollinger Bänder® und dem Keltner Kanal unter Verwendung von MQL5 ist wie folgt:

  1. Es stellt sich heraus, dass die Erstellung eines Multiwährungs-Expert Advisors in MQL5 sehr einfach ist und sich nicht wesentlich von der Erstellung eines Expert Advisors für eine einzelne Währung unterscheidet.
  2. Im Vergleich zur alten Plattform (MetaTrader 4) ist die Verwendung von Indikator-Handles in MQL5 zum Abrufen von Indikatorwerten und Signalen einfacher und bequemer.
  3. Die Erstellung eines Multi-Currency Expert Advisors erhöht die Effizienz und Effektivität von Händlern, da sie nicht mehr viele Chart-Symbole für den Handel öffnen müssen.
  4. Die Anwendung der richtigen Handelsstrategie erhöht die Gewinnwahrscheinlichkeit im Vergleich zur Verwendung eines einzelnen Währungsexperten. Das liegt daran, dass Verluste in einem Paar durch Gewinne in anderen Paaren ausgeglichen werden.
  5. Dieser BBOnKeltnerChannel_MCEA Multi-Currency Expert Advisor ist nur ein Beispiel zum Lernen und zur Ideenfindung. Die Testergebnisse des Strategietesters sind immer noch nicht gut. Daher ist es möglich, bessere und profitablere Ergebnisse zu erzielen, indem man mit verschiedenen Zeitrahmen oder Berechnungen für verschiedene Indikatorperioden experimentiert und testet.
  6. Die Testergebnisse des Strategy Testers von BBOnKeltnerChannel_MCEA zeigen, dass die Ergebnisse der nutzerdefinierten Eingabeparameter-Eigenschaften besser sind als die der Standard-Eingabeparameter-Eigenschaften.

Wir hoffen, dass dieser Artikel und das MQL5 Multi-Currency Expert Advisor Programm für Händler nützlich sein werden, um zu lernen und Ideen zu entwickeln.

Danke fürs Lesen.

Anmerkung: Wenn Sie eine Idee für die Erstellung eines einfachen Mehr-Währungs-EA auf der Grundlage der eingebauten MQL5-Standardindikatoren haben, schlagen Sie sie bitte in den Kommentaren vor.

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/13861

Letzte Kommentare | Zur Diskussion im Händlerforum (13)
Roberto Jacobs
Roberto Jacobs | 10 Jan. 2024 in 06:19
hdhyxiaobin #:

Hallo Roberto, ich habe die beiden vom EA benötigten Indikatoren in den Chart geladen, aber der EA meldet immer noch, dass diese beiden Indikatoren nicht geöffnet werden können.

siehe Anhang

Danke

automatische Übersetzung durch einen Moderator

Wie auf dem von Ihnen zur Verfügung gestellten Bild zu sehen ist, ist der von Ihnen verwendete Dateiname des Keltner-Kanal-Indikators falsch.
Bitte beachten Sie den Unterschied in den Dateinamen der Indikatoren.

6a1p_20240109203550_ed

falscher_dateiname


Sie verwenden andere Indikatoren als die, die von den Expertenberatern benötigt werden.

hdhyxiaobin
hdhyxiaobin | 13 Jan. 2024 in 03:32
Roberto Jacobs #:

Wie auf dem von Ihnen zur Verfügung gestellten Bild zu sehen ist, ist der von Ihnen verwendete Dateiname des Keltner-Kanal-Indikators falsch.
Bitte sehen Sie sich den Unterschied zwischen den Dateinamen der Indikatoren an.


Sie verwenden andere Indikatoren als die, die von den Expertenberatern benötigt werden.

hallo roberto
habe den Indikatornamen geändert und der EA läuft gut

aber viele Aufträge für ein Symbol öffnen

Roberto Jacobs
Roberto Jacobs | 13 Jan. 2024 in 11:41
hdhyxiaobin #:

hallo roberto
habe den Indikatornamen geändert und EA läuft OK

aber viele Aufträge für ein Symbol öffnen

Vielleicht verstehen Sie nicht oder wissen nicht, dass es im Internet viele Versionen des Keltner Channel Indikators gibt.

Haben Sie meine Erklärung im Artikel gelesen, oder haben Sie einfach das EA-Programm heruntergeladen.

In Teil 2. Signalindikatoren, habe ich erklärt:
"Den Keltner-Kanal-Indikator, der in diesem Artikel für Expert Advisors verwendet wird, habe ich speziell mit einer Methode erstellt, die heute sehr beliebt ist, nämlich dem Exponential Moving Average (EMA) Periode 20 mit oberen und unteren Bändern unter Verwendung des ATR-Indikators Periode 20."

Hoffen Sie also nicht, dass der EA durch die Umbenennung des Indikators korrekt funktionieren wird, denn verschiedene Indikatoren haben unterschiedliche Eingabeparameter und Berechnungen.

Wenn Sie den Keltner-Kanal-Indikator nicht verwenden, den ich speziell für den Bollinger Bands® On Keltner Channel EA erstellt habe, sollten Sie nicht erwarten, dass Sie den Bollinger Bands® On Keltner Channel EA verwenden können.

navtrack1959
navtrack1959 | 22 Feb. 2024 in 19:29

Hallo Roberto,

Du hast eine tolle Arbeit geleistet! Ich hoffe, ich kann es auf meinem PC zum Laufen bringen.

Ich habe die folgende Meldung: Keltner Channel.ex5 open error und andere folgen.

Natürlich kein Ergebnis auf dem Testgerät.

Ich danke Ihnen für Ihre Hilfe.

Alain

Roberto Jacobs
Roberto Jacobs | 23 Feb. 2024 in 12:30
navtrack1959 #:

Hallo Roberto,

Du hast eine tolle Arbeit geleistet! Ich hoffe, ich kann es auf meinem PC zum Laufen bringen.

Ich habe die folgende Meldung: Keltner Channel.ex5 open error und weitere werden folgen.

Natürlich, kein Ergebnis auf dem Tester.

Ich danke Ihnen für Ihre Hilfe.

Alain

Hallo,

Mein Expert Advisor heißt BBOnKeltnerChannel_MCEA, NICHT Multi-Currency BB-Keltner (auf dem Bild, das Sie mir per E-Mail geschickt haben, heißt der EA Multi-Currency BB-Keltner)
. Der Name des Indikators, den ich speziell für BBOnKeltnerChannel_MCEA erstellt habe, ist Keltner Channel.mq5 (siehe und laden Sie den Anhang zu diesem Artikel herunter)

Es gibt viele Versionen des Keltner Channel Indikators im Internet.
Achten Sie bitte genau auf den Dateinamen und die Eingabe der Eigenschaften in Indikatoren und Experten, da hier zwischen Groß- und Kleinschreibung unterschieden wird.
Wenn die eingegebenen Eigenschaften nicht übereinstimmen, wird das Programm nicht ausgeführt.

Wenn Sie das EA-Programm ändern und ein Fehler auftritt, sollten Sie nicht mich fragen.

Alle Programme in MQL5 wurden von dem dafür zuständigen Moderator validiert. Wenn sie die Validierung nicht bestehen, ist es unmöglich, dass ein Programm von MQL5 veröffentlicht wird.

Entwurfsmuster in der Softwareentwicklung und MQL5 (Teil 3): Verhaltensmuster 1 Entwurfsmuster in der Softwareentwicklung und MQL5 (Teil 3): Verhaltensmuster 1
Ein neuer Artikel aus der Reihe der Artikel über Entwurfmuster. Wir werden einen Blick auf einen seiner Typen werfen, nämlich den Verhaltensmuster, um zu verstehen, wie wir Kommunikationsmethoden zwischen erstellten Objekten effektiv aufbauen können. Durch die Vervollständigung dieser Verhaltensmuster werden wir in der Lage sein zu verstehen, wie wir eine wiederverwendbare, erweiterbare und getestete Software erstellen und aufbauen können.
Modifizierter Grid-Hedge EA in MQL5 (Teil I): Erstellung eines einfachen Hedge EA Modifizierter Grid-Hedge EA in MQL5 (Teil I): Erstellung eines einfachen Hedge EA
Wir werden einen einfachen Hedge EA als Basis für unseren fortgeschritteneren Grid-Hedge EA erstellen, der eine Mischung aus klassischen Grid- und klassischen Hedge-Strategien sein wird. Am Ende dieses Artikels werden Sie wissen, wie Sie eine einfache Hedge-Strategie erstellen können, und Sie werden auch erfahren, was die Leute darüber sagen, ob diese Strategie wirklich zu 100 % profitabel ist.
Wie man einen einfachen Multi-Currency Expert Advisor mit MQL5 erstellt (Teil 4): Triangulärer gleitender Durchschnitt — Indikatorensignale Wie man einen einfachen Multi-Currency Expert Advisor mit MQL5 erstellt (Teil 4): Triangulärer gleitender Durchschnitt — Indikatorensignale
Der Multi-Currency Expert Advisor in diesem Artikel ist ein Expert Advisor oder Handelsroboter, der mehr als nur ein Symbolpaar von dessen Symbolchart handeln kann (Aufträge öffnen, schließen und verwalten oder zum Beispiel Trailing Stop Loss und Trailing Profit). Dieses Mal werden wir nur 1 Indikator verwenden, nämlich den Triangulären gleitenden Durchschnitt in Multi-Timeframes oder Single-Timeframes.
Kombinatorisch symmetrische Kreuzvalidierung in MQL5 Kombinatorisch symmetrische Kreuzvalidierung in MQL5
In diesem Artikel stellen wir die Implementierung der kombinatorisch symmetrischen Kreuzvalidierung in reinem MQL5 vor, um den Grad der Überanpassung nach der Optimierung einer Strategie unter Verwendung des langsamen vollständigen Algorithmus des Strategietesters zu messen.