Discusión sobre el artículo "Algoritmos avanzados de ejecución de órdenes en MQL5: TWAP, VWAP y órdenes Iceberg"

 

Artículo publicado Algoritmos avanzados de ejecución de órdenes en MQL5: TWAP, VWAP y órdenes Iceberg:

Un marco MQL5 que ofrece algoritmos de ejecución de nivel institucional (TWAP, VWAP, Iceberg) a los operadores minoristas a través de un gestor de ejecución unificado y un analizador de rendimiento para un corte y análisis de órdenes más fluido y preciso.

«Claro», dirás encogiéndote de hombros, «pero yo no muevo sumas institucionales». Aquí está la clave: no tienes por qué hacerlo. Tanto si está desplegando medio lote como un puñado de minilotes, la volatilidad puede seguir afectando a su ejecución. Estas herramientas te ayudan a:

  • Control del deslizamiento: Incluso las órdenes modestas pueden variar en mercados volátiles.
  • Afilá tu ventaja: Las ejecuciones por capas suelen ofrecerte un precio medio más favorable que una apuesta única.
  • Mantén la calma: Los flujos de trabajo automatizados eliminan la tentación de comprar o vender de forma precipitada.
  • Escalabilidad sin fisuras: A medida que su cuenta crece, la ejecución sigue siendo ágil, independientemente del volumen de sus órdenes.
  • Pasa desapercibido: Las órdenes Iceberg, en particular, ocultan el tamaño real de tu orden, lo que mantiene a los algoritmos entrometidos en la incertidumbre.

El panorama democratizado actual significa que la misma tecnología de ejecución que antes requería presupuestos multimillonarios ahora puede funcionar en su estación de operaciones personal. Al incorporar el código MQL5 optimizado para las estrategias TWAP, VWAP e Iceberg en su plataforma, se dotará de la potencia institucional sin abandonar el ámbito minorista.


Autor: N Soumik

 

Buen artículo.

¿Qué pares recomienda para este Algo?

¿Qué plazos? M5, M30 etc.

¿En qué sesión?

Gracias y saludos

 
Gran Artículo
Prueba de su algo.
EN el archivo, ExecutionAlgorithm.mqh, añadido este request.type_filling línea = ORDER_FILLING_IOC; en la colocación de la orden para solucionar el problema de colocación de pedidos.
Probado en M5, abrió sólo 1 operación durante 2 meses, no abrió ninguna orden parcial.
Probado en H1, nunca aplicó el SL, o TP y todas las operaciones cerraron con pérdidas.

también durante la compilación genera advertencias
posible perdida de datos debido a la conversion de tipo de 'long' a 'double' VWAP.mqh 271 41
posible pérdida de datos debido a la conversión de tipo de 'long' a 'double' VWAP.mqh 272 22
posible pérdida de datos debido a la conversión del tipo "long" a "double" VWAP.mqh 449 17
posible pérdida de datos debido a la conversión de tipo de 'long' a 'double' PerformanceAnalyzer.mqh 222 17
Posible pérdida de datos debido a la conversión de tipo "long" a "double" ExecutionManager.mqh 418 17


sugiera cómo probar el algo,
Time frame. y cualquier otra recomendación.
 
arreglar los warnins
también al compilar genera warnings
posible pérdida de datos debido a la conversión de tipo de 'long' a 'double' VWAP .mqh 271 41
posible pérdida de datos debido a la conversión del tipo 'long' a 'double' VWAP .mqh 272 22
Posible pérdida de datos por conversión de tipo "long" a "double" VWAP .mqh 449 17
posible pérdida de datos debido a la conversión de tipo de 'long' a 'double' PerformanceAnalyzer .mqh 222 17
posible pérdida de datos debido a la conversión de tipo de 'long' a 'double' ExecutionManager .mqh 418 17


he cambiado la línea de código
m_volumeProfile[intervalIndex] += rates[i].tick_volu

a
m_volumeProfile[intervalIndex] += (double)rates[i].tick_volume;

Se fijaron las advertencias
Ahora necesito que guidence con respecto a mis otras preguntas, como
marco de tiempo
y también
por qué todas las operaciones durante backtest resultado en la pérdida
cómo probar este gran trabajo de usted ..
[Eliminado]  
i_vergo posible perdida de datos debido a la conversion de tipo de 'long' a 'double' VWAP.mqh 271 41
posible pérdida de datos debido a la conversión de tipo de 'long' a 'double' VWAP.mqh 272 22
posible pérdida de datos debido a la conversión del tipo "long" a "double" VWAP.mqh 449 17
posible pérdida de datos debido a la conversión de tipo de 'long' a 'double' PerformanceAnalyzer.mqh 222 17
Posible pérdida de datos debido a la conversión de tipo "long" a "double" ExecutionManager.mqh 418 17


sugiera cómo probar el algo,
Time frame. y cualquier otra recomendación.

Las advertencias no son el problema pero podrían arreglarse rápidamente. Pero sí sería genial si el autor pudiera mostrar paso a paso qué ajustes y entradas utilizó para el backtest.

 

Estoy de acuerdo con Dominic ya que las advertencias son sólo advertencias. Los resultados de I_Virgo son probablemente porque utilizó el marco de tiempo y el par de divisas equivocado. Desde el informe de Back Test, de casi 2000 barras, debe haber sido M1 o M5 como el marco de tiempo con un par desconocido.

Sería bueno si MQ añadiera el marco de tiempo y el par de divisas o pares y también separara los resultados de los pares en más detalles en el informe de la prueba retrospectiva para que pudiéramos replicar más de cerca los resultados de la prueba retrospectiva del autor, así como determinar su aplicabilidad en los pares de divisas. Además, sería extremadamente útil si el EA pudiera publicar texto en el gráfico mientras se está ejecutando.


Yo también creo que es un gran artículo y el plan para estudiarlo a fondo en previsión de la adaptación de sus técnicas a otras EAs


CapeCoddah

 
//+------------------------------------------------------------------+
//| Clase base para todos los algoritmos de ejecución|
//+------------------------------------------------------------------+
class CExecutionAlgorithm
{
protected:
   string            m_symbol;           // Símbolo comercial
   double            m_totalVolume;      // Volumen total a ejecutar
   double            m_executedVolume;   // Volumen ya ejecutado
   double            m_remainingVolume;  // Volumen restante por ejecutar
   datetime          m_startTime;        // Hora de inicio de la ejecución
   datetime          m_endTime;          // Hora final de ejecución
   int               m_slippage;         // Deslizamiento permitido en puntos
   bool              m_isActive;         // ¿Está activo el algoritmo?
   
   // Estadísticas
   double            m_avgExecutionPrice; // Precio medio de ejecución
   int               m_totalOrders;       // Número total de pedidos realizados
   int               m_filledOrders;      // Número de pedidos ejecutados
   
public:
   // Constructor
   CExecutionAlgorithm(string symbol, double volume, datetime startTime, datetime endTime, int slippage);
   
   // Destructor
   virtual ~CExecutionAlgorithm();
   
   // Métodos virtuales a implementar por las clases derivadas
   virtual bool      Initialize();
   virtual bool      Execute() = 0;
   virtual bool      Update() = 0;
   virtual bool      Terminate() = 0;
   
   // Métodos comunes
   bool              IsActive() { return m_isActive; }
   double            GetExecutedVolume() { return m_executedVolume; }
   double            GetRemainingVolume() { return m_remainingVolume; }
   double            GetAverageExecutionPrice() { return m_avgExecutionPrice; }
   
   // Métodos auxiliares
   bool              PlaceOrder(ENUM_ORDER_TYPE orderType, double volume, double price = 0.0);
   bool              ModifyOrder(ulong ticket, double price, double sl, double tp);
   bool              CancelOrder(ulong ticket);
   void              UpdateAverageExecutionPrice(double price, double volume);
   
   // Método auxiliar para obtener el modo de llenado apropiado
   ENUM_ORDER_TYPE_FILLING GetFillingMode();
};

//+------------------------------------------------------------------+
//| Constructor|
//+------------------------------------------------------------------+
CExecutionAlgorithm::CExecutionAlgorithm(string symbol, double volume, 
                                       datetime startTime, datetime endTime, 
                                       int slippage)
{
   m_symbol = symbol;
   m_totalVolume = volume;
   m_executedVolume = 0.0;
   m_remainingVolume = volume;
   m_startTime = startTime;
   m_endTime = endTime;
   m_slippage = slippage;
   m_isActive = false;
   
   m_avgExecutionPrice = 0.0;
   m_totalOrders = 0;
   m_filledOrders = 0;
}

//+------------------------------------------------------------------+
//| Destructor|
//+------------------------------------------------------------------+
CExecutionAlgorithm::~CExecutionAlgorithm()
{
   // Limpiar los recursos si es necesario
}

//+------------------------------------------------------------------+
//| Inicializar el algoritmo|
//+------------------------------------------------------------------+
bool CExecutionAlgorithm::Initialize()
{
   // Validar entradas
   if(m_symbol == "" || m_totalVolume <= 0.0)
   {
      Print("Invalid inputs for execution algorithm");
      return false;
   }
   
   // Comprobar si el símbolo existe
   if(!SymbolSelect(m_symbol, true))
   {
      Print("Symbol not found: ", m_symbol);
      return false;
   }
   
   // Restablecer estadísticas
   m_executedVolume = 0.0;
   m_remainingVolume = m_totalVolume;
   m_avgExecutionPrice = 0.0;
   m_totalOrders = 0;
   m_filledOrders = 0;
   
   return true;
}

//+------------------------------------------------------------------+
//| Obtener el modo de relleno apropiado para el símbolo |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_FILLING CExecutionAlgorithm::GetFillingMode()
{
   // Obtener modos de llenado de símbolos
   int filling_modes = (int)SymbolInfoInteger(m_symbol, SYMBOL_FILLING_MODE);
   
   // Compruebe los modos de llenado disponibles por orden de preferencia
   if((filling_modes & SYMBOL_FILLING_FOK) == SYMBOL_FILLING_FOK)
      return ORDER_FILLING_FOK;
   else if((filling_modes & SYMBOL_FILLING_IOC) == SYMBOL_FILLING_IOC)
      return ORDER_FILLING_IOC;
   else
      return ORDER_FILLING_RETURN;
}

//+------------------------------------------------------------------+
//| Hacer un pedido|
//+------------------------------------------------------------------+
bool CExecutionAlgorithm::PlaceOrder(ENUM_ORDER_TYPE orderType, double volume, double price = 0.0)
{
   // Validar entradas
   if(volume <= 0.0)
   {
      Print("Invalid order volume");
      return false;
   }
   
   // Preparar la solicitud
   MqlTradeRequest request;
   MqlTradeResult result;
   ZeroMemory(request);
   
   request.symbol = m_symbol;
   request.volume = volume;
   request.type = orderType;
   request.deviation = m_slippage;
   request.magic = 123456; // Número mágico de identificación
   
   // Establecer la acción y el precio adecuados en función del tipo de orden
   if(orderType == ORDER_TYPE_BUY || orderType == ORDER_TYPE_SELL)
   {
      // Orden de mercado
      request.action = TRADE_ACTION_DEAL;
      request.type_filling = GetFillingMode();
      
      if(orderType == ORDER_TYPE_BUY)
         request.price = SymbolInfoDouble(m_symbol, SYMBOL_ASK);
      else
         request.price = SymbolInfoDouble(m_symbol, SYMBOL_BID);
   }
   else
   {
      // Orden pendiente
      request.action = TRADE_ACTION_PENDING;
      if(price <= 0.0)
      {
         Print("Price must be specified for pending orders");
         return false;
      }
      request.price = price;
   }
   
   // Enviar el pedido
   if(!OrderSend(request, result))
   {
      Print("OrderSend error: ", GetLastError());
      return false;
   }
   
   // Comprobar el resultado
   if(result.retcode != TRADE_RETCODE_DONE)
   {
      Print("OrderSend failed with code: ", result.retcode, " - ", result.comment);
      return false;
   }
   
   // Actualizar estadísticas
   m_totalOrders++;
   
   // Para las órdenes de mercado, actualizar inmediatamente las estadísticas de ejecución
   if(orderType == ORDER_TYPE_BUY || orderType == ORDER_TYPE_SELL)
   {
      m_filledOrders++;
      UpdateAverageExecutionPrice(request.price, volume);
      m_executedVolume += volume;
      m_remainingVolume -= volume;
   }
   
   Print("Order placed successfully. Ticket: ", result.order, " Volume: ", volume, " Price: ", request.price);
   
   return true;
}

//+------------------------------------------------------------------+
//| Modificar un pedido existente|
//+------------------------------------------------------------------+
bool CExecutionAlgorithm::ModifyOrder(ulong ticket, double price, double sl, double tp)
{
   // Preparar la solicitud
   MqlTradeRequest request;
   MqlTradeResult result;
   ZeroMemory(request);
   
   request.action = TRADE_ACTION_MODIFY;
   request.order = ticket;
   request.price = price;
   request.sl = sl;
   request.tp = tp;
   
   // Enviar la solicitud de modificación
   if(!OrderSend(request, result))
   {
      Print("OrderModify error: ", GetLastError());
      return false;
   }
   
   // Comprobar el resultado
   if(result.retcode != TRADE_RETCODE_DONE)
   {
      Print("OrderModify failed with code: ", result.retcode, " - ", result.comment);
      return false;
   }
   
   Print("Order modified successfully. Ticket: ", ticket);
   
   return true;
}

//+------------------------------------------------------------------+
//| Cancelar un pedido existente|
//+------------------------------------------------------------------+
bool CExecutionAlgorithm::CancelOrder(ulong ticket)
{
   // Preparar la solicitud
   MqlTradeRequest request;
   MqlTradeResult result;
   ZeroMemory(request);
   
   request.action = TRADE_ACTION_REMOVE;
   request.order = ticket;
   
   // Enviar la solicitud de anulación
   if(!OrderSend(request, result))
   {
      Print("OrderCancel error: ", GetLastError());
      return false;
   }
   
   // Comprobar el resultado
   if(result.retcode != TRADE_RETCODE_DONE)
   {
      Print("OrderCancel failed with code: ", result.retcode, " - ", result.comment);
      return false;
   }
   
   Print("Order cancelled successfully. Ticket: ", ticket);
   
   return true;
}

//+------------------------------------------------------------------+
//| Actualizar el precio medio de ejecución|
//+------------------------------------------------------------------+
void CExecutionAlgorithm::UpdateAverageExecutionPrice(double price, double volume)
{
   // Calcular el nuevo precio medio de ejecución
   if(m_executedVolume > 0.0)
   {
      // Media ponderada de los precios antiguos y nuevos
      m_avgExecutionPrice = (m_avgExecutionPrice * m_executedVolume + price * volume) / 
                           (m_executedVolume + volume);
   }
   else
   {
      // Primera ejecución
      m_avgExecutionPrice = price;
   }
}
//+------------------------------------------------------------------+