English Русский Deutsch 日本語 Português
preview
Creamos un asesor multidivisa sencillo utilizando MQL5 (Parte 4): Media móvil triangular - Señales del indicador

Creamos un asesor multidivisa sencillo utilizando MQL5 (Parte 4): Media móvil triangular - Señales del indicador

MetaTrader 5Trading | 16 abril 2024, 14:31
349 0
Roberto Jacobs
Roberto Jacobs

Introducción

Por asesor multidivisa en este artículo entendemos un asesor, o un robot comercial que puede operar (abrir/cerrar órdenes, gestionar órdenes como Trailing Stop Loss y Trailing Profit) con más de un par de símbolos desde un gráfico. En este artículo, el asesor comerciará con 30 pares.

Esta vez usaremos un solo indicador, a saber, la media móvil triangular en uno o varios marcos temporales.
    En este artículo, al calcular las señales del asesor, podremos elegir si deseamos activar uno o más marcos temporales.

    Triangular Moving Average es un indicador personalizado para MetaTrader 5 creado por Mladen Rakic. En nuestro caso, hemos obtenido el permiso del autor para usar su indicador como una señal en el asesor multidivisa TriangularMA_MTF_MCEA.
    Gracias a Mladen Rakic por la oportunidad.

    Sabemos que el trading multidivisa tanto en el terminal comercial como en el simulador de estrategias es posible gracias a MQL5.

    Así pues, el objetivo consistirá en cumplir las necesidades básicas de los tráders que desean robots comerciales eficientes y eficaces. Confiando en las fortalezas y capacidades de MQL5, podemos crear un asesor multidivisa sencillo que utilice las señales de las medias móviles triangulares en este artículo.

    Observación: El asesor multidivisa TriangularMA_MTF_MCEA fue creado a petición de los tráders.


    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,NZDCHF,NZDJPY,NZDJPY,CADCHF,CADJPY,CHFJPY = 28 pares

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

    30 pares en total.

    En el artículo anterior, utilizamos una función automática para detectar los pares de nombres con prefijos y/o sufijos.
    En este artículo, hemos simplificado la tarea añadiendo propiedades de entrada especiales para el prefijo y el sufijo del nombre del par.
    A continuación, utilizaremos una función sencilla para procesar los nombres de pares de prefijos y/o sufijos en combinación con los 30 nombres de pares registrados, por lo que si estamos utilizando un asesor con estos nombres de símbolos especiales en MetaTrader 5, todo funcionará sin problemas.

    Una desventaja de la función para detectar nombres de símbolos con prefijos y sufijos es que solo funciona con pares o nombres de símbolos para divisas y metales en MetaTrader 5, pero no funciona con símbolos especiales e índices.
    Asimismo, otra desventaja de este método es la necesidad de evitar errores tipográficos (debe introducirse distinguiendo entre mayúsculas y minúsculas) en el nombre del prefijo y/o sufijo del par.

    Como en el artículo anterior, también hemos añadido a este asesor 10 opciones sobre pares comerciados.
    Uno de los 10 pares de opciones que se comerciarán es Trader Wishes Pairs, donde los pares comerciados deben ser introducidos manualmente por el tráder en las propiedades del asesor. No olvide que el nombre del par introducido debe figurar ya en la lista de 30.

    Al igual que en el artículo anterior, en esta versión del asesor también hemos añadido una opción de sesión comercial (zona horaria), por lo que los pares comerciados se corresponderán con la hora de la sesión comercial.


    2. Indicador de señales.

    En la descripción de la media móvil triangular, el autor escribe:

    "Uso:
    Puede usar el cambio de color como señal".

    Colores por defecto del indicador de media móvil triangular:

    • 0-DarkGray = señal desconocida
    • 1-DeepPink = señal de venta
    • 2-MediumSeaGreen = señal de compra.

    En esta versión del asesor, hemos creado dos opciones para usar marcos temporales al calcular la señal de media móvil triangular.

    1. Cálculo de señales basado en un marco temporal múltiple.
    En un sistema de cálculo de marco temporal múltiple, los tráders deberán seleccionar la serie de marcos temporales deseada de una lista de enumeración.
    Las series temporales seleccionadas van de M5 a D1 (11 marcos temporales).
    Los tráders pueden seleccionar una serie de marcos temporales, de inicio (por ejemplo, M15) y de fin (por ejemplo, H4).
    Por lo tanto, el asesor calculará la señal de media móvil triangular partiendo del marco temporal M15 y terminando con el H4.

    Cálculos de medias móviles triangulares en múltiples marcos temporales:

    • Tendremos una señal de compra si el indicador es de color MediumSeaGreen en todos los marcos temporales seleccionados.
    • Tendremos una señal de venta si el indicador es de color DeepPink en todos los marcos temporales seleccionados.

    2. Cálculo de señales basado en un único marco temporal.
    En el sistema de cálculo de señales de un solo marco temporal, los tráders deberán elegir un marco temporal entre 11, empezando por M5 y terminando por D1.
    Así, el asesor calculará la señal del indicador de media móvil triangular en el marco temporal seleccionado.

    El cálculo de la señal de media móvil triangular en un marco temporal tendrá el aspecto que sigue:

    • Tendremos una señal de compra si las 2 barras anteriores son DeepPink, la barra anterior es MediumSeaGreen y la barra actual es MediumSeaGreen.
    • Tendremos una señal de venta si las 2 barras anteriores son MediumSeaGreen, la 1 barra anterior es DeepPink y la barra actual es DeepPink.

    Podrá ver la media móvil triangular para señales de compra y venta en las figuras 1 y 2.

    H4_TriangularMA01

      H4_TriangularMA02


      3. Gestión comercial y de órdenes.

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

      1. Órdenes Stop Loss

      • Opciones: Use Order Stop Loss (Yes) o (No) - Usar orden Stop Loss: Sí o No

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

                  Si selecciona Use Order Stop Loss (Yes):

                  De nuevo se le dará a elegir: Use Automatic Calculation Stop Loss (Yes) o (No) - utilizar cálculo automático de Stop Loss: sí o no

                  Si selecciona Automatic Calculation Stop Loss (Yes), el Stop Loss será calculado por el asesor.

                  Si se selecciona Automatic Calculation Stop Loss (No), el tráder deberá introducir el valor de Stop Loss en pips.

                  Si Use Order Stop Loss (No):

                  A continuación, el asesor comprobará el estado de la señal para cada orden abierta y evaluará el

                  potencial de los beneficios. Si la señal es cada vez más débil, significará que la orden deberá cerrarse para conservar

                  el beneficio. O bien la señal indica un cambio de dirección, y la orden deberá cerrarse con pérdidas.

                  Observación:
                  Antes de cerrar una operación debido a una señal débil, se solicitará la confirmación del usuario.


      2. Órdenes Take Profit

      • Opciones: Use Order Take Profit (Yes) o (No) - Usar orden Take Profit: Sí o No

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

                  Si se utiliza Use Order Take Profit (Yes):

                  De nuevo se le dará a elegir: Use Automatic Calculation Order Take Profit (Yes) o (No) - Utilizar cálculo automático de Take Profit: Sí o No

                  Si se selecciona Use Automatic Calculation Order Take Profit (Yes), el Take Profit será calculado por el asesor.

                  Si se selecciona Use Automatic Calculation Order Take Profit (No), el tráder deberá introducir el valor del Take Profit en pips.


      3. Trailing stop y Trailing Take Profit

      • Opciones: Use Trailing SL/TP (Yes) o (No) - Usar Trailing Stop Loss/Take Profit: Sí o No

                  Con la opción Use Trailing SL/TP (No), el asesor no utilizará Trailing Stop Loss y Take Profit.

                  Si Use Trailing SL/TP (Yes):

                  De nuevo se le dará a elegir: Use Automatic Trailing (Yes) o (No) - Utilizar Trailing automático: Sí o No           

                  Si Use Automatic Trailing (Yes), el Trailing Stop será ejecutado por el asesor utilizando la función 

                  búfer cero de la media móvil triangular (datos del indicador) en el marco temporal seleccionado automáticamente por el asesor, y simultáneamente

                  con un beneficio móvil basado en el valor de la variable TPmin (valor mínimo del beneficio móvil).

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

                  Observación: El asesor realizará el Trailing Take Profit simultáneamente con el Trailing Stop.


      Función Trailing Stop Price:

      double MCEA::TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type)
        {
      //---
          int br=2;
          double pval=0.0;
          int x=PairsIdxArray(xsymb);
          Pips(xsymb);
          //--
          switch(TS_type)
            {
              case 0:
                {
                  RefreshTick(xsymb);
                  if(ptype==POSITION_TYPE_BUY)  pval=mc_symbol.NormalizePrice(mc_symbol.Bid()-TSval*pip);
                  if(ptype==POSITION_TYPE_SELL) pval=mc_symbol.NormalizePrice(mc_symbol.Ask()+TSval*pip);
                  break;
                }
              case 1:
                {
                  double TriMAID[];
                  //--
                  ArrayResize(TriMAID,br,br);
                  ArraySetAsSeries(TriMAID,true);
                  CopyBuffer(hTriMAt[x],0,0,br,TriMAID); // Copy buffer 0 from the hTriMAt indicator handle
                  //--
                  RefreshTick(xsymb);
                  if(ptype==POSITION_TYPE_BUY  && (mc_symbol.Bid()>mc_symbol.NormalizePrice(TriMAID[0]+TSval*pip))) pval=TriMAID[0];
                  if(ptype==POSITION_TYPE_SELL && (mc_symbol.Ask() 0 ]-TSval*pip))) pval=TriMAID[0];
                  break;
                }
            }
          //--
          return(pval);
      //---
        } //-end TSPrice()
      //---------//


      Cambio de la función SL/TP:

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


      4. Gestión manual de órdenes.

      Para aumentar la eficacia, se añadirán 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 quiere utilizar Stop Loss o Take Profit para todas las órdenes, solo deberá clicar en el botón
      Set SL / TP All Orders para cambiar todas las órdenes y aplicar Stop Loss y/o Take Profit.

      2. Close All Orders
      Cerrar todas las órdenes.

      3. Close All Orders Profit
      Si un tráder desea cerrar todas las órdenes que ya son rentables, bastará con pulsar un solo botón
      Close All Orders Profit para cerrar todas las órdenes rentables abiertas.


      5. Management Orders and Chart Symbols.

      Una característica muy útil para los asesores multidivisa que operan con 30 pares desde un único gráfico sería disponer de una única barra de botones para que los tráders pudieran cambiar de gráfico o de símbolo con un solo clic.


      Aplicación de la planificación en un 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 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 utiliza para las opciones (Yes) o (No) en el parámetro del asesor

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


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

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


      Enumeración para seleccionar el marco temporal que se usará en marcos temporales únicos y múltiples

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


      Enumeración para utilizar uno o varios marcos temporales

      //--
      enum SMTF
        {
          MTF,   // Use Multi-Timeframe
          STF    // Use Single-Timeframe
        };
      //--


      Parámetros de entrada del asesor

      //---
      input group               "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter
      input SMTF                tfinuse = MTF;              // Select Calculation in Multi or Single Timeframe
      input TFMTF              singletf = TFH1;             // Select Single Calculation TimeFrame, default PERIOD_H1
      input TFMTF               tfstart = TFM15;            // Select Multi Timeframe calculation start 
      input TFMTF               tfclose = TFH4;             // Select Multi Timeframe calculation end
      input int              Trmaperiod = 14;               // Input Triangular MA Indicator period, default 14
      input ENUM_APPLIED_PRICE  Trprice = PRICE_CLOSE;      // Select Triangular MA Applied Price, default Price Close
      //---
      input group               "=== Select Pairs to Trade ===";  // Selected Pairs to trading
      input PairsTrade         usepairs = All30;           // Select Pairs to Use
      input string         traderwishes = "eg. eurusd,usdchf"; // If Use Trader Wishes Pairs, input pair name here, separate by comma
      input string           sym_prefix = "";              // Input the symbol prefix in case sensitive (if any)
      input string           sym_suffix = "";              // Input the symbol suffix in case sensitive (if any)
      //--
      input group               "=== Money Management Lot Size Parameter ==="; // Money Management Lot Size Parameter
      input mmt                  mmlot = DynamLot;         // Money Management Type
      input double                Risk = 10.0;             // Percent Equity Risk per Trade (Min=1.0% / Max=10.0%)
      input double                Lots = 0.01;             // Input Manual Lot Size FixedLot
      //--Trade on Specific Time
      input group               "=== Trade on Specific Time ==="; // Trade on Specific Time
      input YN           trd_time_zone = Yes;              // Select If You Like to Trade on Specific Time Zone
      input tm_zone            session = Cus_Session;      // Select Trading Time Zone
      input swhour            stsescuh = hr_00;            // Time Hour to Start Trading Custom Session (0-23)
      input inmnt             stsescum = mn_15;            // Time Minute to Start Trading Custom Session (0-55)
      input swhour            clsescuh = hr_23;            // Time Hour to Stop Trading Custom Session (0-23)
      input inmnt             clsescum = mn_55;            // Time Minute to Stop Trading Custom Session (0-55)
      //--Day Trading On/Off
      input group               "=== Day Trading On/Off ==="; // Day Trading On/Off
      input YN                    ttd0 = No;               // Select Trading on Sunday (Yes) or (No)
      input YN                    ttd1 = Yes;              // Select Trading on Monday (Yes) or (No)
      input YN                    ttd2 = Yes;              // Select Trading on Tuesday (Yes) or (No)
      input YN                    ttd3 = Yes;              // Select Trading on Wednesday (Yes) or (No)
      input YN                    ttd4 = Yes;              // Select Trading on Thursday (Yes) or (No)
      input YN                    ttd5 = Yes;              // Select Trading on Friday (Yes) or (No)
      input YN                    ttd6 = No;               // Select Trading on Saturday (Yes) or (No)
      //--Trade & Order management Parameter
      input group               "=== Trade & Order management Parameter ==="; // Trade & Order management Parameter
      input YN                  use_sl = No;               // Use Order Stop Loss (Yes) or (No)
      input YN                  autosl = Yes;              // Use Automatic Calculation Stop Loss (Yes) or (No)
      input double               SLval = 30;               // If Not Use Automatic SL - Input SL value in Pips
      input YN                  use_tp = Yes;               // Use Order Take Profit (Yes) or (No)
      input YN                  autotp = Yes;              // Use Automatic Calculation Take Profit (Yes) or (No)
      input double               TPval = 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 = 2023111;          // Expert ID (Magic Number)
      //---


      En el grupo de propiedades de los datos de entrada de parámetros del asesor de estrategia global, los tráders deberán seleccionar si desean utilizar el cálculo de señales en un único marco temporal o en varios marcos temporales.

      Si seleccionamos un marco temporal (STF), deberemos especificarlo.
      En el parámetro de entrada asesor, seleccionaremos Select Single Calculation timeframe (elegir un marco temporal para el cálculo), el valor por defecto será PERIOD_H1.

      Si se seleccionan varios marcos temporales (MTF), deberán especificarse.
      En el parámetro de entrada asesor, seleccionaremos Select Multi Timeframe calculation start (inicio del cálculo en el marco temporal múltiple) y Multi Timeframe calculation end (fin del cálculo en el marco temporal múltiple).

      Las líneas 478-518 de la función TriangularMA_MTF_MCEA_Config() explican cómo trabajar con marcos temporales simples y múltiples.

          ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1};
          int arTFs=ArraySize(TFs);
          //--
          for(int x=0; x if (singletf==x) TFt=TFs[x]; // TF for single-timeframe
              if(tfstart==x)  arstr=x;    // multi-timeframe start calculation timeframe
              if(tfclose==x)  arend=x;    // multi-timeframe end calculation timeframe
            }
          //--
          if(arstr>=arend)
            {
              Alert("Error selecting Start and End Timeframe, Start Timeframe must be smaller than End Timeframe");
              Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart.");
              ExpertRemove();
            }
          //--
          switch(tfinuse)
            {
              case MTF: 
                {
                  TFArrays=arend-arstr+1;
                  ArrayResize(TFTri,TFArrays,TFArrays);
                  ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY);
                  tfcinws=arstr+1;
                  tftrlst=(int)TFArrays/2;
                  TFts=TFs[tftrlst+arstr-1];   // TF for Trailing Stop
                  TFCWS=TFs[tfcinws];          // TF for Close Order in weak signal
                  break;
                }
              case STF: 
                {
                  TFArrays=arTFs;
                  ArrayResize(TFTri,TFArrays,TFArrays);
                  ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY);
                  tfcinws=TFIndexArray(TFt)-2 <=0 ? 1 : TFIndexArray(TFt)-2;
                  TFts=TFt;            // TF for Trailing Stop
                  TFCWS=TFs[tfcinws];  // TF for Close Order in weak signal
                  break;
                }
            }


      La variable ENUM_TIMEFRAMES TFs[] deberá ser una propiedad de la opción de enumeración enum TFMTF

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


      A continuación, el tráder deberá determinar el periodo del indicador MA triangular. El periodo por defecto será de 14.
      Además, deberemos especificar el precio de cálculo de Triangular MA. El precio por defecto será PRICE_CLOSE.

      En el grupo de propiedades de los datos de entrada Select Pairs to Trade deberemos seleccionar un par para comerciar de las 10 opciones proporcionadas. El valor por defecto será All Forex 30 Pairs (todos los 30 pares).

      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)
            {
              string to_split=traderwishes; // A string to split into substrings pairs name
              string sep=",";               // A separator as a character 
              ushort u_sep;                 // The code of the separator character 
              //--- Get the separator code 
              u_sep=StringGetCharacter(sep,0);
              //--- Split the string to substrings 
              int p=StringSplit(to_split,u_sep,SPC); 
              if(p>0)
                {
                  for(int i=0; i StringToUpper (SPC[i]);
                  //--
                  for(int i=0; i if (ValidatePairs(SPC[i])<0) ArrayRemove(SPC,i,1);
                    }
                }
              arspc=ArraySize(SPC);
            }
          //--
          SetSymbolNamePS();      // With this function we will detect whether the Symbol Name has a prefix and/or suffix
          //--
          if(inpre>0 || insuf>0)
            {
              if(usepairs==TrdWi && arspc>0)
                {
                  for(int t=0; t //-- 
              for(int t=0; t for (int t=0; t for (int t=0; t for (int t=0; t for (int t=0; t for (int t=0; t for (int t=0; t for (int t=0; t for (int t=0; t //-- 
          ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY);
          ArrayResize(AS30,sall,sall);
          ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY);
          for(int x=0; x SymbolSelect (AS30[x],true);}
          if(ValidatePairs(Symbol())>=0) symbfix=true;
          if(!symbfix) 
            {
              Alert("Expert Advisors will not trade on pairs "+Symbol());
              Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart.");
              ExpertRemove();
            }
          //--
          switch(usepairs)
            {
              case 0: // All Forex 30 Pairs
                {
                  ArrayResize(DIRI,sall,sall);
                  arrsymbx=sall;
                  ArraySymbolResize();
                  ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY);
                  pairs="Multi Currency 30 Pairs";
                  //--
                  break;
                }
              case 1: // Trader wishes pairs
                {
                  ArrayResize(DIRI,arspc,arspc);
                  arrsymbx=arspc;
                  ArraySymbolResize();
                  ArrayCopy(DIRI,SPC,0,0,WHOLE_ARRAY);
                  pairs="("+string(arspc)+") Trader Wishes Pairs";
                  //--
                  break;
                }
              case 2: // USD pairs
                {
                  ArrayResize(DIRI,arusd,arusd);
                  arrsymbx=arusd;
                  ArraySymbolResize();
                  ArrayCopy(DIRI,USDs,0,0,WHOLE_ARRAY);
                  pairs="("+string(arusd)+") Multi Currency USD Pairs";
                  //--
                  break;
                }
              case 3: // EUR pairs
                {
                  ArrayResize(DIRI,aretc,aretc);
                  arrsymbx=aretc;
                  ArraySymbolResize();
                  ArrayCopy(DIRI,EURs,0,0,WHOLE_ARRAY);
                  pairs="("+string(aretc)+") Forex EUR Pairs";
                  //--
                  break;
                }
              case 4: // GBP pairs
                {
                  ArrayResize(DIRI,aretc,aretc);
                  arrsymbx=aretc;
                  ArraySymbolResize();
                  ArrayCopy(DIRI,GBPs,0,0,WHOLE_ARRAY);
                  pairs="("+string(aretc)+") Forex GBP Pairs";
                  //--
                  break;
                }
              case 5: // AUD pairs
                {
                  ArrayResize(DIRI,aretc,aretc);
                  arrsymbx=aretc;
                  ArraySymbolResize();
                  ArrayCopy(DIRI,AUDs,0,0,WHOLE_ARRAY);
                  pairs="("+string(aretc)+") Forex AUD Pairs";
                  //--
                  break;
                }
              case 6: // NZD pairs
                {
                  ArrayResize(DIRI,aretc,aretc);
                  arrsymbx=aretc;
                  ArraySymbolResize();
                  ArrayCopy(DIRI,NZDs,0,0,WHOLE_ARRAY);
                  pairs="("+string(aretc)+") Forex NZD Pairs";
                  //--
                  break;
                }
              case 7: // CAD pairs
                {
                  ArrayResize(DIRI,aretc,aretc);
                  arrsymbx=aretc;
                  ArraySymbolResize();
                  ArrayCopy(DIRI,CADs,0,0,WHOLE_ARRAY);
                  pairs="("+string(aretc)+") Forex CAD Pairs";
                  //--
                  break;
                }
              case 8: // CHF pairs
                {
                  ArrayResize(DIRI,aretc,aretc);
                  arrsymbx=aretc;
                  ArraySymbolResize();
                  ArrayCopy(DIRI,CHFs,0,0,WHOLE_ARRAY);
                  pairs="("+string(aretc)+") Forex CHF Pairs";
                  //--
                  break;
                }
              case 9: // JPY pairs
                {
                  ArrayResize(DIRI,aretc,aretc);
                  arrsymbx=aretc;
                  ArraySymbolResize();
                  ArrayCopy(DIRI,JPYs,0,0,WHOLE_ARRAY);
                  pairs="("+string(aretc)+") Forex JPY Pairs";
                  //--
                  break;
                }
            }
          //--
          return;
      //---
        } //-end HandlingSymbolArrays()
      //---------//


      Dentro de la función HandlingSymbolArrays(), llamaremos a la función SetSymbolNamePS().
      Podemos utilizarla para manejar nombres de símbolos que tengan prefijos y/o sufijos.

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

      Observación:
      El asesor comprobará los pares.
      Si el tráder comete un error al introducir el nombre de un par o el nombre de prefijo/sufijo
      o la comprobación del par ha fallado, el asesor generará una advertencia y será eliminado del gráfico.


      En el grupo de propiedades Trade on Specific Time, el tráder deberá seleccionar Trade on Specific Time Zone (Yes) o (No).
      - comerciar en una zona horaria específica: sí o no. En caso afirmativo, deberemos seleccionar los parámetros de la enumeración:

      • Trading on Custom Session (sesión personalizada)
      • Trading on New Zealand Session (sesión neozelandesa)
      • Trading on Australia Sydney Session (sesión australiana de Sídney)
      • Trading on Asia Tokyo Session (sesión asiática de Tokio)
      • Trading on Europe London Session (sesión europea de Londres)
      • Trading on America New York Session (sesión americana de Nueva York)

      Trading on Custom Session (sesión personalizada): Los tráders deberán fijar una hora u horas y minutos para iniciar el comercio, así como las horas y minutos para cerrarla.

      Así, el asesor solo realizará acciones durante el tiempo indicado.

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


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

      En particular, hemos implementado las variables utilizadas en la función para manejar los nombres de los símbolos prefijos y/o los nombres de los símbolos de sufijos y los cálculos de 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;
          bool             symbfix;
          string           pre,suf;
          string           prefix,suffix;       
          //--- Variables are used in Trading Time Zone
          int              ishour,
                           onhour;
          int              tftrlst,
                           tfcinws;
          datetime         rem,
                           znop,
                           zncl,
                           zntm;
          datetime         SesCuOp,
                           SesCuCl,
                           Ses01Op,
                           Ses01Cl,
                           Ses02Op,
                           Ses02Cl,
                           Ses03Op,
                           Ses03Cl,
                           Ses04Op,
                           Ses04Cl,
                           Ses05Op,
                           Ses05Cl,
                           SesNoOp,
                           SesNoCl;
          //--
          string           tz_ses,
                           tz_opn,
                           tz_cls;
          //--
          string           tmopcu,
                           tmclcu,
                           tmop01,
                           tmcl01,
                           tmop02,
                           tmcl02,
                           tmop03,
                           tmcl03,
                           tmop04,
                           tmcl04,
                           tmop05,
                           tmcl05,
                           tmopno,
                           tmclno;      
          //----------------------    
          //--
          double           LotPS;
          double           slv,
                           tpv,
                           pip,
                           xpip;              
          double           floatprofit,
                           fixclprofit;
          //--
          string           pairs,
                           hariini,
                           daytrade,
                           trade_mode;
          //--
          double           OPEN[],
                           HIGH[],
                           LOW[],
                           CLOSE[];
          datetime         TIME[];
          datetime         closetime;
          //--
          //------------
           
          //------------
          void             SetSymbolNamePS(void);
          void             HandlingSymbolArrays(void);
          void             Set_Time_Zone(void);
          void             Time_Zone(void);
          bool             Trade_session(void);
          string           PosTimeZone(void);
          int              ThisTime(const int reqmode);
          int              ReqTime(datetime reqtime,const int reqmode);
          //--
          int              DirectionMove(const string symbol,const ENUM_TIMEFRAMES stf);
          int              TriaMASMTF(const string symbol,ENUM_TIMEFRAMES mtf);
          int              GetTriaMASignalMTF(string symbol);
          int              TriaMASignalSTF(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:
          //---
          
          //-- TriangularMA_MTF_MCEA Config --
          string           DIRI[],
                           AS30[],
                           VSym[];
          string           SPC[];
          string           USD[];
          string           EUR[];
          string           GBP[];
          string           AUD[];
          string           NZD[];
          string           CAD[];
          string           CHF[];
          string           JPY[];             
          //--                 
          string           expname;
          string           indiname;
          //--
          int              hTriMAt[];
          int              hTriMAs[];
          int              hTriMAm[];
          int              hTriMAb[][11];
          int              ALO,
                           dgts,
                           arrsar,
                           arrsymbx;
          int              sall,
                           arusd,
                           aretc,
                           arspc,
                           arper;
          ulong            slip;        
          //--
          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,
                           TFts,
                           TFT05,
                           TFCWS;
          ENUM_TIMEFRAMES  TFTri[];
          //--
          bool             PanelExtra;
          //------------
                           MCEA(void);
                           ~MCEA(void);            
          //------------
          //--
          virtual void     TriangularMA_MTF_MCEA_Config(void);
          virtual void     ExpertActionTrade(void);
          //--
          void             ArraySymbolResize(void);
          void             CurrentSymbolSet(const string symbol);
          void             Pips(const string symbol);
          void             TradeInfo(void);
          void             Do_Alerts(const string symbx,string msgText);
          void             CheckOpenPMx(const string symbx);
          void             SetSLTPOrders(void);
          void             CloseBuyPositions(const string symbol);
          void             CloseSellPositions(const string symbol);
          void             CloseAllOrders(void);
          void             CheckClose(const string symbx);
          void             TodayOrders(void);
          void             UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf);
          void             RefreshPrice(const string symbx,ENUM_TIMEFRAMES xtf,int bars);
          //--
          bool             RefreshTick(const string symbx);  
          bool             TradingToday(void);
          bool             OpenBuy(const string symbol);
          bool             OpenSell(const string symbol);
          bool             ModifyOrderSLTP(double mStop,double ordtp);
          bool             ModifySLTP(const string symbx,int TS_type);          
          bool             CloseAllProfit(void);
          bool             ManualCloseAllProfit(void);
          //--
          int              PairsIdxArray(const string symbol);
          int              ValidatePairs(const string symbol);
          int              TFIndexArray(ENUM_TIMEFRAMES TF);
          int              GetOpenPosition(const string symbol);
          int              GetSignalMidTF(const string symbol);
          int              GetCloseInWeakSignal(const string symbol,int exis);
          //--
          string           getUninitReasonText(int reasonCode);
          //--
          //------------
      //---
        }; //-end class MCEA
      //---------//


      La primera y más importante de las funciones en el funcionamiento del asesor multidivisa, llamada desde OnInit(), será TriangularMA_MTF_MCEA_Config().

      En la función TriangularMA_MTF_MCEA_Config(), se configurarán todos los símbolos utilizados, todos los indicadores de manejadores usados y algunas funciones importantes del encabezado del archivo include.

      void MCEA::TriangularMA_MTF_MCEA_Config(void) 
        {
      //---
          //--
          HandlingSymbolArrays(); // With this function we will handle all pairs that will be traded
          //--
          int arstr=0,
              arend=0;
          TFT05=PERIOD_M5;
          ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1};
          int arTFs=ArraySize(TFs);
          //--
          for(int x=0; x if (singletf==x) TFt=TFs[x]; // TF for single-timeframe
              if(tfstart==x)  arstr=x;    // multi-timeframe start calculation timeframe
              if(tfclose==x)  arend=x;    // multi-timeframe end calculation timeframe
            }
          //--
          if(arstr>=arend)
            {
              Alert("Error selecting Start and End Timeframe, Start Timeframe must be smaller than End Timeframe");
              Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart.");
              ExpertRemove();
            }
          //--
          switch(tfinuse)
            {
              case MTF: 
                {
                  TFArrays=arend-arstr+1;
                  ArrayResize(TFTri,TFArrays,TFArrays);
                  ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY);
                  tfcinws=arstr+1;
                  tftrlst=(int)TFArrays/2;
                  TFts=TFs[tftrlst+arstr-1];   // TF for Trailing Stop
                  TFCWS=TFs[tfcinws];          // TF for Close Order in weak signal
                  break;
                }
              case STF: 
                {
                  TFArrays=arTFs;
                  ArrayResize(TFTri,TFArrays,TFArrays);
                  ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY);
                  tfcinws=TFIndexArray(TFt)-2 <=0 ? 1 : TFIndexArray(TFt)-2;
                  TFts=TFt;            // TF for Trailing Stop
                  TFCWS=TFs[tfcinws];  // TF for Close Order in weak signal
                  break;
                }
            }
          //--
          //-- Triangular MA Indicators handle for all symbol
          for(int x=0; x iCustom (DIRI[x],TFT05,indiname,Trmaperiod,Trprice);
              hTriMAm[x]=iCustom(DIRI[x],TFCWS,indiname,Trmaperiod,Trprice);
              hTriMAt[x]=iCustom(DIRI[x],TFts,indiname,Trmaperiod,Trprice);
              //--
              for(int i=0; i if (tfinuse==MTF) // MTF indicator handle
                    {
                      hTriMAb[x][i]=iCustom(DIRI[x],TFTri[i],indiname,Trmaperiod,Trprice);
                    }
                  if(tfinuse==STF)
                    {
                      if(TFs[i]==TFt) // Single-TF indicator handle
                        {
                          hTriMAb[x][i]=iCustom(DIRI[x],TFs[i],indiname,Trmaperiod,Trprice);
                          break;
                        }
                    }
                }
            }
          //--
          ALO=(int)mc_account.LimitOrders()>sall ? sall : (int)mc_account.LimitOrders();
          //--
          LotPS=(double)ALO;
          //--
          mc_trade.SetExpertMagicNumber(magicEA);
          mc_trade.SetDeviationInPoints(slip);
          mc_trade.SetMarginMode();
          Set_Time_Zone();
          //--
          return;
      //---
        } //-end TriangularMA_MTF_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 a la función ExpertActionTrade().

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


      Secuencia de funcionamiento del asesor dentro de esta función.

      La función ExpertActionTrade() realizará 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()
      //---------//


      Especialmente para las zonas horarias comerciales, hemos añadido una llamada de la función lógica Trade_session() a la función ExpertActionTrade().
      Cuando Trade_session() sea true, el asesor funcionará hasta la finalización, y cuando sea false, el asesor solo realizará las tareas Close Trade and Save profit due to weak signal (Yes) y Trailing stop (Yes).

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


      3. Recepción de señales para abrir posiciones

      La función ExpertActionTrade() llama a la función GetOpenPosition() para obtener una señal.

      int MCEA::GetOpenPosition(const string symbol) // Signal Open Position 
        {
      //---
          int ret=0;
          int rise=1,
              down=-1;
          //--
          int trimOp=GetTriaMASignalMTF(symbol);
          int getmid=GetSignalMidTF(symbol);
          if(trimOp==rise && getmid==rise) ret=rise;
          if(trimOp==down && getmid==down) ret=down;
          //--
          return(ret);
      //---
        } //-end GetOpenPosition()
      //---------//


      La función GetOpenPosition() llamará a dos funciones que realizarán los cálculos de las señales:

      1. GetSignalMidTF(const string symbol);          //-- Obtención de señales según las posiciones del marco temporal medio y el movimiento del precio

      int MCEA::GetSignalMidTF(const string symbol) // Signal Indicator Position Close in profit
        {
      //---
          int ret=0;
          int rise=1,
              down=-1;
          //--
          int br=2;
          //--
          double TriMACI[];
          //--
          ArrayResize(TriMACI,br,br);
          ArraySetAsSeries(TriMACI,true);
          int xx=PairsIdxArray(symbol);
          CopyBuffer(hTriMAm[xx],1,0,br,TriMACI);
          //#property indicator_color1  clrDarkGray,clrDeepPink,clrMediumSeaGreen
          //                                 0          1             2
          //--
          int dirmove=DirectionMove(symbol,TFCWS);
          //--
          if(TriMACI[0]==2.0 && dirmove==rise) ret=rise;
          if(TriMACI[0]==1.0 && dirmove==down) ret=down;
          //--
          return(ret);
      //---
        } //-end GetSignalMidTF()
      //---------//


      2. GetTriaMASignalMTF(const string symbol);    //-- Cálculo de la fórmula de la media móvil triangular.

      La función GetTriaMASignalMTF() llama a la función TriaMASMTF(), que calculará la media móvil triangular de la señal según el marco temporal solicitado.

      int MCEA::GetTriaMASignalMTF(string symbol)
        {
      //---
          int mv=0;
          int rise=1,
              down=-1;
          int tfloop=tfinuse==MTF ? TFArrays : 1;
          //--
          int trimup=0,
              trimdw=0;
          //--    
          for(int x=0; x if (TriaMASMTF(symbol,TFTri[x])>0) trimup++;
              if(TriaMASMTF(symbol,TFTri[x])<0) trimdw++;
            }   
          //--
          if(trimup==tfloop) mv=rise;
          if(trimdw==tfloop) mv=down;
          //--
          return(mv);
      //---
        } //- end GetTriaMASignalMTF()
      //---------//


      int MCEA::TriaMASMTF(const string symbol,const ENUM_TIMEFRAMES mtf) // formula Triangular MA on the requested Timeframe
        {
      //---
          int ret=0;
          int rise=1,
              down=-1;
          int br=3;
          ENUM_TIMEFRAMES TFUse=tfinuse==MTF ? mtf : TFt;
          //--
          double TriMACI[];
          ArrayResize(TriMACI,br,br);
          ArraySetAsSeries(TriMACI,true);
          int xx=PairsIdxArray(symbol);
          int tx=TFIndexArray(TFUse);
          CopyBuffer(hTriMAb[xx][tx],1,0,br,TriMACI);
          //#property indicator_color1  clrDarkGray,clrDeepPink,clrMediumSeaGreen
          //                                 0          1             2
          //Print("Symbol = "+symbol+" TF = "+EnumToString(mtf)+" TriMACI[0] = "+string(TriMACI[0]));
          //--
          switch(tfinuse)
            {
              case MTF:
                {
                  if(TriMACI[0]==2.0) ret=rise;
                  if(TriMACI[0]==1.0) ret=down;
                  //--
                  break;
                }
              case STF:
                {
                  if(TriMACI[2]==1.0 && TriMACI[1]==2.0 && TriMACI[0]==2.0) ret=rise;
                  if(TriMACI[2]==2.0 && TriMACI[1]==1.0 && TriMACI[0]==1.0) ret=down;
                  //--
                  break;
                }
            }
          //--
          return(ret);
      //---
        } //-end TriaMASMTF()
      //---------//


      Como podemos ver, utilizamos y llamamos a dos funciones dentro de la función TriaMASMTF():

      • 1. int xx= PairsIdxArray(symbol)
      • 2. int tx=TFIndexArray(mtf).

      La función PairsIdxArray() se usará para obtener el nombre del símbolo solicitado, mientras que la función TFIndexArray() se utilizará para obtener la secuencia del array del marco temporal solicitado.
      A continuación, se llamará al indicador correspondiente para obtener el valor de la media móvil triangular de ese marco temporal.

      Como dice el autor del indicador:
      "Uso:
      Puede usar el cambio de color como señal".

      Entonces, ¿cómo tomaremos una señal de la media móvil triangular?

      En la propiedad de la media móvil triangular:

      #property indicator_color1  clrDarkGray,clrDeepPink,clrMediumSeaGreen
      //                               0            1             2
      SetIndexBuffer(1,valc,INDICATOR_COLOR_INDEX);
      valc[i] = (i>0) ?(val[i]>val[i-1]) ? 2 :(val[i] 1 ]) ? 1 : valc[i-1]: 0;


      Bien, sabemos que:

      • 0-DarkGray = señal desconocida
      • 1-DeepPink = señal de venta
      • 2-MediumSeaGreen = señal de compra.

      Así, podremos tomar el valor del búfer 1 de la media móvil triangular como señal utilizando la función CopyBuffer, igual que en la función TriaMASMTF().

          double TriMACI[];
          ArrayResize(TriMACI,br,br);
          ArraySetAsSeries(TriMACI,true);
          int xx=PairsIdxArray(symbol);
          int tx=TFIndexArray(TFUse);
          CopyBuffer(hTriMAb[xx][tx],1,0,br,TriMACI);
          //#property indicator_color1  clrDarkGray,clrDeepPink,clrMediumSeaGreen
          //                                 0           1             2
      


      4. Función ChartEvent

      Para una mayor eficiencia de los asesores multidivisa, crearemos varios botones para la gestión de órdenes, así como
      los cambios en los gráficos y 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 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()
      //---------//


      A medida que añadimos una sesión comercial o una zona horaria comercial y los parámetros de pares comerciados en uno o más marcos temporales, necesitaremos añadir 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 tradetf=tfinuse==MTF ? EnumToString(Period()) : EnumToString(TFts);
         string eamode=tfinuse==MTF ? "Multi-Timeframe" : "Single-Timeframe";
         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      :  "+ tradetf+
              "\n      :: Trade Mode      :  "+ eamode+
              "\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()  
      //---------//


      También hemos agregado una función para describir la hora según las condiciones de la zona horaria comercial como parte de TradeInfo().

      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 interfaz del asesor multidivisa TriangularMA_MTF_MCEA tendrá el siguiente aspecto.

      TradeInfo


      Como podemos ver, bajo el nombre EA TriangularMA_MTF_MCEA tenemos los botones M, C y R

      Expert_manual_button

      Si pulsamos M, aparecerá el panel de control manual.

      Expert_manual_button_01

      A continuación, el tráder podrá gestionar las órdenes como se describe en la sección "Gestión manual de ó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 hacer clic en uno de los nombres de los pares o símbolos.
      Al pulsar cualquiera de ellos, se sustituirá inmediatamente el símbolo del gráfico por el indicado en el botón pulsado.

      Expert_manual_button_02


      Al pulsar R, el asesor multidivisa TriangularMA_MTF_MCEA se eliminará del gráfico, por lo que los tráders no necesitarán desactivar los asesores manualmente.



      Simulador de estrategias

      Como ya sabe, el simulador de estrategias de MetaTrader 5 ofrece soporte y permite la prueba de estrategias, comerciar con múltiples símbolos o probar el comercio automatizado para todos los símbolos disponibles y en todos los marcos temporales disponibles.

      Vamos a probar el asesor multidivisa y de marco temporal múltiple TriangularMA_MTF_MCEA en uno y varios marcos temporales en el simulador de estrategias de MetaTrader 5.

      1. Prueba de triangularMA_MTF_MCEA en varios marcos temporales.

      st-mtf/p>


      st-mtf-result


      2. Prueba de triangularMA_MTF_MCEA en un marco temporal.

      st-stf


      st-stf-result



      Conclusión

      La conclusión de los resultados de la creación de un asesor multidivisa y de marco temporal múltiple para trabajar con uno y varios marcos temporales utilizando MQL5 se puede expresar de la siguiente manera:

      • La creación de un asesor multidivisa en MQL5 no resulta muy diferente del desarrollo de un asesor de una sola divisa. Pero para los asesores multidivisa con marcos temporales múltiples, el proceso resulta un poco más complicado que para los asesores de un solo marco temporal.
      • La creación de un asesor multidivisa aumentará la eficiencia y la eficacia de los tráders, ya que no necesitarán abrir muchos gráficos.
      • Una estrategia comercial adecuada aumentará la probabilidad de obtener beneficios en comparación con el uso de un asesor en una sola divisa. Las pérdidas en un par se compensarán con los beneficios en otros pares.
      • El asesor Multidivisa TriangularMA_MTF_MCEA es solo un ejemplo para estudiar y desarrollar nuestras propias ideas. 
      • Los resultados de las pruebas en el simulador de estrategias siguen siendo insatisfactorios. Implementando una mejor estrategia con un cálculo más preciso de las señales y mejores marcos temporales, el resultado, a mi juicio, debería ser mejor que el actual.
      • Según los resultados de la prueba TriangularMA_MTF_MCEA en el simulador de estrategias, hemos aclarado que los resultados en un marco temporal son mejores que en varios marcos temporales.

      Observación:
      Si usted tiene una idea para crear un simple asesor multidivisa basado en las señales incorporadas del indicador estándar MQL5, por favor expóngala en los comentarios.
      Espero que el artículo y el asesor multidivisa le resulten útiles para aprender 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/13770

      Algoritmos de optimización de la población: Algoritmo de optimización de la dinámica espiral (Spiral Dynamics Optimization, SDO) Algoritmos de optimización de la población: Algoritmo de optimización de la dinámica espiral (Spiral Dynamics Optimization, SDO)
      Este artículo presenta un algoritmo de optimización basado en los patrones de las trayectorias en espiral en la naturaleza, como las conchas de los moluscos: el algoritmo de optimización de la dinámica espiral o SDO. El algoritmo propuesto ha sido repensado y modificado a fondo por el autor: en el artículo analizaremos por qué estos cambios han sido necesarios.
      Patrones de diseño en MQL5 (Parte 2): Patrones estructurales Patrones de diseño en MQL5 (Parte 2): Patrones estructurales
      En este artículo, seguiremos estudiando los patrones de diseño que permiten a los desarrolladores crear aplicaciones extensibles y fiables no solo en MQL5, sino también en otros lenguajes de programación. Esta vez hablaremos de un tipo diferente: los patrones estructurales. Asimismo, aprenderemos a diseñar sistemas usando las clases disponibles para formar estructuras mayores.
      Redes neuronales: así de sencillo (Parte 65): Aprendizaje supervisado ponderado por distancia (DWSL) Redes neuronales: así de sencillo (Parte 65): Aprendizaje supervisado ponderado por distancia (DWSL)
      En este artículo, le presentaremos un interesante algoritmo que se basa en la intersección de los métodos de aprendizaje supervisado y por refuerzo.
      Patrones de diseño en MQL5 (Parte I): Patrones de creación (Creational Patterns) Patrones de diseño en MQL5 (Parte I): Patrones de creación (Creational Patterns)
      Existen métodos que pueden usarse para resolver problemas típicos. Una vez entendemos cómo utilizar estas técnicas una vez, podemos escribir programas de forma eficaz y aplicar el concepto DRY (No te repitas, en inglés, don't repeat yourself). En este contexto, resultan muy útiles los patrones de diseño que pueden aportar soluciones a problemas bien descritos y recurrentes.