English Русский 中文 Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Libro de Recetas MQL5: Usar Indicadores para Configurar Condiciones de Trading en Asesores Expertos

Libro de Recetas MQL5: Usar Indicadores para Configurar Condiciones de Trading en Asesores Expertos

MetaTrader 5Ejemplos | 28 mayo 2014, 11:22
1 601 0
Anatoli Kazharski
Anatoli Kazharski

Introducción

En este artículo reforzaremos el Asesor Experto con indicadores cuyos valores se usarán para comprobar las condiciones de apertura de posición. Además crearemos una lista desplegable en los parámetros externos para poder seleccionar uno de los tres indicadores de trading.

Por favor, tenga en cuenta que continuaremos modificando el Asesor Experto en el que hemos trabajando durante los artículos anteriores de la serie de Libros de Recetas MQL5. La última versión del Asesor Experto se puede bajar del artículo titulado "MQL5 Cookbook: The History of Deals And Function Library for Getting Position Properties" (“Libro de Recetas MQL5: El Historial de Transacciones y la Biblioteca de Funciones para Obtener Propiedades de Posición”).

Además, en este artículo trataremos una función que crearemos para comprobar si se pueden realizar operaciones de trading o no. La función de apertura de posición se modificará para permitir al Asesor Experto determinar el modo de trading (Instant Execution, o ejecución instantánea, y Market Execution, o ejecución de mercado).

Puesto que al código del Asesor Experto, siguiendo todas las modificaciones y mejoras hechas en los artículos anteriores, ya supera las 1.500 líneas, comenzará a ser menos conveniente con cada nueva prestación que le añadamos. De modo que la solución lógica sería dividirlo en varias categorías como archivos de biblioteca separados. Ahora que ya hemos establecido los objetivos, comencemos.

 

Desarrollo de Asesor Experto

Colocaremos el código fuente de Asesor Experto (*.mq5) del artículo anterior en una carpeta separada, TestIndicatorConditions, donde necesitaremos crear la subcarpeta Include. Esta será la carpeta en la que crearemos los archivos include (*.mqh). Se puede generar usando el MQL5 Wizard (Ctrl+N), o se pueden crear manualmente en el directorio requerido como archivos de texto estándar (*.txt), renombrándolos después como *.mqh.

A continuación tiene los nombres y comentarios para todos los archivos creados:

  • Enums.mqh contendrá todas las enumeraciones;
  • InfoPanel.mqh incluirá funciones para configurar el panel de información, creando y eliminando objetos gráficos;
  • Errors.mqh cubrirá todas las funciones que devuelvan códigos de error y razones de desinicialización;
  • TradeSignals.mqh incluirá funciones que llenarán arrays con precios y valores de indicador, así como bloques de señal;
  • TradeFunctions.mqh contendrá funciones de trading;
  • ToString.mqh cubrirá funciones que convierten valores numéricos a valores de cadena de caracteres;
  • Auxiliary.mqh se usará para otras funciones auxiliares.

Para incluir estas bibliotecas en el archivo principal usaremos la directiva #include. Puesto que el archivo principal del Asesor Experto y la carpeta de archivos include (Include) se encuentran en la misma carpeta, el código para incluir archivos será el siguiente:

//--- Include custom libraries

#include "Include\Enums.mqh"

#include "Include\InfoPanel.mqh"

#include "Include\Errors.mqh"

#include "Include\TradeSignals.mqh"

#include "Include\TradeFunctions.mqh"

#include "Include\ToString.mqh"

#include "Include\Auxiliary.mqh"

A continuación, podremos abrirlos y modificarlos, y mover una parte del código fuente del archivo principal del Asesor Experto.

Para navegar correctamente por el código, en cada archivo de encabezamiento se añadirán referencias a los códigos de encabezamiento adyacentes y al código principal del Asesor Experto. Por ejemplo, para nuestra biblioteca de funciones de trading, TradeFunctions.mqh, este tendrá el siguiente aspecto:

//--- Connection with the main file of the Expert Advisor

#include "..\TestIndicatorConditions.mq5"

//--- Include custom libraries

#include "Enums.mqh"

#include "InfoPanel.mqh"

#include "Errors.mqh"

#include "TradeSignals.mqh"

#include "ToString.mqh"

#include "Auxiliary.mqh"

En el caso de archivos en el mismo nivel de anidamiento, basta con especificar el nombre. Para ir a un nivel superior, debe poner dos puntos antes de la barra negra en la ruta.

Añadamos una enumeración para indicadores en el archivo Enums.mqh. Para ilustrarlo mejor, en este Asesor Experto usaremos dos indicadores estándar (Moving Average y Commodity Channel Index) y un indicador personalizado (MultiRange_PCH). La enumeración será así:

//--- Indicators

enum ENUM_INDICATORS

  {

   MA       = 0, // Moving Average

   CCI      = 1, // CCI

   PCH      = 2  // Price Channel

  };

Los parámetros externos se modifican de la siguiente manera:

//--- External parameters of the Expert Advisor

sinput   long              MagicNumber=777;        // Magic number

sinput   int               Deviation=10;           // Slippage

input    ENUM_INDICATORS   Indicator=MA;           // Indicator

input    int               IndicatorPeriod=5;      // Indicator period

input    int               IndicatorSegments=2;    // Number of one direction indicator segments

input    double            Lot=0.1;                // Lot

input    double            VolumeIncrease=0.1;     // Position volume increase

input    double            VolumeIncreaseStep=10;  // Step for volume increase

input    double            StopLoss=50;            // Stop Loss

input    double            TakeProfit=100;         // Take Profit

input    double            TrailingStop=10;        // Trailing Stop

input    bool              Reverse=true;           // Position reversal

sinput   bool              ShowInfoPanel=true;     // Display of the info panel

Tal y como dijimos arriba, podrá seleccionar uno de los tres indicadores de la lista desplegable del parámetro Indicator.

Solo hay un parámetro aplicable a todos los indicadores donde se puede configurar el período de indicador: IndicatorPeriod. El parámetro NumberOfBars de la versión anterior del Asesor Experto ha sido renombrado a IndicatorSegments, y ahora indica el número de barras durante las cuales un indicador debe ir hacia arriba o hacia abajo para satisfacer la condición de apertura de posición.

Además, hemos añadido otro parámetro externo, VolumeIncreaseStep, que se puede usar para configurar el paso para el aumento de volumen en puntos.

El valor de la variable AllowedNumberOfBars (que ahora se llama AllowedNumberOfSegments) se solía ajustar en la función personalizada GetBarsData(). Ahora se colocará en una función separada que solo se llamará durante la inicialización.

Puesto que ahora se comprobarán todas las condiciones de apertura usando valores de indicador, el valor que se asignará siempre será mayor de dos. En otras palabras, si a la variable externa IndicatorSegments se asigna el valor de 1, a la variable AllowedNumberOfSegments se asignará el valor de 3, puesto que para satisfacer la condición (por ejemplo, para una compra, o BUY), el valor de indicador en la barra completada debe ser mayor que el valor de la barra anterior. Para ello, necesitaremos obtener los valores de los tres últimos indicadores.

Abajo tiene el código de la función CorrectInputParameters():

//+------------------------------------------------------------------+

//| Adjusting input parameters                                       |

//+------------------------------------------------------------------+

void CorrectInputParameters()

  {

//--- Adjust the number of bars for the position opening condition

   if(AllowedNumberOfSegments<=0)

     {

      if(IndicatorSegments<=1)

         AllowedNumberOfSegments=3;                     // At least three bars are required

      if(IndicatorSegments>=5)

         AllowedNumberOfSegments=5;                     // but no more than 7

      else

         AllowedNumberOfSegments=IndicatorSegments+1;   // and always greater by two

     }

  }

Antes de comenzar a trabajar con los indicadores, creemos una función que comprobará si se permite realizar operaciones de trading: CheckTradingPermission(). Si no está permitido por alguna de las razones especificadas en la función, se devolverá un valor de cero. Esto significará que el siguiente intento se deberá realizar en la siguiente barra. Esto significará que el siguiente intento se deberá realizar en la siguiente barra.

//+------------------------------------------------------------------+

//| Checking if trading is allowed                                   |

//+------------------------------------------------------------------+

bool CheckTradingPermission()

  {

//--- For real-time mode

   if(IsRealtime())

     {

      //--- Checking server connection

      if(!TerminalInfoInteger(TERMINAL_CONNECTED))

         return(1);

      //--- Permission to trade at the running program level

      if(!MQL5InfoInteger(MQL5_TRADE_ALLOWED))

         return(2);

      //--- Permission to trade at the terminal level

      if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))

         return(3);

      //--- Permission to trade for the current account

      if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED))

         return(4);

      //--- Permission to trade automatically for the current account

      if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT))

         return(5);

     }

//---

   return(0);

  }

Vayamos ahora al tema principal del artículo. Para tener acceso a los valores del indicador deberemos obtener primero su identificador. Esto se hace usando funciones especiales cuyos nombres se componen del nombre corto del indicador y el símbolo 'i' que lo precede.

Por ejemplo, el indicador Moving Average (Media Móvil, o MA) tiene la función correspondiente iMA(). Todos los identificadores de indicadores estándar en el terminal de MetaTrader 5 se pueden obtener usando estas funciones. La lista completa está disponible en la sección del Material de Referencia de MQL5 llamada Technical Indicators. Si necesita obtener el identificador de un indicador personalizado, utilice la función iCustom().

Implementaremos la función GetIndicatorHandle() allá donde, dependiendo del indicador seleccionado en el parámetro Indicator, el valor del identificador del indicador correspondiente se asigne a la variable global indicator_handle. El código de la función se puede encontrar en nuestra biblioteca de funciones de señales de trading (el archivo \Include\TradeSignals.mqh), mientras que la variable con el identificador del indicador se encuentra en el archivo principal del Asesor Experto.

//+------------------------------------------------------------------+

//| Getting the indicator handle                                     |

//+------------------------------------------------------------------+

void GetIndicatorHandle()

  {

//--- If the Moving Average indicator is selected

   if(Indicator==MA)

      indicator_handle=iMA(_Symbol,Period(),IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE);

//--- If the CCI indicator is selected

   if(Indicator==CCI)

      indicator_handle=iCCI(_Symbol,Period(),IndicatorPeriod,PRICE_CLOSE);

//--- If the MultiRange_PCH indicator is selected

   if(Indicator==PCH)

      indicator_handle=iCustom(_Symbol,Period(),"MultiRange_PCH",IndicatorPeriod);

//--- If the indicator handle could not be obtained

   if(indicator_handle==INVALID_HANDLE)

      Print("Failed to get the indicator handle!");

  }

Además, crearemos la función GetDataIndicators(), con la que, una vez obtenidos los identificadores del indicador, podremos obtener sus valores. Esto se hace usando la función CopyBuffer() de forma similar a la obtención de valores de barra usando las funciones CopyTime(), CopyClose(), CopyOpen(), CopyHigh() y CopyLow() que ya se trataron en el artículo "MQL5 Cookbook: Analyzing Position Properties in the MetaTrader 5 Strategy Tester" (“Libro de Recetas MQL5: Analizar Propiedades de Posición en el Probador de Estrategias de MetaTrader5”).

Puesto que el indicador puede tener varios buffers o filas de valores, el índice de buffer se pasa a la función CopyBuffer() como segundo parámetro. Los índices de buffer para indicadores estándar se pueden encontrar en el Material de Referencia de MQL5. En el caso de indicadores personalizados, los índices de buffer se pueden encontrar en el código, suponiendo que el código fuente esté disponible. Si no hay código, deberá encontrar el índice mediante la experimentación, observando cómo se satisfacen las condiciones en el modo de visualización de Probador de Estrategias.

Antes de ello, deberemos crear arrays dinámicos para valores de buffer de indicador en el archivo principal del Asesor Experto:

//--- Arrays for indicator values

double indicator_buffer1[];

double indicator_buffer2[];

A continuación tiene el código de la función GetIndicatorsData():

//+------------------------------------------------------------------+

//| Getting indicator values                                         |

//+------------------------------------------------------------------+

bool GetIndicatorsData()

  {

//--- If the indicator handle has been obtained

   if(indicator_handle!=INVALID_HANDLE)

     {

      //--- For the Moving Average or CCI indicator

      if(Indicator==MA || Indicator==CCI)

        {

         //--- Reverse the indexing order (... 3 2 1 0)

         ArraySetAsSeries(indicator_buffer1,true);

         //--- Get indicator values

         if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments)

           {

            Print("Failed to copy the values ("+

                  _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 array! Error ("+

                  IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));

            return(false);

           }

        }

      //--- For the MultiRange_PCH indicator

      if(Indicator==PCH)

        {

         //--- Reverse the indexing order (... 3 2 1 0)

         ArraySetAsSeries(indicator_buffer1,true);

         ArraySetAsSeries(indicator_buffer2,true);

         //--- Get indicator values

         if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments || 

            CopyBuffer(indicator_handle,1,0,AllowedNumberOfSegments,indicator_buffer2)<AllowedNumberOfSegments)

           {

            Print("Failed to copy the values ("+

                  _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 or indicator_buffer2 array! Error ("+

                  IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));

            return(false);

           }

        }

      //---

      return(true);

     }

//--- If the indicator handle has not been obtained, retry

   else

      GetIndicatorHandle();

//---

   return(false);

  }

La función GetTradingSignal() ha cambiado sustancialmente. Las condiciones son diferentes en ausencia de la posición y allá donde existe la posición. Para los indicadores Moving Average y CCI, las condiciones son las mismas. En el caso de MultiRange_PCH, se ordenan en un bloque separado. Para hacer el código más comprensible y evitar repeticiones crearemos una función auxiliar, GetSignal(), que devuelve una señal para apertura de posición o inversión, suponiendo que la posición exista y que la acción relevante esté permitida en el parámetro externo.

A continuación tiene el código de la función GetSignal():

//+------------------------------------------------------------------+

//| Checking the condition and returning a signal                    |

//+------------------------------------------------------------------+

ENUM_ORDER_TYPE GetSignal()

  {

//--- Check conditions for the Moving Average and CCI indicators

   if(Indicator==MA || Indicator==CCI)

     {

      //--- A Sell signal

      if(AllowedNumberOfSegments==3 && 

         indicator_buffer1[1]<indicator_buffer1[2])

         return(ORDER_TYPE_SELL);

      //---

      if(AllowedNumberOfSegments==4 && 

         indicator_buffer1[1]<indicator_buffer1[2] && 

         indicator_buffer1[2]<indicator_buffer1[3])

         return(ORDER_TYPE_SELL);

      //---

      if(AllowedNumberOfSegments==5 && 

         indicator_buffer1[1]<indicator_buffer1[2] && 

         indicator_buffer1[2]<indicator_buffer1[3] && 

         indicator_buffer1[3]<indicator_buffer1[4])

         return(ORDER_TYPE_SELL);

      //---

      if(AllowedNumberOfSegments==6 && 

         indicator_buffer1[1]<indicator_buffer1[2] && 

         indicator_buffer1[2]<indicator_buffer1[3] && 

         indicator_buffer1[3]<indicator_buffer1[4] && 

         indicator_buffer1[4]<indicator_buffer1[5])

         return(ORDER_TYPE_SELL);

      //---

      if(AllowedNumberOfSegments>=7 && 

         indicator_buffer1[1]<indicator_buffer1[2] && 

         indicator_buffer1[2]<indicator_buffer1[3] && 

         indicator_buffer1[3]<indicator_buffer1[4] && 

         indicator_buffer1[4]<indicator_buffer1[5] && 

         indicator_buffer1[5]<indicator_buffer1[6])

         return(ORDER_TYPE_SELL);



      //--- A Buy signal

      if(AllowedNumberOfSegments==3 && 

         indicator_buffer1[1]>indicator_buffer1[2])

         return(ORDER_TYPE_BUY);

      //---

      if(AllowedNumberOfSegments==4 && 

         indicator_buffer1[1]>indicator_buffer1[2] && 

         indicator_buffer1[2]>indicator_buffer1[3])

         return(ORDER_TYPE_BUY);

      //---

      if(AllowedNumberOfSegments==5 && 

         indicator_buffer1[1]>indicator_buffer1[2] && 

         indicator_buffer1[2]>indicator_buffer1[3] && 

         indicator_buffer1[3]>indicator_buffer1[4])

         return(ORDER_TYPE_BUY);

      //---

      if(AllowedNumberOfSegments==6 && 

         indicator_buffer1[1]>indicator_buffer1[2] && 

         indicator_buffer1[2]>indicator_buffer1[3] && 

         indicator_buffer1[3]>indicator_buffer1[4] && 

         indicator_buffer1[4]>indicator_buffer1[5])

         return(ORDER_TYPE_BUY);

      //---

      if(AllowedNumberOfSegments>=7 && 

         indicator_buffer1[1]>indicator_buffer1[2] && 

         indicator_buffer1[2]>indicator_buffer1[3] && 

         indicator_buffer1[3]>indicator_buffer1[4] && 

         indicator_buffer1[4]>indicator_buffer1[5] && 

         indicator_buffer1[5]>indicator_buffer1[6])

         return(ORDER_TYPE_BUY);

     }

//--- Block that checks conditions for the MultiRange_PCH indicator

   if(Indicator==PCH)

     {

      //--- A Sell signal

      if(close_price[1]<indicator_buffer2[1] && 

         open_price[1]>indicator_buffer2[1])

         return(ORDER_TYPE_SELL);

      //--- A Buy signal

      if(close_price[1]>indicator_buffer1[1] && 

         open_price[1]<indicator_buffer1[1])

         return(ORDER_TYPE_BUY);

     }

//--- No signal

   return(WRONG_VALUE);

  }

El código de la función GetTradingSignal() tiene ahora el siguiente aspecto:

//+------------------------------------------------------------------+

//| Determining trading signals                                      |

//+------------------------------------------------------------------+

ENUM_ORDER_TYPE GetTradingSignal()

  {

//--- If there is no position

   if(!pos.exists)

     {

      //--- A Sell signal

      if(GetSignal()==ORDER_TYPE_SELL)

         return(ORDER_TYPE_SELL);

      //--- A Buy signal

      if(GetSignal()==ORDER_TYPE_BUY)

         return(ORDER_TYPE_BUY);

     }

//--- If the position exists

   if(pos.exists)

     {

      //--- Get the position type

      GetPositionProperties(P_TYPE);

      //--- Get the last deal price

      GetPositionProperties(P_PRICE_LAST_DEAL);

      //--- Block that checks conditions for the Moving Average and CCI indicators

      if(Indicator==MA || Indicator==CCI)

        {

         //--- A Sell signal

         if(pos.type==POSITION_TYPE_BUY && 

            GetSignal()==ORDER_TYPE_SELL)

            return(ORDER_TYPE_SELL);

         //---

         if(pos.type==POSITION_TYPE_SELL && 

            GetSignal()==ORDER_TYPE_SELL && 

            close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))

            return(ORDER_TYPE_SELL);

         //--- A Buy signal

         if(pos.type==POSITION_TYPE_SELL && 

            GetSignal()==ORDER_TYPE_BUY)

            return(ORDER_TYPE_BUY);

         //---

         if(pos.type==POSITION_TYPE_BUY && 

            GetSignal()==ORDER_TYPE_BUY && 

            close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))

            return(ORDER_TYPE_BUY);

        }

      //--- Block that checks conditions for the MultiRange_PCH indicator

      if(Indicator==PCH)

        {

         //--- A Sell signal

         if(pos.type==POSITION_TYPE_BUY && 

            close_price[1]<indicator_buffer2[1] && 

            open_price[1]>indicator_buffer2[1])

            return(ORDER_TYPE_SELL);

         //---

         if(pos.type==POSITION_TYPE_SELL && 



            close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))

            return(ORDER_TYPE_SELL);

         //--- A Buy signal

         if(pos.type==POSITION_TYPE_SELL && 

            close_price[1]>indicator_buffer1[1] && 

            open_price[1]<indicator_buffer1[1])

            return(ORDER_TYPE_BUY);

         //---

         if(pos.type==POSITION_TYPE_BUY && 

            close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))

            return(ORDER_TYPE_BUY);

        }

     }

//--- No signal

   return(WRONG_VALUE);

  }

Ahora solo debemos fijarnos en los modos Instant Execution y Market Execution, que son parte de las propiedades de símbolo, y en si la modificación de la función de apertura de posición OpenPosition() funciona correctamente. Los modos cuyos nombres explican sus cualidades se pueden encontrar en el material de referencia MQL5:

  • Instant Execution
  • Market Execution

Por favor, tenga en cuenta que, al trabajar con el modo Market Execution no podrá abrir una posición con los niveles Stop Loss y Take Profit configurados: deberá abrir una posición primero y después modificarla, configurando los niveles.

A partir de la construcción 803, Stop Loss y Take Profit se pueden configurar al abrir una posición para los modos Market Execution y Exchange Execution (Ejecución de Intercambio).

Añadamos el modo de ejecución a la estructura de propiedades de símbolo:

//--- Symbol properties

struct symbol_properties

  {

   int               digits;           // Number of decimal places in the price

   int               spread;           // Spread in points

   int               stops_level;      // Stops level

   double            point;            // Point value

   double            ask;              // Ask price

   double            bid;              // Bid price

   double            volume_min;       // Minimum volume for a deal

   double            volume_max;       // Maximum volume for a deal

   double            volume_limit;     // Maximum permissible volume for a position and orders in one direction

   double            volume_step;      // Minimum volume change step for a deal

   double            offset;           // Offset from the maximum possible price for a transaction

   double            up_level;         // Upper Stop level price

   double            down_level;       // Lower Stop level price

   ENUM_SYMBOL_TRADE_EXECUTION execution_mode; // Execution mode

  };

A continuación, debemos modificar la enumeración ENUM_SYMBOL_PROPERTIES...

//--- Enumeration of position properties

enum ENUM_SYMBOL_PROPERTIES

  {

   S_DIGITS          = 0,

   S_SPREAD          = 1,

   S_STOPSLEVEL      = 2,

   S_POINT           = 3,

   S_ASK             = 4,

   S_BID             = 5,

   S_VOLUME_MIN      = 6,

   S_VOLUME_MAX      = 7,

   S_VOLUME_LIMIT    = 8,

   S_VOLUME_STEP     = 9,

   S_FILTER          = 10,

   S_UP_LEVEL        = 11,

   S_DOWN_LEVEL      = 12,

   S_EXECUTION_MODE  = 13,

   S_ALL             = 14

  };

... y la función GetSymbolProperties():

case S_EXECUTION_MODE: symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE);   break;

      //---

      case S_ALL           :

         symb.digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);

         symb.spread=(int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD);

         symb.stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);

         symb.point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);

         symb.ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),symb.digits);

         symb.bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),symb.digits);

         symb.volume_min=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);

         symb.volume_max=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);

         symb.volume_limit=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_LIMIT);

         symb.volume_step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);

         symb.offset=NormalizeDouble(CorrectValueBySymbolDigits(lot_offset*symb.point),symb.digits);

         symb.up_level=NormalizeDouble(symb.ask+symb.stops_level*symb.point,symb.digits);

         symb.down_level=NormalizeDouble(symb.bid-symb.stops_level*symb.point,symb.digits);

         symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE);                       break;

         //---

Como resultado, el código de la función OpenPosition() tendrá el siguiente aspecto:

//+------------------------------------------------------------------+

//| Opening a position                                               |

//+------------------------------------------------------------------+

void OpenPosition(double lot,

                  ENUM_ORDER_TYPE order_type,

                  double price,

                  double sl,

                  double tp,

                  string comment)

  {

//--- Set the magic number in the trading structure

   trade.SetExpertMagicNumber(MagicNumber);

//--- Set the slippage in points

   trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation));

//--- The Instant Execution mode

//    A position can be opened with the Stop Loss and Take Profit levels set

   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT)

     {

      //--- If the position failed to open, print the relevant message

      if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))

         Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));

     }

//--- The Market Execution mode 

//    First open a position and only then set the Stop Loss and Take Profit levels

//    *** Starting with build 803, Stop Loss and Take Profit can be set upon position opening ***

   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET)

     {

      //--- If there is no position, first open a position and then set Stop Loss and Take Profit

      if(!pos.exists)

        {

         //--- If the position failed to open, print the relevant message

         if(!trade.PositionOpen(_Symbol,order_type,lot,price,0,0,comment))

            Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));

         //--- Get the flag of presence/absence of the position

         pos.exists=PositionSelect(_Symbol);

         //--- If the position exists

         if(pos.exists)

           {

            //--- Set Stop Loss and Take Profit

            if(!trade.PositionModify(_Symbol,sl,tp))

               Print("Error modifying the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));

           }

        }

      //--- If the position exists, increase its volume and leave the Stop Loss and Take Profit levels unchanged

      else

        {

         //--- If the position failed to open, print the relevant message

         if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))

            Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));

        }

     }

  }

Todavía tenemos que añadir el toque final a las funciones de gestión de eventos:

  • OnInit
    //+------------------------------------------------------------------+
    
    //| Expert initialization function                                   |
    
    //+------------------------------------------------------------------+
    
    int OnInit()
    
      {
    
    //--- Adjust the input parameters
    
       CorrectInputParameters();
    
    //--- Get indicator handles
    
       GetIndicatorHandle();
    
    //--- Initialize the new bar
    
       CheckNewBar();
    
    //--- Get the properties
    
       GetPositionProperties(P_ALL);
    
    //--- Set the info panel
    
       SetInfoPanel();
    
    //---
    
       return(0);
    
      }
  • OnDeinit
    //+------------------------------------------------------------------+
    
    //| Expert deinitialization function                                 |
    
    //+------------------------------------------------------------------+
    
    void OnDeinit(const int reason)
    
      {
    
    //--- Print the deinitialization reason to the journal
    
       Print(GetDeinitReasonText(reason));
    
    //--- When deleting from the chart
    
       if(reason==REASON_REMOVE)
    
         {
    
          //--- Delete all objects relating to the info panel from the chart
    
          DeleteInfoPanel();
    
          //--- Delete the indicator handle
    
          IndicatorRelease(indicator_handle);
    
         }
    
      }
  • OnTick
    //+------------------------------------------------------------------+
    
    //| Expert tick function                                             |
    
    //+------------------------------------------------------------------+
    
    void OnTick()
    
      {
    
    //--- If the bar is not new, exit
    
       if(!CheckNewBar())
    
         {
    
          if(IsVisualMode() || IsRealtime())
    
            {
    
             //--- Get the properties and update the values on the panel
    
             GetPositionProperties(P_ALL);
    
             //--- Set/update the info panel
    
             SetInfoPanel();
    
            }
    
          return;
    
         }
    
    
    
    //--- If there is a new bar
    
       else
    
         {
    
          //--- If trading is allowed
    
          if(CheckTradingPermission()==0)
    
            {
    
             if(!GetIndicatorsData())
    
                return;
    
             GetBarsData();          // Get bar data
    
             TradingBlock();         // Check the conditions and trade
    
             ModifyTrailingStop();   // Modify the Trailing Stop level
    
            }
    
         }
    
    //--- Get the properties
    
       GetPositionProperties(P_ALL);
    
    //--- Update the info panel
    
       SetInfoPanel();
    
      }

Ahora que todas las funciones están listas, podemos optimizar los parámetros. Tenga en cuenta que debe compilar el código desde el archivo del programa principal.

 

Optimizar Parámetros y Simular el Asesor Experto

El Probador de Estrategias debe configurarse tal y como se muestra abajo:

Fig. 1. Configuración de Probador de Estrategias.

Fig. 1. Configuración de Probador de Estrategias.

Además, configuraremos los parámetros del Asesor Experto para su optimización (vea también el archivo adjunto *.set con la configuración):

Fig. 2. Configuración del Asesor Experto.

Fig. 2. Configuración del Asesor Experto.

La optimización dura unos 40 minutos en un procesador dual-core. El gráfico de optimización le permite examinar en parte la calidad de un sistema de trading basándonos en los resultados de la zona de beneficio:

Fig. 3. Gráfico de optimización.

Fig. 3. Gráfico de optimización.

Los resultados de la simulación del factor de recuperación máximo son los siguientes:

Fig. 4. Resultados de la simulación del factor de recuperación máximo.

Fig. 4. Resultados de la simulación del factor de recuperación máximo.

 

Conclusión

Puede encontrar un archivo adjunto al artículo con los códigos fuente del Asesor Experto. Una vez descomprimido, debe colocar la carpeta de archivos \TestIndicatorConditions en <Metatrader 5 terminal>\MQL5\Experts. Para asegurarse de que el Asesor Experto funciona correctamente, debe descargarse el indicador MultiRange_PCH y colocarlo en <Metatrader 5 terminal>\MQL5\Indicators.

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/645

El Indicador ZigZag: Nuevo Enfoque y Soluciones El Indicador ZigZag: Nuevo Enfoque y Soluciones
Este artículo examina la posibilidad de crear un indicador ZigZag avanzado. La idea de identificar nodos se basa en el uso del indicador Envelopes (Envolturas). Suponemos que podemos obtener una determinada combinación de parámetros centrada para una serie de Envelopes, mientras que todos los nodos de ZigZag se encuentran dentro de los confines de las bandas de Envelopes. Por tanto, podemos tratar de predecir las coordenadas del nuevo nodo.
Libro de Recetas MQL5: El Historial de Transacciones y la Biblioteca de Funciones para Obtener Propiedades de Posición Libro de Recetas MQL5: El Historial de Transacciones y la Biblioteca de Funciones para Obtener Propiedades de Posición
Es momento de resumir brevemente la información facilitada los artículos anteriores sobre propiedades de posición. En este artículo crearemos unas cuantas funciones adicionales para obtener las propiedades que solo se pueden conseguir tras acceder al historial de transacciones. También nos familiarizaremos con estructuras de datos que nos permitirán acceder a propiedades de posición y del símbolo de una forma más conveniente.
Libro de Recetas MQL5: Desarrollo de un Marco de Trabajo para un Sistema de Trading Basado en la Estrategia de Triple Pantalla Libro de Recetas MQL5: Desarrollo de un Marco de Trabajo para un Sistema de Trading Basado en la Estrategia de Triple Pantalla
En este artículo desarrollaremos un marco de trabajo para un sistema de trading basado en la estrategia de Triple Pantalla en MQL5. El Asesor Experto no se desarrollará de cero. En lugar de ello, simplemente modificaremos el programa del artículo anterior "MQL5 Cookbook: Using Indicators to Set Trading Conditions in Expert Advisors" (“Libro de Recetas MQL5: Usar Indicadores Para Configurar Condiciones de Trading en Asesores Expertos”), que sustancialmente ya vale para nuestros propósitos. El artículo también demostrará cómo se pueden modificar fácilmente los patrones de programas ya hechos.
Libro de Recetas MQL5: Cómo Evitar Errores al Configurar/Modificar Niveles de Trading Libro de Recetas MQL5: Cómo Evitar Errores al Configurar/Modificar Niveles de Trading
Continuando con nuestro trabajo en el Asesor Experto desde el artículo anterior de la serie llamado "MQL5 Cookbook: Analyzing Position Properties in the MetaTrader 5 Strategy Tester" (“Libro de Recetas MQL5: Analizar Propiedades de Posición en el Probador de Estrategias de MetaTrader 5”), seguiremos trabajando en nuestro código, reforzándolo con un buen número de útiles funciones, mejorando y optimizando también las funciones ya existentes. El Asesor Experto tendrá, en esta ocasión, parámetros externos que se podrán optimizar en el Probador de Estrategias de MetaTrader 5, y se parecerán en algunos aspectos a un sistema de trading simple.