English Русский 中文 Deutsch 日本語 Português
preview
Creamos un asesor multidivisa sencillo utilizando MQL5 (Parte 1): Señales basadas en ADX combinadas con Parabolic SAR

Creamos un asesor multidivisa sencillo utilizando MQL5 (Parte 1): Señales basadas en ADX combinadas con Parabolic SAR

MetaTrader 5Ejemplos | 25 enero 2024, 10:10
385 0
Roberto Jacobs
Roberto Jacobs

Introducción

En este artículo, entenderemos por asesor multidivisa un asesor o robot comercial que puede comerciar (abrir/cerrar órdenes, gestionar órdenes, etc.) con más de un par de símbolos de un gráfico.

La necesidad y el interés en los sistemas de automatización del comercio y los robots de comercio multidivisa es en la actualidad enorme, pero vemos que la implementación de programas de sistemas multidivisa con los robots comerciales MQL5 no está muy extendida o muchos programadores aún la mantienen en secreto.

Por ello, el objetivo consistirá en satisfacer las necesidades básicas de los tráders que necesitan robots comerciales eficientes y eficaces. Basándonos en los puntos fuertes y las capacidades de MQL5, podemos crear un asesor multidivisa sencillo, que en este artículo utilizará el movimiento direccional promedio en combinación con el indicador Parabolic SAR.


Peculiaridades

1. Pares comerciales.

El asesor operará con los siguientes pares:

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 pares

Más 2 pares de metales: XAUUSD (oro) y XAGUSD (plata).

Eso hace un total de 30 pares.

Todos ellos son utilizados habitualmente por los brókeres. Por lo tanto, este asesor multidivisa no funcionará con brókeres cuyos símbolos o nombres de pares tengan prefijos o sufijos.


2. Señales.

El asesor multidivisa utilizará 2 señales indicadoras: 1. El indicador de movimiento direccional promedio (ADX) con un periodo de 7 como señal principal y 2. el indicador Parabolic SAR como confirmación de la señal.

Los dos indicadores principales usarán el mismo periodo de tiempo especificado en la propiedad del asesor. Además de determinar la fuerza o debilidad de una tendencia, el indicador Parabolic SAR también se usará con los marcos temporales M15 y M5.

Fórmula de la estrategia del estado de la señal: iADX

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

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

donde la diferencia = 0,34:

(+DI[1] > -DI[1]+0.34) = la señal de compra es correcta;   

(+DI[1] < -DI[1]-0.34) = la señal de venta es correcta;     

El porcentaje de la barra PLUSDI_LINE actual dividido por la barra MINUSDI_LINE actual. 

comparado con   

El porcentaje de la barra anterior PLUSDI_LINE dividido por la barra anterior MINUSDI_LINE.

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

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

   Entonces:

IF V0 > V1 = porcentaje de la condición ADX = Crecimiento

IF V0 < V1 = porcentaje de la condición ADX = Caída


Estrategia del estado de la señal Parabolic SAR: Parabolic Stop And Reverse System (iSAR) - sistema parabólico de parada y reversión

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

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


La figura 1 muestra la señal iADX combinada con iSAR.

Fig. 1. Señal indicadora


3. Gestión de transacciones y órdenes.

La gestión comercial en este asesor multidivisa tiene varias opciones:

1. Órdenes de Stop Loss

  • Opciones: Use Order Stop Loss (Yes) o (No) - utilizar una orden Stop Loss: sí o no

                Si selecciona Use Order Stop Loss (No), todas las órdenes se abrirán sin un Stop Loss.

                Al seleccionar Use Order Stop Loss (Yes), la opción aparecerá nuevamente: Use Automatic Calculation Stop Loss (Yes) o (No) - utilizar Stop Loss calculado automáticamente: sí o no

                Al seleccionar Automatic Calculation Stop Loss (Yes), el asesor calculará el Stop Loss.

                Al seleccionar Automatic Calculation Stop Loss (No), el tráder deberá ingresar el valor del Stop Loss en pips.

                Al seleccionar Use Order Stop Loss (No), el asesor verificará si se cumplen las condiciones de la señal. Si se cumplen,

                la orden se guardará. Si la señal se debilita, la orden deberá cerrarse para mantener los beneficios

                o bien la señal indicará un cambio de dirección y la orden deberá cerrarse con pérdidas.

               

2. Órdenes de Take Profit

   Opciones: Use Order Take Profit (Yes) o (No) - usar órdenes de Take Profit: sí o no

                Al seleccionar Use Order Take Profit (No), todas las órdenes se abrirán sin Take Profit.

                Al seleccionar Use Order Take Profit (Yes), la opción aparecerá nuevamente: Use Automatic Calculation Order Take Profit (Yes) o (No) - utilizar el Take Profit calculado automáticamente: sí o no

                Al seleccionar Automatic Calculation Order Take Profit (Yes), el asesor calculará el Take Profit.

                Al seleccionar Automatic Calculation Order Take Profit (No), el tráder deberá ingresar el valor de Take Profit en pips.


3. Trailing Stop y Trailing Take Profit

   Opciones: Use Trailing SL/TP (Yes) o (No) - utilizar Traling Stop Loss/Take Profit: sí o no

                Con Use Trailing SL/TP option (No), el asesor no utilizará el Traling Stop Loss ni el Traling Take Profit.

                Con Use Trailing SL/TP (Yes), la opción aparecerá nuevamente: Use Automatic Trailing (Yes) o (No) - usar trailing automático: sí o no

                Con Use Automatic Trailing (Yes), el asesor realizará el Trailing Stop utilizando el valor de Parabolic SAR.

                Con Use Automatic Trailing (No), el asesor realizará el Trailing Stop utilizando el valor del parámetro de entrada.

                Nota: El asesor realizará simultáneamente el Trailing Take Profit y el Trailing Stop.


4. Gestión manual de órdenes.

Para mejorar la eficiencia, hemos añadido varios botones.

   1. Set SL / TP All Orders (establecer Stop Loss/Take Profit para todas las órdenes)

       Si el tráder establece Use Order Stop Loss (No) y/o Use Order Take Profit (No),

       pero luego quiere usar Stop Loss o Take Profit para todas las órdenes, solo necesitará clicar en el botón "Set SL / TP All Orders" para

       modificar todas las órdenes y aplicar Stop Loss y/o Take Profit.

   2. Close All Orders (cerrar todas las órdenes)

   3. Close All Orders Profit (cerrar todas las órdenes rentables)

       

5. Gestionar órdenes y gráficos de símbolos.

Una característica muy útil para los asesores multidivisa que comercian con 30 pares de un gráfico es la presencia de una barra de botones única para que los tráders puedan cambiar los gráficos o símbolos con un solo clic.


Implementamos la planificación en un programa MQL5

1. Encabezado del programa y parámetros de entrada.

Inclusión de un archivo de encabezado en MQL5

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


La enumeración YN se usa para las opciones (Sí) o (No) en el parámetro del asesor.

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


Enumeración para utilizar el tamaño del lote en la gestión de capital

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


Enumeración de marcos temporales para calcular la señal del asesor

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


Parámetros de entrada del asesor

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


Para declarar todas las variables, objetos y funciones necesarias en este asesor multidivisa, crearemos una clase para especificar la construcción y la configuración operativa del asesor.

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


La primera y principal función en el funcionamiento del asesor multidivisa, llamada desde OnInit(), será ADXPSAR_MCEA_Config().

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


La función ADXPSAR_MCEA_Config() configurará todos los símbolos utilizados, todos los indicadores de gestión usados y algunas funciones importantes del encabezado del archivo de inclusión.

//+------------------------------------------------------------------+
//| 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. Función Expert Tick

En la función Expert Tick (OnTick()) llamaremos a una de las funciones principales del asesor multidivisa, concretamente la función ExpertActionTrade().

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


La función ExpertActionTrade() realizará todas las acciones y gestionará el comercio automático, incluidas las órdenes de apertura/cierre, el Trailing Stop, el Trailing Take Profit y otras acciones adicionales.

La secuencia de funcionamiento se muestra a continuación.

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. Obtención de señales comerciales para abrir/cerrar una posición

Para recibir una señal indicadora, llamaremos a la función GetOpenPosition(symbol) para recibir una señal de apertura

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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()
//---------//


La función GetOpenPosition() llamará a las cuatro funciones de señal y las guardará en la variable OpOr[].

1. DirectionMove(symbol); //-- Función para verificar la presencia de un precio en la barra de velas en el marco temporal del asesor

2. PARSAR15(symbol); //-- Función para verificar el crecimiento o disminución del indicador iSAR en el periodo M15

3. PARSARop(símbolo); //-- Función para verificar el aumento o la disminución del indicador iSAR en el marco temporal del asesor

4. iADXCross(symbol); //-- Función para verificar el aumento o la disminución del indicador iADX en el marco temporal del asesor


Luego la función iADXCross(symbol) llamará a la función iADXpct() para verificar el movimiento porcentual entre +DI y -DI, ​​​​como se describe en la sección "Señales".

Para obtener el estado del indicador, deberemos obtener el número ordinal de cada identificador de indicador requerido en las cuatro funciones PARSAR15(symbol), PARSAROP(symbol), iADXCross(symbol) e iADXpct().

Para obtener el número de índice del identificador del indicador, llamaremos a la función PairsIdxArray(symbol) usando 

int x=PairsIdxArray(symbol);

El valor x representa los arrays del número ordinal del identificador del símbolo en cuestión.

Usando la función PARSAR15() como ejemplo, podemos ver cómo llamar al identificador del indicador iSAR para el símbolo en cuestión.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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. Función ChartEvent

Para que los asesores multidivisa sean más eficaces, crearemos varios botones para gestionar las órdenes y cambiar los gráficos o símbolos.

//+------------------------------------------------------------------+
//| 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()
//---------//


La interfaz del asesor multidivisa tendrá el aspecto que sigue.

ADXPSAR_MCEA


Botones

Botones

Presionando M, se mostrará el panel de control manual.

Expert_manual_button_01

A continuación, el tráder podrá gestionar las órdenes:

1. Set SL/TP All Orders (establecer Stop Loss/Take Profit para todas las órdenes)

2. Close All Orders (cerrar todas las órdenes)

3. Close All Profits (cerrar todas las órdenes rentables)


Presionando C, se mostrará una barra de botones con 30 pares.

Expert_manual_button_02

Clicando en cualquiera de ellos, el símbolo del gráfico será reemplazado inmediatamente por el indicado en el botón en el que se ha clicado.

Clicando en R, el asesor multidivisa ADXPSAR_MCEA se eliminará del gráfico.



Simulador de estrategias

Como sabemos, el simulador permite comprobar la historia de estrategias comerciales de varios instrumentos, así como poner a prueba el comercio automático de todos los símbolos disponibles.

Simulación de estrategias comerciales Pruebas multidivisa

Probemos el asesor multidivisa ADXPSAR_MCEA en el simulador de estrategias MetaTrader 5.

Resultados del simulador de estrategias

Curva de balance


Entradas al mercado y beneficios


Correlación


Posición mínima


Conclusión

  • Crear un asesor multidivisa en MQL5 no resulta muy diferente de desarrollar un asesor monodivisa.
  • La creación de un asesor multidivisa aumentará la eficiencia de los tráders, ya que no necesitarán abrir muchos gráficos.
  • Una estrategia comercial correcta, combinada con señales de indicadores de alta calidad, aumentará la probabilidad de obtener beneficios en comparación con el uso de un asesor monodivisa. Las pérdidas de un par se compensarán con los beneficios de otros pares.
  • El asesor multidivisa ADXPSAR_MCEA supone solo un ejemplo para estudiar y desarrollar nuestras propias ideas. Los resultados de las pruebas todavía no resultan impresionantes. Si implementamos una estrategia mejor con un cálculo más preciso de las señales, el resultado, a mi juicio, debería ser mejor que el actual.

Espero que el artículo y el asesor multidivisa resulten útiles a los tráders para estudiar y desarrollar ideas.

¡Gracias por su atención!


Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/13008

Archivos adjuntos |
ADXPSAR_MCEA.mq5 (84.17 KB)
Biblioteca de análisis numérico ALGLIB en MQL5 Biblioteca de análisis numérico ALGLIB en MQL5
En este artículo, echaremos un vistazo rápido a la biblioteca de análisis numérico ALGLIB 3.19, sus aplicaciones y sus nuevos algoritmos, que pueden mejorar la eficiencia del análisis de datos financieros.
Redes neuronales: así de sencillo (Parte 53): Descomposición de la recompensa Redes neuronales: así de sencillo (Parte 53): Descomposición de la recompensa
Ya hemos hablado más de una vez de la importancia de seleccionar correctamente la función de recompensa que utilizamos para estimular el comportamiento deseado del Agente añadiendo recompensas o penalizaciones por acciones individuales. Pero la cuestión que sigue abierta es el descifrado de nuestras señales por parte del Agente. En este artículo hablaremos sobre la descomposición de la recompensa en lo que respecta a la transmisión de señales individuales al Agente entrenado.
Teoría de categorías en MQL5 (Parte 16): Funtores con perceptrones multicapa Teoría de categorías en MQL5 (Parte 16): Funtores con perceptrones multicapa
Seguimos analizando los funtores y cómo se pueden implementar utilizando redes neuronales artificiales. Dejaremos temporalmente el enfoque que implica el pronóstico de la volatilidad e intentaremos implementar nuestra propia clase de señales para establecer señales de entrada y salida para una posición.
Mejore sus gráficos comerciales con una GUI interactiva basada en MQL5 (Parte III): Interfaz comercial simple y móvil Mejore sus gráficos comerciales con una GUI interactiva basada en MQL5 (Parte III): Interfaz comercial simple y móvil
En esta serie de artículos analizamos la integración de interfaces gráficas interactivas en paneles comerciales móviles en MQL5. En la tercera parte, utilizaremos los desarrollos de las partes anteriores para convertir paneles comerciales estáticos en dinámicos.