Descargar MetaTrader 5

Libro de Recetas MQL5: El Historial de Transacciones y la Biblioteca de Funciones para Obtener Propiedades de Posición

28 mayo 2014, 11:21
Anatoli Kazharski
0
536

Introducció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.

Los sistemas de trading donde los volúmenes de posición permanecen inalterables durante toda su existencia no requieren realmente el uso de las funciones que se facilitarán en este artículo. Pero si está pensando implementar un sistema de gestión de dinero y de control del tamaño de un lote de posición en su estrategia de trading en una fase posterior, estas funciones serán indispensables.

Antes de empezar, me gustaría sugerir a aquellos electores que siguieron el enlace a este artículo y que visitan esta página web por primera vez, o que acaban de empezar a aprender el lenguaje MQL 5, que comiencen con artículos anteriores de la serie de “Libros de recetas MQL 5”.


Desarrollo de Asesor Experto

Para poder ver las operaciones de las nuevas funciones en el Asesor Experto modificado en el artículo anterior llamado "MQL5 Cookbook: How to Avoid Errors When Setting/Modifying Trade Levels" (“Libro de Recetas MQL 5: Cómo Evitar Errores al Configurar/Modificar Niveles de Trading”), añadiremos la posibilidad de aumentar el volumen de posición si se da una señal de apertura de nuevo mientras la posición ya está ahí.

Puede que haya muchas transacciones en el historial de posiciones, y si se dieron cambios en el volumen de posición durante el curso de trading, deberá haber también cambios en el precio de posición actual. Para descubrir el primer punto de entrada del precio, debemos acceder al historial de transacciones con respecto a esa posición específica. La figura de abajo es una demostración del caso donde una posición solo tiene una transacción (punto de entrada):

Fig. 1. Primera transacción en la posición.

Fig. 1. Primera transacción en la posición.

La siguiente figura muestra un cambio en el precio de posición siguiendo a la segunda transacción:

Fig. 2. Segunda transacción en la posición.

Fig. 2. Segunda transacción en la posición.

Tal y como se demostró en los artículos anteriores, los identificadores estándar le permiten obtener solo el precio de posición actual (POSITION_PRICE_OPEN) y el precio actual del símbolo (POSITION_PRICE_CURRENT) por el cual se abrió la posición.

Sin embargo, en algunos sistemas de trading necesitamos saber la distancia cubierta por el precio desde el primer punto de entrada, así como el precio de la última transacción. Toda esta información está disponible en el historial de transacciones/órdenes de la cuenta. Abajo está la lista de transacciones asociada con la figura anterior:

Fig. 3. El historial de transacciones en la cuenta.

Fig. 3. El historial de transacciones en la cuenta.

Creo que la situación ahora está clara y que todos los objetivos se han configurado. Continuemos modificando el Asesor Experto tratado en los artículos anteriores. Primero, añadiremos nuevos identificadores con los números 0, 6, 9, 12 y 16 a la enumeración de propiedades de posición:

//--- Enumeration of position properties
enum ENUM_POSITION_PROPERTIES
  {
   P_TOTAL_DEALS     = 0,
   P_SYMBOL          = 1,
   P_MAGIC           = 2,
   P_COMMENT         = 3,
   P_SWAP            = 4,
   P_COMMISSION      = 5,
   P_PRICE_FIRST_DEAL= 6,
   P_PRICE_OPEN      = 7,
   P_PRICE_CURRENT   = 8,
   P_PRICE_LAST_DEAL = 9,
   P_PROFIT          = 10,
   P_VOLUME          = 11,
   P_INITIAL_VOLUME  = 12,
   P_SL              = 13,
   P_TP              = 14,
   P_TIME            = 15,
   P_DURATION        = 16,
   P_ID              = 17,
   P_TYPE            = 18,
   P_ALL             = 19
  };

Los comentarios para cada una de las propiedades se darán en una estructura que se revisará un poco más abajo.

Aumentemos ahora el número de los parámetros externos. Podemos especificar:

  • MagicNumber - un identificador único del Asesor Experto (número mágico);
  • Deviation - desviación;
  • VolumeIncrease - el valor por el que se aumentará el volumen de posición;
  • InfoPanel - un parámetro que le permitirá activar/desactivar la visualización del panel de información.

Se implementan de la siguiente manera:

//--- External parameters of the Expert Advisor
sinput   long        MagicNumber=777;     // Magic number
sinput   int         Deviation=10;        // Slippage
input    int         NumberOfBars=2;      // Number of Bullish/Bearish bars for a Buy/Sell
input    double      Lot=0.1;             // Lot
input    double      VolumeIncrease=0.1;  // Position 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

Por favor, note los parámetros cuyo modificador sinput ya está configurado. Este modificador le permitirá desactivar la optimización en el Probador de Estrategias. De hecho, al desarrollar un programa para su uso propio comprenderá perfectamente qué parámetros afectarán al resultado final, de modo que simplemente desactívelos para la optimización. Pero si se trata de un gran número de parámetros, este método le permitirá separarlos visualmente de los demás, puesto que se muestran en gris:

Fig. 4. Los parámetros desactivados para la optimización se muestran en gris.

Fig. 4. Los parámetros desactivados para la optimización se muestran en gris.

Reemplazaremos ahora las variables globales que almacenan valores de propiedad de posición y símbolo con estructuras de datos (struct):

//--- Position properties
struct position_properties
  {
   uint              total_deals;      // Number of deals
   bool              exists;           // Flag of presence/absence of an open position
   string            symbol;           // Symbol
   long              magic;            // Magic number
   string            comment;          // Comment
   double            swap;             // Swap
   double            commission;       // Commission   
   double            first_deal_price; // Price of the first deal in the position
   double            price;            // Current position price
   double            current_price;    // Current price of the position symbol      
   double            last_deal_price;  // Price of the last deal in the position
   double            profit;           // Profit/Loss of the position
   double            volume;           // Current position volume
   double            initial_volume;   // Initial position volume
   double            sl;               // Stop Loss of the position
   double            tp;               // Take Profit of the position
   datetime          time;             // Position opening time
   ulong             duration;         // Position duration in seconds
   long              id;               // Position identifier
   ENUM_POSITION_TYPE type;            // Position type
  };
//--- 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
  }

Ahora, para acceder a un determinado elemento de la estructura, necesitaremos crear una variable de este tipo de estructura. El procedimiento es similar a la creación del objeto para una clase de trading que ya se trató en el artículo 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”).

//--- variables for position and symbol properties
position_properties  pos;
symbol_properties    symb;

Puede acceder a los elementos de la misma manera al trabajar con métodos de clase. En otras palabras, es suficiente poner un punto después del nombre de una variable de estructura para mostrar la lista de elementos contenida en esa estructura específica. Esto es muy conveniente. Si existen comentarios en los campos de la estructura (como en el caso de nuestro ejemplo), se mostrarán en un mensaje emergente a la derecha.

Fig. 5a. Lista de campos de estructura. Fig. 5b. Lista de campos de estructura para propiedades de símbolo

Fig. 5. Lista de campos de estructura.

Otro elemento importante: al modificar el Asesor Experto, hemos cambiado virtualmente todas sus variables globales usadas en varias funciones, de modo que ahora debemos reemplazarlas con los campos de estructura correspondiente para las propiedades de posición y símbolo. Por ejemplo, la variable pos_open, que se usó para almacenar la flag de presencia/ausencia de una posición abierta, se ha sustituido con el campo exists del tipo de estructura position_properties. Por tanto, allá donde se usó la variable pos_open, se debe sustituir con pos.exists.

Será un proceso largo y agotador si lo hace manualmente. Por ello sería mejor automatizar la solución de esta tarea usando las prestaciones de MetaEditor: Find and Replace (buscar y reemplazar) -> Replace, en el menú Edit (editar), o la combinación de teclas Ctrl+H:


Fig. 6. Encontrar y sustituir el texto.

Fig. 6. Encontrar y sustituir el texto.

Debemos encontrar y reemplazar todas las variables globales de propiedades de símbolo y posición para ejecutar a continuación una simulación tras compilar el archivo. Si no se detectaron errores, significa que lo tenemos todo correcto. No facilitaré el código aquí para no hacer el artículo innecesariamente largo. Además, un código fuente listo para usar se puede descargar al final del artículo.

Ahora que ya hemos arreglado todo con las variables, procedamos a modificar las funciones existentes y crear nuevas.

En los parámetros externos puede ahora configurar el número mágico y la desviación en puntos. Por tanto, ahora necesitamos hacer los cambios relevantes en el código del Asesor Experto. Crearemos una función auxiliar definida por el usuario OpenPosition(), en la que se configurarán estas propiedades usando las funciones de la clase CTrade antes de enviar una orden para abrir una posición.

//+------------------------------------------------------------------+
//| Opening a position                                               |
//+------------------------------------------------------------------+
void OpenPosition(double lot,
                  ENUM_ORDER_TYPE order_type,
                  double price,
                  double sl,
                  double tp,
                  string comment)
  {
   trade.SetExpertMagicNumber(MagicNumber); // Set the magic number in the trading structure
   trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation)); // Set the slippage in points
//--- 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())); }
  }

Solo debemos hacer algunos cambios pequeños en el código de la función de trading principal del Asesor Experto: TradingBlock(). A continuación se encuentra la parte del código de la función que ha cambiado:

//--- If there is no position
   if(!pos.exists)
     {
      //--- Adjust the volume
      lot=CalculateLot(Lot);
      //--- Open a position
      OpenPosition(lot,order_type,position_open_price,sl,tp,comment);
     }
//--- If there is a position
   else
     {
      //--- Get the position type
      GetPositionProperties(P_TYPE);
      //--- If the position is opposite to the signal and the position reversal is enabled
      if(pos.type==opposite_position_type && Reverse)
        {
         //--- Get the position volume
         GetPositionProperties(P_VOLUME);
         //--- Adjust the volume
         lot=pos.volume+CalculateLot(Lot);
         //--- Reverse the position
         OpenPosition(lot,order_type,position_open_price,sl,tp,comment);
         return;
        }
      //--- If the signal is in the direction of the position and the volume increase is enabled, increase the position volume
      if(!(pos.type==opposite_position_type) && VolumeIncrease>0)
        {
         //--- Get the Stop Loss of the current position
         GetPositionProperties(P_SL);
         //--- Get the Take Profit of the current position
         GetPositionProperties(P_TP);
         //--- Adjust the volume
         lot=CalculateLot(Increase);
         //--- Increase the position volume
         OpenPosition(lot,order_type,position_open_price,pos.sl,pos.tp,comment);
         return;
        }

El código de arriba se ha reforzado con el bloque donde la dirección de la posición actual se comprueba con respecto a la dirección de la señal. Si sus direcciones coinciden y el aumento del volumen de la posición está activado en los parámetros externos (el valor del parámetro VolumeIncrease es mayor de cero), comprobaremos/ajustaremos un lote específico y enviaremos la orden correspondiente. Ahora, todo lo que debe hacer para enviar una orden de apertura o inversión de posición o de aumento del volumen de la posición es escribir una línea de código.

Creemos funciones para obtener las propiedades de posición del historial de transacciones. Empezaremos con una función CurrentPositionTotalDeals() que devuelva el número de transacciones en la posición actual:

//+------------------------------------------------------------------+
//| Returning the number of deals in the current position            |
//+------------------------------------------------------------------+
uint CurrentPositionTotalDeals()
  {
   int    total       =0;  // Total deals in the selected history list
   int    count       =0;  // Counter of deals by the position symbol
   string deal_symbol =""; // symbol of the deal
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list
      for(int i=0; i<total; i++)
        {
            //--- Get the symbol of the deal
            deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
            //--- If the symbol of the deal and the current symbol are the same, increase the counter
            if(deal_symbol==_Symbol)
               count++;
        }
     }
//---
   return(count);
  }

El código de arriba se facilita con comentarios muy detallados. El código de arriba se facilita con comentarios muy detallados. En nuestro caso, obtuvimos la lista del punto de apertura de la posición actual determinado por el período desde el momento de apertura hasta el punto actual usando la función HistorySelect(). Después de seleccionar el historial, podemos ver el número de transacciones en la lista usando la función HistoryDealsTotal(). El resto debería quedar claro leyendo los comentarios.

El historial de una posición particular también se puede seleccionar con su identificador usando la función HistorySelectByPosition(). Aquí debe considerar que el identificador de posición permanece igual cuando se invierte la posición, como ocurre a veces en nuestro Asesor Experto. Sin embargo, el momento de apertura de la posición no cambia con la inversión, por tanto esta variante es más fácil de implementar. Pero si usted tiene que trabajar con el historial de transacciones que no se aplica solo a la posición de apertura actual, deberá usar identificadores. Volveremos al historial de transacciones en próximos artículos.

Continuemos creando una función CurrentPositionFirstDealPrice() que devuelva el precio de la primera transacción en la posición, es decir, el precio de la transacción en la que se abrió la posición.

//+------------------------------------------------------------------+
//| Returning the price of the first deal in the current position    |
//+------------------------------------------------------------------+
double CurrentPositionFirstDealPrice()
  {
   int      total       =0;    // Total deals in the selected history list
   string   deal_symbol ="";   // symbol of the deal
   double   deal_price  =0.0;  // Price of the deal
   datetime deal_time   =NULL; // Time of the deal
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list
      for(int i=0; i<total; i++)
        {
         //--- Get the price of the deal
         deal_price=HistoryDealGetDouble(HistoryDealGetTicket(i),DEAL_PRICE);
         //--- Get the symbol of the deal
         deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
         //--- Get the time of the deal
         deal_time=(datetime)HistoryDealGetInteger(HistoryDealGetTicket(i),DEAL_TIME);
         //--- If the time of the deal equals the position opening time, 
         //    and if the symbol of the deal and the current symbol are the same, exit the loop
         if(deal_time==pos.time && deal_symbol==_Symbol)
            break;
        }
     }
//---
   return(deal_price);
  }

El principio aquí es el mismo que en la función anterior. Obtenemos el historial del punto de apertura de posición y después comprobamos el momento de la transacción y el momento de la apertura de la posición en cada iteración. Obtendremos el nombre del símbolo y el momento de la transacción junto con el precio de la misma. La primera transacción se identifica cuando el momento de la transacción coincide con el momento de la apertura de la posición. Puesto que su precio ya se ha asignado a la variable relevante, solo deberemos devolver el valor.

Continuemos. A veces, puede que necesite obtener el precio de la última transacción en la posición actual. Para ello, crearemos una función CurrentPositionLastDealPrice():

//+------------------------------------------------------------------+
//| Returning the price of the last deal in the current position     |
//+------------------------------------------------------------------+
double CurrentPositionLastDealPrice()
  {
   int    total       =0;   // Total deals in the selected history list
   string deal_symbol ="";  // Symbol of the deal 
   double deal_price  =0.0; // Price
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list from the last deal in the list to the first deal
      for(int i=total-1; i>=0; i--)
        {
         //--- Get the price of the deal
         deal_price=HistoryDealGetDouble(HistoryDealGetTicket(i),DEAL_PRICE);
         //--- Get the symbol of the deal
         deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
         //--- If the symbol of the deal and the current symbol are the same, exit the loop
         if(deal_symbol==_Symbol)
            break;
        }
     }
//---
   return(deal_price);
  }

En esta ocasión, el bucle empezó con la última transacción en la lista, y a menudo se da el caso de que la transacción requerida se identifica en la primera iteración del bucle. Pero si realiza operaciones de trading en varios símbolos, el bucle continuará hasta que el símbolo de la transacción coincida con el símbolo actual.

El volumen de la posición actual se puede obtener usando el identificador estándar POSITION_VOLUME. Para descubrir el volumen de la posición inicial (el volumen de la primera transacción), crearemos una función CurrentPositionInitialVolume():

//+------------------------------------------------------------------+
//| Returning the initial volume of the current position             |
//+------------------------------------------------------------------+
double CurrentPositionInitialVolume()
  {
   int             total       =0;           // Total deals in the selected history list
   ulong           ticket      =0;           // Ticket of the deal
   ENUM_DEAL_ENTRY deal_entry  =WRONG_VALUE; // Position modification method
   bool            inout       =false;       // Flag of position reversal
   double          sum_volume  =0.0;         // Counter of the aggregate volume of all deals, except for the first one
   double          deal_volume =0.0;         // Volume of the deal
   string          deal_symbol ="";          // Symbol of the deal 
   datetime        deal_time   =NULL;        // Deal execution time
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list from the last deal in the list to the first deal
      for(int i=total-1; i>=0; i--)
        {
         //--- If the order ticket by its position is obtained, then...
         if((ticket=HistoryDealGetTicket(i))>0)
           {
            //--- Get the volume of the deal
            deal_volume=HistoryDealGetDouble(ticket,DEAL_VOLUME);
            //--- Get the position modification method
            deal_entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket,DEAL_ENTRY);
            //--- Get the deal execution time
            deal_time=(datetime)HistoryDealGetInteger(ticket,DEAL_TIME);
            //--- Get the symbol of the deal
            deal_symbol=HistoryDealGetString(ticket,DEAL_SYMBOL);
            //--- When the deal execution time is less than or equal to the position opening time, exit the loop
            if(deal_time<=pos.time)
               break;
            //--- otherwise calculate the aggregate volume of deals by the position symbol, except for the first one
            if(deal_symbol==_Symbol)
               sum_volume+=deal_volume;
           }
        }
     }
//--- If the position modification method is a reversal
   if(deal_entry==DEAL_ENTRY_INOUT)
     {
      //--- If the position volume has been increased/decreased
      //    I.e. the number of deals is more than one
      if(fabs(sum_volume)>0)
        {
         //--- Current volume minus the volume of all deals except for the first one
         double result=pos.volume-sum_volume;
         //--- If the resulting value is greater than zero, return the result, otherwise return the current position volume         
         deal_volume=result>0 ? result : pos.volume;
        }
      //--- If there are no more deals, other than the entry,
      if(sum_volume==0)
         deal_volume=pos.volume; // return the current position volume
     }
//--- Return the initial position volume
   return(NormalizeDouble(deal_volume,2));
  }

Esta función resultó ser más compleja que las anteriores. He intentado tener en cuenta todas las situaciones posibles que podrían resultar en un valor incorrecto. Una simulación detallada no reveló problema alguno. Los comentarios facilitados en el código deberían serle de ayuda para entenderlo.

También será útil tener una función que devuelva la duración de la posición. Lo haremos de forma que permita al usuario seleccionar el formato apropiado del valor devuelto: segundos, minutos, horas o días. Para ello, creemos otra enumeración:

//--- Position duration
enum ENUM_POSITION_DURATION
  {
   DAYS     = 0, // Days
   HOURS    = 1, // Hours
   MINUTES  = 2, // Minutes
   SECONDS  = 3  // Seconds
  };

Debajo está el código de la función CurrentPositionDuration(), responsable para todos los cálculos relevantes:

//+------------------------------------------------------------------+
//| Returning the duration of the current position                   |
//+------------------------------------------------------------------+
ulong CurrentPositionDuration(ENUM_POSITION_DURATION mode)
  {
   ulong     result=0;   // End result
   ulong     seconds=0;  // Number of seconds
//--- Calculate the position duration in seconds
   seconds=TimeCurrent()-pos.time;
//---
   switch(mode)
     {
      case DAYS      : result=seconds/(60*60*24);   break; // Calculate the number of days
      case HOURS     : result=seconds/(60*60);      break; // Calculate the number of hours
      case MINUTES   : result=seconds/60;           break; // Calculate the number of minutes
      case SECONDS   : result=seconds;              break; // No calculations (number of seconds)
      //---
      default        :
         Print(__FUNCTION__,"(): Unknown duration mode passed!");
         return(0);
     }
//--- Return result
   return(result);
  }

Creemos una función CurrentPositionDurationToString() para el panel de información donde se muestren las propiedades de posición. La función convertirá la duración de la posición en segundos a un formato fácilmente comprensible para el usuario. El número de segundo se pasará a la función, y la función a su vez devolverá una cadena de caracteres que contendrá la duración de la posición en días, horas, minutos y segundos:

//+------------------------------------------------------------------+
//| Converting the position duration to a string                     |
//+------------------------------------------------------------------+
string CurrentPositionDurationToString(ulong time)
  {
//--- A dash if there is no position
   string result="-";
//--- If the position exists
   if(pos.exists)
     {
      //--- Variables for calculation results
      ulong days=0;
      ulong hours=0;
      ulong minutes=0;
      ulong seconds=0;
      //--- 
      seconds=time%60;
      time/=60;
      //---
      minutes=time%60;
      time/=60;
      //---
      hours=time%24;
      time/=24;
      //---
      days=time;
      //--- Generate a string in the specified format DD:HH:MM:SS
      result=StringFormat("%02u d: %02u h : %02u m : %02u s",days,hours,minutes,seconds);
     }
//--- Return result
   return(result);
  }

Ya está todo listo. No voy a facilitar los códigos de las funciones GetPositionProperties() and GetPropertyValue() que se debe modificar de acuerdo con los cambios explicados arriba. Si ha leído todo los artículos anteriores de la serie, no debería tener ninguna dificultad para hacer esto por usted mismo. En cualquier caso, el código fuente está junto al artículo.

Como resultado, el panel de información debería tener el siguiente aspecto:

Fig. 7. Demostración de todas las propiedades de posición en el panel información.

Fig. 7. Demostración de todas las propiedades de posición en el panel información.

Por tanto, ahora tenemos la biblioteca de funciones para obtener propiedades de posición, y probablemente continuaremos trabajando en ello en próximos artículos, según la necesidad.


Optimizar Parámetros y Simular el Asesor Experto

Como experimento, tratemos de optimizar los parámetros del Asesor Experto. Aunque lo que tenemos actualmente todavía no se puede llamar un sistema de trading completo, el resultado que conseguiremos abrirá nuestros ojos con respecto a algunas cosas y reforzará nuestra experiencia como creadores de sistemas de trading.

Configuraremos el Probador de Estrategias tal y como se muestra abajo:

Fig. 8. Configuración del Probador de Estrategias para optimización de parámetros.

Fig. 8. Configuración de Probador de Estrategias para la optimización de parámetros.

La configuración de los parámetros externos del Asesor Experto debería ser la siguiente:

Fig. 9. Configuración de parámetros del Asesor Experto para la optimización.

Fig. 9. Configuración de parámetros del Asesor Experto para la optimización.

Después de la optimización, ordenaremos los resultados obtenidos según el factor máximo de recuperación:

Fig. 10. Resultados según el factor máximo de recuperación.

Fig. 10. Resultados según el factor máximo de recuperación.

Simulemos ahora el conjunto de parámetros de arriba con el valor del Factor de Recuperación igual a 4.07. Aún con el hecho de que la optimización se ha realizado para EURUSD, podemos ver resultados positivos para muchos símbolos:

Resultados para EURUSD:

Fig. 11. Resultados para EURUSD

Fig. 11. Resultados para EURUSD.

Resultados para AUDUSD:

Fig. 12. Resultados para AUDUSD

Fig. 12. Resultados para AUDUSD.

Resultados para NZDUSD:

Fig. 13. Resultados para NZDUSD

Fig. 13. Resultados para NZDUSD.


Conclusión

Virtualmente, cualquier idea se puede desarrollar y reforzar. Cada sistema de trading se debe simular detalladamente antes de rechazarlo como defectuoso. En próximos artículos echaremos un vistazo a varios mecanismos y esquemas que podrían jugar un papel muy positivo en la personalización y adaptación de casi cualquier sistema de trading.

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

Archivos adjuntos |
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.

Libro de Recetas MQL5: Analizar Propiedades de Posición en el Probador de Estrategias de MetaTrader 5 Libro de Recetas MQL5: Analizar Propiedades de Posición en el Probador de Estrategias de MetaTrader 5

En esta ocasión presentaremos una versión modificada del Asesor Experto del artículo anterior "MQL5 Cookbook: Position Properties on the Custom Info Panel" (“Propiedades de Posición en el Panel de Información Personalizada”). Algunos de los aspectos a los que nos referiremos incluyen la obtención de datos de barras, la comprobación de eventos de barra nueva en el símbolo actual, la inclusión de una clase de trading de la Biblioteca Estándar a un archivo, la creación de una función para buscar señales de trading, y una función para ejecutar operaciones de trading, así como para terminar eventos de trading en la función OnTrade().

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

En este artículo continuaremos modificando el Asesor Experto en el que hemos estado trabajando durante los artículos anteriores de la serie de Libros de Recetas MQL5. En esta ocasión, 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.

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.