English Русский 中文 Deutsch 日本語 Português
preview
Kit de herramientas de negociación MQL5 (Parte 2): Ampliación e implantación de la biblioteca EX5 de gestión de posiciones

Kit de herramientas de negociación MQL5 (Parte 2): Ampliación e implantación de la biblioteca EX5 de gestión de posiciones

MetaTrader 5Ejemplos | 20 enero 2025, 09:58
398 0
Wanateki Solutions LTD
Kelvin Muturi Muigua

Introducción

En el primer artículo, analizamos en detalle las bibliotecas de código MQL5. Hemos tratado los diferentes tipos de bibliotecas, sus ventajas, la creación de bibliotecas EX5 y los componentes de un archivo de código fuente de biblioteca EX5 (.mq5). Esto le proporcionó una base sólida en las bibliotecas EX5 y su proceso de creación. A continuación, creamos un ejemplo práctico de una biblioteca de gestión de posiciones EX5, demostrando cómo codificar funciones exportables con MQL5.

En este artículo, seguiremos construyendo sobre esa base. Ampliaremos la biblioteca EX5 de gestión de posiciones y crearemos dos Asesores Expertos básicos. Uno de estos Asesores Expertos de ejemplo utilizará un panel gráfico de operaciones e información, demostrando cómo importar e implementar en la práctica la biblioteca EX5 de gestión de posiciones. Esto servirá como un ejemplo real de cómo crear e integrar una biblioteca EX5 en su código MQL5. Para empezar, desglosemos primero el proceso de importación y uso de una biblioteca binaria .ex5 ya desarrollada y compilada.


Cómo importar e implementar una biblioteca EX5

Para importar y utilizar una librería .EX5 en su código MQL5 (Asesores Expertos, Indicadores Personalizados, Scripts o Servicios), necesita insertar las directivas #import justo debajo de las directivas #property en la cabecera o sección superior de su archivo de código fuente. Para incluir la biblioteca binaria compilada, comience especificando la directiva #import seguida de la ruta del archivo donde se almacena la biblioteca. Por defecto, MQL5 busca bibliotecas en dos ubicaciones para ahorrarte tiempo referenciándolas directamente en tu código. La primera ubicación es la carpeta «MQL5/Libraries», que es la ubicación predefinida por defecto para almacenar las librerías. Si la biblioteca no se encuentra allí, MQL5 buscará entonces en la carpeta donde se encuentra el propio programa MQL. Si su librería EX5 está almacenada directamente en la carpeta «MQL5/Libraries/» o en la misma carpeta que su código fuente, simplemente especifique el nombre de la librería entre comillas dobles después de la directiva #import sin especificar la ruta de la carpeta.

Tras especificar la ruta de la carpeta de la biblioteca, indique el nombre de la biblioteca seguido de la extensión .ex5. En la siguiente línea nueva, añada las definiciones o descripciones de todos los prototipos de función exportados que se importarán en su código. Por último, termina el segmento de código de importación con otra directiva #import para cerrarlo.

#import "FilePath/LibraryName.ex5" //-- Opening .EX5 Library import directive

   //-- Function definitions/descriptions prototypes
   int  FunctionPrototype1();
   void FunctionPrototype2(bool y);
   bool FunctionPrototype3(double x);

#import //--- Closing .EX5 Library import directive

Es necesario especificar y proporcionar la extensión .ex5 después del nombre de la biblioteca al declarar la directiva de importación. La omisión de la extensión indicará que está importando una biblioteca .DLL por defecto.

También puedes importar e implementar múltiples bibliotecas .ex5 en un único archivo MQL5. La estructura del código para importar varias bibliotecas .ex5 es similar a la de importar una sola biblioteca, con la única diferencia de la colocación de las directivas de cierre #import. Para múltiples importaciones de bibliotecas, la directiva de cierre #import de la primera biblioteca debe ir seguida del nombre de la siguiente biblioteca .ex5 que se importa. Esto cerrará la primera directiva de importación mientras inicia la siguiente directiva de importación, y así sucesivamente. Al cerrar la última directiva de importación de la última biblioteca, asegúrese de que termina sin nombre de biblioteca.

#import "FilePath/LibraryName.ex5"  //-- Opening .EX5 Library import directive

   //-- Function definitions/descriptions prototypes for the first library here
   int  FunctionPrototype1();
   void FunctionPrototype2(bool y);
   
#import "FilePath/SecondLibraryName.ex5"
   //-- Function definitions/descriptions prototypes for the second library here
   bool  FunctionPrototype();
   string FunctionPrototype2(bool z);

#import //--- Closing .EX5 Library import directive

Cuando se trabaja con múltiples bibliotecas en MQL5, es necesario dar a cada uno un nombre único. No importa si todas estas bibliotecas están almacenadas en carpetas diferentes, tener nombres distintos es un requisito para no encontrar errores.

Cada biblioteca crea su propio entorno aislado o «espacio de nombres». Esto significa que las funciones dentro de una biblioteca se asocian con el nombre de esa biblioteca. Puede nombrar libremente las funciones dentro de una biblioteca sin preocuparse por los conflictos, incluso si coinciden con nombres de funciones incorporadas. Sin embargo, por lo general se recomienda evitar este tipo de denominaciones en aras de la claridad.

Si por casualidad tiene funciones con el mismo nombre en bibliotecas diferentes, el sistema dará prioridad a la función basándose en reglas específicas. Esto evita confusiones al llamar a funciones con nombres idénticos. Una vez que haya importado correctamente los prototipos de función de la biblioteca, podrá integrarlos sin problemas en su código y tratarlos como cualquier otra función local que haya definido usted mismo.

Más adelante en el artículo, ofrezco una explicación detallada de cómo incorporar y utilizar las bibliotecas EX5 en un entorno práctico. Encontrará dos demostraciones en profundidad: una en la que codificamos un Asesor Experto basado en la estrategia de trading VIDyA, y otra en la que utilizamos una interfaz gráfica de usuario (GUI). Estos Asesores Expertos integrarán y aprovecharán nuestra biblioteca personalizada Positions Management EX5. Estos ejemplos prácticos ofrecerán información valiosa sobre la implementación de las bibliotecas EX5 en Expert Advisors del mundo real.


Errores comunes de ejecución de la biblioteca EX5

La depuración de las bibliotecas EX5 puede ser un reto, ya que la mayoría de los errores comunes relacionados con las funciones prototipo importadas se producen durante el tiempo de ejecución al cargar la aplicación MQL5 final compilada en el terminal de operaciones. Estos errores suelen producirse al codificar la sección de directivas de biblioteca de importación del encabezado con valores incorrectos como las rutas o los nombres de los archivos de biblioteca, las descripciones de los prototipos de funciones, los tipos, los nombres, la lista completa de parámetros y los valores de retorno durante las declaraciones de importación. No se espera que el compilador detecte estos errores de declaración de importación en tiempo de compilación, ni se le encomienda esta tarea, porque no puede acceder al código fuente de la biblioteca importada, ya que está encapsulada y ya compilada en un módulo de formato binario ejecutable (.ex5).

Cualquier archivo de código fuente que contenga estos errores se compilará correctamente, pero cuando intentes cargar la aplicación MQL5 compilada en el terminal de trading, fallará y generará errores de ejecución. Estos errores se muestran en la pestaña Expertos o en la pestaña Diario del Terminal MetaTrader 5. Estos son los errores más comunes que puede encontrar:

Llamada a función de importación no resuelta: (no se encuentra <nombre_función> en <nombre_biblioteca.ex5>).

    • Descripción: Este error de ejecución se produce al intentar cargar la aplicación MQL5 en un gráfico de MetaTrader 5 y se muestra en la pestaña Expertos. Está causado por definiciones o descripciones incorrectas de prototipos de funciones, como tipo, nombre o parámetros, proporcionadas en la sección de directivas de importación de la biblioteca.
    • Resolución: Asegúrese de que el segmento de código de importación de la biblioteca está codificado correctamente con las definiciones de prototipo de función correctas según sea necesario y vuelva a compilar su código.

Llamada a función de importación no resuelta


No se puede abrir el archivo 'Nombre_Biblioteca.ex5': (la carga de Nombre_del_asesor_experto (GBPJPY,M15) falló [0]).

    • Descripción: Este error de ejecución se produce al intentar cargar la aplicación MQL5 en un gráfico de MetaTrader 5 y se muestra en la pestaña Diario. Se produce cuando no se puede localizar y cargar el archivo de biblioteca EX5 importado.
    • Resolución: Asegúrese de que se especifica la ruta de archivo correcta a la biblioteca en el segmento de código de importación de la biblioteca y vuelva a compilar el código.
No se puede abrir el archivo de biblioteca

Mientras que otros errores pueden surgir cuando se trabaja con las bibliotecas importadas en MQL5, los errores en tiempo de ejecución anteriores son los más comunes y problemáticos para los desarrolladores principiantes. Estos errores son especialmente difíciles porque se pasan por alto con facilidad y no están diseñados para que el compilador los detecte durante la compilación.


Cómo actualizar y reimplementar bibliotecas EX5

Es importante seguir la secuencia correcta a la hora de redesplegar tus librerías EX5 después de cada actualización para asegurar que los nuevos cambios se integran correctamente en los proyectos MQL5 que utilizan la librería. La secuencia de compilación es el paso más crucial en la actualización y redistribución de las bibliotecas en MQL5. Para garantizar que todos los nuevos cambios y actualizaciones se utilicen en todos los proyectos que importen la biblioteca, siga estos pasos:

  1. Compilar el nuevo archivo EX5: Comience compilando el archivo de código fuente actualizado de la biblioteca .mq5 para crear el nuevo archivo binario ejecutable .ex5.
  2. Actualizar prototipos de función importados: En todos los proyectos MQL5 que utilicen la librería EX5, actualice cualquier definición de importación de prototipos de función si han cambiado en la nueva actualización de la librería .ex5.
  3. Compilar los proyectos: Recompila todos los proyectos MQL5 que implementen la librería EX5.
Siguiendo esta secuencia, se asegurará de que todas las actualizaciones de la biblioteca EX5 se reflejen e integren en todos los proyectos que importen la biblioteca.


Función Trailing Stop Loss

Antes de poner en marcha nuestra biblioteca de gestión de puestos, vamos a ampliarla añadiendo algunas funciones vitales. Empezaremos añadiendo un módulo o función de gestión de trailing stop loss, ya que nuestra biblioteca no estará completa sin esta característica esencial. Un trailing stop loss es una parte importante de cualquier estrategia de negociación, ya que cuando se aplica correctamente, tiene el potencial de aumentar los márgenes de beneficio de un sistema y la tasa de éxito global.

La función trailing stop loss se llamará SetTrailingStopLoss() y se encargará de establecer el trailing SL de una posición abierta existente utilizando la entrada de la posición como mecanismo de filtrado. Tomará el número de ticket de una posición y el trailing stop loss deseado en pips (puntos) como argumentos o parámetros e intentará actualizar el trailing stop loss de la posición en el servidor de negociación cuando se cumplan ciertas condiciones. Esta función debe ser llamada continuamente en cada tick para modificar el trailing stop loss en tiempo real, ya que el estado de las posiciones objetivo cambia constantemente.

Primero comprobará si la negociación está permitida y si el trailing stop loss en pips (puntos) es válido. A continuación, seleccionará la posición, recuperará y guardará toda la información necesaria sobre el símbolo y calculará el precio de arrastre de pérdidas. Si el precio calculado es válido, enviará una orden al servidor de operaciones para fijar el stop loss. Si la orden se ejecuta correctamente, la función devolverá true; en caso contrario, devolverá false.

En primer lugar, empezaremos por crear la definición de la función. Nuestra función trailing stop loss será de tipo bool y tomará dos parámetros:

  1. ulong positionTicket: Se trata de un identificador único para la posición que vamos a modificar.
  2. int trailingStopLoss: Es el nivel de Stop Loss deseado en pips (puntos) desde el precio actual de la posición.

La palabra clave export indica que esta función de biblioteca se puede llamar desde cualquier archivo de código fuente MQL5 o proyecto que la importe.

bool SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss) export
  {
    //-- place the function body here
  }

Tenemos que comprobar si se permite la negociación y si el parámetro trailingStopLoss es mayor que cero. Si no se cumple alguna de las dos condiciones, salimos de la función y devolvemos false para terminar la operación.

if(!TradingIsAllowed() || trailingStopLoss == 0)
     {
      return(false); //--- algo trading is disabled or trailing stop loss is invalid, exit function
     }

A continuación, confirmamos y seleccionamos la posición utilizando el positionTicket proporcionado. Si la selección de posición falla, imprimimos un mensaje de error y salimos de la función.

//--- Confirm and select the position using the provided positionTicket
   ResetLastError(); //--- Reset error cache incase of ticket selection errors
   if(!PositionSelectByTicket(positionTicket))
     {
      //---Position selection failed
      Print("\r\n_______________________________________________________________________________________");
      Print(__FUNCTION__, ": Selecting position with ticket:", positionTicket, " failed. ERROR: ", GetLastError());
      return(false); //-- Exit the function
     }

A continuación, creamos algunas variables para ayudarnos a almacenar y validar el trailing stop loss. Comenzamos creando la variable slPrice para almacenar el precio calculado del trailing stop loss y, a continuación, guardamos las propiedades de la posición, como el símbolo, el precio de entrada, el volumen, el precio actual del stop loss, el precio actual del take profit y el tipo de posición.

//-- create variable to store the calculated trailing sl prices to send to the trade server
   double slPrice = 0.0;

//--- Position ticket selected, save the position properties
   string positionSymbol = PositionGetString(POSITION_SYMBOL);
   double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN);
   double volume = PositionGetDouble(POSITION_VOLUME);
   double currentPositionSlPrice = PositionGetDouble(POSITION_SL);
   double currentPositionTpPrice = PositionGetDouble(POSITION_TP);
   ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

Asimismo, seguimos guardando las distintas propiedades del símbolo asociadas a la posición seleccionada. Estas propiedades también se utilizarán más adelante para validar y calcular el trailing stop loss.

//-- Get some information about the positions symbol
   int symbolDigits = (int)SymbolInfoInteger(positionSymbol, SYMBOL_DIGITS); //-- Number of symbol decimal places
   int symbolStopLevel = (int)SymbolInfoInteger(positionSymbol, SYMBOL_TRADE_STOPS_LEVEL);
   double symbolPoint = SymbolInfoDouble(positionSymbol, SYMBOL_POINT);
   double positionPriceCurrent = PositionGetDouble(POSITION_PRICE_CURRENT);
   int spread = (int)SymbolInfoInteger(positionSymbol, SYMBOL_SPREAD);

Comprobamos si el valor de trailing stop loss proporcionado es inferior al nivel de stop de la operación del símbolo. Si lo es, ajustamos el trailing stop loss para que sea igual al nivel de stop del símbolo.

//-- Check if the trailing stop loss is less than the symbol trade stop levels
   if(trailingStopLoss < symbolStopLevel)
     {
      //-- Trailing stop loss is less than the allowed level for the current symbol
      trailingStopLoss = symbolStopLevel; //-- Set it to the symbol stop level by default
     }

El siguiente paso consiste en calcular el precio de arrastre de pérdidas en función de si la posición es de compra o de venta. Para las posiciones de compra, el precio de stop loss se fija por debajo del precio actual, mientras que para las posiciones de venta, se fija por encima del precio actual. También validamos que el precio de stop loss calculado está dentro de los límites válidos.

//-- Calculate and store the trailing stop loss price
   if(positionType == POSITION_TYPE_BUY)
     {
      slPrice = positionPriceCurrent - (trailingStopLoss * symbolPoint);

      //-- Check if the proposed slPrice for the trailing stop loss is valid
      if(slPrice < entryPrice || slPrice < currentPositionSlPrice)
        {
         return(false); //-- Exit the function, proposed trailing stop loss price is invalid
        }
     }
   else  //-- SELL POSITION
     {
      slPrice = positionPriceCurrent + (trailingStopLoss * symbolPoint);

      //-- Check if the proposed slPrice for the trailing stop loss is valid
      if(slPrice > entryPrice || slPrice > currentPositionSlPrice)
        {
         return(false); //-- Exit the function, proposed trailing stop loss price is invalid
        }
     }

Antes de establecer el trailing stop loss, imprimamos los detalles de la posición en el registro de MetaTrader 5. Esto incluye el símbolo, el tipo de posición, el volumen, el precio de entrada, los precios actuales de stop loss y take profit, y otra información relevante.

//-- Print position properties before setting the trailing stop loss
   string positionProperties = "--> "  + positionSymbol + " " + EnumToString(positionType) + " Trailing Stop Loss Modification Details" +
                               " <--\r\n";
   positionProperties += "------------------------------------------------------------\r\n";
   positionProperties += "Ticket: " + (string)positionTicket + "\r\n";
   positionProperties += "Volume: " + StringFormat("%G", volume) + "\r\n";
   positionProperties += "Price Open: " + StringFormat("%G", entryPrice) + "\r\n";
   positionProperties += "Current SL: " + StringFormat("%G", currentPositionSlPrice) + "   -> New Trailing SL: " + (string)slPrice + "\r\n";
   positionProperties += "Current TP: " + StringFormat("%G", currentPositionTpPrice) + "\r\n";
   positionProperties += "Comment: " + PositionGetString(POSITION_COMMENT) + "\r\n";
   positionProperties += "Magic Number: " + (string)PositionGetInteger(POSITION_MAGIC) + "\r\n";
   positionProperties += "---";
   Print(positionProperties);

Reseteamos las estructuras tradeRequest y tradeResult a cero. A continuación, inicializamos los parámetros necesarios para establecer el stop loss y el take profit.

//-- reset the the tradeRequest and tradeResult values by zeroing them
   ZeroMemory(tradeRequest);
   ZeroMemory(tradeResult);

//-- initialize the parameters to set the sltp
   tradeRequest.action = TRADE_ACTION_SLTP; //-- Trade operation type for setting sl and tp
   tradeRequest.position = positionTicket;
   tradeRequest.symbol = positionSymbol;
   tradeRequest.sl = slPrice;
   tradeRequest.tp = currentPositionTpPrice;

Por último, restablecemos la caché de errores y enviamos la orden al servidor de operaciones hasta que tenga éxito o hasta 101 reintentos. Si la orden se ejecuta correctamente, imprimimos un mensaje de éxito, devolvemos true y salimos de la función. Si la solicitud de pedido falla, gestionamos el error, devolvemos false y salimos de la función.

ResetLastError(); //--- reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function

   for(int loop = 0; loop <= 100; loop++) //-- try modifying the sl and tp 101 times untill the request is successful
     {
      //--- send order to the trade server
      if(OrderSend(tradeRequest, tradeResult))
        {
         //-- Confirm order execution
         if(tradeResult.retcode == 10008 || tradeResult.retcode == 10009)
           {
            PrintFormat("Successfully set the Trailing SL for #%I64d %s %s", positionTicket, positionSymbol, EnumToString(positionType));
            PrintFormat("retcode=%u  runtime_code=%u", tradeResult.retcode, GetLastError());
            Print("_______________________________________________________________________________________\r\n\r\n");
            return(true); //-- exit function
            break; //--- success - order placed ok. exit for loop
           }
        }
      else  //-- Order request failed
        {
         //-- order not sent or critical error found
         if(!ErrorAdvisor(__FUNCTION__, positionSymbol, tradeResult.retcode) || IsStopped())
           {
            PrintFormat("ERROR setting the Trailing SL for #%I64d %s %s", positionTicket, positionSymbol, EnumToString(positionType));
            Print("_______________________________________________________________________________________\r\n\r\n");
            return(false); //-- exit function
            break; //-- exit for loop
           }
        }
     }
   return(false);
  }

Asegúrese de que todos los segmentos de código de la función SetTrailingStopLoss() estén completos en la secuencia siguiente:

bool SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss) export
  {
//-- first check if the EA is allowed to trade and the trailing stop loss parameter is more than zero
   if(!TradingIsAllowed() || trailingStopLoss == 0)
     {
      return(false); //--- algo trading is disabled or trailing stop loss is invalid, exit function
     }

//--- Confirm and select the position using the provided positionTicket
   ResetLastError(); //--- Reset error cache incase of ticket selection errors
   if(!PositionSelectByTicket(positionTicket))
     {
      //---Position selection failed
      Print("\r\n_______________________________________________________________________________________");
      Print(__FUNCTION__, ": Selecting position with ticket:", positionTicket, " failed. ERROR: ", GetLastError());
      return(false); //-- Exit the function
     }

//-- create variable to store the calculated trailing sl prices to send to the trade server
   double slPrice = 0.0;

//--- Position ticket selected, save the position properties
   string positionSymbol = PositionGetString(POSITION_SYMBOL);
   double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN);
   double volume = PositionGetDouble(POSITION_VOLUME);
   double currentPositionSlPrice = PositionGetDouble(POSITION_SL);
   double currentPositionTpPrice = PositionGetDouble(POSITION_TP);
   ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

//-- Get some information about the positions symbol
   int symbolDigits = (int)SymbolInfoInteger(positionSymbol, SYMBOL_DIGITS); //-- Number of symbol decimal places
   int symbolStopLevel = (int)SymbolInfoInteger(positionSymbol, SYMBOL_TRADE_STOPS_LEVEL);
   double symbolPoint = SymbolInfoDouble(positionSymbol, SYMBOL_POINT);
   double positionPriceCurrent = PositionGetDouble(POSITION_PRICE_CURRENT);
   int spread = (int)SymbolInfoInteger(positionSymbol, SYMBOL_SPREAD);

//-- Check if the trailing stop loss is less than the symbol trade stop levels
   if(trailingStopLoss < symbolStopLevel)
     {
      //-- Trailing stop loss is less than the allowed level for the current symbol
      trailingStopLoss = symbolStopLevel; //-- Set it to the symbol stop level by default
     }

//-- Calculate and store the trailing stop loss price
   if(positionType == POSITION_TYPE_BUY)
     {
      slPrice = positionPriceCurrent - (trailingStopLoss * symbolPoint);

      //-- Check if the proposed slPrice for the trailing stop loss is valid
      if(slPrice < entryPrice || slPrice < currentPositionSlPrice)
        {
         return(false); //-- Exit the function, proposed trailing stop loss price is invalid
        }
     }
   else  //-- SELL POSITION
     {
      slPrice = positionPriceCurrent + (trailingStopLoss * symbolPoint);

      //-- Check if the proposed slPrice for the trailing stop loss is valid
      if(slPrice > entryPrice || slPrice > currentPositionSlPrice)
        {
         return(false); //-- Exit the function, proposed trailing stop loss price is invalid
        }
     }

//-- Print position properties before setting the trailing stop loss
   string positionProperties = "--> "  + positionSymbol + " " + EnumToString(positionType) + " Trailing Stop Loss Modification Details" +
                               " <--\r\n";
   positionProperties += "------------------------------------------------------------\r\n";
   positionProperties += "Ticket: " + (string)positionTicket + "\r\n";
   positionProperties += "Volume: " + StringFormat("%G", volume) + "\r\n";
   positionProperties += "Price Open: " + StringFormat("%G", entryPrice) + "\r\n";
   positionProperties += "Current SL: " + StringFormat("%G", currentPositionSlPrice) + "   -> New Trailing SL: " + (string)slPrice + "\r\n";
   positionProperties += "Current TP: " + StringFormat("%G", currentPositionTpPrice) + "\r\n";
   positionProperties += "Comment: " + PositionGetString(POSITION_COMMENT) + "\r\n";
   positionProperties += "Magic Number: " + (string)PositionGetInteger(POSITION_MAGIC) + "\r\n";
   positionProperties += "---";
   Print(positionProperties);

//-- reset the the tradeRequest and tradeResult values by zeroing them
   ZeroMemory(tradeRequest);
   ZeroMemory(tradeResult);

//-- initialize the parameters to set the sltp
   tradeRequest.action = TRADE_ACTION_SLTP; //-- Trade operation type for setting sl and tp
   tradeRequest.position = positionTicket;
   tradeRequest.symbol = positionSymbol;
   tradeRequest.sl = slPrice;
   tradeRequest.tp = currentPositionTpPrice;

   ResetLastError(); //--- reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function

   for(int loop = 0; loop <= 100; loop++) //-- try modifying the sl and tp 101 times untill the request is successful
     {
      //--- send order to the trade server
      if(OrderSend(tradeRequest, tradeResult))
        {
         //-- Confirm order execution
         if(tradeResult.retcode == 10008 || tradeResult.retcode == 10009)
           {
            PrintFormat("Successfully set the Trailing SL for #%I64d %s %s", positionTicket, positionSymbol, EnumToString(positionType));
            PrintFormat("retcode=%u  runtime_code=%u", tradeResult.retcode, GetLastError());
            Print("_______________________________________________________________________________________\r\n\r\n");
            return(true); //-- exit function
            break; //--- success - order placed ok. exit for loop
           }
        }
      else  //-- Order request failed
        {
         //-- order not sent or critical error found
         if(!ErrorAdvisor(__FUNCTION__, positionSymbol, tradeResult.retcode) || IsStopped())
           {
            PrintFormat("ERROR setting the Trailing SL for #%I64d %s %s", positionTicket, positionSymbol, EnumToString(positionType));
            Print("_______________________________________________________________________________________\r\n\r\n");
            return(false); //-- exit function
            break; //-- exit for loop
           }
        }
     }
   return(false);
  }



Cerrar todas las posiciones

Esta función está diseñada para ser muy flexible y se encargará de cerrar todas las posiciones abiertas en función de los parámetros especificados. Llamaremos a la función CloseAllPositions(). Buscará posiciones abiertas que coincidan con los argumentos o parámetros proporcionados de símbolo y número mágico e intentará cerrarlas todas. Si no se permite la negociación, la función dejará de ejecutarse y saldrá inmediatamente. La función recorrerá todas las posiciones abiertas, las filtrará en función de los criterios especificados y cerrará todas las posiciones coincidentes.

Cuando termine de intentar cerrar todas las posiciones, entrará en un bucle para confirmar que se han cerrado todas las posiciones objetivo, gestionar cualquier error y asegurarse de que no entramos en un bucle infinito. Cuando nuestra función cierre con éxito todas las posiciones, saldrá, devolviendo true; en caso contrario, devolverá false.

Empecemos por definir la función CloseAllPositions(). Devolverá un bool y aceptará dos parámetros con valores por defecto:

  1. string symbol: Por defecto es ALL_SYMBOLS.
  2. ulong magicNumber: Este valor por defecto es 0.

bool CloseAllPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- Functions body goes here
  }

Tenemos que comprobar si se permite el comercio. Si no se permite la negociación, salimos de la función y devolvemos false.

if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

Crea una nueva variable de tipo bool returnThis para almacenar el valor de retorno de la función y dale un valor por defecto de false.

bool returnThis = false;

Recuperar y guardar el número total de posiciones abiertas y utilizar este valor en un bucle for que nos permitirá acceder y procesar todas las posiciones abiertas. En cada iteración, guardaremos las propiedades de posición seleccionadas y utilizaremos estos datos para filtrar las posiciones en función del símbolo y el número mágico proporcionados. Si la posición no coincide con los criterios, se pasa a la posición siguiente. Si la posición coincide con los criterios, cerramos la posición utilizando la función ClosePositionByTicket().

int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);

      //-- Filter positions by symbol and magic number
      if(
         (symbol != ALL_SYMBOLS && symbol != selectedSymbol) ||
         (magicNumber != 0 && positionMagicNo != magicNumber)
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

Ahora hemos iterado sobre todas las posiciones abiertas especificadas y enviado solicitudes de terminación al servidor de operaciones para cerrarlas. Antes de concluir la función, debemos confirmar que todas las posiciones objetivo se han cerrado realmente. Para ello, utilizaremos un bucle que llame repetidamente a la función CloseAllPositions() de forma recursiva hasta que se cierren todas las posiciones que coincidan con nuestros criterios. En cada iteración, intentaremos cerrar las posiciones restantes, pausar el envío de la orden durante un breve periodo de tiempo para acelerar la ejecución y evitar saturar el servidor de operaciones e incrementar un contador de interrupciones para evitar bucles infinitos. También comprobaremos los errores críticos y otras condiciones de salida (como que el script se detenga o exceda el número máximo de bucles). Si se cumple alguna de estas condiciones, saldremos del bucle.

int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop
   while(SymbolPositionsTotal(symbol, magicNumber) > 0)
     {
      breakerBreaker++;
      CloseAllPositions(symbol, magicNumber); //-- We still have some open positions, do a function callback
      Sleep(100); //-- Micro sleep to pace the execution and give some time to the trade server

      //-- Check for critical errors so that we exit the loop if we run into trouble
      if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > 101)
        {
         break;
        }
     }

Vuelva a comprobar que se han cerrado todas las posiciones objetivo y guarde este estado en la variable de retorno antes de concluir y salir de la función.

if(SymbolPositionsTotal(symbol, magicNumber) == 0)
     {
      returnThis = true; //-- Save this status for the function return value
     }

   return(returnThis);

Confirme que todos los segmentos de código de la función CloseAllPositions() están completos en la secuencia siguiente:

bool CloseAllPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

   bool returnThis = false;

//-- Scan for symbol and magic number specific positions and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);

      //-- Filter positions by symbol and magic number
      if(
         (symbol != ALL_SYMBOLS && symbol != selectedSymbol) ||
         (magicNumber != 0 && positionMagicNo != magicNumber)
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

//-- Confirm that we have closed all the positions being targeted
   int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop
   while(SymbolPositionsTotal(symbol, magicNumber) > 0)
     {
      breakerBreaker++;
      CloseAllPositions(symbol, magicNumber); //-- We still have some open positions, do a function callback
      Sleep(100); //-- Micro sleep to pace the execution and give some time to the trade server

      //-- Check for critical errors so that we exit the loop if we run into trouble
      if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > 101)
        {
         break;
        }
     }

//-- Final confirmations that all targeted positions have been closed
   if(SymbolPositionsTotal(symbol, magicNumber) == 0)
     {
      returnThis = true; //-- Save this status for the function return value
     }

   return(returnThis);
  }


Cerrar todas las posiciones y función de sobrecarga

Por comodidad, sobrecargaremos la función CloseAllPositions() con una segunda versión que no acepta parámetros y cierra todas las posiciones abiertas en la cuenta cuando se llama. Esta función también podrá exportarse y utilizarse en la biblioteca EX5 'Positions Manager'.

//+------------------------------------------------------------------+
//| CloseAllPositions(): Closes all positions in the account         |
//+------------------------------------------------------------------+
bool CloseAllPositions() export
  {
   return(CloseAllPositions(ALL_SYMBOLS, 0));
  }


Clasificación y filtrado de funciones de cierre de posiciones

Si navega por los foros de desarrolladores de MQL5, a menudo encontrará preguntas de desarrolladores principiantes de MQL5 que buscan ayuda con la codificación de algoritmos para filtrar, ordenar y gestionar diversas operaciones de posición, como el cierre o la modificación de posiciones específicas en función de criterios como el número mágico, el estado de ganancias o pérdidas, etc. La siguiente biblioteca de funciones pretende dar respuesta a esta necesidad, facilitando y agilizando la aplicación eficaz de estas operaciones.

Las funciones de ordenación y filtrado de cierre de posiciones que aparecen a continuación implementan un enfoque similar al de la función CloseAllPositions(), pero presentan diferencias notables propias de cada una. Utilizan una estrategia de programación recursiva para garantizar que se cierran todas las posiciones especificadas e incluyen registros de seguimiento para imprimir y registrar cualquier error encontrado en el registro de Asesores Expertos para el diagnóstico del usuario final. Una ventaja añadida de estas funciones es su elevada tasa de éxito en el cumplimiento de los objetivos especificados, ya que buscan recursivamente errores recuperables y envían las solicitudes de operaciones especificadas varias veces para garantizar que las órdenes tengan éxito. Para una comprensión más profunda de cómo funciona cada función, he incluido comentarios de código detallados para explicar la estructura y organización de cada componente de código dentro de las funciones.


Cerrar todas las posiciones de compra

La función CloseAllBuyPositions() se encarga de cerrar todas las posiciones de compra abiertas que coincidan con los parámetros o argumentos de la función proporcionados de nombre de símbolo y número mágico. Devuelve un bool, indicando true si cierra con éxito todas las posiciones especificadas y false en caso contrario.

bool CloseAllBuyPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

   bool returnThis = false;

//-- Scan for symbol and magic number specific buy positions and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      ulong positionType = PositionGetInteger(POSITION_TYPE);

      //-- Filter positions by symbol, type and magic number
      if(
         (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (positionType != POSITION_TYPE_BUY) ||
         (magicNumber != 0 && positionMagicNo != magicNumber)
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

//-- Confirm that we have closed all the buy positions being targeted
   int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop
   while(SymbolBuyPositionsTotal(symbol, magicNumber) > 0)
     {
      breakerBreaker++;
      CloseAllBuyPositions(symbol, magicNumber); //-- We still have some open buy positions, do a function callback
      Sleep(100); //-- Micro sleep to pace the execution and give some time to the trade server

      //-- Check for critical errors so that we exit the loop if we run into trouble
      if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > 101)
        {
         break;
        }
     }

   if(SymbolBuyPositionsTotal(symbol, magicNumber) == 0)
     {
      returnThis = true;
     }
   return(returnThis);
  }

Cerrar todas las posiciones de venta

La función CloseAllSellPositions() se encarga de cerrar todas las posiciones de venta abiertas que coincidan con los parámetros o argumentos de la función proporcionados de nombre de símbolo y número mágico. Devuelve un bool, indicando true si cierra con éxito todas las posiciones especificadas y false en caso contrario.

bool CloseAllSellPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

   bool returnThis = false;

//-- Scan for symbol and magic number specific sell positions and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      ulong positionType = PositionGetInteger(POSITION_TYPE);

      //-- Filter positions by symbol, type and magic number
      if(
         (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (positionType != POSITION_TYPE_SELL) ||
         (magicNumber != 0 && positionMagicNo != magicNumber)
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

//-- Confirm that we have closed all the sell positions being targeted
   int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop
   while(SymbolSellPositionsTotal(symbol, magicNumber) > 0)
     {
      breakerBreaker++;
      CloseAllSellPositions(symbol, magicNumber); //-- We still have some open sell positions, do a function callback
      Sleep(100); //-- Micro sleep to pace the execution and give some time to the trade server

      //-- Check for critical errors so that we exit the loop if we run into trouble
      if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > 101)
        {
         break;
        }
     }

   if(SymbolSellPositionsTotal(symbol, magicNumber) == 0)
     {
      returnThis = true;
     }
   return(returnThis);
  }



Cerrar todas las posiciones "mágicas"

La función CloseAllMagicPositions() se encarga de cerrar todas las posiciones abiertas que coincidan con el parámetro o argumento de función de número mágico proporcionado. Devuelve un bool, indicando true si cierra con éxito todas las posiciones especificadas y false en caso contrario.

bool CloseAllMagicPositions(ulong magicNumber) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

   bool returnThis = false;

//-- Variables to store the selected positions data
   ulong positionTicket, positionMagicNo;
   string positionSymbol;

//-- Scan for magic number specific positions and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      positionSymbol = PositionGetString(POSITION_SYMBOL);

      //-- Filter positions by magic number
      if(magicNumber == positionMagicNo)
        {
         //-- Close the position
         ClosePositionByTicket(positionTicket);
        }
     }

//-- Confirm that we have closed all the positions being targeted
   int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop
   while(MagicPositionsTotal(magicNumber) > 0)
     {
      breakerBreaker++;
      CloseAllMagicPositions(magicNumber); //-- We still have some open positions, do a function callback
      Sleep(100); //-- Micro sleep to pace the execution and give some time to the trade server

      //-- Check for critical errors so that we exit the loop if we run into trouble
      if(!ErrorAdvisor(__FUNCTION__, positionSymbol, GetLastError()) || IsStopped() || breakerBreaker > 101)
        {
         break;
        }
     }

   if(MagicPositionsTotal(magicNumber) == 0)
     {
      returnThis = true;
     }
   return(returnThis);
  }



Cerrar todas las posiciones rentables

La función CloseAllProfitablePositions() cierra todas las posiciones abiertas rentables que coincidan con los parámetros o argumentos de la función de nombre de símbolo y número mágico proporcionados. Devuelve un bool, indicando true si cierra con éxito todas las posiciones especificadas y false en caso contrario.

bool CloseAllProfitablePositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

//-- Scan for profitable positions that match the specified symbol and magic number to close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      double positionProfit = PositionGetDouble(POSITION_PROFIT);

      //-- Filter positions by symbol, magic number and profit
      if(
         ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) ||
         positionProfit <= 0
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }
   return(true);
  }

___


Cerrar todas las posiciones de compra rentables

La función CloseAllProfitableBuyPositions() cierra todas las posiciones de compra abiertas rentables que coincidan con los parámetros o argumentos de la función proporcionados de nombre de símbolo y número mágico. Devuelve un bool, indicando true si cierra con éxito todas las posiciones especificadas y false en caso contrario.

bool CloseAllProfitableBuyPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

//-- Scan for profitable positions that match the specified symbol and magic number to close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      double positionProfit = PositionGetDouble(POSITION_PROFIT);

      //-- Filter positions by symbol, magic number, profit and type
      if(
         ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) ||
         positionProfit <= 0 || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }
   return(true);
  }


Cerrar todas las posiciones de venta rentables

La función CloseAllProfitableSellPositions() cierra todas las posiciones de venta abiertas rentables que coincidan con los parámetros o argumentos de la función proporcionados de nombre de símbolo y número mágico. Devuelve un bool, indicando true si cierra con éxito todas las posiciones especificadas y false en caso contrario.

bool CloseAllProfitableSellPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

//-- Scan for profitable positions that match the specified symbol and magic number to close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      double positionProfit = PositionGetDouble(POSITION_PROFIT);

      //-- Filter positions by symbol, magic number, profit and type
      if(
         ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) ||
         positionProfit <= 0 || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_SELL
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }
   return(true);
  }


Cerrar todas las posiciones con pérdidas

La función CloseAllLossPositions() cierra todas las posiciones abiertas perdedoras que coincidan con los parámetros o argumentos de la función de nombre de símbolo y número mágico proporcionados. Devuelve un bool, indicando true si cierra con éxito todas las posiciones especificadas y false si no lo hace.

bool CloseAllLossPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

//-- Scan for loss positions that match the specified symbol and magic number and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      double positionProfit = PositionGetDouble(POSITION_PROFIT);

      //-- Filter positions by symbol, magic number and profit
      if(
         ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) ||
         positionProfit > 0
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

   return(true);
  }


Cerrar todas las posiciones de compra con pérdidas

La función CloseAllLossBuyPositions() cierra todas las posiciones de compra abiertas perdedoras que coincidan con los parámetros o argumentos de la función proporcionados de nombre de símbolo y número mágico. Devuelve un bool, indicando true si cierra con éxito todas las posiciones especificadas y false si no lo hace.

bool CloseAllLossBuyPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

//-- Scan for loss positions that match the specified symbol and magic number and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      double positionProfit = PositionGetDouble(POSITION_PROFIT);

      //-- Filter positions by symbol, magic number, profit and type
      if(
         ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) ||
         positionProfit > 0 || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

   return(true);
  }


Cerrar todas las posiciones de venta con pérdidas

La función CloseAllLossSellPositions() cierra todas las posiciones de venta abiertas perdedoras que coincidan con los parámetros o argumentos de la función proporcionados de nombre de símbolo y número mágico. Devuelve un bool, indicando true si cierra con éxito todas las posiciones especificadas y false si no lo hace.

bool CloseAllLossSellPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

//-- Scan for loss positions that match the specified symbol and magic number and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      double positionProfit = PositionGetDouble(POSITION_PROFIT);

      //-- Filter positions by symbol, magic number, profit and type
      if(
         ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) ||
         positionProfit > 0 || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_SELL
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

   return(true);
  }  



Funciones de estado de la posición

Al desarrollar un sistema de negociación, es importante realizar un seguimiento del estado de la cuenta utilizando datos en tiempo real sobre las distintas posiciones. Tanto si está desarrollando una estrategia basada en cuadrículas como una estrategia conservadora de acción de precios, tener una visión clara y directa de todas las posiciones abiertas es fundamental para el éxito de su sistema de negociación. Sin embargo, no existen funciones estándar del lenguaje que proporcionen esta información. Esta biblioteca EX5 pretende simplificar la recopilación de información de posición con llamadas a funciones de una sola línea. Las funciones exportables que se indican a continuación le proporcionarán la ventaja que necesita para supervisar las posiciones y decidir si cerrarlas o ampliarlas, constituyendo uno de los pilares fundamentales de su sistema de negociación.


Obtener datos de posiciones

La función GetPositionsData() desempeña un papel crucial en la recopilación y almacenamiento de toda la información necesaria sobre el estado de las posiciones. Guarda estos datos en variables globales que son fácilmente accesibles dentro de toda la biblioteca. Estas variables se actualizan continuamente con cada tick, lo que garantiza su precisión y fiabilidad.

Coloque las siguientes declaraciones de variables globales en la parte superior de nuestra biblioteca debajo de las declaraciones de variables globales de las estructuras de datos de solicitud y resultado de las operaciones comerciales.

string accountCurrency = AccountInfoString(ACCOUNT_CURRENCY);

//-- Position status global variables
//-------------------------------------------------------------------------------------------------------------------
int accountBuyPositionsTotal = 0, accountSellPositionsTotal = 0,
    symbolPositionsTotal = 0, symbolBuyPositionsTotal = 0, symbolSellPositionsTotal = 0,
    magicPositionsTotal = 0, magicBuyPositionsTotal = 0, magicSellPositionsTotal = 0;
double accountPositionsVolumeTotal = 0.0, accountBuyPositionsVolumeTotal = 0.0, accountSellPositionsVolumeTotal = 0.0,
       accountBuyPositionsProfit = 0.0, accountSellPositionsProfit = 0.0,
       symbolPositionsVolumeTotal = 0.0, symbolBuyPositionsVolumeTotal = 0.0,
       symbolSellPositionsVolumeTotal = 0.0, symbolPositionsProfit = 0.0,
       symbolBuyPositionsProfit = 0.0, symbolSellPositionsProfit = 0.0,
       magicPositionsVolumeTotal = 0.0, magicBuyPositionsVolumeTotal = 0.0,
       magicSellPositionsVolumeTotal = 0.0, magicPositionsProfit = 0.0,
       magicBuyPositionsProfit = 0.0, magicSellPositionsProfit = 0.0;

Actualice y guarde los datos de estado de posición en la función GetPositionsData() a continuación.

void GetPositionsData(string symbol, ulong magicNumber)
  {
//-- Reset the acount open positions status
   accountBuyPositionsTotal = 0;
   accountSellPositionsTotal = 0;
   accountPositionsVolumeTotal = 0.0;
   accountBuyPositionsVolumeTotal = 0.0;
   accountSellPositionsVolumeTotal = 0.0;
   accountBuyPositionsProfit = 0.0;
   accountSellPositionsProfit = 0.0;

//-- Reset the EA's magic open positions status
   magicPositionsTotal = 0;
   magicBuyPositionsTotal = 0;
   magicSellPositionsTotal = 0;
   magicPositionsVolumeTotal = 0.0;
   magicBuyPositionsVolumeTotal = 0.0;
   magicSellPositionsVolumeTotal = 0.0;
   magicPositionsProfit = 0.0;
   magicBuyPositionsProfit = 0.0;
   magicSellPositionsProfit = 0.0;

//-- Reset the symbol open positions status
   symbolPositionsTotal = 0;
   symbolBuyPositionsTotal = 0;
   symbolSellPositionsTotal = 0;
   symbolPositionsVolumeTotal = 0.0;
   symbolBuyPositionsVolumeTotal = 0.0;
   symbolSellPositionsVolumeTotal = 0.0;
   symbolPositionsProfit = 0.0;
   symbolBuyPositionsProfit = 0.0;
   symbolSellPositionsProfit = 0.0;

//-- Update and save the open positions status with realtime data
   int totalOpenPositions = PositionsTotal();
   if(totalOpenPositions > 0)
     {
      //-- Scan for symbol and magic number specific positions and save their status
      for(int x = 0; x < totalOpenPositions; x++)
        {
         //--- Get position properties
         ulong  positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
         string selectedSymbol = PositionGetString(POSITION_SYMBOL);
         ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);

         //-- Filter positions by magic number
         if(magicNumber != 0 && positionMagicNo != magicNumber)
           {
            continue;
           }

         //-- Save the account positions status first
         accountPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);

         if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
           {
            //-- Account properties
            ++accountBuyPositionsTotal;
            accountBuyPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
            accountBuyPositionsProfit += PositionGetDouble(POSITION_PROFIT);
           }
         else //-- POSITION_TYPE_SELL
           {
            //-- Account properties
            ++accountSellPositionsTotal;
            accountSellPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
            accountSellPositionsProfit += PositionGetDouble(POSITION_PROFIT);
           }

         //-- Filter positions openend by EA and save their status
         if(
            PositionGetInteger(POSITION_REASON) == POSITION_REASON_EXPERT &&
            positionMagicNo == magicNumber
         )
           {
            ++magicPositionsTotal;
            magicPositionsProfit += PositionGetDouble(POSITION_PROFIT);
            magicPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
            if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
              {
               //-- Magic properties
               ++magicBuyPositionsTotal;
               magicBuyPositionsProfit += PositionGetDouble(POSITION_PROFIT);
               magicBuyPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
              }
            else //-- POSITION_TYPE_SELL
              {
               //-- Magic properties
               ++magicSellPositionsTotal;
               magicSellPositionsProfit += PositionGetDouble(POSITION_PROFIT);
               magicSellPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
              }
           }

         //-- Filter positions by symbol
         if(symbol == ALL_SYMBOLS || selectedSymbol == symbol)
           {
            ++symbolPositionsTotal;
            symbolPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
            symbolPositionsProfit += PositionGetDouble(POSITION_PROFIT);
            if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
              {
               ++symbolBuyPositionsTotal;
               symbolBuyPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
               symbolBuyPositionsProfit += PositionGetDouble(POSITION_PROFIT);
              }
            else //-- POSITION_TYPE_SELL
              {
               ++symbolSellPositionsTotal;
               symbolSellPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
               symbolSellPositionsProfit += PositionGetDouble(POSITION_PROFIT);
              }
           }
        }
     }
  }

Para acceder a las diferentes propiedades de estado de posición que hemos capturado y guardado en las variables globales anteriores, necesitamos crear funciones exportables simples que puedan ser accesibles externamente desde una base de código externa. Para ello, codificaremos las funciones que se indican a continuación.


Posiciones de compra totales

Devuelve un valor entero del número total de todas las posiciones de compra abiertas en la cuenta.

int BuyPositionsTotal() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountBuyPositionsTotal);
  }

Posiciones de venta totales

Devuelve un valor entero del número total de todas las posiciones de venta abiertas en la cuenta.

int SellPositionsTotal() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountSellPositionsTotal);
  }


Volumen total de posiciones

Devuelve un valor doble del volumen/lote/cantidad total de todas las posiciones abiertas en la cuenta.

double PositionsTotalVolume() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountPositionsVolumeTotal);
  }


Volumen total de posiciones de compra

Devuelve un valor doble del volumen/lote/cantidad total de todas las posiciones de compra abiertas en la cuenta.

double BuyPositionsTotalVolume() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountBuyPositionsVolumeTotal);
  }


Volumen total de posiciones de venta

Devuelve un valor doble del volumen/lote/cantidad total de todas las posiciones de venta abiertas en la cuenta.

double SellPositionsTotalVolume() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountSellPositionsVolumeTotal);
  }


Posiciones de compra con ganancias

Devuelve un valor doble del beneficio total de todas las posiciones de compra abiertas en la cuenta.

double BuyPositionsProfit() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountBuyPositionsProfit);
  }


Posiciones de venta con ganancias

Devuelve un valor doble del beneficio total de todas las posiciones de venta abiertas en la cuenta.

double SellPositionsProfit() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountSellPositionsProfit);
  }


Total de posiciones "mágicas"

Devuelve un valor entero del número total de todas las posiciones abiertas para el número mágico especificado en la cuenta.

int MagicPositionsTotal(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicPositionsTotal);
  }


Total de posiciones de compra "mágicas"

Devuelve un valor entero del número total de todas las posiciones de compra abiertas para el número mágico especificado en la cuenta.

int MagicBuyPositionsTotal(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicBuyPositionsTotal);
  }


Posiciones de venta "mágicas" totales

Devuelve un valor entero del número total de todas las posiciones de venta abiertas para el número mágico especificado en la cuenta.

int MagicSellPositionsTotal(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicSellPositionsTotal);
  }


Volumen total de posiciones "mágicas"

Devuelve un valor doble del volumen/lote/cantidad total de todas las posiciones abiertas para el número mágico especificado en la cuenta.

double MagicPositionsTotalVolume(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicPositionsVolumeTotal);
  }


Volumen total de posiciones de compra "mágicas"

Devuelve un valor doble del volumen/lote/cantidad total de todas las posiciones de compra abiertas para el número mágico especificado en la cuenta.

double MagicBuyPositionsTotalVolume(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicBuyPositionsVolumeTotal);
  }


Volumen total de posiciones de venta "mágicas"

Devuelve un valor doble del volumen/lote/cantidad total de todas las posiciones de venta abiertas para el número mágico especificado en la cuenta.

double MagicSellPositionsTotalVolume(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicSellPositionsVolumeTotal);
  }


Posiciones "mágicas" de ganancias

Devuelve un valor doble de la ganancia total de todas las posiciones abiertas para el número mágico especificado en la cuenta.

double MagicPositionsProfit(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicPositionsProfit);
  }


Posiciones de compra "mágicas" con ganancias

Devuelve un valor doble de la ganancia total de todas las posiciones de compra abiertas para el número mágico especificado en la cuenta.

double MagicBuyPositionsProfit(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicBuyPositionsProfit);
  }


Posiciones de venta "mágicas" con beneficios

Devuelve un valor doble de la ganancia total de todas las posiciones de venta abiertas para el número mágico especificado en la cuenta.

double MagicSellPositionsProfit(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicSellPositionsProfit);
  }


Posiciones totales del símbolo

Devuelve un valor entero del número total de todas las posiciones abiertas para un símbolo específico en la cuenta.

int SymbolPositionsTotal(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(symbolPositionsTotal);
  }


Posiciones totales de compra del símbolo

Devuelve un valor entero del número total de todas las posiciones de compra abiertas para un símbolo específico en la cuenta.

int SymbolBuyPositionsTotal(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(symbolBuyPositionsTotal);
  }


Posiciones totales de venta del símbolo

Devuelve un valor entero del número total de todas las posiciones de venta abiertas para un símbolo específico en la cuenta.

int SymbolSellPositionsTotal(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(symbolSellPositionsTotal);
  }


Volumen total de las posiciones del símbolo

Devuelve un valor doble del volumen/lote/cantidad total de todas las posiciones abiertas para un símbolo especificado en la cuenta.

double SymbolPositionsTotalVolume(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(symbolPositionsVolumeTotal);
  }


Volumen total de las posiciones de compra del símbolo

Devuelve un valor doble del volumen/lote/cantidad total de todas las posiciones de compra abiertas para un símbolo específico en la cuenta.

double SymbolBuyPositionsTotalVolume(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(symbolBuyPositionsVolumeTotal);
  }


Volumen total de las posiciones de venta del símbolo

Devuelve un valor doble del volumen/lote/cantidad total de todas las posiciones de venta abiertas para un símbolo especificado en la cuenta.

double SymbolSellPositionsTotalVolume(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(symbolSellPositionsVolumeTotal);
  }


Beneficio de las posiciones del símbolo

Devuelve un valor doble del beneficio total de todas las posiciones abiertas para un símbolo especificado en la cuenta.

double SymbolPositionsProfit(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(NormalizeDouble(symbolPositionsProfit, 2));
  }


Beneficio total de posiciones de compra del símbolo

Devuelve un valor doble del beneficio total de todas las posiciones de compra abiertas para un símbolo especificado en la cuenta.

double SymbolBuyPositionsProfit(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(NormalizeDouble(symbolBuyPositionsProfit, 2));
  }


Beneficio total de posiciones de venta del símbolo

Devuelve un valor doble de la ganancia total de todas las posiciones de venta abiertas para un símbolo específico en la cuenta.

double SymbolSellPositionsProfit(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(NormalizeDouble(symbolSellPositionsProfit, 2));
  }


Estado de las posiciones de la cuenta

Devuelve una cadena preformateada con el estado de las posiciones de la cuenta, que puede imprimirse en el registro o mostrarse en los comentarios del gráfico. La función acepta un único parámetro booleano llamado formatForComment. Si formatForComment es true, la función formatea los datos para mostrarlos en la ventana del gráfico. Si es false, los datos se formatean para su visualización en la pestaña de registros del Asesor Experto.

string AccountPositionsStatus(bool formatForComment) export
  {
   GetPositionsData(ALL_SYMBOLS, 0); //-- Update the position status variables before we display their data
   string spacer = "";
   if(formatForComment) //-- Add some formating space for the chart comment string
     {
      spacer = "                                        ";
     }
   string accountPositionsStatus = "\r\n" + spacer + "|---------------------------------------------------------------------------\r\n";
   accountPositionsStatus += spacer + "| " + (string)AccountInfoInteger(ACCOUNT_LOGIN) + " - ACCOUNT POSTIONS STATUS \r\n";
   accountPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n";
   accountPositionsStatus += spacer + "|     Total Open:   " + (string)PositionsTotal() + "\r\n";
   accountPositionsStatus += spacer + "|     Total Volume: " + (string)accountPositionsVolumeTotal + "\r\n";
   accountPositionsStatus += spacer + "|     Total Profit: " +
   (string)(NormalizeDouble(AccountInfoDouble(ACCOUNT_PROFIT), 2)) + accountCurrency + "\r\n";
   accountPositionsStatus += spacer + "|------------------------------------------------------------------\r\n";
   accountPositionsStatus += spacer + "| BUY POSITIONS: \r\n";
   accountPositionsStatus += spacer + "|     Total Open:   " + (string)accountBuyPositionsTotal + "\r\n";
   accountPositionsStatus += spacer + "|     Total Volume: " + (string)accountBuyPositionsVolumeTotal + "\r\n";
   accountPositionsStatus += spacer + "|     Total Profit: " + (string)(NormalizeDouble(accountBuyPositionsProfit, 2)) +
   accountCurrency + "\r\n";
   accountPositionsStatus += spacer + "|------------------------------------------------------------------\r\n";
   accountPositionsStatus += spacer + "| SELL POSITIONS: \r\n";
   accountPositionsStatus += spacer + "|     Total Open:   " + (string)accountSellPositionsTotal + "\r\n";
   accountPositionsStatus += spacer + "|     Total Volume: " + (string)accountSellPositionsVolumeTotal + "\r\n";
   accountPositionsStatus += spacer + "|     Total Profit: " + (string)(NormalizeDouble(accountSellPositionsProfit, 2)) +
   accountCurrency + "\r\n";
   accountPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n";
   accountPositionsStatus += spacer + "\r\n";
   return(accountPositionsStatus);
  }


Estado de las posiciones mágicas

Devuelve una cadena preformateada que contiene el estado de las posiciones mágicas de la cuenta, que puede imprimirse en el registro o mostrarse en los comentarios del gráfico. La función acepta dos argumentos o parámetros. Un long magicNumber y un booleano formatForComment. Si formatForComment es true, la función formatea los datos para mostrarlos en la ventana del gráfico. Si es false, los datos se formatean para su visualización en la pestaña de registros del Asesor Experto.

string MagicPositionsStatus(ulong magicNumber, bool formatForComment) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber); //-- Update the position status variables before we display their data
   string spacer = "";
   if(formatForComment) //-- Add some formating space for the chart comment string
     {
      spacer = "                                        ";
     }
   string magicPositionsStatus = "\r\n" + spacer + "|---------------------------------------------------------------------------\r\n";
   magicPositionsStatus += spacer + "| " + (string)magicNumber + " - MAGIC POSTIONS STATUS \r\n";
   magicPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n";
   magicPositionsStatus += spacer + "|     Total Open:   " + (string)magicPositionsTotal + "\r\n";
   magicPositionsStatus += spacer + "|     Total Volume: " + (string)magicPositionsVolumeTotal + "\r\n";
   magicPositionsStatus += spacer + "|     Total Profit: " +
   (string)(NormalizeDouble(magicPositionsProfit, 2)) + accountCurrency + "\r\n";
   magicPositionsStatus += spacer + "|------------------------------------------------------------------\r\n";
   magicPositionsStatus += spacer + "| BUY POSITIONS: \r\n";
   magicPositionsStatus += spacer + "|     Total Open:   " + (string)magicBuyPositionsTotal + "\r\n";
   magicPositionsStatus += spacer + "|     Total Volume: " + (string)magicBuyPositionsVolumeTotal + "\r\n";
   magicPositionsStatus += spacer + "|     Total Profit: " + (string)(NormalizeDouble(magicBuyPositionsProfit, 2)) +
   accountCurrency + "\r\n";
   magicPositionsStatus += spacer + "|------------------------------------------------------------------\r\n";
   magicPositionsStatus += spacer + "| SELL POSITIONS: \r\n";
   magicPositionsStatus += spacer + "|     Total Open:   " + (string)magicSellPositionsTotal + "\r\n";
   magicPositionsStatus += spacer + "|     Total Volume: " + (string)magicSellPositionsVolumeTotal + "\r\n";
   magicPositionsStatus += spacer + "|     Total Profit: " + (string)(NormalizeDouble(magicSellPositionsProfit, 2)) +
   accountCurrency + "\r\n";
   magicPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n";
   magicPositionsStatus += spacer + "\r\n";
   return(magicPositionsStatus);
  }


Estado de las posiciones del símbolo

Devuelve una cadena preformateada con el estado de las posiciones del símbolo de la cuenta, que puede imprimirse en el registro o mostrarse en los comentarios del gráfico. La función acepta tres argumentos o parámetros. Un string para el símbolo, un long sin signo para el número mágico, y un bool para formatForComment. Si el valor formatForComment booleano es true, la función formatea los datos para mostrarlos en la ventana del gráfico. Si es false, los datos se formatean para su visualización en la pestaña de registros del Asesor Experto.

string SymbolPositionsStatus(string symbol, ulong magicNumber, bool formatForComment) export
  {
   GetPositionsData(symbol, magicNumber); //-- Update the position status variables before we display their data
   string spacer = "";
   if(formatForComment) //-- Add some formating space for the chart comment string
     {
      spacer = "                                        ";
     }
   string symbolPositionsStatus = "\r\n" + spacer + "|---------------------------------------------------------------------------\r\n";
   symbolPositionsStatus += spacer + "| " + symbol + " - SYMBOL POSTIONS STATUS \r\n";
   symbolPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n";
   symbolPositionsStatus += spacer + "|     Total Open:   " + (string)symbolPositionsTotal + "\r\n";
   symbolPositionsStatus += spacer + "|     Total Volume: " + (string)symbolPositionsVolumeTotal + "\r\n";
   symbolPositionsStatus += spacer + "|     Total Profit: " +
   (string)(NormalizeDouble(symbolPositionsProfit, 2)) + accountCurrency + "\r\n";
   symbolPositionsStatus += spacer + "|------------------------------------------------------------------\r\n";
   symbolPositionsStatus += spacer + "| BUY POSITIONS: \r\n";
   symbolPositionsStatus += spacer + "|     Total Open:   " + (string)symbolBuyPositionsTotal + "\r\n";
   symbolPositionsStatus += spacer + "|     Total Volume: " + (string)symbolBuyPositionsVolumeTotal + "\r\n";
   symbolPositionsStatus += spacer + "|     Total Profit: " + (string)(NormalizeDouble(symbolBuyPositionsProfit, 2)) +
   accountCurrency + "\r\n";
   symbolPositionsStatus += spacer + "|------------------------------------------------------------------\r\n";
   symbolPositionsStatus += spacer + "| SELL POSITIONS: \r\n";
   symbolPositionsStatus += spacer + "|     Total Open:   " + (string)symbolSellPositionsTotal + "\r\n";
   symbolPositionsStatus += spacer + "|     Total Volume: " + (string)symbolSellPositionsVolumeTotal + "\r\n";
   symbolPositionsStatus += spacer + "|     Total Profit: " + (string)(NormalizeDouble(symbolSellPositionsProfit, 2)) +
   accountCurrency + "\r\n";
   symbolPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n";
   symbolPositionsStatus += spacer + "\r\n";
   return(symbolPositionsStatus);
  }



Cómo importar e implementar nuestra biblioteca EX5 de gestión de posiciones

Hemos desarrollado una completa biblioteca de gestión de posiciones EX5, que contiene todas las funciones esenciales para las operaciones de posición, la extracción de estados y los módulos de visualización. Ahora es el momento de documentar y explicar cómo importar y utilizar eficazmente esta biblioteca en cualquier proyecto MQL5.

Para agilizar el proceso de implementación, comencemos por esbozar todas las funciones o módulos dentro de la biblioteca de gestión de posiciones, junto con algunos casos de uso de ejemplos de código del mundo real. Esto proporcionará a los usuarios de la biblioteca una rápida visión general de los componentes incluidos en el archivo binario PositionsManager.ex5.

Documentación de la biblioteca EX5 para la gestión de posiciones

Descripción del prototipo de la función Descripción Ejemplo de uso
bool ErrorAdvisor(
   string callingFunc, 
   string symbol, 
   int tradeServerErrorCode
);
Gestiona el servidor de operaciones y los errores de ejecución al gestionar posiciones y órdenes. Devuelve true si el error es recuperable y se puede volver a enviar la solicitud de operación, false si el error es crítico y se debe detener el envío de la solicitud.
ResetLastError(); //-- Reset and clear the last error
//--------------------------------------------------------------
//-- Insert code to send the order request to the trade server
//--------------------------------------------------------------
string symbol = _Symbol; //Symbol being traded
int retcode = tradeResult.retcode;//Trade Request Structure (MqlTradeRequest)
if(!ErrorAdvisor(__FUNCTION__, symbol, retcode)
  {
//Critical error found
//Order can not be executed. Exit function or log this error
  }
bool TradingIsAllowed();
Verifica si el usuario, el servidor de operaciones y el corredor han dado permiso al asesor experto para ejecutar operaciones. 
if(!TradingIsAllowed())
  {
   //--- algo trading is disabled, exit function
   return(false);
  }

bool OpenBuyPosition(
   ulong magicNumber,
   string symbol,
   double lotSize,
   int sl, int tp,
   string positionComment
);
Abre una nueva posición de compra que coincide con los parámetros especificados.
ulong magicNo = 123;
string symbol = _Symbol;
double lotSize = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
int sl = 500; //-- pips
int tp = 1000; //-- pips
string comment = "Buy position";
OpenBuyPosition(magicNo, symbol, lotSize, sl, tp, comment);
bool OpenSellPosition(
   ulong magicNumber,
   string symbol,
   double lotSize,
   int sl,
   int tp,
   string positionComment
);
Abre una nueva posición de venta que coincide con los parámetros especificados.
ulong magicNo = 123;
string symbol = _Symbol;
double lotSize = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
int sl = 500; //-- pips
int tp = 1000; //-- pips
string comment = "Sell position";
OpenSellPosition(magicNo, symbol, lotSize, sl, tp, comment);
bool SetSlTpByTicket(
   ulong positionTicket,
   int sl,
   int tp
);
Establece el stop loss para una posición que coincida con la entrada especificada.
int sl = 500, int tp = 1000; //-- pips
int totalOpenPostions = PositionsTotal();
for(int x = 0; x < totalOpenPostions; x++)
{
   ulong positionTicket = PositionGetTicket(x);
   if(positionTicket > 0)
   {
      SetSlTpByTicket(positionTicket, sl, tp);
   }   
}
bool ClosePositionByTicket(
   ulong positionTicket
);
Cierra una posición que coincide con el ticket especificado.
//-- Example to close all open positions
for(int x = 0; x < totalOpenPostions; x++)
{
   ulong positionTicket = PositionGetTicket(x);
   if(positionTicket > 0)
   {
      ClosePositionByTicket(positionTicket);
   }   
}
bool SetTrailingStopLoss(
   ulong positionTicket,
   int trailingStopLoss
);
Establece un trailing stop loss para una posición que coincida con la entrada especificada. Esta función debe ejecutarse en cada tick en la función OnTick() para actualizar el trailing stop loss en tiempo real.
//-- Execute this on every tick
//-- Example to set 500 pips trailing stop loss for all positions
int trailingStopLoss = 500; //-- 500 pips trailing stop loss
for(int x = 0; x < totalOpenPostions; x++)
{
   ulong positionTicket = PositionGetTicket(x);
   if(positionTicket > 0)
   {
      SetTrailingStopLoss(positionTicket, trailingStopLoss);
   }   
}
bool CloseAllPositions(
   string symbol, 
   ulong magicNumber
);
Función versátil que cierra todas las posiciones abiertas que coincidan con los parámetros especificados.
//Close all positions
CloseAllPositions("", 0);

//Only close all positions matching a magic number value of 1
CloseAllPositions("", 1);

//Only close all current symbol positions
CloseAllPositions(_Symbol, 0);
bool CloseAllPositions();

Cierra todas las posiciones abiertas.
//Close all open positions in the account
CloseAllPositions();
 
bool CloseAllBuyPositions(
   string symbol, 
   ulong magicNumber
);
Cierra todas las posiciones de compra que coincidan con los parámetros especificados.
//Close all buy positions for the current symbol
CloseAllBuyPositions(_Symbol, 0);

//Close all buy positions matching magic number 1 for all symbols
CloseAllBuyPositions("", 1);

//Close all buy positions in the account
CloseAllBuyPositions("", 0);
 
bool CloseAllSellPositions(
   string symbol,
   ulong magicNumber
);

Cierra todas las posiciones de venta que coincidan con los parámetros especificados.  
//Close all sell positions for the current symbol
CloseAllSellPositions(_Symbol, 0);

//Close all sell positions matching magic number 1 for all symbols
CloseAllSellPositions("", 1);

//Close all sell positions in the account
CloseAllSellPositions("", 0);
 
bool CloseAllMagicPositions(
   ulong magicNumber
);
Cierra todas las posiciones que coincidan con el número mágico especificado.  
//Close all positions matching magic number 1
CloseAllMagicPositions(1);

//Close all positions in the account
CloseAllMagicPositions(0);
 
bool CloseAllProfitablePositions(
   string symbol,
   ulong magicNumber
);

Cierra todas las posiciones rentables que coincidan con los parámetros especificados.
//Close all profitable positions for the current symbol
CloseAllProfitablePositions(_Symbol, 0);

//Close all profitable positions matching magic number 1 for all symbols
CloseAllProfitablePositions("", 1);

//Close all profitable positions in the account
CloseAllProfitablePositions("", 0);
 
bool CloseAllProfitableBuyPositions(
   string symbol,
   ulong magicNumber
);
Cierra todas las posiciones de compra rentables que coincidan con los parámetros especificados.
//Close all profitable buy positions for the current symbol
CloseAllProfitableBuyPositions(_Symbol, 0);

//Close all profitable buy positions matching magic number 1 for all symbols
CloseAllProfitableBuyPositions("", 1);

//Close all profitable buy positions in the account
CloseAllProfitableBuyPositions("", 0);
 
bool CloseAllProfitableSellPositions(
   string symbol,
   ulong magicNumber
);
Cierra todas las posiciones de venta rentables que coincidan con los parámetros especificados.
//Close all profitable sell positions for the current symbol
CloseAllProfitableSellPositions(_Symbol, 0);

//Close all profitable sell positions matching magic number 1 for all symbols
CloseAllProfitableSellPositions("", 1);

//Close all profitable sell positions in the account
CloseAllProfitableSellPositions("", 0);
 
bool CloseAllLossPositions(
   string symbol,
   ulong magicNumber
);

Cierra todas las posiciones de pérdidas que coincidan con los parámetros especificados.
//Close all loss positions for the current symbol
CloseAllLossPositions(_Symbol, 0);

//Close all loss positions matching magic number 1 for all symbols
CloseAllLossPositions("", 1);

//Close all loss positions in the account
CloseAllLossPositions("", 0);
 
bool CloseAllLossBuyPositions(
   string symbol,
   ulong magicNumber
);
Cierra todas las posiciones de compra con pérdidas que coincidan con los parámetros especificados.
//Close all loss buy positions for the current symbol
CloseAllLossBuyPositions(_Symbol, 0);

//Close all loss buy positions matching magic number 1 for all symbols
CloseAllLossBuyPositions("", 1);

//Close all loss buy positions in the account
CloseAllLossBuyPositions("", 0);

 
bool CloseAllLossSellPositions(
   string symbol,
   ulong magicNumber
);

Cierra todas las posiciones de venta con pérdidas que coincidan con los parámetros especificados.
//Close all loss sell positions for the current symbol
CloseAllLossSellPositions(_Symbol, 0);

//Close all loss sell positions matching magic number 1 for all symbols
CloseAllLossSellPositions("", 1);

//Close all loss sell positions in the account
CloseAllLossSellPositions("", 0);
 
int BuyPositionsTotal();

Devuelve el número de posiciones de compra abiertas.  
//Get the total number of open buy positions in the account
BuyPositionsTotal();

 
int SellPositionsTotal();

Devuelve el número de posiciones de venta abiertas.
//Get the total number of open sell positions in the account
SellPositionsTotal();

 
double PositionsTotalVolume();

Devuelve el volumen total de todas las posiciones abiertas.
//Get the total volume of all open positions in the account
PositionsTotalVolume();

 
double BuyPositionsTotalVolume();
Devuelve el volumen total de todas las posiciones abiertas de compra.
//Get the total volume of all open buy positions in the account
BuyPositionsTotalVolume();

 
double SellPositionsTotalVolume();

Devuelve el volumen total de todas las posiciones abiertas de venta.
//Get the total volume of all open sell positions in the account
SellPositionsTotalVolume();

 
double BuyPositionsProfit();
Devuelve el beneficio total de todas las posiciones abiertas de compra.
//Get the total profit of all open buy positions in the account
BuyPositionsProfit();

 
double SellPositionsProfit();

Devuelve el beneficio total de todas las posiciones abiertas de venta.
//Get the total profit of all open sell positions in the account
SellPositionsProfit();

 
int MagicPositionsTotal(
   ulong magicNumber
);

Devuelve el número de posiciones abiertas que coinciden con el número mágico especificado.
//Get the total number of open positions matching magic number 1
MagicPositionsTotal(1);
 
int MagicBuyPositionsTotal(
   ulong magicNumber
);

Devuelve el número de posiciones de compra abiertas que coinciden con el número mágico especificado.
//Get the total number of open buy positions matching magic number 1
MagicBuyPositionsTotal(1);
 
int MagicSellPositionsTotal(
   ulong magicNumber
);

Devuelve el número de posiciones de venta abiertas que coinciden con el número mágico especificado.
//Get the total number of open sell positions matching magic number 1
MagicSellPositionsTotal(1);
 
double MagicPositionsTotalVolume(
   ulong magicNumber
);

Devuelve el volumen total de todas las posiciones abiertas que coinciden con el número mágico especificado.
//Get the total volume of open positions matching magic number 1
MagicPositionsTotalVolume(1);
 
double MagicBuyPositionsTotalVolume(
   ulong magicNumber
);

Devuelve el volumen total de todas las posiciones de compra abiertas que coinciden con el número mágico especificado.
//Get the total volume of open buy positions matching magic number 1
MagicBuyPositionsTotalVolume(1);
 
double MagicSellPositionsTotalVolume(
   ulong magicNumber
);

Devuelve el volumen total de todas las posiciones de venta abiertas que coinciden con el número mágico especificado.
 
//Get the total volume of open sell positions matching magic number 1
MagicSellPositionsTotalVolume(1);
 
double MagicPositionsProfit(
   ulong magicNumber
);

Devuelve la ganancia total de todas las posiciones abiertas que coinciden con el número mágico especificado.
//Get the total profit of open positions matching magic number 1
MagicPositionsProfit(1);
 
double MagicBuyPositionsProfit(
   ulong magicNumber
);
Devuelve la ganancia total de todas las posiciones de compra abiertas que coinciden con el número mágico especificado.
//Get the total profit of open buy positions matching magic number 1
MagicBuyPositionsProfit(1);
 
double MagicSellPositionsProfit(
   ulong magicNumber
);
Devuelve la ganancia total de todas las posiciones de venta abiertas que coinciden con el número mágico especificado.
//Get total profit of sell positions matching magic number 1
MagicSellPositionsProfit(1);

 
int SymbolPositionsTotal(
   string symbol,
   ulong magicNumber
);

Devuelve el número total de todas las posiciones abiertas que coinciden con el símbolo y el número mágico especificados.
//Get total number of positions matching symbol and magic number 1
MagicPositionsTotal(_Symbol, 1);
 
int SymbolBuyPositionsTotal(
   string symbol,
   ulong magicNumber
);
Devuelve el número total de todas las posiciones de compra abiertas que coinciden con el símbolo especificado y el número mágico.
//Get total number of buy positions matching symbol and magic number 1
SymbolBuyPositionsTotal(_Symbol, 1);

 
int SymbolSellPositionsTotal(
   string symbol,
   ulong magicNumber
);
Devuelve el número total de todas las posiciones de venta abiertas que coinciden con el símbolo y el número mágico especificados.
//Get total number of sell positions matching symbol and magic number 1
SymbolSellPositionsTotal(_Symbol, 1);

 
double SymbolPositionsTotalVolume(
   string symbol,
   ulong magicNumber
);

Devuelve el volumen total de todas las posiciones abiertas que coinciden con el símbolo y el número mágico especificados.
//Get the volume of positions matching symbol and magic number 1
SymbolPositionsTotalVolume(_Symbol, 1);

 
double SymbolBuyPositionsTotalVolume(
   string symbol,
   ulong magicNumber
);

Devuelve el volumen total de todas las posiciones de compra abiertas que coinciden con el símbolo y el número mágico especificados.
//Get the volume of buy positions matching symbol and magic number 1
SymbolBuyPositionsTotalVolume(_Symbol, 1);
 
double SymbolSellPositionsTotalVolume(
   string symbol,
   ulong magicNumber
);

Devuelve el volumen total de todas las posiciones de venta abiertas que coinciden con el símbolo y el número mágico especificados.
//Get the volume of sell positions matching symbol and magic number 1
SymbolSellPositionsTotalVolume(_Symbol, 1);
 
double SymbolPositionsProfit(
   string symbol,
   ulong magicNumber
);

Devuelve la ganancia total de todas las posiciones abiertas que coinciden con el símbolo especificado y el número mágico.
//Get the profit of all positions matching symbol and magic number 1
SymbolPositionsProfit(_Symbol, 1);
 
double SymbolBuyPositionsProfit(
   string symbol,
   ulong magicNumber
);
Devuelve la ganancia total de todas las posiciones de compra abiertas que coinciden con el símbolo especificado y el número mágico.
//Get the profit of all buy positions matching symbol and magic number 1
SymbolBuyPositionsProfit(_Symbol, 1);

 
double SymbolSellPositionsProfit(
   string symbol,
   ulong magicNumber
);
Devuelve la ganancia total de todas las posiciones de venta abiertas que coinciden con el símbolo y el número mágico especificados.
//Get the profit of all sell positions matching symbol and magic number 1
SymbolSellPositionsProfit(_Symbol, 1);
 
string AccountPositionsStatus(
   bool formatForComment
);
Imprime un estado con formato de cadena de todas las posiciones abiertas en el gráfico de símbolos o en la pestaña Expertos en MetaTrader 5.  
//Print the status of all open positions formatted for the chart comments
AccountPositionsStatus(true);

//Print the status of all open positions formatted for the Experts tab
AccountPositionsStatus(false);
 
string MagicPositionsStatus(
   ulong magicNumber,
   bool formatForComment
);

Imprime un estado con formato de cadena de todas las posiciones abiertas que coinciden con el número mágico especificado en el gráfico de símbolos o en la pestaña Expertos en MetaTrader 5.
//Print the status of all open positions matching
//the magic number 1 formatted for the chart comments
MagicPositionsStatus(1, true);

//Print the status of all open positions matching
//the magic number 1 formatted for the Experts tab
MagicPositionsStatus(1, false);
 
string SymbolPositionsStatus(
   string symbol,
   ulong magicNumber,
   bool formatForComment
);
Imprime un estado con formato de cadena de todas las posiciones abiertas que coinciden con el símbolo especificado y el número mágico en el gráfico de símbolos o en la pestaña Expertos en MetaTrader 5.
//Print the status of all open positions matching
//the symbol and magic number 1 formatted for the chart comments
SymbolPositionsStatus(_Symbol, 1, true);

//Print the status of all open positions matching
//the symbol and magic number 1 formatted for the Experts tab
SymbolPositionsStatus(_Symbol, 1, false);

Integrar la biblioteca en sus proyectos MQL5 es sencillo. Siga estos dos pasos para importarPositionsManager.ex5 en su código MQL5:

  • Paso 1: Copie el archivo ejecutable de la biblioteca (PositionsManager.ex5)

Coloque el archivo PositionsManager.ex5 en la carpeta MQL5/Libraries/Toolkit. Asegúrese de haber descargado y copiado este archivo en la ubicación especificada si aún no está presente. Una copia de PositionsManager.ex5 se adjunta al final de este artículo para su conveniencia.

  • Paso 2: Importar las descripciones de los prototipos de funciones

Añade las directivas de importación de la librería Positions Manager, y sus descripciones de prototipos de funciones en la sección de cabecera de tu fichero de código fuente. Utilice el siguiente segmento de código para importar eficientemente todas las funciones o módulos de la biblioteca PositionsManager.ex5. También he creado una plantilla en blanco de un Asesor Experto (PositionsManager_Imports_Template.mq5) que incluye el segmento de código a continuación. Puede comentar o eliminar las descripciones de funciones que no necesite para su proyecto. El archivo PositionsManager_Imports_Template.mq5 también se adjunta al final de este artículo.

//+-------------------------------------------------------------------------------------+
//| PositionsManager.ex5 imports template                                               |
//+-------------------------------------------------------------------------------------+
#import "Toolkit/PositionsManager.ex5" //-- Opening import directive
//-- Function descriptions for the imported function prototypes

//-- Error Handling and Permission Status Functions
bool   ErrorAdvisor(string callingFunc, string symbol, int tradeServerErrorCode);
bool   TradingIsAllowed();

//-- Position Execution and Modification Functions
bool   OpenBuyPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment);
bool   OpenSellPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment);
bool   SetSlTpByTicket(ulong positionTicket, int sl, int tp);
bool   ClosePositionByTicket(ulong positionTicket);
bool   SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss);
bool   CloseAllPositions(string symbol, ulong magicNumber);
bool   CloseAllPositions();
bool   CloseAllBuyPositions(string symbol, ulong magicNumber);
bool   CloseAllSellPositions(string symbol, ulong magicNumber);
bool   CloseAllMagicPositions(ulong magicNumber);
bool   CloseAllProfitablePositions(string symbol, ulong magicNumber);
bool   CloseAllProfitableBuyPositions(string symbol, ulong magicNumber);
bool   CloseAllProfitableSellPositions(string symbol, ulong magicNumber);
bool   CloseAllLossPositions(string symbol, ulong magicNumber);
bool   CloseAllLossBuyPositions(string symbol, ulong magicNumber);
bool   CloseAllLossSellPositions(string symbol, ulong magicNumber);

//-- Position Status Monitoring Functions
int    BuyPositionsTotal();
int    SellPositionsTotal();
double PositionsTotalVolume();
double BuyPositionsTotalVolume();
double SellPositionsTotalVolume();
double BuyPositionsProfit();
double SellPositionsProfit();

//-- Positions Filtered By Magic Number Status Monitoring Functions
int    MagicPositionsTotal(ulong magicNumber);
int    MagicBuyPositionsTotal(ulong magicNumber);
int    MagicSellPositionsTotal(ulong magicNumber);
double MagicPositionsTotalVolume(ulong magicNumber);
double MagicBuyPositionsTotalVolume(ulong magicNumber);
double MagicSellPositionsTotalVolume(ulong magicNumber);
double MagicPositionsProfit(ulong magicNumber);
double MagicBuyPositionsProfit(ulong magicNumber);
double MagicSellPositionsProfit(ulong magicNumber);

//-- Positions Filtered By Symbol and/or Magic Number Status Monitoring Functions
int    SymbolPositionsTotal(string symbol, ulong magicNumber);
int    SymbolBuyPositionsTotal(string symbol, ulong magicNumber);
int    SymbolSellPositionsTotal(string symbol, ulong magicNumber);
double SymbolPositionsTotalVolume(string symbol, ulong magicNumber);
double SymbolBuyPositionsTotalVolume(string symbol, ulong magicNumber);
double SymbolSellPositionsTotalVolume(string symbol, ulong magicNumber);
double SymbolPositionsProfit(string symbol, ulong magicNumber);
double SymbolBuyPositionsProfit(string symbol, ulong magicNumber);
double SymbolSellPositionsProfit(string symbol, ulong magicNumber);

//-- Log and Data Display Functions
string AccountPositionsStatus(bool formatForComment);
string MagicPositionsStatus(ulong magicNumber, bool formatForComment);
string SymbolPositionsStatus(string symbol, ulong magicNumber, bool formatForComment);

#import //--- Closing import directive

Con la biblioteca importada, ahora puede abrir, cerrar, modificar o recuperar datos de estado de posición sin esfuerzo mediante sencillas llamadas a funciones. Para ilustrar esto, vamos a crear tres Asesores Expertos básicos en las siguientes secciones.


Desarrollo de un asesor experto dual VIDyA con trailing stop potenciado por la biblioteca EX5 'Positions Manager'

En esta sección, desarrollaremos un asesor experto con trailing stop basado en el indicador técnico de Promedio Dinámico de Índice Variable (Variable Index Dynamic Average, VIDyA) como un ejemplo práctico de implementación de la librería Positions Manager en una aplicación de trading en el mundo real.

La estrategia VIDyA con trailing stop utilizará un par de Indicadores Técnicos de Media Dinámica de Índice Variable para generar señales de compra y venta. Dado que el indicador VIDyA se muestra como una línea en el gráfico, utilizaremos una estrategia de cruce de líneas para señalar la entrada de una nueva operación. Para una estrategia de cruce, los pares de indicadores deben tener configuraciones diferentes. El primer indicador VIDyA, con valores de entrada más bajos, se denominará «fast VIDyA», ya que reaccionará y generará señales más rápidamente. El segundo, con valores de entrada más altos, se llamará «slow VIDyA», ya que responde a las variaciones de precios más lentamente. Para una entrada de compra, la línea «fast VIDyA» debe estar por encima de la línea «slow VIDyA», y para una entrada de venta, la línea «fast VIDyA» debe estar por debajo de la línea «slow VIDyA».

Estrategia dual VIDyA


Cree un nuevo Asesor Experto utilizando MetaEditor IDE y cree un nuevo archivo en MQL Wizard y llámelo «DualVidyaTrader.mq5». Dado que nuestro Asesor Experto utilizará la biblioteca PositionsManager.ex5, el primer paso es importar e insertar las descripciones de los prototipos de las funciones de la biblioteca como se ha descrito anteriormente. Coloque el segmento de código de importación de la biblioteca debajo de las directivas #property. Dado que la biblioteca contiene muchas funciones, no las importaremos ni utilizaremos todas; sólo importaremos los prototipos de función que se indican en el código siguiente.

//--- Import the PositionsManager EX5 Library
#import "Toolkit/PositionsManager.ex5" //-- Open the ex5 import directive
//-- Prototype function descriptions of the EX5 PositionsManager library
bool   OpenBuyPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment);
bool   OpenSellPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment);
bool   SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss);
int    MagicPositionsTotal(ulong magicNumber);
int    MagicBuyPositionsTotal(ulong magicNumber);
int    MagicSellPositionsTotal(ulong magicNumber);
bool   CloseAllProfitableBuyPositions(string symbol, ulong magicNumber);
bool   CloseAllProfitableSellPositions(string symbol, ulong magicNumber);
string MagicPositionsStatus(ulong magicNumber, bool formatForComment);
#import //-- Close the ex5 import directive

Después del segmento de código de importación de la biblioteca PositionsManager.ex5, inserte las variables globales de entrada de usuario como se muestra.

input group ""
input ulong magicNo = 1234;
input ENUM_TIMEFRAMES timeframe = PERIOD_H1;
input ENUM_APPLIED_PRICE  appliedPrice = PRICE_CLOSE; // Applied VIDyA Price

//-- Fast Vidya user inputs
input group "-- FAST VIDyA INPUTS"
input int fast_cmoPeriod = 5; // Fast Chande Momentum Period
input int fast_maPeriod = 10; // Fast MA Smoothing Period
input int fast_emaShift = 0; // Fast Horizontal Shift

//-- Slow Vidya user inputs
input group "-- SLOW VIDyA INPUTS"
input int slow_cmoPeriod = 9; //  Slow Chande Momentum Period
input int slow_maPeriod = 12; // Slow MA Smoothing Period
input int slow_emaShift = 0; // Slow Horizontal Shift

input group "-- PROFIT MANAGEMENT"
input bool liquidateProfitOnCrossover = false; // Liquidate Profit On VIDyA Signal
input bool enableTrailingStops = true; // Use Trailing Stop Losses

Creemos más variables globales para almacenar los valores de stop loss, take profit, trailing stop loss y lote o volumen.

//-- Get and save the SL, trailingSL and TP values from the spread
int spreadMultiForSl = 1000;
int spreadMultiForTrailingSl = 300;
int spreadMultiForTp = 1000;
int sl = int(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)) * spreadMultiForSl;
int trailingSl = int(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)) * spreadMultiForTrailingSl;
int tp = int(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)) * spreadMultiForTp;

//-- Set the lot or volume to the symbol allowed min value
double lotSize = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);

Crear las variables del indicador técnico VIDyA en el ámbito global para asegurar que también son accesibles desde cualquier parte de nuestro código de asesor experto.

//-- Vidya indicator variables
double fastVidya[], slowVidya[];
int fastVidyaHandle, slowVidyaHandle;
bool buyOk, sellOk, vidyaBuy, vidyaSell;
string vidyaTrend;

Después de la sección de variables globales, cree la función de inicialización del Asesor Experto que se llamará desde la función estándar de manejo de eventos MQL5 OnInit(), que se ejecuta por primera vez durante la puesta en marcha o inicialización del Asesor Experto. Nombre esta función GetInit(). Realizaremos todas nuestras inicializaciones de datos en esta función, incluyendo las inicializaciones del indicador VIDyA y manejando el procesamiento de arranque.

int GetInit()
  {
   int returnVal = 1;

//-- Helps to regulate and prevent openning multiple trades on a single signal trigger
   buyOk = true;
   sellOk = true;

//-- Create the fast iVIDyA indicator handle
   fastVidyaHandle = iVIDyA(_Symbol, timeframe, fast_cmoPeriod, fast_maPeriod, fast_emaShift, appliedPrice);
   if(fastVidyaHandle < 0)
     {
      Print("Error creating fastVidyaHandle = ", INVALID_HANDLE);
      Print("Handle creation: Runtime error = ", GetLastError());
      //-- Close the EA if the handle is not properly loaded
      return(-1);
     }
   ArraySetAsSeries(fastVidya, true); //-- set the vidya array to series access

//-- Create the slow iVIDyA indicator handle
   slowVidyaHandle = iVIDyA(_Symbol, timeframe, slow_cmoPeriod, slow_maPeriod, slow_emaShift, appliedPrice);
   if(slowVidyaHandle < 0)
     {
      Print("Error creating vidyaHandle = ", INVALID_HANDLE);
      Print("Handle creation: Runtime error = ", GetLastError());
      //-- Close the EA if the handle is not properly loaded
      return(-1);
     }
   ArraySetAsSeries(slowVidya, true); //-- set the vidya array to series access

   return(returnVal);
  }

Después de la función de inicialización, crea la función de desinicialización y llámala GetDeinit(). Esta función será llamada dentro de la función estándar de manejo de eventos MQL5 OnDeinit() para realizar una limpieza en todo el sistema de todos los recursos utilizados por nuestro Asesor Experto. Esto incluye la liberación del indicador VIDyA, la liberación de todos los recursos vinculados a las matrices de control del indicador y la eliminación de cualquier comentario u objeto del gráfico.

void GetDeinit()  //-- De-initialize the robot on shutdown and clean everything up
  {
//-- Delete the vidya handles and de-allocate the memory spaces occupied
   IndicatorRelease(fastVidyaHandle);
   ArrayFree(fastVidya);
   IndicatorRelease(slowVidyaHandle);
   ArrayFree(slowVidya);

//-- Delete and clear all chart displayed messages
   Comment("");
  }

A continuación, necesitamos crear una función personalizada para detectar y recuperar las señales de operación generadas por nuestro par de indicadores VIDyA. Esta función se llamará GetVidya(). Se ejecutará y actualizará cada vez que haya un nuevo tick entrante para garantizar que la generación de señales sea precisa y en tiempo real.

void GetVidya()
  {
//-- Get vidya line directions
   if(CopyBuffer(fastVidyaHandle, 0, 0, 100, fastVidya) <= 0 || CopyBuffer(slowVidyaHandle, 0, 0, 100, slowVidya) <= 0)
     {
      return;
     }

//-- Reset vidya status variables
   vidyaBuy = false;
   vidyaSell = false;
   vidyaTrend = "FLAT";

//-- Scan for vidya crossover buy signal
   if(fastVidya[1] > slowVidya[1])
     {
      //-- Save the vidya signal
      vidyaTrend = "BUY/LONG";
      vidyaBuy = true;
      vidyaSell = false;
     }

//-- Scan for vidya crossover sell signal
   if(fastVidya[1] < slowVidya[1])
     {
      //-- Save the vidya signal
      vidyaTrend = "SELL/SHORT";
      vidyaSell = true;
      vidyaBuy = false;
     }
  }

Ahora que hemos creado la función para obtener y actualizar la señal VIDyA, vamos a crear otra función personalizada que se ejecutará en cada nuevo tick para escanear y abrir nuevas posiciones basadas en la señal VIDyA actual. Esta función se llamará ScanForTradeOpportunities(). En esta función llamaremos y ejecutaremos las funciones prototipo de apertura y estado de posición importadas de nuestra librería PositionsManager.ex5.

void ScanForTradeOpportunities()
  {
//-- Get the VIDyA signal
   GetVidya();

   if(MagicPositionsTotal(magicNo) == 0)
     {
      buyOk = true;
      sellOk = true;
     }

//-- Check for a buy entry when a VIDyA buy signal is found
   if(buyOk && vidyaBuy) //-- Open a new buy position
     {
      if(OpenBuyPosition(magicNo, _Symbol, lotSize, sl, tp, "Vidya_BUY: " + IntegerToString(MagicBuyPositionsTotal(magicNo) + 1)))
        {
         buyOk = false;
         sellOk = true;
        }
      //-- Market has a strong buy trend, close all profitable sell positions
      if(liquidateProfitOnCrossover)
        {
         CloseAllProfitableSellPositions(_Symbol, magicNo);
        }
     }

//-- Check for a sell entry when a VIDyA sell signal is found
   if(sellOk && vidyaSell) //-- Open a new sell position
     {
      if(OpenSellPosition(magicNo, _Symbol, lotSize, sl, tp, "Vidya_SELL: " + IntegerToString(MagicSellPositionsTotal(magicNo) + 1)))
        {
         sellOk = false;
         buyOk = true;
        }
      //-- Market has a strong sell trend, close all profitable buy positions
      if(liquidateProfitOnCrossover)
        {
         CloseAllProfitableBuyPositions(_Symbol, magicNo);
        }
     }
  }

También tenemos que comprobar y establecer trailing stops en todas las posiciones abiertas. Esto será sencillo ya que nuestra biblioteca PositionsManager.ex5 contiene una función prototipo de trailing stop loss para ayudarnos a conseguirlo. Creemos una nueva función llamada CheckAndSetTrailingSl() para escanear todas las posiciones abiertas y recuperar sus tickets para utilizarlos como parámetros en la función prototipo importada SetTrailingStopLoss().

void CheckAndSetTrailingSl()
  {
   int totalOpenPostions = PositionsTotal();
   for(int x = 0; x < totalOpenPostions; x++)
     {
      //--- Get position properties
      ulong  positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      int positionType = int(PositionGetInteger(POSITION_TYPE));

      //-- modify only the positions we have opened with this EA (magic number)
      if(selectedSymbol != _Symbol && positionMagicNo != magicNo)
        {
         continue;
        }
      //-- Only set the trailing stop loss when the market trend is in the opposing direction of the position type
      if((positionType == POSITION_TYPE_BUY && vidyaBuy) || (positionType == POSITION_TYPE_SELL && vidyaSell))
        {
         continue;
        }
      //--- set the trailing stop loss
      SetTrailingStopLoss(positionTicket, trailingSl); //-- call the imported function from our ex5 library
     }
  }

Ahora que hemos creado todos los módulos importantes para nuestro Asesor Experto, vamos a reunirlos en la función de manejo de eventos MQL5 OnTick() que se ejecuta en cada nuevo tick. Colóquelos en el orden especificado a continuación para garantizar que ejecutan sistemáticamente nuestro sistema de negociación en la secuencia correcta.

void OnTick()
  {
//-- Scan and open new positions based on the vidya signal
   ScanForTradeOpportunities();

//-- Check and set the trailing stop
   if(enableTrailingStops)
     {
      CheckAndSetTrailingSl();
     }

//-- Display the vidya trend and positions status for the EA's magicNo
   Comment(
      "\nvidyaTrend: ", vidyaTrend,
      MagicPositionsStatus(magicNo, true)
   );
  }

Finalmente, no olvides colocar las funciones de inicialización y desinicialización en sus respectivas funciones estándar de manejo de eventos MQL5.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(GetInit() <= 0)
     {
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   GetDeinit();
  }

Puede acceder y descargar el archivo de código fuente de DualVidyaTrader.mq5 al final de este artículo. He adjuntado el archivo de código fuente completo para asegurar que usted tiene todos los componentes necesarios para implementar y personalizar la estrategia de negociación según sea necesario.

Cuando compile y cargue nuestro nuevo DualVidyaTrader en MetaTrader 5, observará que en la pestaña «Dependencias» aparecen listados todos los prototipos de funciones de la biblioteca importados de PositionsManager.ex5, junto con la ruta completa del archivo donde se guarda la biblioteca EX5. Esto asegura que todas las dependencias requeridas están correctamente referenciadas antes de que el Asesor Experto se cargue en el gráfico. Si se encuentra algún error de referencia a bibliotecas, como los comentados anteriormente en el artículo, se registrará en las pestañas Expertos o Diario de la ventana Caja de herramientas de MetaTrader 5.

Pestaña de dependencias de Dual Vidya Trader


Panel de operaciones de Positions Manager desarrollado con la biblioteca EX5 Positions Manager

En este segundo ejemplo, crearemos un panel de operaciones básico de interfaz gráfica de usuario (GUI) de Asesor Experto que también funciona con nuestra biblioteca PositionsManager.ex5.

Interfaz gráfica de usuario del panel de gestión de posiciones


Cree un nuevo Asesor Experto utilizando el MetaEditor IDE y cree un nuevo archivo MQL Wizard y llámelo PositionsManagerPanel.mq5. Bajo el segmento de código #property, importa la librería PositionsManager.ex5. En la sección de descripciones de funciones de importación, importe únicamente los siguientes prototipos de funciones.

//+------------------------------------------------------------------+
//| EX5 PositionsManager imports                                     |
//+------------------------------------------------------------------+
#import "Toolkit/PositionsManager.ex5" //-- Open import directive
//-- Function descriptions for the imported function prototypes

//--Position Execution and Modification Functions
bool   OpenBuyPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment);
bool   OpenSellPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment);
bool   SetSlTpByTicket(ulong positionTicket, int sl, int tp);
bool   ClosePositionByTicket(ulong positionTicket);
bool   SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss);
bool   CloseAllPositions(string symbol, ulong magicNumber);
bool   CloseAllBuyPositions(string symbol, ulong magicNumber);
bool   CloseAllSellPositions(string symbol, ulong magicNumber);
bool   CloseAllMagicPositions(ulong magicNumber);
bool   CloseAllProfitablePositions(string symbol, ulong magicNumber);
bool   CloseAllLossPositions(string symbol, ulong magicNumber);

//--Position Status Monitoring Functions
int    BuyPositionsTotal();
int    SellPositionsTotal();
double PositionsTotalVolume();
double BuyPositionsTotalVolume();
double SellPositionsTotalVolume();
double BuyPositionsProfit();
double SellPositionsProfit();
int    MagicPositionsTotal(ulong magicNumber);
int    MagicBuyPositionsTotal(ulong magicNumber);
int    MagicSellPositionsTotal(ulong magicNumber);
double MagicPositionsTotalVolume(ulong magicNumber);
double MagicBuyPositionsTotalVolume(ulong magicNumber);
double MagicSellPositionsTotalVolume(ulong magicNumber);
double MagicPositionsProfit(ulong magicNumber);
double MagicBuyPositionsProfit(ulong magicNumber);
double MagicSellPositionsProfit(ulong magicNumber);
int    SymbolPositionsTotal(string symbol, ulong magicNumber);
int    SymbolBuyPositionsTotal(string symbol, ulong magicNumber);
int    SymbolSellPositionsTotal(string symbol, ulong magicNumber);
double SymbolPositionsTotalVolume(string symbol, ulong magicNumber);
double SymbolBuyPositionsTotalVolume(string symbol, ulong magicNumber);
double SymbolSellPositionsTotalVolume(string symbol, ulong magicNumber);
double SymbolPositionsProfit(string symbol, ulong magicNumber);
double SymbolBuyPositionsProfit(string symbol, ulong magicNumber);
double SymbolSellPositionsProfit(string symbol, ulong magicNumber);
string AccountPositionsStatus(bool formatForComment);
string MagicPositionsStatus(ulong magicNumber, bool formatForComment);
string SymbolPositionsStatus(string symbol, ulong magicNumber, bool formatForComment);
#import //--- Close import directive

El PositionsManagerPanel.mq5 sólo contendrá una entrada de usuario (número mágico).

//--User input variables
input ulong magicNo = 101010;

A continuación, creamos las variables globales para almacenar el volumeLot, sl y tp.

//-- Global variables
//-----------------------
//-- Get the current symbol spread and multiply it by a significant number
//-- to simulate user-input SL and TP values
double volumeLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
int sl = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * 50;
int tp = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * 100;

Vamos a crear nuestro primer objeto gráfico, que servirá de fondo para nuestra interfaz gráfica de usuario. Para ello utilizaremos una etiqueta rectangular. Para ello, crearemos una función personalizada llamada CreateRectangleLabel().

//+-----------------------------------------------------------------------+
//| CreateRectangleLabel(): Creates a rectangle label on the chart window |
//+-----------------------------------------------------------------------+
void CreateRectangleLabel()
  {
//--- Detect if we have an object named the same as our rectangle label
   if(ObjectFind(0, "mainRectangleLabel") >= 0)
     {
      //--- Delete the specified object if it is not a rectangle label
      if(ObjectGetInteger(0, "mainRectangleLabel", OBJPROP_TYPE) != OBJ_RECTANGLE_LABEL)
        {
         ObjectDelete(0, "mainRectangleLabel");
        }
     }
   else
     {
      //-- Create the mainRectangleLabel
      ObjectCreate(0, "mainRectangleLabel", OBJ_RECTANGLE_LABEL, 0, 0, 0);
     }
//--- Set up the new rectangle label properties
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_XDISTANCE, 240);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_YDISTANCE, 2);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_XSIZE, 460);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_YSIZE, 520);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_BGCOLOR, clrMintCream);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_BACK, false);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_HIDDEN, true);
  }

También necesitamos etiquetas para mostrar texto en nuestro panel comercial. Crearemos otra función personalizada llamada CreateLabel() para manejar esta tarea.

//+---------------------------------------------------------+
//| CreateLabel(): Creates a text label on the chart window |
//+---------------------------------------------------------+
void CreateLabel(
   string labelName, int xDistance, int yDistance, int xSize, int ySize,
   string labelText, color textColor, string fontType, int fontSize
)
  {
//--- Detect if we have an object with the same name as our label
   if(ObjectFind(0, labelName) >= 0)
     {
      //--- Delete the specified object if it is not a label
      if(ObjectGetInteger(0, labelName, OBJPROP_TYPE) != OBJ_LABEL)
        {
         ObjectDelete(0, labelName);
        }
     }
   else
     {
      //-- Create the label
      ObjectCreate(0, labelName, OBJ_LABEL, 0, 0, 0);
     }
//--- Set up the new rectangle label properties
   ObjectSetInteger(0, labelName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, xDistance);
   ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, yDistance);
   ObjectSetInteger(0, labelName, OBJPROP_XSIZE, xSize);
   ObjectSetInteger(0, labelName, OBJPROP_YSIZE, ySize);
   ObjectSetString(0, labelName, OBJPROP_TEXT, labelText);
   ObjectSetInteger(0, labelName, OBJPROP_COLOR, textColor);
   ObjectSetString(0, labelName, OBJPROP_FONT, fontType);
   ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, fontSize);
   ObjectSetInteger(0, labelName, OBJPROP_BACK, false);
   ObjectSetInteger(0, labelName, OBJPROP_HIDDEN, true);
   ObjectSetInteger(0, labelName, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, labelName, OBJPROP_SELECTED, false);
  }

Los botones clicables o sensibles son necesarios para que nuestro panel de operaciones realice diferentes operaciones comerciales. Por lo tanto, debemos crear una función personalizada para manejar la creación de botones. Llamemos a esta función CreateButton().

//+------------------------------------------------------+
//| CreateButton(): Creates buttons on the chart window  |
//+------------------------------------------------------+
void CreateButton(
   string btnName, int xDistance, int yDistance, int xSize, int ySize, string btnText,
   string tooltip, color textColor, string fontType, int fontSize, color bgColor
)
  {
//--- Detect if we have an object named the same as our button
   if(ObjectFind(0, btnName) >= 0)
     {
      //--- Delete the specified object if it is not a button
      if(ObjectGetInteger(0, btnName, OBJPROP_TYPE) != OBJ_BUTTON)
        {
         ObjectDelete(0, btnName);
        }
     }
   else
     {
      //-- Create the button
      ObjectCreate(0, btnName, OBJ_BUTTON, 0, 0, 0);
     }
//--- Set up the new button properties
   ObjectSetInteger(0, btnName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, btnName, OBJPROP_XDISTANCE, xDistance);
   ObjectSetInteger(0, btnName, OBJPROP_YDISTANCE, yDistance);
   ObjectSetInteger(0, btnName, OBJPROP_XSIZE, xSize);
   ObjectSetInteger(0, btnName, OBJPROP_YSIZE, ySize);
   ObjectSetString(0, btnName, OBJPROP_TEXT, btnText);
   ObjectSetString(0, btnName, OBJPROP_TOOLTIP, tooltip);
   ObjectSetInteger(0, btnName, OBJPROP_COLOR, textColor);
   ObjectSetString(0, btnName, OBJPROP_FONT, fontType);
   ObjectSetInteger(0, btnName, OBJPROP_FONTSIZE, fontSize);
   ObjectSetInteger(0, btnName, OBJPROP_BGCOLOR, bgColor);
  }

Ahora necesitamos otra función personalizada para cargar todos los diferentes objetos gráficos y componentes gráficos de entrada de usuario creados con las funciones que hemos escrito anteriormente. Llamemos a esta función LoadChartObjects().

//+--------------------------------------------------------------------+
//| LoadChartObjects(): Create and load the buttons and chart objects  |
//| for demonstrating how the imported library functions work          |
//+--------------------------------------------------------------------+
void LoadChartObjects()
  {
//-- Create the rectangle label first
   CreateRectangleLabel();

//-- Create the heading label
   CreateLabel(
      "headingLabel", 250, 10, 440, 60,
      "PositionsManager ex5 Library Demo Trade Panel",
      clrMidnightBlue, "Calibri", 10
   );

//-- Create the second heading label
   CreateLabel(
      "headingLabel2", 250, 30, 440, 60,
      ("Trading " + _Symbol + " with Magic Number: " + (string)magicNo),
      clrBlack, "Consolas", 11
   );

//-- "BUY": Button to call the imported ex5 OpenBuyPosition() function
   CreateButton(
      "OpenBuyPositionBtn", 250, 50, 215, 35, "BUY",
      "OpenBuyPosition() Function", clrMintCream, "Arial Black", 10, clrDodgerBlue
   );

//-- "SELL": Button to call the imported ex5 OpenSellPosition() function
   CreateButton(
      "OpenSellPositionBtn", 475, 50, 215, 35, "SELL",
      "OpenSellPosition() Function", clrMintCream, "Arial Black", 10, clrCrimson
   );

//-- "SetSlTpByTicket": Button to call the imported ex5 SetSlTpByTicket() function
   CreateButton(
      "SetSlTpBtn", 250, 90, 215, 35, "SetSlTpByTicket",
      "SetSlTpByTicket() Function", clrMintCream, "Arial Black", 10, clrDarkSlateGray
   );

//-- "SetTrailingStopLoss": Button to call the imported ex5 SetTrailingStopLoss() function when clicked
   CreateButton(
      "SetTrailingStopLossBtn", 475, 90, 215, 35, "SetTrailingStopLoss",
      "SetTrailingStopLoss Function", clrMintCream, "Arial Black", 10, clrDarkSlateGray
   );

//-- "ClosePositionsByTicket": Button to call the imported ex5 ClosePositionByTicket() function
   CreateButton(
      "ClosePositionsBtn", 250, 130, 215, 35, "ClosePositionsByTicket",
      "ClosePositionByTicket() Function", clrMintCream, "Arial Black", 10, clrMaroon
   );

//-- "CloseAllSymbolPositions": Button to call the imported ex5 CloseAllSymbolPositions() function
   CreateButton(
      "CloseAllPositionsBtn", 475, 130, 215, 35, "CloseAllPositions",
      "CloseAllPositions() Function", clrMintCream, "Arial Black", 10, clrMaroon
   );

//-- "CloseAllBuySymbolPositions": Button to call the imported ex5 CloseAllBuySymbolPositions() function
   CreateButton(
      "CloseAllBuyPositionsBtn", 250, 170, 215, 35, "CloseAllBuyPositions",
      "CloseAllBuyPositions() Function", clrMintCream, "Arial Black", 10, clrBrown
   );

//-- "CloseAllSellSymbolPositions": Button to call the imported ex5 CloseAllSellSymbolPositions() function
   CreateButton(
      "CloseAllSellPositionsBtn", 475, 170, 215, 35, "CloseAllSellPositions",
      "CloseAllSellPositions() Function", clrMintCream, "Arial Black", 10, clrBrown
   );

//-- "CloseAllMagicPositions": Button to call the imported ex5 CloseAllMagicPositions() function
   CreateButton(
      "CloseAllMagicPositionsBtn", 250, 210, 440, 35, "CloseAllMagicPositions",
      "CloseAllMagicPositions() Function", clrMintCream, "Arial Black", 10, C'203,18,55'
   );

//-- "CloseAllProfitablePositions": Button to call the imported ex5 CloseAllMagicPositions() function
   CreateButton(
      "CloseAllProfitablePositionsBtn", 250, 250, 215, 35, "CloseAllProfitablePositions",
      "CloseAllProfitablePositions() Function", clrMintCream, "Arial Black", 10, clrSeaGreen
   );

//-- "CloseAllLossPositions": Button to call the imported ex5 CloseAllLossPositions() function
   CreateButton(
      "CloseAllLossPositionsBtn", 475, 250, 215, 35, "CloseAllLossPositions",
      "CloseAllLossPositions() Function", clrMintCream, "Arial Black", 10, C'179,45,0'
   );

//-- Create the bottomHeadingLabel
   CreateLabel(
      "bottomHeadingLabel", 250, 310, 440, 60,
      (_Symbol + " - (Magic Number: " + (string)magicNo + ") Positions Status"),
      clrBlack, "Calibri", 12
   );

//-- Create totalOpenPositionsLabel
   CreateLabel(
      "totalOpenPositionsLabel", 250, 340, 440, 60,
      ("  Total Open:   " + (string)MagicPositionsTotal(magicNo)),
      clrNavy, "Consolas", 11
   );

//-- Create totalPositionsVolumeLabel
   CreateLabel(
      "totalPositionsVolumeLabel", 250, 360, 440, 60,
      ("  Total Volume: " + (string)NormalizeDouble(MagicPositionsTotalVolume(magicNo), 2)),
      clrNavy, "Consolas", 11
   );

//-- Create the totalPositionsProfitLabel
   CreateLabel(
      "totalPositionsProfitLabel", 250, 380, 100, 60,
      (
         "  Total Profit: " + (string)(NormalizeDouble(MagicPositionsProfit(magicNo), 2)) +
         " " + AccountInfoString(ACCOUNT_CURRENCY)
      ),
      clrNavy, "Consolas", 11
   );

//-- Create the buyPositionsHeadingLabel
   CreateLabel(
      "buyPositionsHeadingLabel", 250, 410, 440, 60,
      ("BUY POSITIONS:"),
      clrBlack, "Calibri", 12
   );

//-- Create the totalBuyPositionsLabel
   CreateLabel(
      "totalBuyPositionsLabel", 250, 430, 440, 60,
      ("  Total Open:   " + (string)MagicBuyPositionsTotal(magicNo)),
      clrNavy, "Consolas", 11
   );

//-- Create the totalBuyPositionsVolumeLabel
   CreateLabel(
      "totalBuyPositionsVolumeLabel", 250, 450, 440, 60,
      ("  Total Volume: " + (string)NormalizeDouble(MagicBuyPositionsTotalVolume(magicNo), 2)),
      clrNavy, "Consolas", 11
   );

//-- Create the totalBuyPositionsProfitLabel
   CreateLabel(
      "totalBuyPositionsProfitLabel", 250, 470, 440, 60,
      (
         "  Total Profit: " + (string)(NormalizeDouble(MagicBuyPositionsProfit(magicNo), 2)) +
         " " + AccountInfoString(ACCOUNT_CURRENCY)
      ),
      clrNavy, "Consolas", 11
   );

//-- Create the sellPositionsHeadingLabel
   CreateLabel(
      "sellPositionsHeadingLabel", 475, 410, 440, 60,
      ("SELL POSITIONS:"),
      clrBlack, "Calibri", 12
   );

//-- Create the totalSellPositionsLabel
   CreateLabel(
      "totalSellPositionsLabel", 475, 430, 440, 60,
      ("  Total Open:   " + (string)MagicSellPositionsTotal(magicNo)),
      clrNavy, "Consolas", 11
   );

//-- Create the totalSellPositionsVolumeLabel
   CreateLabel(
      "totalSellPositionsVolumeLabel", 475, 450, 440, 60,
      ("  Total Volume: " + (string)NormalizeDouble(MagicSellPositionsTotalVolume(magicNo), 2)),
      clrNavy, "Consolas", 11
   );

//-- Create the totalSellPositionsProfitLabel
   CreateLabel(
      "totalSellPositionsProfitLabel", 475, 470, 100, 60,
      (
         "  Total Profit: " + (string)(NormalizeDouble(MagicSellPositionsProfit(magicNo), 2)) +
         " " + AccountInfoString(ACCOUNT_CURRENCY)
      ),
      clrNavy, "Consolas", 11
   );

//--- Redraw the chart to refresh it so that it loads our new chart objects
   ChartRedraw();
//---
  }

La siguiente función personalizada se encargará de limpiar y borrar todos los objetos y datos del gráfico cuando el Asesor Experto finalice o se desinicialice. Llamémosla DeleteChartObjects(). Se colocará y ejecutará en la función OnDeinit() MQL5 de manejo de eventos estándar.

//+------------------------------------------------------------------------------+
//| DeleteChartObjects(): Delete all the chart objects when the EA is terminated |
//| on De-initialization                                                         |
//+------------------------------------------------------------------------------+
void DeleteChartObjects()
  {
//---
//--- Clean up and delete all the buttons or graphical objects
   ObjectDelete(0, "OpenBuyPositionBtn");
   ObjectDelete(0, "OpenSellPositionBtn");
   ObjectDelete(0, "SetSlTpBtn");
   ObjectDelete(0, "SetTrailingStopLossBtn");
   ObjectDelete(0, "ClosePositionsBtn");
   ObjectDelete(0, "CloseAllPositionsBtn");
   ObjectDelete(0, "CloseAllBuyPositionsBtn");
   ObjectDelete(0, "CloseAllSellPositionsBtn");
   ObjectDelete(0, "CloseAllMagicPositionsBtn");
   ObjectDelete(0, "CloseAllProfitablePositionsBtn");
   ObjectDelete(0, "CloseAllLossPositionsBtn");
   ObjectDelete(0, "mainRectangleLabel");

   ObjectDelete(0, "headingLabel");
   ObjectDelete(0, "headingLabel2");

   ObjectDelete(0, "bottomHeadingLabel");
   ObjectDelete(0, "totalOpenPositionsLabel");
   ObjectDelete(0, "totalPositionsVolumeLabel");
   ObjectDelete(0, "totalPositionsProfitLabel");

   ObjectDelete(0, "buyPositionsHeadingLabel");
   ObjectDelete(0, "totalBuyPositionsLabel");
   ObjectDelete(0, "totalBuyPositionsVolumeLabel");
   ObjectDelete(0, "totalBuyPositionsProfitLabel");

   ObjectDelete(0, "sellPositionsHeadingLabel");
   ObjectDelete(0, "totalSellPositionsLabel");
   ObjectDelete(0, "totalSellPositionsVolumeLabel");
   ObjectDelete(0, "totalSellPositionsProfitLabel");
  }

Ahora que hemos terminado de crear y gestionar los objetos gráficos, vamos a crear las funciones personalizadas que implementarán algunas de las funciones importadas de la librería PositionsManager.ex5. La primera función de este grupo, que llamaremos ModifySlTp(), se encargará de modificar el stop loss (sl) y el take profit (tp) de todas las posiciones abiertas por este Asesor Experto que coincidan con el número mágico introducido por el usuario. Esta función se ejecutará cada vez que se pulse el botón setSLTP del gráfico.

//+-------------------------------------------------------------------------+
// ModifySlTp(): This function demonstrates how to use the imported ex5     |
// bool SetSlTpByTicket(ulong positionTicket, int sl, int tp);              |
// It runs this function when the setSLTP button on the chart is clicked.   |
//+-------------------------------------------------------------------------+
void ModifySlTp()
  {
//-- Get positions that we have openend with the chart buy and sell buttons to test the imported function with
   int totalOpenPostions = PositionsTotal();
//--- Scan open positions
   for(int x = 0; x < totalOpenPostions; x++)
     {
      //--- Get position properties
      ulong  positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);

      //-- modify only the positions we have opened with this EA (magic number) using the BUY and SELL buttons on the chart
      if(selectedSymbol != _Symbol && positionMagicNo != magicNo)
        {
         continue;
        }
      //--- modify the sl and tp of the position
      SetSlTpByTicket(positionTicket, sl, tp);//-- call the imported function from our ex5 library
     }
  }

La siguiente función, SetTrailingSl(), se encargará de actualizar el trailing stop loss. Se ejecutará tanto cuando se haga clic en el botón SetTrailingStopLoss del gráfico como en cada nuevo tick entrante en la función de gestión de eventos OnTick().

//+-----------------------------------------------------------------------------------+
// SetTrailingSl(): This function demonstrates how to use the imported ex5            |
// bool SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss);              |
// It runs this function when the SetTrailingStopLoss button on the chart is clicked. |
//+-----------------------------------------------------------------------------------+
void SetTrailingSl()
  {
   int trailingSl = sl;

//-- Get positions that we have openend with the chart buy and sell buttons to test the imported function with
   int totalOpenPostions = PositionsTotal();
//--- Scan open positions
   for(int x = 0; x < totalOpenPostions; x++)
     {
      //--- Get position properties
      ulong  positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);

      //-- modify only the positions we have opened with this EA (magic number) using the BUY and SELL buttons on the chart
      if(selectedSymbol != _Symbol && positionMagicNo != magicNo)
        {
         continue;
        }
      //--- set the trailing stop loss
      SetTrailingStopLoss(positionTicket, trailingSl); //-- call the imported function from our ex5 library
     }
  }

La función ClosePositionWithTicket() se encargará de cerrar todas las posiciones abiertas y se ejecutará cuando se pulse el botón ClosePositions del gráfico.

//+-----------------------------------------------------------------------------------+
// ClosePositionWithTicket(): This function demonstrates how to use the imported ex5  |
// bool ClosePositionByTicket(ulong positionTicket)                                   |
// It runs this function when the ClosePositions button on the chart is clicked.      |
//+-----------------------------------------------------------------------------------+
void ClosePositionWithTicket()
  {
//-- Get positions that we have openend with the chart buy and sell buttons to test the imported function with
   int totalOpenPostions = PositionsTotal();
//--- Scan open positions
   for(int x = 0; x < totalOpenPostions; x++)
     {
      //--- Get position properties
      ulong  positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);

      //-- close only the positions we have opened with this EA (magic number) using the BUY and SELL buttons on the chart
      if(selectedSymbol != _Symbol && positionMagicNo != magicNo)
        {
         continue;
        }

      //--- Close the position
      ClosePositionByTicket(positionTicket);//-- call the imported function from our ex5 library
     }
  }

La última función es la función estándar OnChartEvent() MQL5, que detectará cuando se pulsan nuestros distintos botones y realizará las acciones correspondientes. Casi todas las funciones importadas de gestión de posiciones de la librería PositionsManager.ex5 serán llamadas y ejecutadas desde esta función.

//+------------------------------------------------------------------+
//| ChartEvent function to detect when the buttons are clicked       |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
//--- Detected a CHARTEVENT_CLICK event
   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      Print(__FUNCTION__, ": ", sparam);

      //--- Buy when OpenBuyPositionBtn button (BUY) is pressed or clicked
      if(sparam == "OpenBuyPositionBtn")
        {
         //-- Call our imported function from the Toolkit/PositionsManager ex5 library
         OpenBuyPosition(magicNo, _Symbol, volumeLot, sl, tp, "ex5 PositionsManager");

         //--- Release and unpress the button
         ObjectSetInteger(0, "OpenBuyPositionBtn", OBJPROP_STATE, false);
        }

      //--- Sell when OpenSellPositionBtn button (SELL) is pressed
      if(sparam == "OpenSellPositionBtn")
        {
         //-- Call our imported function from the Toolkit/PositionsManager ex5 library
         OpenSellPosition(magicNo, _Symbol, volumeLot, sl, tp, "ex5 PositionsManager");
         //OpenSellPosition(magicNo, "NON-EXISTENT-Symbol-Name"/*_Symbol*/, volumeLot, sl, tp, "ex5 PositionsManager");

         //--- Release and unpress the button
         ObjectSetInteger(0, "OpenSellPositionBtn", OBJPROP_STATE, false);
        }

      //--- Modify specified positions SL and TP when SetSlTpBtn button (setSLTP) is pressed
      if(sparam == "SetSlTpBtn")
        {
         ModifySlTp();//-- Modify the SL and TP of the positions generated by the BUY and SELL buttons
         //--- Release and unpress the button
         ObjectSetInteger(0, "SetSlTpBtn", OBJPROP_STATE, false);
        }

      //--- Set the Trailing Stop Loss when SetSlTpBtn button (SetTrailingStopLossBtn) is pressed
      if(sparam == "SetTrailingStopLossBtn")
        {
         SetTrailingSl();//-- Set the Trailing Stop Loss for the positions generated by the BUY and SELL buttons
         //--- Release and unpress the button
         ObjectSetInteger(0, "SetTrailingStopLossBtn", OBJPROP_STATE, false);
        }

      //--- Close specified positions when SetSlTpBtn button (setSLTP) is pressed
      if(sparam == "ClosePositionsBtn")
        {
         ClosePositionWithTicket();//-- Close all the positions generated by the BUY and SELL buttons
         //--- Release and unpress the button
         ObjectSetInteger(0, "ClosePositionsBtn", OBJPROP_STATE, false);
        }

      //--- Close all positions for the current symbol when the CloseAllPositionsBtn button is pressed
      if(sparam == "CloseAllPositionsBtn")
        {
         CloseAllPositions(_Symbol, 0);//-- Close all the open symbol positions
         //--- Release and unpress the button
         ObjectSetInteger(0, "CloseAllPositionsBtn", OBJPROP_STATE, false);
        }

      //--- Close all buy positions for the current symbol when the CloseAllBuyPositionsBtn button is pressed
      if(sparam == "CloseAllBuyPositionsBtn")
        {
         CloseAllBuyPositions(_Symbol, magicNo);//-- Close all the open symbol buy positions
         //--- Release and unpress the button
         ObjectSetInteger(0, "CloseAllBuyPositionsBtn", OBJPROP_STATE, false);
        }

      //--- Close all sell positions for the current symbol when the CloseAllSellPositionsBtn button is pressed
      if(sparam == "CloseAllSellPositionsBtn")
        {
         CloseAllSellPositions(_Symbol, magicNo);//-- Close all the open symbol sell positions
         //--- Release and unpress the button
         ObjectSetInteger(0, "CloseAllSellPositionsBtn", OBJPROP_STATE, false);
        }

      //--- Close all positions with the specified magic number when the CloseAllMagicPositionsBtn button is pressed
      if(sparam == "CloseAllMagicPositionsBtn")
        {
         CloseAllMagicPositions(magicNo);//-- Close all the open positions with the specified magic number
         //--- Release and unpress the button
         ObjectSetInteger(0, "CloseAllMagicPositionsBtn", OBJPROP_STATE, false);
        }

      //--- Close all profitable positions with the specified symbol and magic number when the CloseAllProfitablePositionsBtn button is pressed
      if(sparam == "CloseAllProfitablePositionsBtn")
        {
         CloseAllProfitablePositions(_Symbol, magicNo);//-- Close all the open profitable positions with the specified symbol and magic number
         //--- Release and unpress the button
         ObjectSetInteger(0, "CloseAllProfitablePositionsBtn", OBJPROP_STATE, false);
        }

      //--- Close all loss positions with the specified symbol and magic number when the CloseAllLossPositionsBtn button is pressed
      if(sparam == "CloseAllLossPositionsBtn")
        {
         CloseAllLossPositions(_Symbol, magicNo);//-- Close all the open loss positions with the specified symbol and magic number
         //--- Release and unpress the button
         ObjectSetInteger(0, "CloseAllLossPositionsBtn", OBJPROP_STATE, false);
        }

      //--- Redraw the chart to refresh it
      ChartRedraw();
     }
//---
  }

Antes de ejecutar PositionsTradePanel.mq5, necesitamos incorporar todos los componentes necesarios en las funciones de manejo de eventos OnInit(), OnDeinit(), y OnTick(). Comience cargando todos los objetos gráficos durante la inicialización del Experto con la función LoadChartObjects() en la función OnInit().

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
//create buttons to demonstrate how the different ex5 library functions work
   LoadChartObjects();
//---
   return(INIT_SUCCEEDED);
  }

Llama y ejecuta las siguientes funciones en la función OnTick().

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//-- Check for profitable positions and set the trailing stop loss on every new tick
   SetTrailingSl(); //-- Calls the ex5 library function responsible for setting Trailing stops
   LoadChartObjects(); //--- Update chart objects
  }

Añada la función de desinicialización al manejador de eventos OnDeinit() para eliminar todos los objetos gráficos y de gráfico cuando se cierre o finalice el Asesor Experto.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
//-- Clean up the chart
   DeleteChartObjects();

//-- Clear any chart comments
   Comment("");
  }

Encontrará el archivo de código fuente completo de PositionsManagerPanel.mq5 adjunto al final de este artículo para un examen más detallado.

Guarde, compile y cargue PositionsManagerPanel.mq5 en cualquier gráfico de MetaTrader 5. En la pestaña Dependencias, verás todos los prototipos de funciones de la biblioteca importados de PositionsManager.ex5, junto con la ruta completa del archivo donde se guarda la biblioteca EX5. Una vez cargado en el gráfico, pruébelo abriendo algunas posiciones y comprobando en el registro de la pestaña Expertos del panel Caja de herramientas del terminal de negociación los datos de registro impresos de las funciones prototipo de PositionsManager.ex5.

Panel de posiciones de Dependencias EX5


Conclusión

Ahora ya conoce en profundidad las bibliotecas EX5 de MQL5. Hemos cubierto su creación, integración e implementación en proyectos MQL5 externos, incluyendo cómo depurar varios errores de las librerías EX5, y cómo actualizarlas y redistribuirlas. Además, hemos creado una biblioteca de gestión de posiciones EX5 potente y repleta de funciones, con documentación detallada y ejemplos prácticos de casos de uso. También he demostrado cómo importar e implementar esta biblioteca en dos diferentes asesores expertos MQL5 prácticos, proporcionando ejemplos del mundo real sobre la implementación efectiva de las bibliotecas EX5. En el próximo artículo, seguiremos un enfoque similar para desarrollar una completa librería EX5 de gestión de órdenes pendientes, diseñada para simplificar las tareas de procesamiento de órdenes pendientes en tus aplicaciones MQL5. Gracias por seguirme y te deseo mucho éxito en tu viaje por el trading y la programación.


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

Creación de un modelo de restricción de tendencia de velas (Parte 7): Perfeccionamos nuestro modelo de desarrollo de la EA Creación de un modelo de restricción de tendencia de velas (Parte 7): Perfeccionamos nuestro modelo de desarrollo de la EA
En este artículo, profundizaremos en la preparación detallada de nuestro indicador para el desarrollo del Asesor Experto (EA). Nuestro debate abarcará mejoras adicionales en la versión actual del indicador para mejorar su precisión y funcionalidad. Además, introduciremos nuevas características que marcan puntos de salida, abordando una limitación de la versión anterior, que solo identificaba puntos de entrada.
Análisis causal de series temporales mediante entropía de transferencia Análisis causal de series temporales mediante entropía de transferencia
En este artículo, analizamos cómo se puede aplicar la causalidad estadística para identificar variables predictivas. Exploraremos el vínculo entre causalidad y entropía de transferencia, además de presentar código MQL5 para detectar transferencias direccionales de información entre dos variables.
Gestión de Riesgo (Parte 1): Fundamentos para Construir una Clase de Gestión de Riesgo Gestión de Riesgo (Parte 1): Fundamentos para Construir una Clase de Gestión de Riesgo
En este artículo exploraremos los fundamentos de la gestión de riesgo en el trading, y aprenderemos a crear nuestras primeras funciones para obtener el lote adecuado para una operación y el stop loss. Además, profundizaremos en cómo funcionan estas funciones, explicando cada paso detalladamente. Nuestro objetivo es proporcionar una comprensión clara de cómo aplicar estos conceptos en el trading automatizado. Al final, pondremos todo en práctica creando un script simple con el archivo de inclusión que hemos diseñado.
Algoritmo de optimización del comportamiento social adaptativo — Adaptive Social Behavior Optimization (ASBO): Método de Schwefel, método de Box-Muller Algoritmo de optimización del comportamiento social adaptativo — Adaptive Social Behavior Optimization (ASBO): Método de Schwefel, método de Box-Muller
Este artículo presenta una fascinante inmersión en el mundo del comportamiento social de los organismos vivos y su influencia en la creación de un nuevo modelo matemático, el ASBO (Adaptive Social Behavior Optimisation). Hoy exploraremos cómo los principios de liderazgo, vecindad y cooperación observados en las sociedades de seres vivos inspiran el desarrollo de algoritmos de optimización innovadores.