English Русский Deutsch 日本語 Português
preview
Creamos un asesor multidivisa sencillo utilizando MQL5 (Parte 2): Señales del indicador - Parabolic SAR de marco temporal múltiple

Creamos un asesor multidivisa sencillo utilizando MQL5 (Parte 2): Señales del indicador - Parabolic SAR de marco temporal múltiple

MetaTrader 5Ejemplos | 7 marzo 2024, 16:44
406 0
Roberto Jacobs
Roberto Jacobs

Introducción

En este artículo, entenderemos por asesor multidivisa un asesor o robot comercial que puede comerciar (abrir/cerrar órdenes, gestionar órdenes, por ejemplo, trailing-stop y trailing-profit, etc.) con más de un par de símbolos de un gráfico. En este artículo, el asesor comerciará con 30 pares. Esta vez usaremos solo un indicador, a saber, Parabolic SAR o iSAR en varios marcos temporales, comenzando desde PERIOD_M15 y terminando con PERIOD_D1.

Sabemos que el comercio multidivisa, tanto en el terminal comercial como en el simulador de estrategias, es posible gracias al poder y las capacidades de MQL5.

Por ello, el objetivo consistirá en satisfacer las necesidades básicas de los tráders que necesitan robots comerciales eficientes. Basándonos en las fortalezas y capacidades de MQL5, podemos crear un asesor multidivisa simple, que en este artículo utilizará Parabolic SAR o iSAR de marco temporal múltiple.



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 pairs

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

Con esos, tenemos un total de 30 pares.

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


2. Indicadores de señal.

El asesor multidivisa utilizará 1 señal del indicador en 5 marcos temporales, comenzando con PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4 y PERIOD_D1.

Este asesor no utilizará un marco temporal fijo para calcular las señales del indicador, por lo que no es necesario definir el marco temporal de cálculo de la señal.

Esto significa que FXSAR_MTF_MCEA se podrá utilizar en cualquier marco temporal desde PERIOD_M1 hasta PERIOD_MN1, y FXSAR_MTF_MCEA seguirá calculando señales basadas en iSAR PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4 y PERIOD_D1.

Estos cinco marcos temporales de Parabolic SAR determinarán la señal para abrir órdenes.

Mientras tanto, para cerrar órdenes cuando la señal se debilita, utilizaremos el indicador iSAR PERIOD_M15, siempre que la orden genere ganancias.

Para utilizar el trailing-stop y el trailing-profit, utilizaremos iSAR PERIOD_H1.


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

UP (arriba) = (PRICE_LOW[0] es mayor que la línea iSAR) o PRICE_LOW[0] > iSAR[0]

DOWN (abajo) = (PRICE-HIGH[0] es menor que la línea iSAR) o PRICE-HIGH[0] < iSAR[0]

Dónde obtener una señal de COMPRA o VENTA:

Los cinco marcos temporales del indicador iSAR deben sumar 5 x UP para COMPRAR y 5 x DOWN para VENDER.

La figura 1 muestra el indicador iSAR.

iSAR_Signal_Buy y Sell


3. Gestión de transacciones y órdenes.

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

1. Órdenes de Stop Loss   

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

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

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

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

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

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

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

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


2. Órdenes de Take Profit

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

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

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

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

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


3. Trailing Stop y Trailing Take Profit
  • Opciones: Use Trailing SL/TP (Yes) o (No) - utilizar Traling Stop Loss/Take Profit: sí o no
Con Use Trailing SL/TP option (No), el asesor no utilizará el Traling Stop Loss ni el Traling Take Profit. Con Use Trailing SL/TP (Yes) de nuevo se ofrecerá elegir - Use Automatic Trailing (Yes) o (No) (utilizar trading automático). Con Use Automatic Trailing (Yes), el asesor ejecutará el trailing stop utilizando el valor Parabolic SAR PERIOD_H1, recibiendo simultáneamente un beneficio móvil basado en el valor de la variable TPmin (valor de beneficio móvil). Con Use Automatic Trailing (No), el asesor realizará el Trailing Stop utilizando el valor del parámetro de entrada.
Nota: El asesor realizará simultáneamente el Trailing Take Profit y el Trailing Stop.


4. Gestión manual de órdenes.

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

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

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

pero luego quiere usar Stop Loss o Take Profit para todas las órdenes, solo necesita hacer clic 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 (cerrar todas las órdenes rentables)

Si un tráder quiere cerrar todas las órdenes que ya son rentables, entonces bastará con hacer clic en el botón Close All Orders Profit 

para cerrar todas las órdenes rentables abiertas.


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

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



Implementamos la planificación en un programa MQL5

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

Inclusión de un archivo de encabezado en MQL5

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


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

enum YN
 {
   No,
   Yes
 };


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

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


Parámetros de entrada del asesor

//---
input group               "=== Money Management Lot Size Parameter ==="; // Money Management Lot Size Parameter
input mmt                  mmlot = DynamLot;         // Money Management Type
input double                Risk = 10.0;             // Percent Equity Risk per Trade (Min=1.0% / Max=10.0%)
input double                Lots = 0.01;             // Input Manual Lot Size FixedLot
//--Day Trading On/Off
input group               "=== Day Trading On/Off ==="; // Day Trading On/Off
input YN                    ttd0 = No;               // Select Trading on Sunday (Yes) or (No)
input YN                    ttd1 = Yes;              // Select Trading on Monday (Yes) or (No)
input YN                    ttd2 = Yes;              // Select Trading on Tuesday (Yes) or (No)
input YN                    ttd3 = Yes;              // Select Trading on Wednesday (Yes) or (No)
input YN                    ttd4 = Yes;              // Select Trading on Thursday (Yes) or (No)
input YN                    ttd5 = Yes;              // Select Trading on Friday (Yes) or (No)
input YN                    ttd6 = No;               // Select Trading on Saturday (Yes) or (No)
//--Trade & Order management Parameter
input group               "=== Trade & Order management Parameter ==="; // Trade & Order management Parameter
input YN                  use_sl = No;               // Use Order Stop Loss (Yes) or (No)
input YN                  autosl = Yes;              // Use Automatic Calculation Stop Loss (Yes) or (No)
input double               SLval = 30;               // If Not Use Automatic SL - Input SL value in Pips
input YN                  use_tp = 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)
//---


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

//+------------------------------------------------------------------+
//| Class for working Expert Advisor                                 |
//+------------------------------------------------------------------+
class MCEA
  {
//---
    private:
    //---- 
    int              x_year;       // Year 
    int              x_mon;        // Month 
    int              x_day;        // Day of the month 
    int              x_hour;       // Hour in a day 
    int              x_min;        // Minutes 
    int              x_sec;        // Seconds
    //--
    int              oBm,
                     oSm,
                     ldig;
    int              posCur1,
                     posCur2;        
    //--
    double           LotPS;
    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;
     
    //------------
    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 Config --
    string           DIRI[],
                     AS30[];
    string           expname;
    int              hPar05[];   // Handle for the iSAR indicator for M5 Timeframe
    int              hPSAR[][5]; // Handle Indicator, where each Symbol has 5 arrays for Timeframe starting from TF_M15 to TF_D1
    int              ALO,
                     dgts,
                     arrsar,
                     arrsymbx;
    int              sall,
                     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_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              TFIndexArray(ENUM_TIMEFRAMES TF);
    int              GetOpenPosition(const string symbol);
    int              GetCloseInWeakSignal(const string symbol,int exis);
    int              ThisTime(const int reqmode);
    //--
    string           getUninitReasonText(int reasonCode);
    //------------
//---
  }; //-end class MCEA


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

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


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

//+------------------------------------------------------------------+
//| Expert Configuration                                             |
//+------------------------------------------------------------------+
void MCEA::FXSAR_MTF_MCEA_Config(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
    //--
    sall=ArraySize(All30);
    ArrayResize(AS30,sall,sall);
    ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY);
    //--
    arrsymbx=sall;
    ArraySymbolResize();
    ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY);
    for(int x=0; x<arrsymbx; x++) {SymbolSelect(DIRI[x],true);}
    pairs="Multi Currency 30 Pairs";
    //--
    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<arrsymbx; x++) 
      {
        hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi);  //-- Handle for the iSAR indicator for M5 Timeframe
        //--
        for(int i=0; i<TFArrays; i++)
          {
            hPSAR[x][i]=iSAR(DIRI[x],TFSAR[i],SARstep,SARmaxi); // Handle for iSAR Indicator array sequence of the requested timeframe
          }
      }
    //--
    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();
    //--
    return;
//---
  } //-end FXSAR_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 la función ExpertActionTrade().

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


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

La secuencia de funcionamiento se muestra a continuación.

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


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

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

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

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

1. DirectionMove(symbol);         //-- Función para verificar la presencia de un precio en la barra de velas en el marco temporal del asesor
2. GetPSARSignalMTF(symbol);   //-- Función para calcular la fórmula de Parabolic iSAR en el marco temporal solicitado.
int MCEA::GetPSARSignalMTF(string symbol) // iSAR MTF signal calculation
  {
//---
    int mv=0;
    int rise=1,
        down=-1;
    //--
    int sarup=0,
        sardw=0;
    //--    
    for(int x=0; x<TFArrays; x++) // The TFArrays variable has a value of 5 which is taken from the number of time frames from TF_M1 to TF_H1.
      {
        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()


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 PARSAMTF() usaremos y llamaremos dos funciones:

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 usará para obtener la secuencia de array del marco temporal solicitado.

Luego se llamará al descriptor correspondiente del indicador para obtener el valor del búfer del indicador iSAR de ese marco temporal solicitado.

int MCEA::PARSARMTF(const string symbol,ENUM_TIMEFRAMES mtf) // formula Parabolic iSAR on the requested 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]<LOW0 && CLS0>OPN0) ret=rise;
    if(PSAR[0]>HIG0 && CLS0<OPN0) ret=down;
    //--
    return(ret);
//---
  } //-end PARSARMTF()


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

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


4. Función ChartEvent


Para que los asesores multidivisa sean más eficaces, crearemos varios botones para gestionar las órdenes y cambiar los gráficos o símbolos.
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
//--- handling CHARTEVENT_CLICK event ("Clicking the chart")
   ResetLastError();
   //--
   ENUM_TIMEFRAMES CCS=mc.TFt;
   //--
   if(id==CHARTEVENT_OBJECT_CLICK) 
     {
       int lensymbol=StringLen(Symbol());
       int lensparam=StringLen(sparam);
       //--
       //--- if "Set SL 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.PairsIdxArray(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, la función ChangeChartSymbol() llamará al evento OnChartEvent().

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


Si la propiedad del asesor Display Trading Info on Chart está configurada en Yes, el gráfico en el que se coloque el asesor mostrará la información comercial llamando a la función TradeInfo().

void MCEA::TradeInfo(void) // function: write comments on the chart
  {
//----
   Pips(Symbol());
   double spread=SymbolInfoInteger(Symbol(),SYMBOL_SPREAD)/xpip;
   //--
   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     ------------------------------------------------------------"+ 
      "\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()  


La interfaz del asesor multidivisa tendrá el aspecto siguiente.

FXSAR_MTF_MCEA_look


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

Al presionar M o C se mostrará el panel de control manual.

MCR_Combine

Al clicar en M, se mostrará el panel de control manual, después del cual el tráder podrá gestionar las órdenes:

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

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

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

Al clicar en C, se mostrará un botón de panel con los 30 nombres de símbolos o pares, y los tráders podrán clicar en uno de los nombres de pares o símbolos. Clicando en cualquiera de ellos, el símbolo del gráfico será reemplazado de inmediato por el indicado en el botón en el que se ha clicado.

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



Simulador de estrategias

Como usted sabrá, el simulador de estrategias del terminal MetaTrader 5 admite y permite probar estrategias, operar con varios símbolos o probar el trading automático para todos los símbolos disponibles y en todos los marcos temporales disponibles.

Vamos a probar el asesor multidivisa de marco temporal múltiple FXSAR_MTF_MCEA en el simulador de estrategias MetaTrader 5.




Conclusión

Tras crear un asesor multidivisa de marco temporal múltiple utilizando MQL5 podemos llegar a la siguiente conclusión:

  1. Crear un asesor multidivisa en MQL5 no resulta muy diferente de desarrollar un asesor monodivisa, pero para los asesores multidivisa con marco temporal múltiple, el proceso resulta un poco más complicado, si lo comparamos con los asesores de un solo marco temporal.
  2. La creación de un asesor multidivisa aumentará la eficiencia de los tráders, ya que no necesitarán abrir muchos gráficos.
  3. Una estrategia comercial correcta, combinada con señales de indicadores de alta calidad, aumentará la probabilidad de obtener beneficios en comparación con el uso de un asesor monodivisa. Las pérdidas de un par se compensarán con los beneficios de otros pares.
  4. El asesor multidivisa ADXPSAR_MCEA supone solo un ejemplo que permite estudiar y desarrollar nuestras propias ideas. 
  5. Los resultados de las pruebas en el simulador de estrategias siguen pareciéndonos insatisfactorios. Si implementamos una mejor estrategia con cálculos de señales más precisos y mejores marcos temporales, el resultado, a nuestro juicio, debería ser mejor que el actual.


Notas:

Si tiene una idea para crear un asesor multidivisa sencillo basado en las señales integradas del indicador estándar MQL5, indíquela en los comentarios.

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

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

Archivos adjuntos |
FXSAR_MTF_MCEA.mq5 (80.52 KB)
Teoría de Categorías en MQL5 (Parte 23): Otra mirada a la media móvil exponencial doble Teoría de Categorías en MQL5 (Parte 23): Otra mirada a la media móvil exponencial doble
En este artículo, seguiremos analizando desde un nuevo ángulo los indicadores comerciales más populares. Vamos a procesar una composición horizontal de transformaciones naturales. El mejor indicador para ello será la media móvil exponencial doble (Double Exponential Moving Average, DEMA).
Interfaz gráfica: consejos y recomendaciones para crear una biblioteca gráfica en MQL Interfaz gráfica: consejos y recomendaciones para crear una biblioteca gráfica en MQL
Hoy abarcaremos los conceptos básicos de las bibliotecas GUI para comprender cómo funcionan estas o incluso comenzar a crear bibliotecas propias.
Marcado de datos en el análisis de series temporales (Parte 3): Ejemplo de uso del marcado de datos Marcado de datos en el análisis de series temporales (Parte 3): Ejemplo de uso del marcado de datos
En esta serie de artículos, presentaremos varias técnicas de marcado de series temporales que pueden producir datos que se ajusten a la mayoría de los modelos de inteligencia artificial (IA). El marcado dirigido de datos puede hacer que un modelo de IA entrenado resulte más relevante para las metas y objetivos del usuario, mejorando la precisión del modelo y ayudando a este a dar un salto de calidad.
Desarrollo de un sistema de repetición (Parte 32): Sistema de órdenes (I) Desarrollo de un sistema de repetición (Parte 32): Sistema de órdenes (I)
De todas las cosas desarrolladas hasta ahora, esta, como seguramente también notarás y con el tiempo estarás de acuerdo, es la más desafiante de todas. Lo que tenemos que hacer es algo simple: hacer que nuestro sistema simule lo que hace un servidor comercial en la práctica. Esto de tener que implementar una forma de simular exactamente lo que haría el servidor comercial parece simple. Al menos en palabras. Pero necesitamos hacer esto de manera que, para el usuario del sistema de repetición/simulación, todo suceda de la manera más invisible o transparente posible.