English Русский Deutsch 日本語 Português
preview
Creamos un asesor multidivisa sencillo utilizando MQL5 (Parte 3): Prefijos/sufijos de símbolos y sesión comercial

Creamos un asesor multidivisa sencillo utilizando MQL5 (Parte 3): Prefijos/sufijos de símbolos y sesión comercial

MetaTrader 5Trading | 2 abril 2024, 12:43
255 0
Roberto Jacobs
Roberto Jacobs

Introducción

Últimamente, he recibido comentarios de varios compañeros tráders sobre cómo usar el asesor multidivisa que estamos analizando con brókeres que utilizan prefijos y/o sufijos con nombres de símbolos, así como sobre la forma de implementar zonas horarias comerciales o sesiones comerciales en el asesor.

Hoy crearemos y describiremos una función que se incluirá en el asesor FXSAR_MTF_MCEA descrito en el artículo anterior. La función está diseñada para detectar automáticamente los símbolos de los brókeres con prefijos y/o sufijos, así como las zonas horarias comerciales.


Particularidades

1. Pares comerciales.

El asesor operará con los siguientes pares: 

Fórex:

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

30 pares en total.


En el artículo anterior dijimos que este asesor multidivisa no funcionará con brókeres cuyos nombres de símbolos o pares tengan prefijos o sufijos.

Al utilizar asesores que trabajan solo con divisas individuales (un par, un asesor), no debería haber problemas con los brókeres cuyos nombres de símbolos tienen prefijos y/o sufijos.

Pero en el asesor multidivisa que creamos, registramos 30 pares para ser comerciados con nombres de símbolos estándar comúnmente utilizados por muchos brókeres. Este es un método más sencillo y rápido en comparación con tener que introducir los nombres de los pares uno a uno en las propiedades de asesor. También existe la posibilidad de errores debidos a erratas.

Los tráders o programadores que usen los principios de asesores descritos pueden editar manualmente todos los 30 pares enumerados y no tendrán ningún problema.

Pero yo (como probablemente muchos de ustedes) prefiero usar la función para manejar automáticamente los nombres de símbolos que tienen prefijos y/o sufijos para lograr un funcionamiento sin problemas.

Una desventaja de la función para detectar nombres de símbolos que tienen prefijos y sufijos es que solo funciona con pares o nombres de símbolos para divisas y metales en MetaTrader 5, pero no funcionará con símbolos e índices personalizados.

En esta versión, como estamos añadiendo una sesión comercial (la zona horaria comercial), también añadiremos 10 pares de opciones para comerciar que coincidan con la sesión comercial.

Uno de los 10 pares de opciones que se comerciarán es Trader Wishes Pairs (pares de trading), donde los pares negociados deberán ser introducidos manualmente por el tráder en las propiedades del asesor.

Observación: El nombre del par introducido ya debería encontrarse en la lista de 30 pares.



2. Sesión comercial (zona horaria).

Como sabemos, la plataforma Metatrader tiene dos versiones: MetaTrader 4 y MetaTrader 5, creados por MetaQuotes Software Corporation en 2005 y 2010, respectivamente. Esta empresa de origen ruso es líder en el mercado de software financiero.

La configuración horaria de MetaTrader 5 es distinta para cada bróker dependiendo de su zona horaria (hora GMT/UTC). En la esquina superior izquierda de la plataforma MetaTrader 5 podemos ver el ajuste del desfase horario del servidor comercial. Por lo general, la hora del servidor comercial del bróker está vinculada al horario de la Bolsa de Nueva York (NYEM). Cuando MetaTrader 5 muestra 00:00, NYEM está cerrado.

El mercado Forex está abierto 24 horas al día, 5 días a la semana en todo el mundo. El mercado abre el lunes en Nueva Zelanda a las 8:00 de la mañana hora local o 20:00 GMT/UTC, después de lo cual comienza la sesión bursátil en Sídney a las 9:00 de la mañana del lunes hora local, que son las 21:00 GMT/UTC del domingo. (Desfase horario estándar)

Para obtener la zona horaria comercial, primero deberemos averiguar la hora más tardía a partir de la hora actual del servidor comercial. También necesitaremos conocer la diferencia horaria (en horas) entre la hora del servidor del tráder y la hora GMT/UTC. El adelanto de 1 hora en verano no afectará a la hora del servidor comercial, ya que la hora del servidor comercial de MetaTrader 5 también se adelantará 1 hora.

Existen 5 zonas horarias de Fórex que son las más utilizadas por los tráders:

  • Nueva Zelanda abre a las 20:00 y cierra a las 05:00 GMT/UTC, que son las 8:00 y las 17:00 hora local.
  • Sídney abre a las 21:00 y cierra a las 7:00 GMT/UTC, es decir, a las 9:00 y las 17:00 hora local.
  • Tokio abre a las 00:00 y cierra a las 9:00 GMT/UTC, o sea, las 8:00 y las 18:00 hora local.
  • Londres abre a las 9:00 y cierra a las 19:00 GMT/UTC, que son las 9:00 y las 19:00 hora local.
  • Nueva York abre a las 13:00 y cierra a las 22:00 GMT/UTC, es decir, las 9:00 y las 19:00 hora local.


    Aplicación de la planificación en el programa MQL5

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

    Inclusión del archivo de encabezado en MQL5

    //+------------------------------------------------------------------+
    //|                             Include                              |
    //+------------------------------------------------------------------+
    #include 
    #include 
    #include 
    #include 
    //--
    CTrade              mc_trade;
    CSymbolInfo         mc_symbol;
    CPositionInfo       mc_position; 
    CAccountInfo        mc_account;
    //---


    Enumeración para el uso de la zona horaria

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


    Enumeración para seleccionar las horas

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


    Enumeración para seleccionar los minutos

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


    Enumeración para seleccionar 10 pares de opciones para comerciar

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


    La enumeración YN se usa para las opciones (Yes) o (No) en los parámetros del asesor.

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


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

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


    Parámetros de entrada del asesor:

    //---
    input group               "=== Select Pairs to Trade ===";  // Selected Pairs to trading
    input PairsTrade         usepairs = All30;           // Select Pairs to Use
    input string         traderwishes = "eg. eurusd,usdchf,gbpusd,gbpchf"; // If Use Trader Wishes Pairs, input pair name here, separate by comma
    //--
    input group               "=== Money Management Lot Size Parameter ==="; // Money Management Lot Size Parameter
    input mmt                  mmlot = DynamLot;         // Money Management Type
    input double                Risk = 10.0;             // Percent Equity Risk per Trade (Min=1.0% / Max=10.0%)
    input double                Lots = 0.01;             // Input Manual Lot Size FixedLot
    //--Trade on Specific Time
    input group               "=== Trade on Specific Time ==="; // Trade on Specific Time
    input YN           trd_time_zone = Yes;              // Select If You Like to Trade on Specific Time Zone
    input tm_zone            session = Cus_Session;      // Select Trading Time Zone
    input swhour            stsescuh = hr_00;            // Time Hour to Start Trading Custom Session (0-23)
    input inmnt             stsescum = mn_15;            // Time Minute to Start Trading Custom Session (0-55)
    input swhour            clsescuh = hr_23;            // Time Hour to Stop Trading Custom Session (0-23)
    input inmnt             clsescum = mn_55;            // Time Minute to Stop Trading Custom Session (0-55)
    //--Day Trading On/Off
    input group               "=== Day Trading On/Off ==="; // Day Trading On/Off
    input YN                    ttd0 = No;               // Select Trading on Sunday (Yes) or (No)
    input YN                    ttd1 = Yes;              // Select Trading on Monday (Yes) or (No)
    input YN                    ttd2 = Yes;              // Select Trading on Tuesday (Yes) or (No)
    input YN                    ttd3 = Yes;              // Select Trading on Wednesday (Yes) or (No)
    input YN                    ttd4 = Yes;              // Select Trading on Thursday (Yes) or (No)
    input YN                    ttd5 = Yes;              // Select Trading on Friday (Yes) or (No)
    input YN                    ttd6 = No;               // Select Trading on Saturday (Yes) or (No)
    //--Trade & Order management Parameter
    input group               "=== Trade & Order management Parameter ==="; // Trade & Order management Parameter
    input YN                  use_sl = No;               // Use Order Stop Loss (Yes) or (No)
    input YN                  autosl = Yes;              // Use Automatic Calculation Stop Loss (Yes) or (No)
    input double               SLval = 30;               // If Not Use Automatic SL - Input SL value in Pips
    input YN                  use_tp = Yes;               // Use Order Take Profit (Yes) or (No)
    input YN                  autotp = Yes;              // Use Automatic Calculation Take Profit (Yes) or (No)
    input double               TPval = 10;               // If Not Use Automatic TP - Input TP value in Pips
    input YN            TrailingSLTP = Yes;              // Use Trailing SL/TP (Yes) or (No)
    input YN                 autotrl = Yes;              // Use Automatic Trailing (Yes) or (No)
    input double               TSval = 5;                // If Not Use Automatic Trailing Input Trailing value in Pips
    input double               TSmin = 5;                // Minimum Pips to start Trailing Stop
    input double               TPmin = 25;               // Input Trailing Profit Value in Pips
    input YN           Close_by_Opps = Yes;              // Close Trade By Opposite Signal (Yes) or (No)
    input YN               SaveOnRev = Yes;              // Close Trade and Save profit due to weak signal (Yes) or (No)
    //--Others Expert Advisor Parameter
    input group               "=== Others Expert Advisor Parameter ==="; // Others EA Parameter
    input YN                  alerts = Yes;              // Display Alerts / Messages (Yes) or (No)
    input YN           UseEmailAlert = No;               // Email Alert (Yes) or (No)
    input YN           UseSendnotify = No;               // Send Notification (Yes) or (No)
    input YN      trade_info_display = Yes;              // Select Display Trading Info on Chart (Yes) or (No)
    input ulong               magicEA = 2023102;          // Expert ID (Magic Number)
    //---


    En el grupo de propiedades Trade on Specific Time input del asesor, el tráder puede seleccionar:

    Comerciar en una zona horaria específica - Trade on Specific Time Zone (Yes) o (No).

    Si tenemos Yes, deberemos seleccionar los parámetros de enumeración:

    • Trading on Custom Session (Comerciar en una sesión personalizada)
    • Trading on New Zealand Session (Comerciar en la sesión neozelandesa)
    • Trading on Australia Sydney Session (Comerciar en la sesión de Sídney)
    • Trading on Asia Tokyo Session (Comerciar en la sesión de Tokio)
    • Trading on Europe London Session (Comerciar en la sesión de Londres)
    • Trading on America New York Session (Comerciar en la sesión de New York)

    Al seleccionar una sesión de usuario:

    Los tráders deberán fijar una hora u horas y minutos para iniciar la negociación, así como las horas y minutos para cerrarla. Así, el asesor solo realizará acciones durante el tiempo especificado.

    En otros casos, las horas de inicio y fin del comercio las elegirá el asesor.


    2. Clase para el funcionamiento del asesor.

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

    En particular, implementaremos las variables utilizadas en la función para definir los nombres de los símbolos de prefijos y/o los nombres de los símbolos de sufijos, así como los cálculos de las zonas horarias en la clase MCEA.

    //+------------------------------------------------------------------+
    //| Class for working Expert Advisor                                 |
    //+------------------------------------------------------------------+
    class MCEA
      {
    //---
        private:
        //---- 
        int              x_year;       // Year 
        int              x_mon;        // Month 
        int              x_day;        // Day of the month 
        int              x_hour;       // Hour in a day 
        int              x_min;        // Minutes 
        int              x_sec;        // Seconds
        //--
        int              oBm,
                         oSm,
                         ldig;
        //--- Variables used in prefix and suffix symbols
        int              posCur1,
                         posCur2;
        int              inpre,
                         insuf;
        string           pre,suf;           
        //--- Variables are used in Trading Time Zone
        int              ishour,
                         onhour;
        datetime         rem,
                         znop,
                         zncl,
                         zntm;
        datetime         SesCuOp,
                         SesCuCl,
                         Ses01Op,
                         Ses01Cl,
                         Ses02Op,
                         Ses02Cl,
                         Ses03Op,
                         Ses03Cl,
                         Ses04Op,
                         Ses04Cl,
                         Ses05Op,
                         Ses05Cl,
                         SesNoOp,
                         SesNoCl;
        //--
        string           tz_ses,
                         tz_opn,
                         tz_cls;
        //--
        string           tmopcu,
                         tmclcu,
                         tmop01,
                         tmcl01,
                         tmop02,
                         tmcl02,
                         tmop03,
                         tmcl03,
                         tmop04,
                         tmcl04,
                         tmop05,
                         tmcl05,
                         tmopno,
                         tmclno;      
        //----------------------    
        //--
        double           LotPS;
        double           slv,
                         tpv,
                         pip,
                         xpip;
        double           differ;                 
        double           floatprofit,
                         fixclprofit;
        //--
        string           pairs,
                         hariini,
                         daytrade,
                         trade_mode;
        //--
        double           OPEN[],
                         HIGH[],
                         LOW[],
                         CLOSE[];
        datetime         TIME[];
        datetime         closetime;
        //--
        //------------
         
        //------------
        void             SetSymbolNamePS(void);
        void             HandlingSymbolArrays(void);
        void             Set_Time_Zone(void);
        void             Time_Zone(void);
        bool             Trade_session(void);
        string           PosTimeZone(void);
        int              ThisTime(const int reqmode);
        int              ReqTime(datetime reqtime,const int reqmode);
        //--
        int              DirectionMove(const string symbol);
        int              GetPSARSignalMTF(string symbol);
        int              PARSAR05(const string symbol);
        int              PARSARMTF(const string symbol,ENUM_TIMEFRAMES mtf);
        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:
        //---
        
        //-- FXSAR_MTF_MCEA_sptz Config --
        string           DIRI[],
                         AS30[],
                         VSym[];
        string           SPC[];
        string           USD[];
        string           EUR[];
        string           GBP[];
        string           AUD[];
        string           NZD[];
        string           CAD[];
        string           CHF[];
        string           JPY[];             
        //--                 
        string           expname;
        //--
        int              hPar05[];
        int              hPSAR[][5];
        int              ALO,
                         dgts,
                         arrsar,
                         arrsymbx;
        int              sall,
                         arusd,
                         aretc,
                         arspc,
                         arper;
        ulong            slip;        
        //--
        double           SARstep,
                         SARmaxi;
        double           profitb[],
                         profits[];
        //--
        int              Buy,
                         Sell;
        int              ccur,
                         psec,
                         xtto,
                         TFArrays,
                         checktml;
        int              OpOr[],xob[],xos[];         
        //--
        int              year,  // Year 
                         mon,   // Month 
                         day,   // Day 
                         hour,  // Hour 
                         min,   // Minutes 
                         sec,   // Seconds 
                         dow,   // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) 
                         doy;   // Day number of the year (January 1st is assigned the number value of zero)
        //--
        ENUM_TIMEFRAMES  TFt,
                         TFT05,
                         TFSAR[];
        //--
        bool             PanelExtra;
        //------------
                         MCEA(void);
                         ~MCEA(void);            
        //------------
        //--
        virtual void     FXSAR_MTF_MCEA_sptz_Config(void);
        virtual void     ExpertActionTrade(void);
        //--
        void             ArraySymbolResize(void);
        void             CurrentSymbolSet(const string symbol);
        void             Pips(const string symbol);
        void             TradeInfo(void);
        void             Do_Alerts(const string symbx,string msgText);
        void             CheckOpenPMx(const string symbx);
        void             SetSLTPOrders(void);
        void             CloseBuyPositions(const string symbol);
        void             CloseSellPositions(const string symbol);
        void             CloseAllOrders(void);
        void             CheckClose(const string symbx);
        void             TodayOrders(void);
        void             UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf);
        void             RefreshPrice(const string symbx,ENUM_TIMEFRAMES xtf,int bars);
        //--
        bool             RefreshTick(const string symbx);  
        bool             TradingToday(void);
        bool             OpenBuy(const string symbol);
        bool             OpenSell(const string symbol);
        bool             ModifyOrderSLTP(double mStop,double ordtp);
        bool             ModifySLTP(const string symbx,int TS_type);          
        bool             CloseAllProfit(void);
        bool             ManualCloseAllProfit(void);
        //--
        int              PairsIdxArray(const string symbol);
        int              ValidatePairs(const string symbol);
        int              TFIndexArray(ENUM_TIMEFRAMES TF);
        int              GetOpenPosition(const string symbol);
        int              GetCloseInWeakSignal(const string symbol,int exis);
        //--
        string           getUninitReasonText(int reasonCode);
        //--
        //------------
    //---
      }; //-end class MCEA
    //---------//


    La primera y más importante función en la operación del asesor multidivisa, llamada desde OnInit(), será FXSAR_MTF_MCEA_sptz_Config().

    La función FXSAR_MTF_MCEA_sptz_Config() configurará todos los símbolos utilizados, todos los indicadores de manejadores utilizados y algunas funciones importantes del encabezado del archivo include.

    //+------------------------------------------------------------------+
    //| Expert Configuration                                             |
    //+------------------------------------------------------------------+
    void MCEA::FXSAR_MTF_MCEA_sptz_Config(void) 
      {
    //---
        //--
        HandlingSymbolArrays(); // With this function we will handle all pairs that will be traded
        //--
        TFT05=PERIOD_M5;
        ENUM_TIMEFRAMES TFA[]={PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H4,PERIOD_D1};
        TFArrays=ArraySize(TFA);
        ArrayResize(TFSAR,TFArrays,TFArrays);
        ArrayCopy(TFSAR,TFA,0,0,WHOLE_ARRAY);
        //--
        TFt=TFSAR[2];
        //--
        //-- iSAR Indicators handle for all symbol
        for(int x=0; x iSAR (DIRI[x],TFT05,SARstep,SARmaxi);
            //--
            for(int i=0; i iSAR (DIRI[x],TFSAR[i],SARstep,SARmaxi);
              }
          }
        //--
        ALO=(int)mc_account.LimitOrders()>arrsymbx ? arrsymbx : (int)mc_account.LimitOrders();
        //--
        LotPS=(double)ALO;
        //--
        mc_trade.SetExpertMagicNumber(magicEA);
        mc_trade.SetDeviationInPoints(slip);
        mc_trade.SetMarginMode();
        Set_Time_Zone();
        //--
        return;
    //---
      } //-end FXSAR_MTF_MCEA_sptz_Config()
    //---------//


    Para configurar el par comerciado, llamaremos a la función HandlingSymbolArrays().

    Usando la función HandlingSymbolArrays(), manejaremos todos los pares comerciados.

    void MCEA::HandlingSymbolArrays(void)
      {
    //---
        string All30[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY","EURGBP",
                        "EURAUD","EURNZD","EURCAD","EURCHF","EURJPY","GBPAUD","GBPNZD","GBPCAD",
                        "GBPCHF","GBPJPY","AUDNZD","AUDCAD","AUDCHF","AUDJPY","NZDCAD","NZDCHF",
                        "NZDJPY","CADCHF","CADJPY","CHFJPY","XAUUSD","XAGUSD"}; // 30 pairs
        string USDs[]={"USDCAD","USDCHF","USDJPY","AUDUSD","EURUSD","GBPUSD","NZDUSD","XAUUSD","XAGUSD"}; // USD pairs
        string EURs[]={"EURAUD","EURCAD","EURCHF","EURGBP","EURJPY","EURNZD","EURUSD"}; // EUR pairs
        string GBPs[]={"GBPAUD","GBPCAD","GBPCHF","EURGBP","GBPJPY","GBPNZD","GBPUSD"}; // GBP pairs
        string AUDs[]={"AUDCAD","AUDCHF","EURAUD","GBPAUD","AUDJPY","AUDNZD","AUDUSD"}; // AUD pairs
        string NZDs[]={"AUDNZD","NZDCAD","NZDCHF","EURNZD","GBPNZD","NZDJPY","NZDUSD"}; // NZD pairs
        string CADs[]={"AUDCAD","CADCHF","EURCAD","GBPCAD","CADJPY","NZDCAD","USDCAD"}; // CAD pairs
        string CHFs[]={"AUDCHF","CADCHF","EURCHF","GBPCHF","NZDCHF","CHFJPY","USDCHF"}; // CHF pairs
        string JPYs[]={"AUDJPY","CADJPY","CHFJPY","EURJPY","GBPJPY","NZDJPY","USDJPY"}; // JPY pairs
        //--
        sall=ArraySize(All30);
        arusd=ArraySize(USDs);
        aretc=ArraySize(EURs);
        ArrayResize(VSym,sall,sall);
        ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY);
        //--
        if(usepairs==TrdWi && StringFind(traderwishes,"eg.",0) 0)
              {
                for(int i=0; i 0 || insuf>0)
          {
            if(usepairs==TrdWi && arspc>0)
              {
                for(int t=0; t  


    Dentro de la función HandlingSymbolArrays(), llama a la función SetSymbolNamePS().

    Con su ayuda, podremos detectar y procesar los nombres de los símbolos que tengan prefijos y/o sufijos.

    void MCEA::SetSymbolNamePS(void)
      {
    //---
       int sym_Lenpre=0;
       int sym_Lensuf=0;
       string sym_pre="";
       string sym_suf="";
       string insymbol=Symbol();
       int inlen=StringLen(insymbol);
       int toseek=-1;
       string dep="";
       string bel="";
       string sym_use ="";
       int pairx=-1;
       string xcur[]={"EUR","GBP","AUD","NZD","USD","CAD","CHF"}; // 7 major currency
       int xcar=ArraySize(xcur);
       //--
       for(int x=0; x StringFind (insymbol,xcur[x],0);
           if(toseek>=0)
             {
               pairx=x;
               break;
             }
         }
       if(pairx>=0)
         {
           int awl=toseek-3 <0 ? 0 : toseek-3;
           int sd=StringFind(insymbol,"SD",0);
           if(toseek==0 && sd<4)
             {
               dep=StringSubstr(insymbol,toseek,3);
               bel=StringSubstr(insymbol,toseek+3,3);
               sym_use=dep+bel;
             }
           else
           if(toseek>0)
             {
               dep=StringSubstr(insymbol,toseek,3);
               bel=StringSubstr(insymbol,toseek+3,3);
               sym_use=dep+bel;
             }
           else
             {
               dep=StringSubstr(insymbol,awl,3);
               bel=StringSubstr(insymbol,awl+3,3);
               sym_use=dep+bel;
             }
         }
       //--
       string sym_nmx=sym_use;
       int lensx=StringLen(sym_nmx);
       //--
       if(inlen>lensx && lensx==6)
         {
           sym_Lenpre=StringFind(insymbol,sym_nmx,0);
           sym_Lensuf=inlen-lensx-sym_Lenpre;
           //--
           if(sym_Lenpre>0)
             {
               sym_pre=StringSubstr(insymbol,0,sym_Lenpre);
               for(int i=0; i if (StringFind(sym_pre,xcur[i],0)>=0) sym_pre="";
             }
           if(sym_Lensuf>0)
             {
               sym_suf=StringSubstr(insymbol,sym_Lenpre+lensx,sym_Lensuf);
               for(int i=0; i if (StringFind(sym_suf,xcur[i],0)>=0) sym_suf="";
             }
         }
       //--
       pre=sym_pre;
       suf=sym_suf;
       inpre=StringLen(pre);
       insuf=StringLen(suf);
       posCur1=inpre;
       posCur2=posCur1+3;
       //--
       return;
    //---
      } //-end SetSymbolNamePS()
    //---------//


    3. Función Expert tick.

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

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


    La secuencia del asesor dentro de esta función.

    La función ExpertActionTrade() ejecutará todas las acciones y gestionará las operaciones automáticas, incluidas las órdenes de apertura/cierre, trailing stop, trailing take profit y otras acciones adicionales.

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


    Hemos añadido una llamada de la función lógica Trade Session() a la función ExpertActionTrade() especialmente para las zonas horarias comerciales.

    Cuando Trade_session() es true, el asesor funcionará hasta la finalización, y cuando es false, el asesor solo realizará las tareas Close Trade and Save profit due to weak signal (Yes) (Cerrar la transacción y guardar los beneficios debido a una señal débil) y Trailing stop (Yes) (trailing stop (sí)).

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


    void MCEA::Set_Time_Zone(void)
      {
    //---
        //-- Server Time==TimeCurrent()
        datetime TTS=TimeTradeServer();
        datetime GMT=TimeGMT();
        //--
        MqlDateTime svrtm,gmttm; 
        TimeToStruct(TTS,svrtm); 
        TimeToStruct(GMT,gmttm); 
        int svrhr=svrtm.hour;  // Server time hour
        int gmthr=gmttm.hour;  // GMT time hour
        int difhr=svrhr-gmthr; // Time difference Server time to GMT time
        //--
        int NZSGMT=12;  // New Zealand Session GMT/UTC+12
        int AUSGMT=10;  // Australia Sydney Session GMT/UTC+10
        int TOKGMT=9;   // Asia Tokyo Session GMT/UTC+9
        int EURGMT=0;   // Europe London Session GMT/UTC 0
        int USNGMT=-5;  // US New York Session GMT/UTC-5
        //--
        int NZSStm=8;   // New Zealand Session time start: 08:00 Local Time
        int NZSCtm=17;  // New Zealand Session time close: 17:00 Local Time 
        int AUSStm=7;   // Australia Sydney Session time start: 07:00 Local Time 
        int AUSCtm=17;  // Australia Sydney Session time close: 17:00 Local Time  
        int TOKStm=9;   // Asia Tokyo Session time start: 09:00 Local Time 
        int TOKCtm=18;  // Asia Tokyo Session time close: 18:00 Local Time  
        int EURStm=9;   // Europe London Session time start: 09:00 Local Time 
        int EURCtm=19;  // Europe London Session time close: 19:00 Local Time  
        int USNStm=8;   // US New York Session time start: 08:00 Local Time 
        int USNCtm=17;  // US New York Session time close: 17:00 Local Time  
        //--
        int nzo = (NZSStm+difhr-NZSGMT)<0 ? 24+(NZSStm+difhr-NZSGMT) : (NZSStm+difhr-NZSGMT);
        int nzc = (NZSCtm+difhr-NZSGMT)<0 ? 24+(NZSCtm+difhr-NZSGMT) : (NZSCtm+difhr-NZSGMT);
        //--
        int auo = (AUSStm+difhr-AUSGMT)<0 ? 24+(AUSStm+difhr-AUSGMT) : (AUSStm+difhr-AUSGMT);
        int auc = (AUSCtm+difhr-AUSGMT)<0 ? 24+(AUSCtm+difhr-AUSGMT) : (AUSCtm+difhr-AUSGMT);
        //--
        int tko = (TOKStm+difhr-TOKGMT)<0 ? 24+(TOKStm+difhr-TOKGMT) : (TOKStm+difhr-TOKGMT);
        int tkc = (TOKCtm+difhr-TOKGMT)<0 ? 24+(TOKCtm+difhr-TOKGMT) : (TOKCtm+difhr-TOKGMT);
        //--
        int euo = (EURStm+difhr-EURGMT)<0 ? 24+(EURStm+difhr-EURGMT) : (EURStm+difhr-EURGMT);
        int euc = (EURCtm+difhr-EURGMT)<0 ? 24+(EURCtm+difhr-EURGMT) : (EURCtm+difhr-EURGMT);
        //--
        int uso = (USNStm+difhr-USNGMT)<0 ? 24+(USNStm+difhr-USNGMT) : (USNStm+difhr-USNGMT);
        int usc = (USNCtm+difhr-USNGMT)<0 ? 24+(USNCtm+difhr-USNGMT) : (USNCtm+difhr-USNGMT);
        if(usc==0||usc==24) usc=23;
        //--
        //---Trading on Custom Session
        int _days00=ThisTime(day);
        int _days10=ThisTime(day);
        if(stsescuh>clsescuh) _days10=ThisTime(day)+1;
        tmopcu=ReqDate(_days00,stsescuh,stsescum); 
        tmclcu=ReqDate(_days10,clsescuh,clsescum); 
        //--
        //--Trading on New Zealand Session GMT/UTC+12
        int _days01=ThisTime(hour) 1  : ThisTime(day);
        int _days11=ThisTime(hour) 1 ;
        tmop01=ReqDate(_days01,nzo,0);    // start: 08:00 Local Time == 20:00 GMT/UTC
        tmcl01=ReqDate(_days11,nzc-1,59); // close: 17:00 Local Time == 05:00 GMT/UTC
        //--
        //--Trading on Australia Sydney Session GMT/UTC+10
        int _days02=ThisTime(hour) 1  : ThisTime(day);
        int _days12=ThisTime(hour) 1 ;
        tmop02=ReqDate(_days02,auo,0);    // start: 07:00 Local Time == 21:00 GMT/UTC
        tmcl02=ReqDate(_days12,auc-1,59); // close: 17:00 Local Time == 07:00 GMT/UTC
        //--
        //--Trading on Asia Tokyo Session GMT/UTC+9
        int _days03=ThisTime(hour) 1 ;
        int _days13=ThisTime(hour) 1 ;
        tmop03=ReqDate(_days03,tko,0);    // start: 09:00 Local Time == 00:00 GMT/UTC
        tmcl03=ReqDate(_days13,tkc-1,59); // close: 18:00 Local Time == 09:00 GMT/UTC
        //--
        //--Trading on Europe London Session GMT/UTC 00:00
        int _days04=ThisTime(hour) 1 ;
        int _days14=ThisTime(hour) 1 ;
        tmop04=ReqDate(_days04,euo,0);     // start: 09:00 Local Time == 09:00 GMT/UTC
        tmcl04=ReqDate(_days14,euc-1,59);  // close: 19:00 Local Time == 19:00 GMT/UTC
        //--
        //--Trading on US New York Session GMT/UTC-5
        int _days05=ThisTime(hour) 1 ;
        int _days15=ThisTime(hour)<=usc ? ThisTime(day) : ThisTime(day)+1;
        tmop05=ReqDate(_days05,uso,0);  // start: 08:00 Local Time == 13:00 GMT/UTC
        tmcl05=ReqDate(_days15,usc,59); // close: 17:00 Local Time == 22:00 GMT/UTC
        //--
        //--Not Use Trading Time Zone
        if(trd_time_zone==No)
          {
            tmopno=ReqDate(ThisTime(day),0,15); 
            tmclno=ReqDate(ThisTime(day),23,59);
          }
        //--
        Time_Zone();
        //--
        return;
    //---
      } //-end Set_Time_Zone()
    //---------//
    void MCEA::Time_Zone(void)
      {
    //---
       //--
       tz_ses="";
       //--
       switch(session)
         {
           case Cus_Session:
             {
               SesCuOp=StringToTime(tmopcu);
               SesCuCl=StringToTime(tmclcu);
               zntm=SesCuOp;
               znop=SesCuOp;
               zncl=SesCuCl;
               tz_ses="Custom_Session";
               tz_opn=timehr(stsescuh,stsescum);
               tz_cls=timehr(clsescuh,clsescum);
               break;
             }
           case New_Zealand:
             {
               Ses01Op=StringToTime(tmop01);
               Ses01Cl=StringToTime(tmcl01);
               zntm=Ses01Op;
               znop=Ses01Op;
               zncl=Ses01Cl;
               tz_ses="New_Zealand/Oceania";
               tz_opn=timehr(ReqTime(Ses01Op,hour),ReqTime(Ses01Op,min));
               tz_cls=timehr(ReqTime(Ses01Cl,hour),ReqTime(Ses01Cl,min));
               break;
             }
           case Australia:
             {
               Ses02Op=StringToTime(tmop02);
               Ses02Cl=StringToTime(tmcl02);
               zntm=Ses02Op;
               znop=Ses02Op;
               zncl=Ses02Cl;
               tz_ses="Australia Sydney";
               tz_opn=timehr(ReqTime(Ses02Op,hour),ReqTime(Ses02Op,min));
               tz_cls=timehr(ReqTime(Ses02Cl,hour),ReqTime(Ses02Cl,min));
               break;
             }
           case Asia_Tokyo:
             {
               Ses03Op=StringToTime(tmop03);
               Ses03Cl=StringToTime(tmcl03);
               zntm=Ses03Op;
               znop=Ses03Op;
               zncl=Ses03Cl;
               tz_ses="Asia/Tokyo";
               tz_opn=timehr(ReqTime(Ses03Op,hour),ReqTime(Ses03Op,min));
               tz_cls=timehr(ReqTime(Ses03Cl,hour),ReqTime(Ses03Cl,min));
               break;
             }
           case Europe_London:
             {
               Ses04Op=StringToTime(tmop04);
               Ses04Cl=StringToTime(tmcl04);
               zntm=Ses04Op;
               znop=Ses04Op;
               zncl=Ses04Cl;
               tz_ses="Europe/London";
               tz_opn=timehr(ReqTime(Ses04Op,hour),ReqTime(Ses04Op,min));
               tz_cls=timehr(ReqTime(Ses04Cl,hour),ReqTime(Ses04Cl,min));
               break;
             }
           case US_New_York:
             {
               Ses05Op=StringToTime(tmop05);
               Ses05Cl=StringToTime(tmcl05);
               zntm=Ses05Op;
               znop=Ses05Op;
               zncl=Ses05Cl;
               tz_ses="US/New_York";
               tz_opn=timehr(ReqTime(Ses05Op,hour),ReqTime(Ses05Op,min));
               tz_cls=timehr(ReqTime(Ses05Cl,hour),ReqTime(Ses05Cl,min));
               break;
             }
         }
       //--
       if(trd_time_zone==No)
         {
           SesNoOp=StringToTime(tmopno);
           SesNoCl=StringToTime(tmclno);
           zntm=SesNoOp;
           znop=SesNoOp;
           zncl=SesNoCl;
           tz_ses="Not Use Time Zone";
           tz_opn=timehr(ReqTime(SesNoOp,hour),ReqTime(SesNoOp,min));
           tz_cls=timehr(ReqTime(SesNoCl,hour),ReqTime(SesNoCl,min));
         }
       //--
       return;
    //---
      } //-end Time_Zone()
    //---------//

    Algunas funciones de apoyo para calcular el tiempo son:

    string MCEA::TradingDay(void)
      {
    //---
       int trdday=ThisTime(dow);
       switch(trdday)
         {
            case 0: daytrade="Sunday";    break;
            case 1: daytrade="Monday";    break;
            case 2: daytrade="Tuesday";   break;
            case 3: daytrade="Wednesday"; break;
            case 4: daytrade="Thursday";  break;
            case 5: daytrade="Friday";    break;
            case 6: daytrade="Saturday";  break;
         }
       return(daytrade);
    //---
      } //-end TradingDay()  
    //---------//
    
    bool MCEA::TradingToday(void)
      {
    //---
        bool tradetoday=false;
        int trdday=ThisTime(dow);
        hariini="No";
        //--
        int ttd[];
        ArrayResize(ttd,7);
        ttd[0]=ttd0;
        ttd[1]=ttd1;
        ttd[2]=ttd2;
        ttd[3]=ttd3;
        ttd[4]=ttd4;
        ttd[5]=ttd5;
        ttd[6]=ttd6;
        //--
        if(ttd[trdday]==Yes) {tradetoday=true; hariini="Yes";}
       //--
       return(tradetoday);
    //---
      } //-end TradingToday()
    //---------//
    
    string MCEA::timehr(int hr,int mn)
      {
    //---
        string scon="";
        string men=mn==0 ? "00" : string(mn);
        int shr=hr==24 ? 0 : hr;
        if(shr<10) scon="0"+string(shr)+":"+men;
        else scon=string(shr)+":"+men;
        //--
        return(scon);
    //---
      } //-end timehr()
    //---------//
    
    string MCEA::ReqDate(int d,int h,int m) 
      { 
    //---
       MqlDateTime mdt; 
       datetime t=TimeCurrent(mdt); 
       x_year=mdt.year; 
       x_mon=mdt.mon; 
       x_day=d; 
       x_hour=h; 
       x_min=m;
       x_sec=mdt.sec;
       //--
       string mdr=string(x_year)+"."+string(x_mon)+"."+string(x_day)+"   "+timehr(x_hour,x_min);
       return(mdr);
    //---
      } //-end ReqDate()
    //---------//
    
    int MCEA::ThisTime(const int reqmode) 
      {
    //---
        MqlDateTime tm;
        TimeCurrent(tm);
        int valtm=0;
        //--
        switch(reqmode)
          {
            case 0: valtm=tm.year; break;        // Return Year 
            case 1: valtm=tm.mon;  break;        // Return Month 
            case 2: valtm=tm.day;  break;        // Return Day 
            case 3: valtm=tm.hour; break;        // Return Hour 
            case 4: valtm=tm.min;  break;        // Return Minutes 
            case 5: valtm=tm.sec;  break;        // Return Seconds 
            case 6: valtm=tm.day_of_week; break; // Return Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) 
            case 7: valtm=tm.day_of_year; break; // Return Day number of the year (January 1st is assigned the number value of zero) 
          }
        //--
        return(valtm);
    //---
      } //-end ThisTime()
    //---------//
    
    int MCEA::ReqTime(datetime reqtime,
                      const int reqmode) 
      {
        MqlDateTime tm;
        TimeToStruct(reqtime,tm);
        int valtm=0;
        //--
        switch(reqmode)
          {
            case 0: valtm=tm.year; break;        // Return Year 
            case 1: valtm=tm.mon;  break;        // Return Month 
            case 2: valtm=tm.day;  break;        // Return Day 
            case 3: valtm=tm.hour; break;        // Return Hour 
            case 4: valtm=tm.min;  break;        // Return Minutes 
            case 5: valtm=tm.sec;  break;        // Return Seconds 
            case 6: valtm=tm.day_of_week; break; // Return Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) 
            case 7: valtm=tm.day_of_year; break; // Return Day number of the year (January 1st is assigned the number value of zero) 
          }
        //--
        return(valtm);
    //---
      } //-end ReqTime()
    //---------//


    4. Obtención de señales comerciales para abrir/cerrar una posición

    En el artículo anterior utilizamos señales de marco temporal múltiple basadas en 5 marcos temporales

    void MCEA::FXSAR_MTF_MCEA_Config(void) 
      {
        //---
    
        ENUM_TIMEFRAMES TFA[]={PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H4,PERIOD_D1};
        TFArrays=ArraySize(TFA);
        ArrayResize(TFSAR,TFArrays,TFArrays);
        ArrayCopy(TFSAR,TFA,0,0,WHOLE_ARRAY);
    
        //--
        return;
    //---
      } //-end FXSAR_MTF_MCEA_Config()
    //---------//
    


    Pero en este artículo, hemos cambiado los cuatro marcos temporales de la señal de marco temporal múltiple a M5, M30, H1 y finalmente H4.

    void MCEA::FXSAR_MTF_MCEA_sptz_Config(void) 
      {
    //---
        //--
        ENUM_TIMEFRAMES TFA[]={PERIOD_M5,PERIOD_M30,PERIOD_H1,PERIOD_H4};
        TFArrays=ArraySize(TFA);
        ArrayResize(TFSAR,TFArrays,TFArrays); // TFArrays now the value of array size is 4
        ArrayCopy(TFSAR,TFA,0,0,WHOLE_ARRAY);
    
        //--
        return;
    //---
      } //-end FXSAR_MTF_MCEA_sptz_Config()
    //---------//


    Para obtener una señal PSAR de marco temporal múltiple, llamaremos a GetPSARSignalMTF() para obtener la posición del indicador ParabolicSAR en el marco temporal solicitado:

    int MCEA::GetPSARSignalMTF(string symbol)
      {
    //---
        int mv=0;
        int rise=1,
            down=-1;
        //--
        int sarup=0,
            sardw=0;
        //--    
        for(int x=0; x // The TFArrays variable has a value of 54which is taken from the number of time frames from TF_M5, M30, H1 and H4. 
          {
            if(PARSARMTF(symbol,TFSAR[x])>0) sarup++;
            if(PARSARMTF(symbol,TFSAR[x])<0) sardw++;
          }   
        //--
        if(sarup==TFArrays) mv=rise;
        if(sardw==TFArrays) mv=down;
        //--
        return(mv);
    //---
      } //- end GetPSARSignalMTF()
    //---------//


    A continuación, llamaremos al descriptor del indicador correspondiente para recuperar el valor del búfer del indicador iSAR de este marco temporal solicitado.

    int MCEA::PARSARMTF(const string symbol,ENUM_TIMEFRAMES mtf) // formula Parabolic SAR in set timeframe
      {
    //---
        int ret=0;
        int rise=1,
            down=-1;
        //--
        int br=2;
        //--
        double PSAR[];
        ArrayResize(PSAR,br,br);
        ArraySetAsSeries(PSAR,true);
        int xx=PairsIdxArray(symbol);
        int tx=TFIndexArray(mtf);
        CopyBuffer(hPSAR[xx][tx],0,0,br,PSAR);
        //--
        double OPN0=iOpen(symbol,TFSAR[tx],0);
        double HIG0=iHigh(symbol,TFSAR[tx],0);
        double LOW0=iLow(symbol,TFSAR[tx],0);
        double CLS0=iClose(symbol,TFSAR[tx],0);
        //--
        if(PSAR[0] OPN0) ret=rise;
        if(PSAR[0]>HIG0 && CLS0 //-- 
        return(ret);
    //---
      } //-end PARSARMTF()
    //---------//


    La función GetPSARSignalMTF se llamará desde GetOpenPosition() para obtener una señal comercial para abrir una posición.

    int MCEA::GetOpenPosition(const string symbol) // Signal Open Position 
      {
    //---
        int ret=0;
        int rise=1,
            down=-1;
        //--
        int dirmov=DirectionMove(symbol);
        int parsOp=GetPSARSignalMTF(symbol);
        //--
        if(parsOp==rise && dirmov==rise) ret=rise;
        if(parsOp==down && dirmov==down) ret=down;
        //--
        return(ret);
    //---
      } //-end GetOpenPosition()
    //---------//


    La función GetPSARSignalMTF() llamará a la función PARSARMTF(), que calculará la señal iSAR según el marco temporal solicitado.

    Como podemos ver, dentro de la función PARSARMTF(), usaremos y llamaremos a dos funciones:

    1. int xx= PairsIdxArray(symbol)

    La función PairsIdxArray() se usará para obtener el nombre del símbolo solicitado.

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

    2. int tx=TFIndexArray(mtf).

    La función TFIndexArray() se utilizará para recuperar la secuencia de arrays del marco temporal solicitado.

    int MCEA::TFIndexArray(ENUM_TIMEFRAMES TF)
      {
    //---
        int res=-1;
        //--
        for(int x=0; x if (TF==TFSAR[x])
              {
                res=x;
                break;
              }
          }
        //--
        return(res);
    //---
      } //-end TFIndexArray() 
    //---------//


    5. Función ChartEvent

    Para que los asesores multidivisa resulten más eficaces, crearemos varios botones para gestionar órdenes y cambiar gráficos o símbolos. Como esta versión utilizará 10 variantes de pares comerciales, la función OnChartEvent se ha modificado ligeramente.

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


    Para cambiar los símbolos del gráfico con un solo clic, al clicar en uno de los nombres de los símbolos, el evento OnChartEvent() será llamado por ChangeChartSymbol().

    void ChangeChartSymbol(string c_symbol,ENUM_TIMEFRAMES cstf)
      {
    //---
       //--- unpress the button 
       ObjectSetInteger(0,c_symbol,OBJPROP_STATE,false);
       ObjectSetInteger(0,c_symbol,OBJPROP_ZORDER,0);
       ObjectsDeleteAll(0,0,OBJ_BUTTON);
       ObjectsDeleteAll(0,0,OBJ_LABEL);
       ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL);
       //--
       ChartSetSymbolPeriod(0,c_symbol,cstf);
       //--
       ChartRedraw(0);
       //--
       return;
    //---
      } //-end ChangeChartSymbol()
    //---------//


    Como estamos añadiendo una sesión comercial o una zona horaria comercial y los parámetros de los pares negociados, necesitaremos agregar nuevos datos a la información comercial mostrada en el gráfico.

    Para ello, hemos modificado la función TradeInfo().

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


    Así, añadiremos una función para explicar la hora según las condiciones de la zona horaria comercial

    string MCEA::PosTimeZone(void)
      {
    //---
        string tzpos="";
        //--
        if(ReqTime(zntm,day)>ThisTime(day))
         {
           tzpos=tz_opn+ " Next day to " +tz_cls + " Next day";
         }
        else
        if(TimeCurrent() if (ThisTime(day)==ReqTime(znop,day) && ThisTime(day)==ReqTime(zncl,day))
              tzpos=tz_opn+" to " +tz_cls+ " Today";
            //else
            if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day) " Today to "  +tz_cls+ " Next day";
          }
        else
        if(TimeCurrent()>=znop && TimeCurrent() if (ThisTime(day) " Today to "  +tz_cls+ " Next day";
            else
            if(ThisTime(day)==ReqTime(zncl,day))
              tzpos=tz_opn+" to " +tz_cls+ " Today";
          }
        else
        if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day) " Today to "  +tz_cls+ " Next day";
          }
        //--
        return(tzpos);
    //----
      } //-end PosTimeZone()
    //---------//


    La pantalla de TradeInfo() tendrá este aspecto.

    waiting_time


    Nota: Para las otras funciones y algoritmos, el procedimiento seguirá siendo el mismo que en el asesor multidivisa del artículo anterior.


    Como podemos ver, tenemos los botones M, C y R bajo el nombre del asesor FXSAR_MTF_MCEA.

    Pulsando M o C aparecerá el panel de control manual.

    MCR_Combine

    Clicando en M aparecerá el panel de control manual, después de lo cual el tráder podrá gestionar las órdenes:

    1. Set SL/TP All Orders (establecer stop loss/stake profit para todas las órdenes)
    2. Close All Orders (cerrar todas las órdenes)
    3. Close All Profits (cerrar todas las órdenes rentables)

    Clicando en C, aparecerá un botón en el panel con los 30 nombres de los símbolos o pares, y los tráders podrán clicar en uno de los nombres de los pares o símbolos. Pulsando cualquiera de ellos, se sustituirá inmediatamente el símbolo del gráfico por el indicado en el botón pulsado.

    void CreateSymbolPanel()
      {
    //---    
        //--
        ResetLastError();
        DeletePanelButton();
        int sydis=83;
        int tsatu=int(mc.sall/2);
        //--
        CreateButtonTemplate(0,"Template",180,367,STYLE_SOLID,5,BORDER_RAISED,clrYellow,clrBurlyWood,clrWhite,CORNER_RIGHT_UPPER,187,45,true);
        CreateButtonTemplate(0,"TempCCS",167,25,STYLE_SOLID,5,BORDER_RAISED,clrYellow,clrBlue,clrWhite,CORNER_RIGHT_UPPER,181,50,true);
        CreateButtonClick(0,"X",14,14,"Arial Black",10,BORDER_FLAT,"X",clrWhite,clrWhite,clrRed,ANCHOR_CENTER,CORNER_RIGHT_UPPER,22,48,true,"Close Symbol Panel");
        //--
        string chsym="Change SYMBOL";
        int cspos=int(181/2)+int(StringLen(chsym)/2);
        CreateButtontLable(0,"CCS","Bodoni MT Black",chsym,11,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,cspos,62,true,"Change Chart Symbol");
        //--
        for(int i=0; i 0 ,mc.AS30[i],80,17,"Bodoni MT Black",8,BORDER_RAISED,mc.AS30[i],clrYellow,clrBlue,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,180,sydis+(i*22),true,"Change to "+mc.AS30[i]);
        //--
        for(int i=tsatu; i 0 ,mc.AS30[i],80,17,"Bodoni MT Black",8,BORDER_RAISED,mc.AS30[i],clrYellow,clrBlue,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,94,sydis+((i-15)*22),true,"Change to "+mc.AS30[i]);
        //--
        ChartRedraw(0);
        //--
        return;
    //---
       } //-end CreateSymbolPanel()
    //---------//

    Pulsando R, el asesor multidivisa FXSAR_MTF_MCEA se eliminará del gráfico.


    Simulador de estrategias

    Hemos realizado algunas pruebas históricas, probando varias zonas horarias y pares con los que podíamos operar.

    Los resultados en el simulador de estrategias pueden verse en la siguiente imagen.

    En la prueba con la historia que se muestra a continuación, hemos seleccionado la zona horaria de Nueva York.

    FXSAR_MTF_MCEA_sptz_01


    En la prueba con la historia que se muestra a continuación, hemos seleccionado la zona horaria de Tokio.

    FXSAR_MTF_MCEA_sptz_02


    En la prueba con la historia que se muestra a continuación, hemos seleccionado una zona horaria de usuario

    FXSAR_MTF_MCEA_sptz_03


    Conclusión

    1. El problema de los nombres de los símbolos con prefijos y/o sufijos en los asesores multidivisa puede resolverse fácilmente en MQL5 sin necesidad de crear símbolos personalizados.
    2. Con la introducción de una sesión comercial o zona horaria comercial, y la adición de 10 pares de opciones para negociar, esperamos que los tráders obtengan una mejor estrategia negociando solo con determinados pares y en determinados momentos o sesiones.
    3. El presente asesor multidivisa supone solo un ejemplo para estudiar y desarrollar determinadas ideas, por lo que si tiene ideas propias para mejorarlo, podrá modificar el código del asesor según sus deseos.

    Esperamos que el artículo y el asesor multidivisa resulten útiles a los tráders para aprender y desarrollar sus ideas. ¡Gracias por su atención!


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

    Archivos adjuntos |
    Cómo desarrollar un agente de aprendizaje por refuerzo en MQL5 con Integración RestAPI (Parte 1): Como usar RestAPIs en MQL5 Cómo desarrollar un agente de aprendizaje por refuerzo en MQL5 con Integración RestAPI (Parte 1): Como usar RestAPIs en MQL5
    Este artículo aborda la importancia de las APIs (application programming interface) en la comunicación entre diferentes aplicaciones y sistemas de software. En él, se destaca el papel de las API a la hora de simplificar la interacción entre aplicaciones, ya que les permiten compartir datos y funcionalidades de forma eficiente.
    Desarrollo de un sistema de repetición (Parte 33): Sistema de órdenes (II) Desarrollo de un sistema de repetición (Parte 33): Sistema de órdenes (II)
    Vamos a continuar el desarrollo del sistema de órdenes, pero verás que haremos una reutilización masiva de cosas ya vistas en otros artículos. Aun así, tendremos una pequeña recompensa en este artículo. Desarrollaremos, en primer lugar, un sistema que pueda ser operado junto al servidor de negociación real, ya sea usando una cuenta demo o una cuenta real. Haremos uso masivo y extensivo de la plataforma MetaTrader 5 para proporcionarnos todo el soporte que necesitaremos en este inicio de viaje.
    Desarrollo de un sistema de repetición (Parte 34): Sistema de órdenes (III) Desarrollo de un sistema de repetición (Parte 34): Sistema de órdenes (III)
    En este artículo concluiremos la primera fase de la construcción. Aunque será algo relativamente rápido, explicaré detalles que quizás no se comentaron anteriormente. Pero aquí explicaré algunas cosas que mucha gente no entiende por qué son como son. Uno de estos casos es el del ratón. ¡¡¡¿Sabes por qué tienes que pulsar la tecla Shift o Ctrl en tu teclado?!!!
    Redes neuronales: así de sencillo (Parte 62): Uso del transformador de decisiones en modelos jerárquicos Redes neuronales: así de sencillo (Parte 62): Uso del transformador de decisiones en modelos jerárquicos
    En artículos recientes, hemos visto varios usos del método Decision Transformer, que permite analizar no solo el estado actual, sino también la trayectoria de los estados anteriores y las acciones realizadas en ellos. En este artículo, veremos una variante del uso de este método en modelos jerárquicos.