English Русский 中文 Deutsch 日本語 Português
preview
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

MetaTrader 5Trading | 21 enero 2025, 08:34
435 0
Clemence Benjamin
Clemence Benjamin

Secciones de interés:


        Introducción

        Es posible desarrollar un Asesor Experto basado en los indicadores disponibles. Hay dos formas que mencionaré en este artículo:

        1. La codificación de las condiciones del indicador en el algoritmo del Asesor Experto es eficiente y muy rápida, incluso en el Probador de Estrategia. Con este método, el EA opera sin necesidad de utilizar un indicador por separado.
        2. Otro enfoque es preparar un algoritmo de Asesor Experto que preste atención a los buffers del indicador. Si el búfer es Verdadero o Falso, el EA está programado para responder de una determinada manera. Hay dos archivos necesarios para que el sistema funcione en la plataforma MetaTrader 5: tanto el EA como el indicador deben existir en directorios específicos dentro de la ruta de la plataforma. Es un desafío publicar un EA que se ejecute en un indicador personalizado, ya que el sistema de validación no encontrará su indicador cuando intente publicar en la comunidad MQL5. Ciertamente lo probé y encontré errores, por lo que solo pude ejecutarlo en mi computadora sin publicar.

        Antes de continuar, debemos preparar nuestro indicador para el trabajo con el EA. Esto implica garantizar que nuestros buffers de indicadores estén bien organizados y comprender sus operaciones, de modo que sea más fácil desarrollar el concepto en un EA. Ambos enfoques mencionados anteriormente funcionan bien, cada uno con sus ventajas y desventajas, que analizaremos en el futuro. La principal ventaja de utilizar un indicador junto con el EA es que reduce la complejidad de escribir el algoritmo del EA. El desarrollador puede centrarse en algunas partes específicas del algoritmo ya que las condiciones ya están codificadas en el indicador.

        En la Parte 6, Trend Constraint V1.08 fue nuestro avance final, combinando dos integraciones importantes en un solo programa. Estamos contentos con este progreso, ya que ahora podemos acceder fácilmente a las señales en Telegram y WhatsApp. Sin embargo, hay algunas preguntas que debemos plantearnos:

        • Sí, ahora estamos recibiendo las señales, pero ¿son las mejores?
        • Podemos ejecutar operaciones, pero ¿cuándo debemos salir?

        Estas preguntas sólo pueden responderse revisando el gráfico para ver cómo se ha comportado históricamente el indicador y recodificando el código fuente para agregar nuevas funciones o mejorar el sistema actual. Para perfeccionar el sistema actual, propongo:

        1. Comprender el propósito de cada buffer lo más completamente posible.
        2. Reintroducir cruces de medias móviles para señales de entrada.
        3. Utilizar relaciones riesgo-recompensa para dibujar rectángulos: verde para ilustrar el rango objetivo de ganancias y rojo para el rango de pérdidas.

        Nuestro objetivo es diseñar el indicador para mostrar los conceptos de entrada y salida, permitiendo a los operadores seguirlos manualmente. Si una estrategia se puede ejecutar manualmente, también se puede automatizar. La relación riesgo-recompensa (Risk-Reward Ratio, RRR) ayuda a los traders a evaluar la rentabilidad potencial de una operación en relación con su riesgo. Discutiremos cómo delinear los niveles de salida potenciales incorporando nuevas características a nuestro indicador, incluida la fórmula para el RRR, que es:

         


        Relación riesgo-recompensa, fórmula.

        Donde:

        RRR es la relación riesgo-recompensa;
        La pérdida potencial es la cantidad que puede perder si el comercio o la inversión se mueve en su contra;
        La ganancia potencial es la cantidad que espera ganar si el comercio o la inversión se mueve a su favor.

        Por ejemplo:

        Supongamos que está considerando comprar una acción a $50. Establece su stop loss en $48 (lo que indica una pérdida potencial de $2 por acción) y establece un precio objetivo de $56 (lo que indica una ganancia potencial de $6 por acción). Cálculo de la relación riesgo-recompensa de la acción:

        • Pérdida potencial: $50 (precio de entrada) - $48 (stop loss) = $2
        • Ganancia potencial: $56 (precio objetivo) - $50 (precio de entrada) = $6

        Sustituyendo los valores en la fórmula: Relación riesgo-recompensa = 1/3

        En detalle, esto significa que por cada dólar que arriesgas, esperas ganar $3. Una relación más baja (por ejemplo, 1:1 o menos) indica un mayor riesgo en relación con la recompensa potencial, mientras que una relación más alta sugiere un escenario de riesgo-recompensa más favorable.

        Basándonos en el ejemplo anterior, aquí tenemos una ilustración que utiliza rectángulos: un rectángulo rojo para el riesgo y un rectángulo verde para la recompensa.

        Ilustración de la relación riesgo-recompensa


        Analicemos esto más a fondo en las siguientes secciones del artículo. Al final de este debate, nuestro objetivo es centrarnos en:

        1. Comprender la importancia de la gestión de riesgos en el trading algorítmico.
        2. Implementación de ratios riesgo-recompensa y sus fundamentos matemáticos.
        3. Desarrollo de estrategias de salida dinámicas para una gestión comercial óptima.
        4. Mejora de los indicadores visuales para una mejor toma de decisiones comerciales.
        5. Probar y validar el indicador para su aplicación en el mundo real.


        Identificación de las limitaciones del sistema actual

        Para avanzar en un sistema de indicadores con nuevas características, es importante revisar partes cruciales para identificar áreas en las que el sistema actual falla. Para lograr esto, he considerado dos técnicas según mi enfoque, que me guiarán en la identificación y solución de problemas. Estos son:

        1. Revisar el gráfico: Esto implica revisar el historial de la ventana del gráfico del indicador, tomar nota de su presentación e identificar cualquier anomalía.  
        2. Revisar el código: Esta es la segunda etapa; después de completar el paso 1, examinaremos las áreas del código relacionadas con los problemas identificados para solucionarlos.


        Revisando el gráfico

        Aquí hay una imagen del gráfico del índice Boom 500. Voy a resumir los problemas tal como los percibo en el gráfico:


        Índice Boom 500 M1


        • Del diagrama, (A) representa una vela en forma de pico. En este caso, la flecha se muestra debajo de la vela cuando debería estar encima de la vela. Este problema surge porque la flecha representa la zona de sobrecompra del RSI, que solo se produce después de que la vela se ha cerrado.
        • La función DRAW_LINE funciona bien y nos permite identificar nuevas tendencias al observar los cambios de color en la línea. Queremos que esto indique una operación de swing porque, normalmente, cuando el mercado cambia de dirección, suele moverse significativamente.
        • Las señales de flecha de compra azules representan una posible continuación de la tendencia y actualmente indican la zona de sobreventa del RSI en una tendencia alcista predominante. Recuerde que nuestro tema es restringir nuestras señales a la vela D1, el sentimiento del mercado. Si bien los niveles extremos del índice de fuerza relativa (RSI) pueden ser buenos para las entradas, generalmente indican la zona de mercado en lugar de una reversión garantizada. El mercado podría continuar prevaleciendo en la tendencia independientemente de los niveles del RSI. Sugiero reintroducir el cruce de media móvil para otras entradas para maximizar las ganancias, ya que esto generalmente se alinea bien con la acción del precio.
        • También imagino el beneficio de presentar rectángulos para que se dibujen las relaciones riesgo-recompensa cuando el indicador envía señales de entrada, como se mencionó durante la introducción. Esta nueva versión debe delinear con precisión los rectángulos para presentar correctamente los riesgos y las recompensas. Vea la idea transmitida en los gráficos a continuación: el primero es EURUSD y el segundo es Boom 500, consecutivamente.

        EURUSD, M1: Euro frente al dólar estadounidense

        EURUSD


        Índice Boom 500, M1:

        BOOM 500 ÍNDICE M1

        En estos diagramas podemos observar claramente el nuevo enfoque. Queremos preparar nuestro código indicador para reflejar exactamente lo que se demostró manualmente. Según varios analistas técnicos y traders, los pivotes han sido tradicionalmente respetados como objetivos para tomar ganancias y detener pérdidas. Por lo tanto, la idea de una relación riesgo-recompensa de 1:3 puede resultar inaplicable en escenarios como los que se muestran en el gráfico, donde a veces el riesgo es mucho mayor que el beneficio potencial.

        En resumen, de las ilustraciones anteriores:

        1. Los pivotes se utilizan como puntos de referencia para establecer puntos de salida, incluidos el stop loss y el take profit.
        2. Los precios de los niveles de entrada y salida se pueden utilizar más adelante en la lógica.  

        En la siguiente sección, examinaremos las áreas críticas del código y las abordaremos.


        Revisando el código:

        Aquí hay un fragmento donde podemos realizar cambios:
        #property indicator_type1 DRAW_ARROW
        #property indicator_width1 5
        #property indicator_color1 0xFF3C00
        #property indicator_label1 "Buy" // We are going to change it to "Buy Zone"
        
        #property indicator_type2 DRAW_ARROW
        #property indicator_width2 5
        #property indicator_color2 0x0000FF
        #property indicator_label2 "Sell"// We are going to change it to "Sell Zone"


        En esta sección del programa fijamos la posición de la flecha en la vela. Implica la función de iteración del Buffer 2. El indicador debe mostrarse en el máximo de la vela, por lo que cambiaremos de Low[i] a High[i];

        //Indicator Buffer 2 // We are going to set the indicator to display at candlestick high by changing the highlighted text to High[i]
              if(RSI[i] > Overbought
              && RSI[i+1] < Overbought //Relative Strength Index crosses above fixed value
              && Open[barshift_M1[i]] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close
              && MA[i] < MA2[i] //Moving Average < Moving Average
              && MA3[i] < MA4[i] //Moving Average < Moving Average
              )
        
                {
                 Buffer2[i] = Low[i]; //Set indicator value at Candlestick Low // change to High[i]
                 if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell Zone"); //Alert on next bar open
                 time_alert = Time[1];
                }
              else
                {
                 Buffer2[i] = EMPTY_VALUE;
                }



        Incorporando el cruce de medias móviles:

        Analicemos los fragmentos de código a continuación para descubrir el proceso de agregar una nueva función a nuestro programa. Además de los buffers existentes, agregaremos dos nuevos, que serán Buffer 6 y Buffer 7.

        Según la lógica de nuestro programa inteligente, comenzaremos definiendo sus propiedades. Dado que recientemente adoptamos 'Zona de venta' y 'Zona de compra' para el indicador RSI, estas serán las nuevas señales de 'Venta' y 'Compra' para el indicador.

        #property indicator_type6 DRAW_ARROW
        #property indicator_width6 1
        #property indicator_color6 0x0000FF
        #property indicator_label6 "Sell"
        
        #property indicator_type7 DRAW_ARROW
        #property indicator_width7 1
        #property indicator_color7 0xFFAA00
        #property indicator_label7 "Buy"

        Necesitamos configurar entradas para la personalización para optimizar las mejores señales. Utilizaremos una media móvil de 7 y una media móvil de 21.

        input int Entry_MA_fast = 7 ;
        input int Entry_MA_slow = 21 ;

        Aquí se muestra la función OnCalculate para las nuevas funciones. Se detalla cómo el programa mostrará los resultados cuando se cumplan las condiciones.

        SetIndexBuffer(5, Buffer6);
           PlotIndexSetDouble(5, PLOT_EMPTY_VALUE, EMPTY_VALUE);
           PlotIndexSetInteger(5, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
           PlotIndexSetInteger(5, PLOT_ARROW, 242);
           SetIndexBuffer(6, Buffer7);
           PlotIndexSetDouble(6, PLOT_EMPTY_VALUE, EMPTY_VALUE);
           PlotIndexSetInteger(6, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
           PlotIndexSetInteger(6, PLOT_ARROW, 241);


        Esta etapa incorpora las condiciones para el cruce de medias móviles. En este escenario, las condiciones del Buffer 7 reflejan las del Buffer 6. Básicamente, el proceso es el mismo pero invertido para cada buffer.

        //Indicator Buffer 6
              if(MA8[i] < MA9[i]
              && MA8[i+1] > MA9[i+1] //Moving Average crosses below Moving Average
              && Open2[i] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close
              )
                {
                 Buffer6[i] = High[i]; //Set indicator value at Candlestick High
                 if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell"); //Alert on next bar open
                 time_alert = Time[1];
                }
              else
                {
                 Buffer6[i] = EMPTY_VALUE;
                }
              //Indicator Buffer 7
              if(MA8[i] > MA9[i]
              && MA8[i+1] < MA9[i+1] //Moving Average crosses above Moving Average
              && Open2[i] >= Close[1+barshift_D1[i]] //Candlestick Open >= Candlestick Close
              )
                {
                 Buffer7[i] = Low[i]; //Set indicator value at Candlestick Low
                 if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy"); //Alert on next bar open
                 time_alert = Time[1];
                }
              else
                {
                 Buffer7[i] = EMPTY_VALUE;
                }


        Dibujar rectángulos

        Me lo he pasado bien trabajando con el código. Consideré desarrollar el programa existente modificando los buffers recientemente incorporados para incluir funcionalidad para colocar rectángulos que marquen las zonas de riesgo y ganancia. Además, comencé describiendo la lógica en papel sobre cómo se colocarán los objetos y qué buffers se asociarán con ellos, específicamente Buffer 6 y Buffer 7.

        Aquí está la lógica del documento antes de la implementación real:

         En un promedio de movimiento rápido, cruce por debajo de un promedio de movimiento lento: 

        Cuando las condiciones de Buffer7 son verdaderas, queremos que se coloque un rectángulo debajo del mínimo de la vela actual.
          • El ancho del rectángulo debe ser de 5 barras o más.
          • La altura del rectángulo es X pips hacia abajo; donde X es el número de pips.
          • El rectángulo debe ser verde.
          • Encima del rectángulo verde, cuando las condiciones de Buffer7 sean verdaderas, coloque un rectángulo rojo cuya altura sea 1/3 de la del rectángulo verde.
          • Todos los parámetros deben ser personalizables.

        En el cruce de la media móvil rápida por encima de la media móvil lenta, cuando las condiciones del Buffer 6 son verdaderas, queremos colocar un rectángulo por encima del máximo de la vela actual.

        A continuación las especificaciones son las siguientes:

          • El ancho del rectángulo debe ser de 5 barras o más.
          • La altura del rectángulo debe ser de X pips hacia arriba, donde X es el número de pips.
          • El rectángulo debe ser verde.
          • Debajo del rectángulo verde, cuando se cumplan las condiciones del Buffer 6, coloque un rectángulo rojo que tenga 1/3 de la altura del rectángulo verde.
          • Todos los parámetros deben ser personalizables.

        En primer lugar, necesitamos la capacidad de ingresar parámetros para la personalización. Aquí está el fragmento de código que muestra la incorporación:

        //--- new inputs for rectangles
        input int RectWidth = 5;                 // Width of the rectangle in bars
        input int RectHeightPointsBuy = 50;      // Height of the profit rectangle in points for Buy
        input int RectHeightPointsSell = 50;     // Height of the profit rectangle in points for Sell
        input color ProfitRectColor = clrGreen;  // Color of the profit rectangle
        input color RiskRectColor = clrRed;      // Color of the risk rectangle
        
        De forma predeterminada, he establecido los puntos en 50, pero estos se pueden ajustar para adaptarse a sus necesidades y objetivos de ganancias. También he incluido una función que ajusta automáticamente la altura del rectángulo de riesgo en relación con el objetivo de beneficio. Esto es importante porque permite que el indicador se adapte a cualquier cambio de color de fondo. Por ejemplo, si utiliza un fondo de gráfico verde, el rectángulo verde podría mezclarse y volverse invisible, mientras que un fondo amarillo proporcionaría un mejor contraste. La personalización es crucial para garantizar un control total sobre nuestras herramientas.


        Ahora, examinemos la función OnCalculate para ver cómo funciona la iteración.

        if(RSI[i] > Overbought) {
                if(close[i] > MA[i])
                    Buffer6[i] = close[i] - pips * myPoint;
            }
        
            if(RSI[i] < Oversold) {
                if(close[i] < MA[i])
                    Buffer7[i] = close[i] + pips * myPoint;
            }
        
            if(Buffer6[i] > 0) {
                Buffer1[i] = close[i] - pips * myPoint;
                Buffer3[i] = close[i] - pips * myPoint;
                if (Buffer6[i - 1] < 0) {
                    myAlert("indicator", "Sell Signal Detected!");
                    if (Audible_Alerts)
                        Alert(Symbol(), " ", Period(), ": Sell Signal Detected!");
        
                    // Create profit rectangle for Sell
                    double highProfitRect = close[i];
                    double lowProfitRect = close[i] - RectHeightPointsSell * myPoint;
                    string profitRectName = "SellProfitRect" + IntegerToString(i);
                    if (ObjectFind(0, profitRectName) != 0) {
                        ObjectCreate(0, profitRectName, OBJ_RECTANGLE, 0, time[i], highProfitRect, time[i + RectWidth], lowProfitRect);
                        ObjectSetInteger(0, profitRectName, OBJPROP_COLOR, ProfitRectColor);
                        ObjectSetInteger(0, profitRectName, OBJPROP_STYLE, STYLE_SOLID);
                        ObjectSetInteger(0, profitRectName, OBJPROP_WIDTH, 2);
                    }
        
                    // Create risk rectangle for Sell
                    double highRiskRect = close[i];
                    double lowRiskRect = close[i] + (RectHeightPointsSell / 3) * myPoint;
                    string riskRectName = "SellRiskRect" + IntegerToString(i);
                    if (ObjectFind(0, riskRectName) != 0) {
                        ObjectCreate(0, riskRectName, OBJ_RECTANGLE, 0, time[i], highRiskRect, time[i + RectWidth], lowRiskRect);
                        ObjectSetInteger(0, riskRectName, OBJPROP_COLOR, RiskRectColor);
                        ObjectSetInteger(0, riskRectName, OBJPROP_STYLE, STYLE_SOLID);
                        ObjectSetInteger(0, riskRectName, OBJPROP_WIDTH, 2);
                    }
                }
            }
        
            if(Buffer7[i] > 0) {
                Buffer2[i] = close[i] + pips * myPoint;
                Buffer4[i] = close[i] + pips * myPoint;
                if (Buffer7[i - 1] < 0) {
                    myAlert("indicator", "Buy Signal Detected!");
                    if (Audible_Alerts)
                        Alert(Symbol(), " ", Period(), ": Buy Signal Detected!");
        
                    // Create profit rectangle for Buy
                    double highProfitRect = close[i] + RectHeightPointsBuy * myPoint;
                    double lowProfitRect = close[i];
                    string profitRectName = "BuyProfitRect" + IntegerToString(i);
                    if (ObjectFind(0, profitRectName) != 0) {
                        ObjectCreate(0, profitRectName, OBJ_RECTANGLE, 0, time[i], highProfitRect, time[i + RectWidth], lowProfitRect);
                        ObjectSetInteger(0, profitRectName, OBJPROP_COLOR, ProfitRectColor);
                        ObjectSetInteger(0, profitRectName, OBJPROP_STYLE, STYLE_SOLID);
                        ObjectSetInteger(0, profitRectName, OBJPROP_WIDTH, 2);
                    }
        
                    // Create risk rectangle for Buy
                    double highRiskRect = close[i] - (RectHeightPointsBuy / 3) * myPoint;
                    double lowRiskRect = close[i];
                    string riskRectName = "BuyRiskRect" + IntegerToString(i);
                    if (ObjectFind(0, riskRectName) != 0) {
                        ObjectCreate(0, riskRectName, OBJ_RECTANGLE, 0, time[i], highRiskRect, time[i + RectWidth], lowRiskRect);
                        ObjectSetInteger(0, riskRectName, OBJPROP_COLOR, RiskRectColor);
                        ObjectSetInteger(0, riskRectName, OBJPROP_STYLE, STYLE_SOLID);
                        ObjectSetInteger(0, riskRectName, OBJPROP_WIDTH, 2);
                    }
                }
            
        

        Aquí es donde se lleva a cabo la creación de rectángulos:

        Rectángulos de beneficio:

        • Para las señales de venta, un rectángulo verde se extiende hacia abajo desde el precio de cierre.
        • Para las señales de compra, un rectángulo verde se extiende hacia arriba desde el precio de cierre.


        Rectángulos de riesgo:

          • Para las señales de venta, un rectángulo rojo se extiende hacia arriba desde el precio de cierre, con una altura de 1/3 del rectángulo de ganancias.
          • Para las señales de compra, un rectángulo rojo se extiende hacia abajo desde el precio de cierre, con una altura de 1/3 del rectángulo de ganancias.

        Ahora vamos a explicar brevemente las nuevas funciones que se están introduciendo:

        • ObjectFind: Función utilizada para comprobar si un objeto con un nombre específico ya existe en el gráfico.

        int ObjectFind(
           long   chart_id,   // Chart ID (0 means the current chart)
           string name        // Name of the object to search for
        );
        


        • ObjectCreate: Función utilizada para crear un nuevo objeto gráfico en el gráfico. Se puede especificar el tipo de objeto (por ejemplo, rectángulo, línea de tendencia, etc.).

        bool ObjectCreate(
           long    chart_id,   // Chart ID (0 means the current chart)
           string  name,       // Name of the object to create
           ENUM_OBJECT type,   // Type of the object (e.g., OBJ_RECTANGLE, OBJ_TREND, etc.)
           int     sub_window, // Number of the subwindow (0 means the main chart window)
           datetime time1,     // First coordinate time
           double  price1,     // First coordinate price
           ...                 // Additional coordinates depending on the object type
        );
        


        • ObjectSetInteger: Función utilizada para establecer propiedades enteras de un objeto gráfico, como el color, el estilo y la anchura.

        bool ObjectSetInteger(
           long   chart_id,     // Chart ID (0 means the current chart)
           string name,         // Name of the object
           int    prop_id,      // ID of the property to set (e.g., OBJPROP_COLOR, OBJPROP_STYLE, etc.)
           long   value         // Value of the property
        );
        

        Esta función devuelve un valor booleano;

        • true: Si la propiedad se establece correctamente.
        • false: Si la configuración de la propiedad falla.

        Por favor, para una explicación más profunda de estas funciones, no dude en consultar la documentación MQL5 que contiene toda la información sobre el lenguaje MQL5. 


        Introduciendo puntos de salida

        La introducción de puntos de salida es una mejora fundamental para Trend Constraint V1.08. Una estrategia de salida eficaz no sólo protege las ganancias y minimiza las pérdidas. Proponemos integrar puntos de salida predefinidos basados en niveles clave de soporte y resistencia, que son cruciales para identificar posibles zonas de reversión. La lógica de señal anterior solo involucraba el nombre del par, pero el nuevo refinamiento proporcionará todos los precios relevantes, incluidos Entrada, Stop Loss y Take Profit. Al utilizar estos niveles, los operadores pueden determinar puntos de salida donde es probable que el precio se revierta o encuentre una resistencia significativa, optimizando así su estrategia de salida.


        Aquí está el enfoque:

        Para modificar el programa para insertar líneas de precios a lo largo de rectángulos, agregaremos tres líneas en niveles de precios específicos:

        • El precio de la señal (precio de cierre de la señal), 
        • el objetivo de ganancias  
        • y el objetivo de riesgo. 

        Estas líneas se colocarán inmediatamente después de que se detecte la señal. También configuraremos alertas para notificar al usuario sobre estos niveles de precios específicos.

        Primero, definimos puntos de ganancia ypuntos de riesgo como entradas para hacerlas personalizables.

        input double profitPoints = 60; // Points for profit target
        input double riskPoints = 20;   // Points for risk target
        

        En este punto, permítanme presentarles funciones personalizadas para colocar líneas. El fragmento a continuación muestra la definición de estas funciones. Si es nuevo en MQL5, tenga en cuenta que void se utiliza para indicar que una función no devuelve un valor. 

        void CreatePriceLine(string name, color lineColor, double price, datetime time) {
            if (ObjectFind(0, name) == -1) {
                ObjectCreate(0, name, OBJ_HLINE, 0, time, price);
                ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor);
                ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
            } else {
                ObjectMove(0, name, 0, time, price);
            }
        }
        
        void PlaceSignalLines(double signalPrice, double profitTarget, double riskTarget, datetime time) {
            CreatePriceLine("SignalPriceLine", clrBlue, signalPrice, time);
            CreatePriceLine("ProfitTargetLine", clrGreen, profitTarget, time);
            CreatePriceLine("RiskTargetLine", clrRed, riskTarget, time);
        }
        


        Finalmente, aquí está la lógica para la detección de señales. Como puede ver, tenemos alertas para indicar niveles de precios cruciales, lo que ayudará al comerciante al ejecutar manualmente el programa. 

        void CheckSignalAndPlaceLines() {
            for (int i = rates_total - 2; i >= 0; i--) {
                if (Buffer6[i] != 0.0) { // Buy Signal Detected
                    double signalPrice = Close[i];
                    double profitTarget = signalPrice + profitPoints * Point;
                    double riskTarget = signalPrice - riskPoints * Point;
                    PlaceSignalLines(signalPrice, profitTarget, riskTarget, Time[i]);
                    Alert("Buy Signal: Signal Price = ", signalPrice, " Profit Target = ", profitTarget, " Risk Target = ", riskTarget);
                }
                if (Buffer7[i] != 0.0) { // Sell Signal Detected
                    double signalPrice = Close[i];
                    double profitTarget = signalPrice - profitPoints * Point;
                    double riskTarget = signalPrice + riskPoints * Point;
                    PlaceSignalLines(signalPrice, profitTarget, riskTarget, Time[i]);
                    Alert("Sell Signal: Signal Price = ", signalPrice, " Profit Target = ", profitTarget, " Risk Target = ", riskTarget);
                }
            }
        }
        


        En resumen, hemos realizado tres cambios importantes en nuestro programa, que describiré a continuación:

        1. Hemos perfeccionado Trend Constraint V1.08 y hemos incluido un cruce de medias móviles para las señales de entrada.
        2. Discutimos la incorporación de rectángulos para representar zonas de riesgo y ganancias.
        3. Además, discutimos la importancia de los puntos de salida en nuestro programa.

        Del resumen surge la posibilidad de tres versiones de nuestro programa a medida que continuamos perfeccionándolo. Ahora disponemos de Trend Constraint V1.09, V1.10 y V1.11. A continuación, procederemos a discutir el rendimiento y los resultados de las pruebas.


        Prueba y validación

        La prueba y compilación de la versión V1.09 fue un éxito, aunque se encontraron algunos problemas que se resolvieron por completo. Aquí hay algunas imágenes que muestran un panel con un lanzamiento exitoso, así como un resumen del generador de perfiles que detalla el rendimiento de la función en la CPU.


        Lanzamiento de Trend Constraint V1.09


        El resultado del perfil del probador:

        Perfilador de MetaEditor


        Antes de lograr el éxito mencionado, nos topamos con errores que posteriormente fueron solucionados. Me complace compartir cómo se desarrolló este proceso. Vea la imagen a continuación:


        Registro de errores


        Después de leer el registro de errores, resultó más fácil revisar el programa e identificar lo que faltaba. Al agregar el cruce de promedios móviles, también necesitábamos declarar MA8, MA9, MA_handle8 y MA_handle9 para los nuevos buffers junto con los existentes. El código siguiente muestra las declaraciones realizadas. Las líneas resaltadas indican las que causaron los errores.

        int RSI_handle;
        double RSI[];
        double Open[];
        double Close[];
        int MA_handle;
        double MA[];
        int MA_handle2;
        double MA2[];
        int MA_handle3;
        double MA3[];
        int MA_handle4;
        double MA4[];
        double Low[];
        double High[];
        int MA_handle5;
        double MA5[];
        int MA_handle6;
        double MA6[];
        int MA_handle7;
        double MA7[];
        int MA_handle8;
        double MA8[];
        int MA_handle9;
        double MA9[];
        double Open2[];

        Después de agregar las declaraciones resaltadas, el programa se compiló exitosamente.

        Pasando a la versión 1.10, el programa se compiló correctamente después de incorporar rectángulos, pero no aparece nada en el gráfico. Es difícil determinar dónde nos perdimos algo, por lo que continuaremos depurando línea por línea hasta que se resuelva el problema y compartiremos los hallazgos en los próximos escritos.

        V1.11 encontró errores de compilación y compartiré todo el proceso de resolución en el próximo escrito.

        Un resumen de los buffers en el programa es importante para el desarrollo de EA, ya que nos ayuda a comprender qué buffer realiza las condiciones necesarias. Vea la tabla a continuación.

        Buffer Descripción
        Buffer1. Este buffer se utiliza para identificar si el RSI cruza por encima de un valor fijo (sobrecompra), el precio de apertura actual es mayor o igual al precio de cierre de una barra específica, dos promedios móviles (MA y MA3) son ambos mayores que sus respectivos promedios móviles de comparación (MA2 y MA4), y marcan una "Zona de compra" en el gráfico.
        Buffer2.
        Este buffer se utiliza para identificar si el RSI cruza por encima de un valor fijo (sobrecompra), el precio de apertura actual es menor o igual al precio de cierre de una barra específica, dos promedios móviles (MA y MA3) son menores que sus respectivos promedios móviles de comparación (MA2 y MA4), y marcan una "Zona de venta" en el gráfico.
        Buffer3.
        Este buffer se utiliza para identificar si MA5 cruza por encima de MA6 y marcar un "Buy Swing" en el gráfico.
        Buffer4.
        Este buffer se utiliza para identificar si MA5 cruza por debajo de MA6 y marcar un "Sell Swing" en el gráfico.
        Buffer5.
        Este búfer rastrea si MA3 es mayor que MA7.
        Buffer6.
        Este buffer se utiliza para identificar si MA8 cruza por debajo de MA9 y marcar una "Venta" en el gráfico.
        Buffer7.
        Este buffer se utiliza para identificar si MA8 cruza por encima de MA9 y marcar una "Compra" en el gráfico.
        Buffer8.  Este búfer rastrea si MA3 es menor que MA7.


        Conclusión

        En conclusión, el desarrollo y perfeccionamiento de Trend Constraint representa un avance significativo en el trading algorítmico. Al abordar las limitaciones del sistema actual e introducir puntos de salida estratégicos, pretendemos crear un indicador más sólido y eficaz. La incorporación de niveles de stop loss y take profit, junto con representaciones visuales mejoradas, garantiza que el indicador sea fácil de usar y adaptable a las condiciones cambiantes del mercado. Estas funciones ahora proporcionan una representación visual clara de los posibles resultados comerciales, lo que ayuda a tomar mejores decisiones.

        A través de rigurosas pruebas y validaciones, hemos demostrado la confiabilidad y eficacia del indicador. Aunque encontramos errores, persistimos y, mediante una investigación exhaustiva, los resolvimos. Utilizaremos la documentación y colaboraremos con la comunidad de desarrolladores para resolver los problemas que queden pendientes.

        En general, Trend Constraint mejorado ofrece una solución completa para los operadores que buscan navegar por las complejidades de los mercados financieros con confianza y precisión. Sus funciones avanzadas y su enfoque estratégico para la gestión de riesgos y la optimización de ganancias lo convierten en una valiosa adición al conjunto de herramientas de cualquier operador.

        A continuación se adjuntan los archivos para un mayor desarrollo en sus proyectos. ¡Feliz desarrollo!

        Nombre del archivo Descripción
        Trend Constraint V1.09 Programa perfeccionado con señales de cruce MA.
        Trend Constraint V1.10 Programa avanzado con funciones de dibujo de objetos. Todavía en la etapa de depuración.


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

        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.
        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
        Aprenda a importar y utilizar bibliotecas EX5 en su código o proyectos MQL5. En este artículo de continuación, ampliaremos la biblioteca EX5 agregando más funciones de gestión de posiciones a la biblioteca existente y creando dos Asesores Expertos. El primer ejemplo utilizará el indicador técnico de promedio dinámico de índice variable para desarrollar un asesor experto en estrategia comercial de trailing stop, mientras que el segundo ejemplo utilizará un panel comercial para monitorear, abrir, cerrar y modificar posiciones. Estos dos ejemplos demostrarán cómo utilizar e implementar la biblioteca de gestión de posiciones EX5 actualizada.
        Características del Wizard MQL5 que debe conocer (Parte 29): Continuación sobre las tasas de aprendizaje con MLP Características del Wizard MQL5 que debe conocer (Parte 29): Continuación sobre las tasas de aprendizaje con MLP
        Concluimos nuestro análisis de la sensibilidad de la tasa de aprendizaje al rendimiento de los Asesores Expertos examinando principalmente las Tasas de Aprendizaje Adaptativo. Estas tasas de aprendizaje pretenden personalizarse para cada parámetro de una capa durante el proceso de entrenamiento, por lo que evaluamos los beneficios potenciales frente al peaje de rendimiento esperado.
        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.