English Русский 中文 Español 日本語 Português
preview
Wie man einen einfachen Multi-Currency Expert Advisor mit MQL5 erstellt (Teil 1): Indikatorsignale basierend auf ADX in Kombination mit Parabolic SAR

Wie man einen einfachen Multi-Currency Expert Advisor mit MQL5 erstellt (Teil 1): Indikatorsignale basierend auf ADX in Kombination mit Parabolic SAR

MetaTrader 5Beispiele | 28 September 2023, 10:33
503 0
Roberto Jacobs
Roberto Jacobs

Einführung

Die Definition eines Multi-Currency Expert Advisors in diesem Artikel bezeichnet einen Expert Advisor oder Handelsroboter, der für mehr als ein Symbolpaar von nur einem Symbolchart aus handeln kann (Positionen eröffnen, schließen, verwalten und mehr).

Der Bedarf und das Interesse an Handelsautomatisierungssystemen oder Handelsrobotern mit Mehrwährungssystemen ist derzeit sehr groß, aber wir sehen, dass die Implementierung von Mehrwährungssystemprogrammen auf automatisierten MQL5-Handelsrobotern noch nicht weithin veröffentlicht wurde oder von vielen Programmierern noch geheim gehalten wird.

Daher ist das Ziel, die wesentlichen Bedürfnisse der Händler, die effiziente und effektive Handelsroboter wollen zu erfüllen, sodass durch den Rückgriff auf die Stärken, Fähigkeiten und Einrichtungen, die von der sehr zuverlässigen MQL5, können wir eine einfache Multi-Currency Expert Advisor, die in diesem Artikel verwendet Indicator Signals erstellen: Average Directional Movement in Kombination mit dem Parabolic SAR Indicator.


Pläne und Merkmale

1. Handel mit Währungspaaren.

Dieser Multi-Currency Expert Advisor ist für den Handel mit einem der folgenden Symbole oder Paare vorgesehen:

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.

Alle diese Symbole oder Paare sind Symbole oder Paare, die üblicherweise von Brokern verwendet werden. Daher funktioniert dieser Multi-Currency Expert Advisor nicht mit Brokern, deren Symbol- oder Paarnamen Präfixe oder Suffixe enthalten.


2. Signalindikatoren.

Der Multi-Currency Expert Advisor wird 2 Indikatorsignale verwenden: 1. Average Directional Movement (ADX) Indikator mit einer Periodenlänge von 7 als Hauptsignal; und 2. den Parabolic SAR-Indikator, zur Trendbestätigung.

Die beiden Hauptindikatoren verwenden denselben Zeitrahmen, der in der Experteneigenschaft angegeben ist, und der Parabolic SAR-Indikator wird nicht nur zur Erkennung der Stärke oder Schwäche eines Trends, sondern auch mit den Zeitrahmen M15 und M5 verwendet.

ADX-Signale Bedingung Strategie Formel: iADX

UP   = (+DI[2] <= -DI[2]) && (+DI[1] > -DI[1]+Differenz) && (+DI[0] > +DI[1]) && ((+DI[0]/-DI[0]) > (+DI[1]/-DI[1]))

DOWN = (+DI[2] >= -DI[2]) && (+DI[1] < -DI[1]-Differenz) && (+DI[0] < +DI[1]) && ((+DI[0]/-DI[0]) < (+DI[1]/-DI[1]))

Wobei die Differenz = 0,34 ist:

(+DI[1] > -DI[1]+0.34) = Kaufsignal true;   

(+DI[1] < -DI[1]-0.34) = Verkaufssignal true;     

Der Prozentsatz des aktuellen Balkens von PLUSDI_LINE dividiert durch den aktuellen Balken von MINUSDI_LINE 

im Vergleich zu   

Der Prozentsatz des vorherigen Balkens PLUSDI_LINE geteilt durch den vorherigen Balken MINUSDI_LINE

(+DI[0]/-DI[0]) = V0 = (Aktueller Balken PLUSDI_LINE / Aktueller Balken MINUSDI_LINE x 100) - 100;

(+DI[1]/-DI[1]) = V1 = (Vorheriger Balken PLUSDI_LINE /Vorheriger Balken MINUSDI_LINE x 100) - 100;

   Dann:

IF V0 > V1 = ADX-Bedingungsprozentwert = Anstieg

IF V0 < V1 = ADX-Bedingungsprozentwert = Abwärts


Parabolische SAR-Signale Bedingungsstrategie: Parabolisches Stop-and-Reverse-System (iSAR)

iSAR UP      = PRICE_LOW[0] > iSAR[0]

iSAR DOWN = PRICE_HIGH[0] < iSAR[0]


Eine Illustration des iADX-Signals in Kombination mit iSAR ist in Abbildung 1 zu sehen.

Abbildung 1. Indikatoren Signal


3. Handels- & Auftragsmanagement

Das Handelsmanagement dieses Multi-Currency Expert Advisors verfügt über mehrere Optionen:

1. Stop-Loss-Aufträge

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

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

                Bei der Option Use Order Stop Loss (Yes), gibt es eine weitere Option: Use Automatic Calculation Stop Loss (Yes) oder (No) (Automatische Berechnung des Stop Loss verwenden, Ja oder Nein).

                Bei der Option Automatic Calculation Stop Loss (Yes), 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): gewählt wird, prüft der Experte für jede geöffnete Order, ob die Signalbedingung noch gut ist und der Auftrag.

                kann in einer Gewinnsituation gehalten werden, ODER das Signal hat sich abgeschwächt und der Auftrag muss geschlossen werden, um den Gewinn zu sichern,

                oder das Signal hat seine Richtung umgekehrt und die Position muss mit einem Verlust geschlossen werden.

               

2. Take-Profit-Aufträge

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

                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) gibt es die weitere Option: 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.


3. Trailing Stop und Trailing Take-Profit

   Optionen: Use Trailing SL/TP (Yes) oder (No) (Nachlaufenden SL/TP verwenden)

                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) gibt es weitere Optionen: Use Automatic Trailing (Yes) oder (No) (Automatisches Nachziehen verwenden, Ja oder Nein).

                Wenn die Option Use Automatic Trailing (Yes) aktiviert ist, wird der Trailing-Stop vom Experten anhand des Parabolic SAR-Wertes ausgeführt.

                Bei der Option Use Automatic Trailing (No) 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.


4. Manuelle Auftragsverwaltung.

Um die Effizienz in diesem Multi-Currency Expert Advisor zu unterstützen, werden mehrere manuelle Klick-Buttons hinzugefügt

   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 werden mit einem einzigen Klick auf die Schaltfläche „Set SL / TP All Orders“ alle Aufträge

       geändert und ein Stop-Loss gesetzt und/oder Gewinne mitgenommen werden.


   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.


   3. Close All Orders Profit (Alle Aufträge im Gewinn schließen)

       Wenn ein Händler alle Aufträge, die bereits profitabel sind, mit einem einzigen Klick auf die Schaltfläche „Close All Orders Profit“ schließen möchte, dann

       werden alle offenen Aufträge, die bereits im Gewinn sind, geschlossen.


5. Tabelle mit Verwaltungsanweisungen und Symbolen.

Für Multi-Currency Expert Advisors, die 30 Paare mit nur einem Chart-Symbol handeln, ist es sehr effektiv und effizient, wenn eine Schalttafel für alle Symbole vorhanden ist, sodass Händler Charts oder Symbole mit nur einem Klick wechseln können.


Umsetzung der Planung im Programm MQL5

1. Programmkopf und die Eingabeeigenschaften des Experten.

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;
//---


Die Enumeration YN wird für die Optionen (Yes) oder (No) in der Eingabeeigenschaft des Experten verwendet.

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


Die Enumeration zur Bestimmung der Losgröße

enum mmt
  {
   FixedLot,     // Fixed Lot Size
   DynamLot    // Dynamic Lot Size
  };
//--


Enumeration der Zeitrahmen für die Berechnung des Expertensignals

enum TFX
  {
   TFH1,     // PERIOD_H1
   TFH2,     // PERIOD_H2
   TFH3,     // PERIOD_H3
   TFH4,     // PERIOD_H4
   TFH6,     // PERIOD_H6
   TFH8,     // PERIOD_H8
   TFH12,    // PERIOD_H12
   TFD1      // PERIOD_D1
  };
//--


Eingabeeigenschaften des Experten

//---
input group               "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter
input TFX             TimeFrames = TFH4;             // Select Expert TimeFrame, default PERIOD_H4
input int              ADXPeriod = 7;                // Input ADX Period
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
//--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 = No;               // Use Order Take Profit (Yes) or (No)
input YN                  autotp = Yes;              // Use Automatic Calculation Take Profit (Yes) or (No)
input double               TPval = 50;               // If Not Use Automatic TP - Input TP value in Pips
input YN            TrailingSLTP = Yes;              // Use Trailing SL/TP (Yes) or (No)
input YN                 autotrl = No;               // 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 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 = 202307;          // Expert ID (Magic Number)
//---


Um alle Variablen, Objekte und Funktionen zu deklarieren, die in diesem Multi-Currency Expert Advisor benötigt werden, werden wir eine Klasse erstellen, um den Aufbau und die Konfiguration im Expert Advisor Workflow zu spezifizieren.

//+------------------------------------------------------------------+
//| 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;
   int               posCur1,
                     posCur2;
   //--
   double            LotPS,
                     difDi;
   double            slv,
                     tpv,
                     pip,
                     xpip;
   double            floatprofit,
                     fixclprofit;
   double            ADXDIp[];
   double            ADXDIm[];
   //--
   string            pairs,
                     hariini,
                     daytrade,
                     trade_mode;
   //--
   double            OPEN[],
                     HIGH[],
                     LOW[],
                     CLOSE[];
   datetime          TIME[];
   datetime          closetime;
   //--
   //------------

   //------------
   int               iADXCross(const string symbol);
   int               iADXpct(const string symbol,const int index);
   int               PARSAR05(const string symbol);
   int               PARSAR15(const string symbol);
   int               PARSAROp(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:
   //---

   //-- ADXPSAR_MCEA Config --
   string            DIRI[],
                     AS30[];
   string            expname;
   int               handADX[];
   int               hParOp[],
                     hPar15[],
                     hPar05[];
   int               ALO,
                     dgts,
                     arrsymbx;
   int               sall,
                     arper;
   ulong             slip;
   ENUM_TIMEFRAMES   TFt,
                     TFT15,
                     TFT05;
   //--
   double            SARstep,
                     SARmaxi;
   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)
   //------------
                     MCEA(void);
                    ~MCEA(void);
   //------------
   //--
   virtual void      ADXPSAR_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               GetOpenPosition(const string symbol);
   int               DirectionMove(const string symbol);
   int               GetCloseInWeakSignal(const string symbol,int exis);
   int               CheckToCloseInWeakSignal(const string symbol,int exis);
   int               ThisTime(const int reqmode);
   //--
   string            getUninitReasonText(int reasonCode);
   //--
   //------------
   //---
  }; //-end class MCEA
//---------//


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

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


In der Funktion ADXPSAR_MCEA_Config() werden alle zu verwendenden Symbole, alle verwendeten Handle-Indikatoren und einige wichtige Funktionen des Include-Dateikopfes für den Expert Advisor Workflow konfiguriert.

//+------------------------------------------------------------------+
//| Expert Configuration                                             |
//+------------------------------------------------------------------+
void MCEA::ADXPSAR_MCEA_Config(void)
  {
//---
//-- Here we will register all the symbols or pairs that will be used on the Multi-Currency Expert Advisor
//--
   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
//--
   sall=ArraySize(All30);
   ArrayResize(AS30,sall,sall);
//-- These AS30[] arrays will be used in the symbol list panel and for the buttons to change symbols and charts
   ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY);
//--
   arrsymbx=sall;
   ArraySymbolResize();
   ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY); //-- The "DIRI[]" array containing the symbol or pair name will be used
//-- in all trading activities of the multi-currency expert
//--
//-- This function is for Select all symbol in the Market Watch window
   for(int x=0; x<arrsymbx; x++)
     {
      SymbolSelect(DIRI[x],true);
     }
   pairs="Multi Currency 30 Pairs";
//---
//-- Here we will provide a Period Timeframe value which will be used for signal calculations according
//-- to the Timeframe option on the expert input property.
   ENUM_TIMEFRAMES TFs[]= {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(x==TimeFrames)
        {
         TFt=TFs[x];
         break;
        }
     }
//--
//-- Indicators handle for all symbol
   for(int x=0; x<arrsymbx; x++)
     {
      handADX[x]=iADX(DIRI[x],TFt,ADXPeriod);         //-- Handle for the iADX indicator according to the selected Timeframe
      hParOp[x]=iSAR(DIRI[x],TFt,SARstep,SARmaxi);    //-- Handle for the iSAR indicator according to the selected Timeframe
      hPar15[x]=iSAR(DIRI[x],TFT15,SARstep,SARmaxi);  //-- Handle for the iSAR indicator for M15 Timeframe
      hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi);  //-- Handle for the iSAR indicator for M5 Timeframe
     }
//--
//-- Since this expert advisor is a multi-currency expert, we must check the maximum number
//-- of account limit orders allowed by the broker.
//-- This needs to be checked, so that when the expert opens an order there will be
//-- no return codes of the trade server error 10040 = TRADE_RETCODE_LIMIT_POSITIONS
   ALO=(int)mc_account.LimitOrders()>arrsymbx ? arrsymbx : (int)mc_account.LimitOrders();
//--
//-- The LotPS variable will later be used for the proportional distribution of Lot sizes for each symbol
   LotPS=(double)ALO;
//--
   mc_trade.SetExpertMagicNumber(magicEA); //-- Set Magic Number as expert ID
   mc_trade.SetDeviationInPoints(slip);    //-- Set expert deviation with slip variable value
   mc_trade.SetMarginMode();               //-- Set the Margin Mode expert to the value of Account Margin Mode
//--
   return;
//---
  } //-end ADXPSAR_MCEA_Config()
//---------//


2. Experten-Tick-Funktion

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

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


Die Funktion ExpertActionTrade() führt alle Aktivitäten aus und verwaltet den automatischen Handel, angefangen bei Eröffnen und Schließen der Positionen, den Trailing Stops oder Trailing Profits und anderen zusätzlichen Aktivitäten.

Der Ablauf des Arbeitsprozesses ist wie folgt, wie ich am Rande des Programms erklärt habe.

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
    //--
    //-- The functions below will be displayed on the expert chart according to
    //-- the Select Display Trading Info on Chart (Yes) or (No) option on expert property.
    //--
    if(trade_info_display==Yes)
       mc.TradeInfo(); //-- Displayed Trading Info on Chart
//--
    //--
    if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart
    //---
    //-- Because the current prices of a specified symbol (SymbolInfoTick) will occur differently
    //-- for each symbol, we reduce the tick update frequency to only every 5 seconds.
    //-- So, looping to check the signal for all trading activity of all symbols will only be done every 5 seconds.
    //--
    int mcsec=mc.ThisTime(mc.sec);
    //-- With the function ThisTime(mc.sec), we will retrieve the current seconds value to mcsec variable.
    //--
    //-- MathMod is a formula that gives the (modulus) real remainder after the division of two numbers.
    //-- By dividing the value of seconds with the value of 5.0, if the result is 0, it means that 5 seconds
    //-- have been reached from the previous psec variable seconds value.
    //--
    if(fmod((double)mcsec,5.0)==0)
       mc.ccur=mcsec;
    //--
    if(mc.ccur!=mc.psec) //-- So, if the seconds value in the ccur variable is not the same as the psec variable value
        {
         //-- (then the psec variable value already 5 seconds before)
         string symbol;
         //-- Here we start with the rotation of the name of all symbol or pairs to be traded
         //-- This is the basic framework for the automated trading workflow of this Multi-Currency Expert Advisor
         //-- Here we start with the rotation of the name of all symbol or pairs to be traded
         //-- This is the basic framework for the automated trading workflow of this Multi-Currency Expert Advisor
         for(int x=0; x<mc.arrsymbx && !IsStopped(); x++) 
           {
             //--
             if(mc.DIRI[x]==Symbol())
                symbol=Symbol();
             else
                symbol=mc.DIRI[x];
             //-- After the symbol or pair name is set, we declare or notify the symbol to MarketWatch
             //-- and the trade server by calling the CurrentSymbolSet(symbol) function.
             mc.CurrentSymbolSet(symbol);
             //--
             if(mc.TradingToday()) //-- The TradingToday() function checks whether today is allowed for trading
               {                   //-- If today is not allowed for trading, then the Expert will only perform management
                                   //-- orders such as trailing stops or trailing profits and closing orders.
                 //-- according to the expert input property Day Trading On/Off group
                 //-- If TradingToday() == Yes, then the next process is to call the function ThisTime(mc.sec)
                 //--
                 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 it turns out that the "Sell Order" has been opened,
                     //-- and Close Trade By Opposite Signal according to the input property is (Yes),
                     //-- then call the function CloseSellPositions(symbol) to close the sell order on that 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); //-- Open BUY order for this symbol
                     else
                     //-- OR
                     //-- If Close Trade and Save profit due to weak signal according to the input property is (Yes)
                     //-- then call the CloseAllProfit() function to close all orders
                     //-- who are already in profit.
                     //--
                     if(mc.xtto>=mc.ALO)
                       {
                         //-- If the total number of orders is greater than or equal
                         //-- to the account limit orders allowed by the broker, then turn on alerts
                         //--
                         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); //-- Call the CheckOpenPMx(symbol) function
                         //--
                         //-- If it turns out that the "Sell Order" has been opened,
                         //-- and the condition of the Sell order has lost more than 1.02 USD,
                         //-- and the "Buy Order" has not been opened, then call CloseSellPositions(symbol)
                         //-- to close "Sell order" and open "Buy order".
                         if(mc.xos[x]>0 && mc.profits[x]<-1.02 && mc.xob[x]==0)
                           {
                            mc.CloseSellPositions(symbol);
                            mc.OpenBuy(symbol);
                           }
                         else
                         //-- OR
                         //-- If Close Trade and Save profit due to weak signal according to the input property is (Yes)
                         //-- then call the CloseAllProfit() function to close all orders
                         //-- who are already in profit.
                         //--
                         if(SaveOnRev==Yes)
                            mc.CloseAllProfit();
                       }
                   }
                 if(mc.OpOr[x]==mc.Sell) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Sell" (value=-1)
                   {
                     //--
                     //-- Call the CheckOpenPMx(symbol) function to check whether there are
                     //-- already open "Buy" or "Sell" orders or no open orders.
                     //--
                     mc.CheckOpenPMx(symbol);
                     //--
                     //-- If it turns out that the "Buy Order" has been opened,
                     //-- and Close Trade By Opposite Signal according to the input property is (Yes),
                     //-- then call the function CloseBuyPositions(symbol) to close the buy order on that symbol.
                     //--
                     if(Close_by_Opps==Yes && mc.xob[x]>0)
                        mc.CloseBuyPositions(symbol);
                     //--
                     //-- The algorithm below means that the expert will only open 1 order per symbol,
                     //-- provided that the total number of orders is still less than
                     //-- the account limit orders allowed by the broker.
                     //--
                     if(mc.xos[x]==0 && mc.xtto<mc.ALO) mc.OpenSell(symbol);  //-- Open SELL order for this symbol
                     else
                     if(mc.xtto>=mc.ALO)
                       {
                         //-- If the total number of orders is greater than or equal
                         //-- to the account limit orders allowed by the broker, then turn on alerts
                         //--
                         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); //-- Call the CheckOpenPMx(symbol) function
                         //--
                         //-- If it turns out that the "Buy Order" has been opened,
                         //-- and the condition of the Buy order has lost more than 1.02 USD,
                         //-- and the "Sell Order" has not been opened, then call CloseBuyPositions(symbol)
                         //-- to close "Buy order" and open "Sell order".
                         if(mc.xob[x]>0 && mc.profitb[x]<-1.02 && mc.xos[x]==0)
                           {
                             mc.CloseBuyPositions(symbol);
                             mc.OpenSell(symbol);
                           }
                         else
                         //-- OR
                         //-- If Close Trade and Save profit due to weak signal according to the input property is (Yes)
                         //-- then call the CloseAllProfit() function to close all orders
                         //-- who are already in profit.
                         //--
                         if(SaveOnRev==Yes)
                            mc.CloseAllProfit();
                       }
                   }
                 //--
                 mc.CheckOpenPMx(symbol);
                 //-- The algorithm block below will check whether there is a weakening of the signal on Buy or Sell positions.
                 //-- If it is true that there is a weakening signal and the iSAR indicator has reversed direction,
                 //-- then close the losing order and immediately opened an order in the opposite direction.
                 //--
                 if(mc.xob[x]>0 && mc.CheckToCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) {mc.CloseBuyPositions(symbol); mc.OpenSell(symbol);}
                 if(mc.xos[x]>0 && mc.CheckToCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) {mc.CloseSellPositions(symbol); mc.OpenBuy(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(mc.xob[x]>0 && mc.CheckToCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) mc.CloseBuyPositions(symbol);
                     if(mc.xos[x]>0 && mc.CheckToCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) mc.CloseSellPositions(symbol);
                   }
                 //--
                 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)
                   }
               }
             //--
             //-- Check if there are orders that were closed in the last 6 seconds.
             //-- If there are give alerts.
             mc.CheckClose(symbol);
           }
        //-- replace the value of the psec variable with the value of the ccur variable.
        mc.psec=mc.ccur;
      }
    //--
    return;
//---
  } //-end ExpertActionTrade()
//---------//


3. Wie erhalte ich Handelssignale für das Öffnen oder Schließen von Positionen?

Um das Indikatorsignal zu erhalten, müssen wir die Funktion GetOpenPosition(Symbol) aufrufen, um ein Handelssignal für die offene Position zu erhalten

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int MCEA::GetOpenPosition(const string symbol) // Signal Open Position
  {
//---
   int ret=0;
   int rise=1,
       down=-1;
//--
   int dirmov=DirectionMove(symbol);
   int pars15=PARSAR15(symbol);
   int parsOp=PARSAROp(symbol);
   int sigADX=iADXCross(symbol);
//--
   if(sigADX==rise && parsOp==rise && dirmov==rise && pars15==rise)
      ret=rise;
   if(sigADX==down && parsOp==down && dirmov==down && pars15==down)
      ret=down;
//--
   return(ret);
//---
  } //-end GetOpenPosition()
//---------//


Die Funktion GetOpenPosition() ruft 4 Signalfunktionen auf und speichert sie in der Variablen OpOr[].

1. DirectionMove(symbol); //-- Funktion, die prüft die Bewegungsrichtung der Preise des Balkens des Experten.

2. PARSAR15(symbol); //-- Funktion zur Überprüfung, ob der Zustand des iSAR-Indikators im Zeitraum M15 steigt oder fällt

3. PARSAROp(symbol); //-- Funktion zur Überprüfung, ob der Zustand des iSAR-Indikators im Zeitrahmen des Experten steigt oder fällt

4. iADXCross(symbol); //-- Funktion zur Überprüfung, ob der Zustand des iADX-Indikators im Zeitrahmen des Experten steigt oder fällt


In der Funktion iADXCross(symbol) wird dann die Funktion iADXpct() aufgerufen, um die prozentuale Bewegung zwischen +DI und -DI zu prüfen, wie im Abschnitt Signalindikatoren beschrieben.

Um den Zustand des Indikators zu ermitteln, müssen wir in den 4 Funktionen PARSAR15(Symbol), PARSAROP(Symbol), iADXCross(Symbol) und iADXpct() die Indexnummer jedes erforderlichen Indikator-Handles ermitteln.

Um die Indexnummer des Indikatorgriffs zu erhalten, rufen wir die Funktion PairsIdxArray(Symbol) mit Hilfe von 

int x=PairsIdxArray(symbol);

Der x-Wert ist die Indexnummer des Indikatorhandles des betreffenden Symbols.

Im Beispiel der Funktion PARSAR15() sehen wir, wie man das iSAR-Indikator-Handle für das betreffende Symbol aufruft.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int MCEA::PARSAR15(const string symbol) // formula Parabolic SAR M15
  {
//---
   int ret=0;
   int rise=1,
       down=-1;
   int br=2;
//--
   double PSAR[];
   ArrayResize(PSAR,br,br);
   ArraySetAsSeries(PSAR,true);
   int xx=PairsIdxArray(symbol);
   CopyBuffer(hPar15[xx],0,0,br,PSAR);
//--
   RefreshPrice(symbol,TFT15,br);
   double HIG0=iHigh(symbol,TFT15,0);
   double LOW0=iLow(symbol,TFT15,0);
//--
   if(PSAR[0]<LOW0)
      ret=rise;
   if(PSAR[0]>HIG0)
      ret=down;
//--
   return(ret);
//---
  } //-end PARSAR15()
//---------//


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, 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/TP 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); //-- Button state (depressed button)
         ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_ZORDER,0);    //-- Priority of a graphical object for receiving events
         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); //-- Button state (depressed button)
         ObjectSetInteger(0,"Close All Order",OBJPROP_ZORDER,0);    //-- Priority of a graphical object for receiving events
         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); //-- Button state (depressed button)
         ObjectSetInteger(0,"Close All Profit",OBJPROP_ZORDER,0);    //-- Priority of a graphical object for receiving events
         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); //-- Button state (depressed button)
         ObjectSetInteger(0,"X",OBJPROP_ZORDER,0);    //-- Priority of a graphical object for receiving events
         //--
         DeleteButtonX();
         mc.PanelExtra=false;
         DisplayManualButton();
        }
      //--- if "M" button is click
      if(sparam=="M")
        {
         //--- unpress the button
         ObjectSetInteger(0,"M",OBJPROP_STATE,false); //-- Button state (depressed button)
         ObjectSetInteger(0,"M",OBJPROP_ZORDER,0);    //-- Priority of a graphical object for receiving events
         mc.PanelExtra=true;
         CreateManualPanel();
        }
      //--- if "C" button is click
      if(sparam=="C")
        {
         //--- unpress the button
         ObjectSetInteger(0,"C",OBJPROP_STATE,false); //-- Button state (depressed button)
         ObjectSetInteger(0,"C",OBJPROP_ZORDER,0);    //-- Priority of a graphical object for receiving events
         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); //-- Button state (depressed button)
         ObjectSetInteger(0,"R",OBJPROP_ZORDER,0);    //-- Priority of a graphical object for receiving events
         if(!ChartSetSymbolPeriod(0,Symbol(),Period()))
            ChartSetSymbolPeriod(0,Symbol(),Period());
         DeletePanelButton();
         ChartRedraw(0);
        }
      //--- if Symbol name button is click
      if(lensparam==lensymbol)
        {
         int sx=mc.PairsIdxArray(sparam);
         ChangeChartSymbol(mc.AS30[sx],CCS);
        }
      //--
     }
//--
   return;
//---
  } //-end OnChartEvent()
//---------//


Die Oberfläche des Multi-Currency Expert Advisor sieht wie in der folgenden Abbildung aus.

ADXPSAR_MCEA


Schaltfläche des Experten zur manuellen Bedienung

Expert Manual-Taste

Wenn die Schaltfläche M angeklickt wird, wird ein manuelles Schaltflächenfeld angezeigt (siehe unten).

Experte_Schaltfläche_01

Damit kann der Händler die Aufträge verwalten:

1. Set SL/TP All Orders (SL/TP für alle Aufträge einstellen)

2. Close All Orders (Alle Aufträge schließen)

3. Close All Profits (Alle Aufträge mit Gewinn schließen)


Wenn die Schaltfläche C angeklickt wird, wird eine Schaltfläche mit 30 Symbolnamen oder -paaren angezeigt, wie unten dargestellt

Experte_Schaltfläche_02

Wird einer der Namen des Paars oder der Symbole angeklickt, wird das Chartsymbol sofort durch das Symbol ersetzt, dessen Name angeklickt wurde.

Wenn Sie auf die Schaltfläche R klicken, wird der Multi-Currency Expert Advisor ADXPSAR_MCEA aus dem Chart entfernt.



Strategie-Tester

Es ist bekannt, dass der Strategy Tester des MetaTrader 5 Terminals das Testen von Strategien, den Handel mit mehreren Symbolen oder das Testen des automatisierten Handels für alle verfügbaren Symbole bereits unterstützt und ermöglicht.

Die Handelsstrategien mehrerer Währungen testen

Bei dieser Gelegenheit werden wir den ADXPSAR_MCEA Multi-Currency Expert Advisor auf den Plattformen des Strategy Tester MetaTrader 5 testen.

Strategie-Tester Ergebnis

Saldo Eigenkapital


Eröffnungen (Entries)


Korrelation


Minimale Position


Schlussfolgerung

Wie ich oben geschrieben habe, bin ich zu dem Schluss gekommen, dass die Erstellung eines Multi-Currency Expert Advisor mit MQL5:

  • Es stellt sich heraus, dass die Erstellung eines Multi-Currency Expert Advisor in MQL5 sehr einfach ist und sich nicht wesentlich von einem Single-Currency Expert Advisor unterscheidet.
  • Die Erstellung eines Multi-Currency Expert Advisors erhöht die Effizienz und Effektivität von Händlern, da sie nicht viele Chart-Symbole für den Handel öffnen müssen.
  • Durch die Anwendung der richtigen Handelsstrategie und die Berechnung besserer Indikatorsignale erhöht sich die Gewinnwahrscheinlichkeit im Vergleich zur Verwendung eines Single-Currency Expert Advisors. Denn die Verluste, die bei einem Paar auftreten, werden durch Gewinne bei anderen Paaren ausgeglichen.
  • Dieser ADXPSAR_MCEA Multi-Currency Expert Advisor ist nur ein Beispiel, um zu lernen und Ideen zu entwickeln. Und die Testergebnisse des Strategietesters sind immer noch nicht gut. Wenn also eine bessere Strategie mit einer genaueren Signalberechnung umgesetzt wird, glaube ich, dass das Ergebnis besser sein wird als das derzeitige.

Wir hoffen, dass dieser Artikel und das MQL5 Multi-Currency Expert Advisor-Programm für Händler beim Lernen und Entwickeln von Ideen nützlich sein werden.

Danke fürs Lesen.


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

Beigefügte Dateien |
ADXPSAR_MCEA.mq5 (84.17 KB)
Kategorientheorie in MQL5 (Teil 15) : Funktoren mit Graphen Kategorientheorie in MQL5 (Teil 15) : Funktoren mit Graphen
Dieser Artikel über die Implementierung der Kategorientheorie in MQL5 setzt die Serie mit der Betrachtung der Funktoren fort, diesmal jedoch als Brücke zwischen Graphen und einer Menge. Wir greifen die Kalenderdaten wieder auf und plädieren trotz der Einschränkungen bei der Verwendung von Strategy Tester für die Verwendung von Funktoren zur Vorhersage der Volatilität mit Hilfe der Korrelation.
Bewertung von ONNX-Modellen anhand von Regressionsmetriken Bewertung von ONNX-Modellen anhand von Regressionsmetriken
Bei der Regression geht es um die Prognose eines realen Wertes anhand eines unbekannten Beispiels. Die so genannten Regressionsmetriken werden verwendet, um die Genauigkeit der Vorhersagen des Regressionsmodells zu bewerten.
Verbessern Sie Ihre Handelscharts mit interaktiven GUI's in MQL5 (Teil III): Ein einfaches, bewegliches Handels-GUI Verbessern Sie Ihre Handelscharts mit interaktiven GUI's in MQL5 (Teil III): Ein einfaches, bewegliches Handels-GUI
Begleiten Sie uns in Teil III der Serie „Verbessern Sie Ihre Handelscharts mit interaktiven GUIs in MQL5“, wenn wir die Integration interaktiver GUIs in bewegliche Handels-Dashboards in MQL5 untersuchen. Dieser Artikel baut auf den Grundlagen von Teil I und II auf und leitet die Leser an, statische Handels-Dashboards in dynamische, bewegliche Dashboards umzuwandeln.
Entwicklung eines Replay-Systems — Marktsimulation (Teil 06): Erste Verbesserungen (I) Entwicklung eines Replay-Systems — Marktsimulation (Teil 06): Erste Verbesserungen (I)
In diesem Artikel werden wir mit der Stabilisierung des gesamten Systems beginnen, ohne die wir möglicherweise nicht in der Lage sind, mit den nächsten Schritten fortzufahren.