English Русский 中文 Deutsch 日本語 Português
preview
Métodos de William Gann (Parte I): Creación del indicador de ángulos de Gann

Métodos de William Gann (Parte I): Creación del indicador de ángulos de Gann

MetaTrader 5Trading |
384 18
Yevgeniy Koshtenko
Yevgeniy Koshtenko

Introducción

William Delbert Gann es un legendario comerciante y analista técnico cuyos innovadores métodos de análisis de mercado aún atraen el interés de los comerciantes modernos. Una de las herramientas clave en el arsenal de Gann eran sus famosos ángulos, utilizados para pronosticar los movimientos de precios e identificar posibles niveles de soporte y resistencia.

En este artículo, nos sumergiremos en el mundo de los métodos de trading de William Gann, empezando por la creación del indicador ángulos de Gann en MQL5. Repasaremos la teoría detrás de esta herramienta y la implementaremos paso a paso como un indicador personalizado para la plataforma MetaTrader 5.

Tanto si es usted un operador experimentado en busca de nuevas herramientas de análisis como si es un principiante que desea ampliar su arsenal de indicadores técnicos, este artículo le ayudará a comprender mejor y a aplicar en sus operaciones uno de los métodos más intrigantes de William Gann.


Historia de la creación de ángulos de Gann

William Delbert Gann (1878-1955) desarrolló su sistema de ángulos a principios del siglo XX basándose en años de investigación sobre los movimientos del mercado y en su comprensión única de la relación entre tiempo y precio.

Gann creía que los mercados se movían según patrones geométricos predecibles y que estos movimientos podían predecirse mediante una combinación de matemáticas, geometría y astrología. Desarrolló el concepto de ángulos, que son líneas diagonales en un gráfico que reflejan el equilibrio perfecto entre el tiempo y el movimiento de los precios.

La clave de la teoría de Gann era la idea de que un ángulo de 45 grados (conocido como ángulo 1x1) representaba el equilibrio perfecto entre tiempo y precio. Creía que cuando el precio sube o baja en este ángulo, indica una tendencia equilibrada y estable.

Gann también desarrolló otros ángulos como 2x1, 3x1, 4x1 y sus recíprocos que representan diferentes relaciones entre el tiempo y el precio. Estos ángulos se convirtieron en la base de su sistema de negociación y análisis del mercado.

Si bien algunos aspectos del trabajo de Gann siguen siendo controvertidos, sus métodos, incluidos los ángulos de Gann, continúan atrayendo la atención de comerciantes y analistas de todo el mundo y siguen siendo relevantes en el trading moderno.


La teoría del ángulo de Gann y su importancia en el análisis técnico

La teoría de los ángulos de Gann se basa en el concepto de que los movimientos del mercado siguen patrones geométricos predecibles que pueden identificarse mediante trazados de ángulos especiales en un gráfico. La teoría se basa en la idea de un equilibrio entre tiempo y precio, donde un ángulo de 1x1 (45 grados) representa un equilibrio perfecto, suponiendo un cambio de precio de una unidad por periodo de tiempo.

Gann desarrolló un sistema de diferentes ángulos como 2x1, 3x1, 4x1 y sus recíprocos, cada uno de los cuales refleja una relación específica entre el tiempo y el movimiento del precio. Estos ángulos sirven como niveles dinámicos de soporte y resistencia, ayudando a los operadores a determinar la fuerza y la dirección de una tendencia. Los ángulos más pronunciados indican una tendencia más fuerte, mientras que los ángulos más planos indican un movimiento más débil.


Principios básicos de la construcción de ángulos de Gann


La construcción de ángulos de Gann se basa en varios principios clave que permiten a los traders utilizar eficazmente esta herramienta en el análisis técnico. La elección del punto de partida (que suele ser un mínimo o máximo significativo en el gráfico) es de importancia primordial. Es a partir de este punto que comienza la construcción de ángulos.

Se considera que el ángulo base es el ángulo 1x1 que forma una línea de 45 grados en el gráfico. Este ángulo refleja el equilibrio perfecto entre tiempo y precio, donde el precio cambia en una unidad en un período de tiempo. Otros ángulos, como 2x1, 3x1, 4x1 y sus recíprocos, se construyen en relación a este ángulo base.

Al trazar un gráfico, es importante tener en cuenta la escala del mismo. Los comerciantes a menudo utilizan plantillas o herramientas especiales para garantizar ángulos precisos. Las líneas de ángulo continúan hacia el futuro, lo que permite pronosticar posibles niveles de soporte y resistencia.


Tipos de ángulos de Gann y su interpretación

William Gann desarrolló un sistema de ángulos, cada uno con su propio significado e interpretación únicos en el análisis técnico. 1x1, o 45 grados, se considera el ángulo principal, que refleja el equilibrio entre el tiempo y el precio. Este ángulo sirve como guía básica para evaluar la fuerza de la tendencia.

El ángulo 2x1 (63,75 grados) indica un movimiento de precio más fuerte donde el precio aumenta el doble de rápido que el tiempo. Esto a menudo se interpreta como una señal de una fuerte tendencia alcista. Por el contrario, un ángulo de 1x2 (26,25 grados) indica un aumento de precio más lento en relación con el tiempo, lo que puede indicar una tendencia de debilitamiento.

Los ángulos 3x1 (71,25 grados) y 4x1 (75 grados) representan una acción del precio aún más agresiva y suelen estar asociados con tendencias muy fuertes o un posible sobrecalentamiento del mercado. Sus recíprocos, 1x3 (18,75 grados) y 1x4 (15 grados), pueden indicar una fuerte resistencia o soporte.

La interpretación de los ángulos de Gann no se limita únicamente a su pendiente. También es importante considerar cómo interactúa el precio con estas líneas. Un precio que cruza la línea del ángulo puede indicar un posible cambio de tendencia. Si el precio se mueve a lo largo de la línea del ángulo, a menudo se interpreta como una confirmación de la fuerza de la tendencia actual.


Aplicación práctica de los ángulos de Gann en el trading

Los comerciantes utilizan estas herramientas para una variedad de propósitos, desde identificar tendencias hasta elegir puntos de entrada y salida para las posiciones.

Para determinar una tendencia, generalmente se comienza trazando un ángulo de 1x1 a partir de un mínimo o máximo significativo. Si el precio se mueve por encima de esta línea, se interpreta como una tendencia alcista, y si está por debajo, como una tendencia bajista. Se utilizan ángulos más pronunciados, como 2x1 o 3x1, para confirmar la fuerza de la tendencia.

Al elegir puntos de entrada, muchos traders buscan momentos en los que el precio rebote o rompa la línea del ángulo de Gann. Por ejemplo, un rebote en la línea 1x1 en la dirección de la tendencia puede verse como una oportunidad potencial para ingresar en una posición.

Para la gestión de riesgos, a menudo se utilizan ángulos de Gann para establecer los límites de pérdidas. Un comerciante puede colocar un stop loss justo debajo de la línea de ángulo más cercana para una posición larga o justo encima de ella para una posición corta.

En el trading a largo plazo, los ángulos de Gann ayudan a determinar la dirección general del mercado. Podemos utilizar ángulos más superficiales, como 1x2 o 1x4, para evaluar tendencias a largo plazo y tomar decisiones estratégicas.


Ejemplos de estrategias comerciales que utilizan ángulos de Gann

Los ángulos de Gann brindan a los operadores una amplia gama de opciones para crear una variedad de estrategias comerciales. A continuación se muestran algunos ejemplos de cómo se pueden utilizar de forma eficaz en el trading real.

La estrategia de rebote angular se basa en el supuesto de que las líneas angulares de Gann suelen actuar como niveles de soporte o resistencia. Un operador busca situaciones en las que el precio se acerca a una línea de ángulo de Gann (especialmente 1x1 o 2x1) y rebota en ella. La entrada en una posición se lleva a cabo tras la confirmación de un rebote, por ejemplo, la formación de un patrón de inversión de velas.

Otra estrategia popular es el ángulo de ruptura. En este caso, el operador espera a que el precio atraviese una línea angular de Gann importante, especialmente si esto va acompañado de un aumento del volumen de operaciones. Una ruptura al alza puede indicar una posible posición larga, mientras que una ruptura a la baja puede indicar una posición corta.

La estrategia de abanico de Gann utiliza múltiples ángulos que irradian desde un único punto para formar una estructura en forma de abanico. El operador analiza cómo interactúa el precio con las distintas líneas de abanico, y lo utiliza para determinar los niveles de soporte y resistencia y los posibles puntos de inversión.

La combinación de ángulos y ciclos temporales es una estrategia más compleja en la que el operador combina los ángulos de Gann con el concepto de ciclos temporales, también desarrollado por Gann. Aquí se analizan los puntos de intersección de las líneas temporales importantes con los ángulos de Gann para determinar los momentos críticos para entrar o salir del mercado.

La estrategia de marcos temporales múltiples consiste en analizar los ángulos de Gann en diferentes marcos temporales. Por ejemplo, un operador puede utilizar un ángulo de 1x1 en un gráfico diario para determinar la tendencia general y, a continuación, cambiar a un gráfico horario para buscar puntos de entrada utilizando ángulos más pronunciados.


Creación del indicador ángulos de Gann en MQL5: Pasos básicos


La creación de un indicador de ángulos de Gann en MQL5 implica varios pasos clave. Este proceso requiere una comprensión tanto de los principios de la construcción de ángulos de Gann como de las particularidades de la programación en el entorno MetaTrader 5.

El primer paso consiste en definir la estructura del indicador. Aquí fijamos los parámetros básicos, como el nombre del indicador, los parámetros de entrada para fijar los ángulos y las bibliotecas necesarias.

La lógica principal para construir los ángulos de Gann se encuentra en la función OnCalculate(). Aquí definimos el punto de partida para trazar los ángulos, calculamos las coordenadas de cada ángulo y dibujamos las líneas en el gráfico.

Un aspecto importante es el cálculo correcto de las coordenadas de los ángulos, teniendo en cuenta la escala de la carta y el intervalo de tiempo seleccionado. Esto requiere un enfoque matemático preciso y una comprensión de la geometría de los ángulos de Gann.

La última etapa consiste en probar y depurar el indicador. Es necesario comprobar la validez de la construcción de ángulos en diferentes plazos e instrumentos.


Estructura del código del indicador

Aquí está el código básico del indicador Ángulos de Gann que se puede utilizar en MetaTrader 5:

#property copyright "Copyright 2024, Evgeniy Shtenco"
#property link      "https://www.mql5.com/en/users/koshtenko"
#property version   "1.00"
#property indicator_chart_window

// Input parameters
input datetime StartDate = D'2023.01.01 00:00'; // Start date for analysis
input datetime EndDate = D'2023.12.31 23:59';   // End date for analysis
input color GannFanColor = clrBlue;             // Color for Gann Fan lines

// Global variables
double extremumPrice;
datetime extremumTime;
double oppositeExtremumPrice;
datetime oppositeExtremumTime;
bool isTrendUp;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    ObjectsDeleteAll(0, "GannFan_");
    ObjectsDeleteAll(0, "OppositeGannFan_");
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
    if(rates_total < 1) return(0);

    // Clear previous objects
    if (prev_calculated == 0)
    {
        ObjectsDeleteAll(0, "GannFan_");
        ObjectsDeleteAll(0, "OppositeGannFan_");
    }

    // Find extremums within the specified date range
    FindExtremums(rates_total, high, low, time);

    // Draw Gann Fans
    DrawGannFan(extremumPrice, extremumTime);
    DrawOppositeGannFan(oppositeExtremumPrice, oppositeExtremumTime);

    return(rates_total);
}

//+------------------------------------------------------------------+
//| Find both extremums within the specified date range              |
//+------------------------------------------------------------------+
void FindExtremums(const int rates_total, const double &high[], const double &low[], const datetime &time[])
{
    int startIndex = -1;
    int endIndex = -1;

    for (int i = 0; i < rates_total; i++)
    {
        if (time[i] >= StartDate && startIndex == -1)
        {
            startIndex = i;
        }
        if (time[i] <= EndDate)
        {
            endIndex = i;
        }
    }

    if (startIndex == -1 || endIndex == -1 || startIndex > endIndex)
    {
        Print("Error: Invalid date range or no data available in the specified range");
        return;
    }

    int highestIndex = ArrayMaximum(high, startIndex, endIndex - startIndex + 1);
    int lowestIndex = ArrayMinimum(low, startIndex, endIndex - startIndex + 1);

    // Determine the most recent extremum
    if (time[highestIndex] > time[lowestIndex])
    {
        extremumPrice = high[highestIndex];
        extremumTime = time[highestIndex];
        oppositeExtremumPrice = low[lowestIndex];
        oppositeExtremumTime = time[lowestIndex];
        isTrendUp = false;
    }
    else
    {
        extremumPrice = low[lowestIndex];
        extremumTime = time[lowestIndex];
        oppositeExtremumPrice = high[highestIndex];
        oppositeExtremumTime = time[highestIndex];
        isTrendUp = true;
    }
}

//+------------------------------------------------------------------+
//| Draw Gann Fan                                                    |
//+------------------------------------------------------------------+
void DrawGannFan(double extremum, datetime extremumTime)
{
    double angles[] = {82.5, 75, 71.25, 63.75, 45, 26.25, 18.75, 15, 7.5};
    string angleNames[] = {"1x8", "1x4", "1x3", "1x2", "1x1", "2x1", "3x1", "4x1", "8x1"};

    datetime endTime = extremumTime + PeriodSeconds() * 300;

    for(int i = 0; i < ArraySize(angles); i++)
    {
        string label = "GannFan_" + angleNames[i];
        double angle = angles[i];
        
        double priceShift = MathTan(angle * M_PI / 180.0) * 300 * _Point;
        double endPrice;
        
        if(isTrendUp)
        {
            endPrice = extremum + priceShift;
        }
        else
        {
            endPrice = extremum - priceShift;
            angle = -angle; // Invert the angle for a downtrend
        }

        if(ObjectCreate(0, label, OBJ_TREND, 0, extremumTime, extremum, endTime, endPrice))
        {
            ObjectSetInteger(0, label, OBJPROP_COLOR, GannFanColor);
            ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSetInteger(0, label, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, true);
            ObjectSetString(0, label, OBJPROP_TOOLTIP, "Gann Fan " + angleNames[i]);
        }
        else
        {
            Print("Failed to create Gann Fan line: ", GetLastError());
        }
    }
}

//+------------------------------------------------------------------+
//| Draw Opposite Gann Fan                                           |
//+------------------------------------------------------------------+
void DrawOppositeGannFan(double extremum, datetime extremumTime)
{
    double angles[] = {82.5, 75, 71.25, 63.75, 45, 26.25, 18.75, 15, 7.5};
    string angleNames[] = {"1x8", "1x4", "1x3", "1x2", "1x1", "2x1", "3x1", "4x1", "8x1"};

    datetime endTime = extremumTime + PeriodSeconds() * 300;

    for(int i = 0; i < ArraySize(angles); i++)
    {
        string label = "OppositeGannFan_" + angleNames[i];
        double angle = angles[i];
        
        double priceShift = MathTan(angle * M_PI / 180.0) * 300 * _Point;
        double endPrice;
        
        if(!isTrendUp) // Opposite trend
        {
            endPrice = extremum + priceShift;
        }
        else
        {
            endPrice = extremum - priceShift;
            angle = -angle; // Invert the angle for a downtrend
        }

        if(ObjectCreate(0, label, OBJ_TREND, 0, extremumTime, extremum, endTime, endPrice))
        {
            ObjectSetInteger(0, label, OBJPROP_COLOR, GannFanColor);
            ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSetInteger(0, label, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, true);
            ObjectSetString(0, label, OBJPROP_TOOLTIP, "Opposite Gann Fan " + angleNames[i]);
        }
        else
        {
            Print("Failed to create Opposite Gann Fan line: ", GetLastError());
        }
    }
}

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
    // Redraw objects when chart changes
    if(id == CHARTEVENT_CHART_CHANGE)
    {
        // Find extremums and redraw Gann Fans
        int rates_total = Bars(_Symbol, PERIOD_CURRENT);
        double high[], low[];
        datetime time[];
        ArraySetAsSeries(high, true);
        ArraySetAsSeries(low, true);
        ArraySetAsSeries(time, true);
        CopyHigh(_Symbol, PERIOD_CURRENT, 0, rates_total, high);
        CopyLow(_Symbol, PERIOD_CURRENT, 0, rates_total, low);
        CopyTime(_Symbol, PERIOD_CURRENT, 0, rates_total, time);
        
        FindExtremums(rates_total, high, low, time);
        DrawGannFan(extremumPrice, extremumTime);
        DrawOppositeGannFan(oppositeExtremumPrice, oppositeExtremumTime);
    }
}


Funciones principales y su finalidad

El código es un indicador de MetaTrader 5 que dibuja ángulos de abanico de Gann en el gráfico. A continuación se describe las funciones principales y su propósito:

  1. OnInit() es la función de inicialización del indicador. En este caso, simplemente devuelve un resultado de inicialización exitoso.
  2. OnDeinit() es una función de desinicialización que elimina todos los objetos creados por el indicador cuando se elimina del gráfico.
  3. OnCalculate() es la función principal del indicador. Se llama a cada tick. Borra objetos anteriores, encuentra extremos en un rango de fechas determinado y dibuja ángulos de Gann.
  4. FindExtremums() es una función para encontrar extremos (máximo y mínimo) de un precio en un rango de fechas determinado. Determina qué extremo es más reciente y establece la dirección de la tendencia.
  5. DrawGannFan() es una función para dibujar el abanico de Gann principal a partir del extremo encontrado. Crea líneas para nueve ángulos diferentes.
  6. DrawOppositeGannFan() es una función para dibujar el abanico de Gann opuesto desde otro extremo. También crea líneas para los nueve ángulos, pero en la dirección opuesta.
  7. OnChartEvent() es una función que responde a eventos de gráficos. En este caso, vuelve a dibujar los abanicos de Gann cuando cambia el gráfico.

El indicador utiliza entradas para establecer el rango de fechas de análisis (StartDate y EndDate) y el color de las líneas (GannFanColor). Encuentra precios extremos en este rango, determina la dirección de la tendencia y dibuja dos abanicos de Gann: uno del último extremo y el otro del opuesto. Cada abanico consta de nueve líneas correspondientes a diferentes ángulos de Gann (82,5°, 75°, 71,25°, 63,75°, 45°, 26,25°, 18,75°, 15° y 7,5°).

El código también incluye manejo de errores y actualización dinámica cuando el gráfico cambia, lo que lo hace bastante robusto y adaptable a diferentes condiciones del mercado. El uso de funciones MQL5, como ArrayMaximum() y ArrayMinimum(), garantiza un manejo eficiente de los datos.

Algoritmo de cálculo del ángulo de Gann

El algoritmo para calcular los ángulos de Gann en este indicador se basa en la construcción geométrica de líneas desde el punto extremo. Estos son los aspectos clave de este algoritmo:

  • Determinación de extremos: el indicador encuentra el precio máximo y mínimo en un rango de tiempo determinado. El último de estos extremos se utiliza como punto de partida para el abanico de Gann principal, y el anterior para el abanico opuesto.
  • Conjunto de ángulos: Se utiliza un conjunto de ángulos fijos: 82,5°, 75°, 71,25°, 63,75°, 45°, 26,25°, 18,75°, 15° y 7,5°. Estos ángulos corresponden a las razones de Gann tradicionales: 1x8, 1x4, 1x3, 1x2, 1x1, 2x1, 3x1, 4x1 y 8x1.
  • Cálculo del punto final: para cada ángulo, se calcula el punto final de la línea. El cálculo se basa en la ecuación:
endPrice = extremum + MathTan(angle * M_PI / 180.0) * 300 * Point
  • Aquí 300 es el número convencional de barras que se utilizan para construir la línea.
  • Inversión para una tendencia bajista: si la tendencia es bajista, el ángulo se invierte (cambia de signo) de modo que las líneas apuntan hacia abajo desde el punto extremo.
  • Construcción de línea: para cada ángulo, se crea un objeto de línea (OBJ_TREND) desde el punto extremo hasta el punto final calculado. Las líneas se extienden hacia la derecha para cubrir datos futuros.
  • Doble ventilador: el algoritmo se aplica dos veces: una para el ventilador principal desde el último extremo y la segunda para el ventilador opuesto desde el extremo inicial. Esto nos permite visualizar niveles potenciales de soporte y resistencia en ambos lados.
  • Actualización dinámica: cuando el gráfico cambia (por ejemplo, cuando llegan nuevos datos), el algoritmo recalcula los extremos y reconstruye los abanicos, lo que garantiza que el análisis esté actualizado.

El algoritmo nos permite visualizar los ángulos de Gann clásicos en un gráfico, proporcionando al trader una herramienta para analizar posibles niveles de soporte, resistencia y dirección de la tendencia. 


¿Es posible realizar trading de forma rentable?

¿Es posible realizar operaciones comerciales rentables utilizando ángulos de Gann? Esta pregunta no tiene una respuesta clara, pero con el enfoque adecuado es posible realizar operaciones comerciales rentables. La clave del éxito radica en el uso integral de esta herramienta.

Sin embargo, incluso con el análisis más cuidadoso y meticuloso, no hay que olvidarse de la gestión de riesgos. Esta es la piedra angular del trading rentable. Ningún método garantiza el éxito del 100%, por lo que la gestión adecuada del capital y del riesgo juegan un papel importante en la rentabilidad a largo plazo.


Perspectivas para la creación de un EA basado en ángulos de Gann


La creación de un EA basado en ángulos de Gann es una tarea interesante y prometedora para los desarrolladores de sistemas de trading algorítmico. Un EA de este tipo podría automatizar el análisis y el comercio utilizando los principios establecidos en la teoría de Gann.

La base para un EA de este tipo puede ser el indicador de ángulos de Gann ya implementado. El algoritmo del EA podría incluir el análisis de la interacción del precio con las líneas de Gann, determinando puntos de entrada y salida basados en la intersección de estas líneas, así como teniendo en cuenta factores adicionales como el volumen de negociación y la volatilidad del mercado.

Una de las principales ventajas de un sistema automatizado basado en los ángulos de Gann sería eliminar el factor emocional del proceso de toma de decisiones de negociación. El EA podría seguir estrictamente la estrategia dada, sin ceder al miedo o la codicia, que a menudo influyen en las decisiones de un operador humano.

Sin embargo, el desarrollo de una EA de este tipo se enfrenta a una serie de retos. En primer lugar, es necesario interpretar con precisión las señales generadas por los ángulos de Gann. La teoría de Gann es en gran medida subjetiva y requiere un profundo conocimiento del mercado, lo que resulta difícil de aplicar plenamente en forma de algoritmo.

Por supuesto, el éxito de un EA de este tipo dependerá en gran medida de la profundidad de la comprensión de la teoría de Gann por parte del desarrollador, así como de su capacidad para combinar eficazmente esta teoría con los métodos modernos de análisis de mercado y gestión de riesgos.


Mayor reto: escalar ángulos

Uno de los problemas más graves a la hora de crear y utilizar indicadores y EA basados en ángulos de Gann es la dificultad para escalarlos. Este problema afecta significativamente a la precisión y eficacia de los sistemas de negociación basados en el método de Gann.

La esencia del problema es que los ángulos de Gann, al ser construcciones geométricas, dependen en gran medida de la escala del gráfico. Al cambiar la escala del eje temporal o la escala de precios, la representación visual de los ángulos puede distorsionarse considerablemente. Lo que parece un ángulo perfecto de 1x1 (45 grados) a una escala puede convertirse en un ángulo completamente distinto al cambiar de escala.

Esto crea serias dificultades para la implantación del software. El indicador o EA debe tener en cuenta constantemente la escala actual del gráfico y ajustar los cálculos del ángulo en consecuencia. Además, el propio concepto de «unidad de tiempo igual a unidad de precio» en el que se basan los ángulos de Gann se vuelve ambiguo cuando se trabaja con diferentes instrumentos financieros y marcos temporales.

Los intentos de resolver este problema suelen desembocar en compromisos. Algunos desarrolladores fijan la escala, lo que limita la aplicabilidad de la herramienta. Otros introducen complejos algoritmos para recalcular los ángulos, lo que puede reducir la velocidad del indicador o EA.

Además, el problema de la escala dificulta la comparación de los resultados de los análisis entre distintas herramientas o plazos. Un ángulo que funciona eficazmente en un gráfico diario de un par de divisas puede producir resultados completamente diferentes en un gráfico horario, o para otro instrumento de negociación.

Este problema cuestiona la aplicabilidad universal de los ángulos de Gann en la negociación automatizada. Requiere que los desarrolladores conozcan a fondo no sólo la teoría de Gann, sino también las particularidades del trabajo con gráficos en plataformas de negociación.


Conclusión

Los ángulos de Gann son una herramienta de análisis técnico única que sigue atrayendo la atención de operadores y desarrolladores de sistemas de negociación. Nuestra revisión mostró que la creación del indicador de ángulos de Gann en MQL5 es bastante factible, y el código proporcionado sirve como un buen punto de partida para un mayor desarrollo.

Sin embargo, el uso de ángulos de Gann en la negociación automatizada conlleva una serie de retos importantes. El principal es el problema del escalado, que hace mucho más difícil crear un EA de trading universal y fiable basado en este método.

A pesar de estas dificultades, el potencial de los ángulos de Gann como herramienta de análisis del mercado sigue siendo elevado. Si se utilizan correctamente, en combinación con otros métodos de análisis técnico y una gestión adecuada del riesgo, pueden ser un complemento eficaz de las herramientas de un operador.

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

Archivos adjuntos |
Bogard_11
Bogard_11 | 15 ago 2024 en 18:56
Eva-oren #:
Gunn era un brillante comerciante, astrólogo y numerólogo, un matemático que creía en los números mágicos. Un gran adivino que predijo el principio y el final de la Primera y la Segunda Guerra Mundial. Tuvo un enorme número de alumnos, pero como afirman sus seguidores, no dio su estrategia a nadie. Tuvo un enorme movimiento de dinero, y al final de su vida se hizo con la modesta suma de 100.000 dólares. Esperaré con impaciencia los próximos artículos sobre la genial personalidad de Gunn, muy interesantes.

Olvidé mencionar que tenía un jet privado, lo cual era una rareza en aquellos tiempos. Más 100.000 dólares en aquel entonces, eso es por lo menos una mulit de verde ahora, si no 10 mulit.

P.D. - pasó de la estrategia. En sus escritos. Quien quiso, recopilados de diferentes capítulos del TC completo. Gunn lo dispersó todo para que nadie pudiera conseguirlo gratis.

Ivan Butko
Ivan Butko | 21 ago 2024 en 17:11
Encontrado una manera de negociar en google

Maxim Kuznetsov
Maxim Kuznetsov | 22 ago 2024 en 03:16
Ivan Butko #:
Encontrado una manera de negociar en Google

en la segunda imagen - No entiendo el principio :-(

Bogard_11
Bogard_11 | 22 ago 2024 en 06:58

Te daré una imagen. Quién entiende Gunn, entenderá inmediatamente el principio de trabajar con esquinas, dónde buscar una entrada larga y dónde rodar.


Avatar2025
Avatar2025 | 25 jun 2025 en 09:50
Descargo de responsabilidad: No sé MQL5 sintaxis de programación para los indicadores.

Pero creo que el algoritmo de la línea de ángulo no es correcto (ver adjunto indicador de línea de ángulo que escribí en otro software), aquí está mi diálogo con DeepSeek:

下面代码是通达信的代码,里面计算斜率的方法才是正确的,请阅读理解后,把上面priceShift 的计算方法改为下列代码正确的范式:

涨周期数:= IF(低点k位置 > 高点k位置, 低点k位置 - 高点k位置 + 1, 低点k位置), NODRAW;
跌周期数:= IF(高点k位置 > 低点k位置, 高点k位置 - 低点k位置 + 1, 高点k位置), NODRAW;

天线:= CONST(IF(高点k位置 = 1, H, REF(H, 高点k位置 - 1))), NODRAW;
地线:= CONST(IF(低点k位置 = 1, L, REF(L, 低点k位置 - 1))), NODRAW;

上涨天数:= IF(ISVALID(地线), BARSLAST(L = 地线), DRAWNULL), NODRAW;
下跌天数:= IF(ISVALID(天线), BARSLAST(H = 天线), DRAWNULL), NODRAW;

上涨高度:= IF(低点k位置 > 高点k位置, 天线 - 地线, HHV(H, 上涨天数) - 地线), NODRAW;
下跌高度:= IF(高点k位置 > 低点k位置, 天线 - 地线, 天线 - LLV(L, 下跌天数)), NODRAW;

上涨斜率:= IF(上涨天数 > 0, ROUND2(上涨高度 / 涨周期数, 4), 0), NODRAW;
下跌斜率:= IF(下跌天数 > 0, ROUND2(下跌高度 / 跌周期数, 4), 0), NODRAW;

Sin embargo, DeepSeek me dio un código de modificación que no parecía funcionar para mí:
//+------------------------------------------------------------------+
//| Trazar la línea del sector de Venn & nbsp; ||
//+------------------------------------------------------------------+
void DrawGannFan(double extremum, datetime extremumTime)
{
    // Define el ángulo de Gann y el nombre correspondiente.
    double angles[] = {82.5, 75, 71.25, 63.75, 45, 26.25, 18.75, 15, 7.5};
    string angleNames[] = {"1x8", "1x4", "1x3", "1x2", "1x1", "2x1", "3x1", "4x1", "8x1"};

    // Obtiene el número de periodos desde el punto extremo hasta la línea K actual
    int extremumBar = iBarShift(_Symbol, PERIOD_CURRENT, extremumTime);
    int currentBar = 0; // La línea K actual es 0
    int barDiff = currentBar - extremumBar; // Diferencia de número de ciclo
    
    // Calcular la diferencia de altura de precios
    double priceDiff;
    if(isTrendUp)
    {
        // Tendencia alcista: calcula la altura desde el mínimo extremo hasta el precio máximo actual
        double currentHigh = iHigh(_Symbol, PERIOD_CURRENT, 0);
        priceDiff = currentHigh - extremum;
    }
    else
    {
        // Tendencia bajista: calcula la altura desde el máximo extremo hasta el precio mínimo actual
        double currentLow = iLow(_Symbol, PERIOD_CURRENT, 0);
        priceDiff = extremum - currentLow;
    }
    
    // Calcular la pendiente de la base (pendiente de la línea 1x1)
    double baseSlope = (barDiff > 0) ? priceDiff / barDiff : 0;
    
    // Dibuja líneas de sector para cada ángulo
    for(int i = 0; i < ArraySize(angles); i++)
    {
        string label = "GannFan_" + angleNames[i];  // Etiquetas de objetos
        double angle = angles[i];                  // Ángulo actual
        
        // Calcular el multiplicador de la pendiente en función del ángulo
        double slopeMultiplier = MathTan(angle * M_PI / 180.0) / MathTan(45 * M_PI / 180.0);
        
        // Calcular el desplazamiento del precio (en función de la pendiente subyacente y del multiplicador del ángulo)
        double priceShift = baseSlope * barDiff * slopeMultiplier * _Point;
        double endPrice;
        
        // Cálculo del precio de cierre en función de la dirección de la tendencia
        if(isTrendUp)
        {
            endPrice = extremum + priceShift;
        }
        else
        {
            endPrice = extremum - priceShift;
            angle = -angle; // Ángulo de inversión en tendencia bajista
        }

        // Crear un objeto línea de tendencia
        if(ObjectCreate(0, label, OBJ_TREND, 0, extremumTime, extremum, TimeCurrent(), endPrice))
        {
            // Establecer las propiedades de la línea de tendencia
            ObjectSetInteger(0, label, OBJPROP_COLOR, GannFanColor);
            ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSetInteger(0, label, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, true);
            ObjectSetString(0, label, OBJPROP_TOOLTIP, "Gann Fan " + angleNames[i]);
        }
        else
        {
            Print("Failed to create Gann Fan line: ", GetLastError());
        }
    }
}

//+------------------------------------------------------------------+
//|| Trazado de una línea de abanico de Gann inverso & nbsp; &nbsp ; ||
//+------------------------------------------------------------------+
void DrawOppositeGannFan(double extremum, datetime extremumTime)
{
    // Define el ángulo de Gann y el nombre correspondiente.
    double angles[] = {82.5, 75, 71.25, 63.75, 45, 26.25, 18.75, 15, 7.5};
    string angleNames[] = {"1x8", "1x4", "1x3", "1x2", "1x1", "2x1", "3x1", "4x1", "8x1"};

    // Obtiene el número de periodos desde el punto extremo hasta la línea K actual
    int extremumBar = iBarShift(_Symbol, PERIOD_CURRENT, extremumTime);
    int currentBar = 0; // La línea K actual es 0
    int barDiff = currentBar - extremumBar; // Diferencia de número de ciclo
    
    // Calcular la diferencia de altura de precios
    double priceDiff;
    if(!isTrendUp)
    {
        // Tendencia inversa (alcista): calcula la altura desde el mínimo extremo hasta el precio máximo actual.
        double currentHigh = iHigh(_Symbol, PERIOD_CURRENT, 0);
        priceDiff = currentHigh - extremum;
    }
    else
    {
        // Tendencia inversa (bajista): calcula la altura desde el máximo extremo hasta el precio mínimo actual.
        double currentLow = iLow(_Symbol, PERIOD_CURRENT, 0);
        priceDiff = extremum - currentLow;
    }
    
    // Calcular la pendiente de la base (pendiente de la línea 1x1)
    double baseSlope = (barDiff > 0) ? priceDiff / barDiff : 0;
    
    // Dibuja líneas de sector para cada ángulo
    for(int i = 0; i < ArraySize(angles); i++)
    {
        string label = "OppositeGannFan_" + angleNames[i];  // Etiquetas de objetos
        double angle = angles[i];                          // Ángulo actual
        
        // Calcular el multiplicador de la pendiente en función del ángulo
        double slopeMultiplier = MathTan(angle * M_PI / 180.0) / MathTan(45 * M_PI / 180.0);
        
        // Calcular el desplazamiento del precio (en función de la pendiente subyacente y del multiplicador del ángulo)
        double priceShift = baseSlope * barDiff * slopeMultiplier * _Point;
        double endPrice;
        
        // Cálculo del precio de cierre basado en la dirección de la tendencia inversa
        if(!isTrendUp)
        {
            endPrice = extremum + priceShift;
        }
        else
        {
            endPrice = extremum - priceShift;
            angle = -angle; // Ángulo de inversión en tendencia bajista
        }

        // Crear un objeto línea de tendencia
        if(ObjectCreate(0, label, OBJ_TREND, 0, extremumTime, extremum, TimeCurrent(), endPrice))
        {
            // Establecer las propiedades de la línea de tendencia
            ObjectSetInteger(0, label, OBJPROP_COLOR, GannFanColor);
            ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSetInteger(0, label, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, true);
            ObjectSetString(0, label, OBJPROP_TOOLTIP, "Opposite Gann Fan " + angleNames[i]);
        }
        else
        {
            Print("Failed to create Opposite Gann Fan line: ", GetLastError());
        }
    }
}





Al final, tuve que pedirle a DeepSeek que modificara su código fuente (funciona bien y dibuja las líneas automáticamente):
#property copyright "Copyright 2024, Evgeniy Shtenco"  // Información sobre derechos de autor
#property link      "https://www.mql5.com/en/users/koshtenko"  // Enlaces de autores
#property version   "1.00"  // Número de versión del indicador
#property indicator_chart_window  // Los indicadores se muestran en la ventana del gráfico

// Parámetros de entrada
input int LookBackBars = 300;      // Número de líneas K analizadas atrás
input color GannFanColor = clrBlue; // Los colores de la línea de fans de Vaughan

// Variables globales
double extremumPrice;        // Precio del punto extremo
datetime extremumTime;       // Momento extremo
double oppositeExtremumPrice; // Precio del punto extremo inverso
datetime oppositeExtremumTime; // Inversión del punto de polaridad
bool isTrendUp;              // Indicador de dirección de la tendencia (verdadero para tendencia alcista)

//+------------------------------------------------------------------+
//| Funciones de Inicialización de Indicadores Personalizados & nbsp; &nbsp ; ||
//+------------------------------------------------------------------+
int OnInit()
{
    return (INIT_SUCCEEDED);  // Inicialización correcta
}

//+------------------------------------------------------------------+
//| Funciones personalizadas de reinicialización de indicadores & nbsp; &nbsp ; ||
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
    {
        // Borrar todos los objetos del sector Gann
        ObjectsDeleteAll(0, "GannFan_");
ObjectsDeleteAll(0, "OppositeGannFan_");
}

//+------------------------------------------------------------------+
//| Funciones de cálculo de indicadores personalizados & nbsp; &nbsp ; | | | | | | | |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,          // Número actual de ciclos
const int prev_calculated,      // Número de ciclos calculados previamente
const datetime & time[],         // Matrices temporales
                const double & open[],          // Matriz de precios de apertura
                const double & high[],           // Matriz de precios más altos
                const double & low[],            // Matriz de precios más bajos
                const double & close[],         // Matriz de precios de cierre
                const long & tick_volume[],      // Matriz de volumen
                const long & volume[],           // Matriz de volumen real
                const int & spread[])            // Matriz de diferenciales de puntos
{
    if (rates_total < LookBackBars) return (0);  // Devuelve si no hay suficientes datos

    // Borrar los objetos dibujados anteriormente
    if (prev_calculated == 0) {
        ObjectsDeleteAll(0, "GannFan_");
        ObjectsDeleteAll(0, "OppositeGannFan_");
    }

    // Encontrar los puntos extremos en las últimas 300 K-líneas
    FindExtremums(rates_total, high, low, time);

    // Trazar la línea de abanico de Venn
    DrawGannFan(extremumPrice, extremumTime);
    DrawOppositeGannFan(oppositeExtremumPrice, oppositeExtremumTime);

    return (rates_total);  // Devuelve el número total de columnas procesadas
}

//+------------------------------------------------------------------+
//| Encontrar puntos extremos dentro de un número especificado de líneas K. |
//+------------------------------------------------------------------+
void FindExtremums(const int rates_total, const double & high[], const double & low[], const datetime & time[])
{
    int startIndex = rates_total - LookBackBars;  // Comienza la indexación (hace 300 K-líneas)
    int endIndex = rates_total - 1;               // Índice final (última línea K)

    // Encontrar altos y bajos
    int highestIndex = ArrayMaximum(high, startIndex, LookBackBars);
    int lowestIndex = ArrayMinimum(low, startIndex, LookBackBars);

    // Determinar la dirección de la tendencia (comparar el momento de máximos y mínimos)
    if (time[highestIndex] > time[lowestIndex]) {
        // Tendencia bajista si el punto más alto está después del punto más bajo
        extremumPrice = high[highestIndex];
        extremumTime = time[highestIndex];
        oppositeExtremumPrice = low[lowestIndex];
        oppositeExtremumTime = time[lowestIndex];
        isTrendUp = false;
    }
    else {
        // en caso contrario, tendencia alcista
        extremumPrice = low[lowestIndex];
        extremumTime = time[lowestIndex];
        oppositeExtremumPrice = high[highestIndex];
        oppositeExtremumTime = time[highestIndex];
        isTrendUp = true;
    }
}

//+------------------------------------------------------------------+
//| Trazar la línea del sector de Venn & nbsp; ||
//+------------------------------------------------------------------+
void DrawGannFan(double extremum, datetime extremumTime)
{
    // Define el ángulo de Gann y el nombre correspondiente.
    double angles[] = { 82.5, 75, 71.25, 63.75, 45, 26.25, 18.75, 15, 7.5};
    string angleNames[] = { "1x8", "1x4", "1x3", "1x2", "1x1", "2x1", "3x1", "4x1", "8x1"};

    // Calcular el tiempo final de la línea de sector (tiempo actual + 300 ciclos)
    datetime endTime = TimeCurrent();  // Utilizar la hora actual como hora final

    // Dibuja líneas de sector para cada ángulo
    for (int i = 0; i < ArraySize(angles); i++)
    {
        string label = "GannFan_" + angleNames[i];  // Etiquetas de objetos
        double angle = angles[i];                  // Ángulo actual

        // Calcular la diferencia de precio (en función de la diferencia horaria)
        double secondsDiff = endTime - extremumTime;
        double priceShift = MathTan(angle * M_PI / 180.0) * secondsDiff / PeriodSeconds();
        double endPrice;

        // Cálculo del precio de cierre en función de la dirección de la tendencia
        if (isTrendUp) {
            endPrice = extremum + priceShift;
        }
        else {
            endPrice = extremum - priceShift;
            angle = -angle; // Ángulo de inversión en tendencia bajista
        }

        // Crear un objeto línea de tendencia
        if (ObjectCreate(0, label, OBJ_TREND, 0, extremumTime, extremum, endTime, endPrice)) {
            // Establecer las propiedades de la línea de tendencia
            ObjectSetInteger(0, label, OBJPROP_COLOR, GannFanColor);
            ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSetInteger(0, label, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, true);
            ObjectSetString(0, label, OBJPROP_TOOLTIP, "Gann Fan " + angleNames[i]);
        }
        else {
            Print("Failed to create Gann Fan line: ", GetLastError());
        }
    }
}

//+------------------------------------------------------------------+
//|| Trazado de una línea de abanico de Gann inverso & nbsp; &nbsp ; ||
//+------------------------------------------------------------------+
void DrawOppositeGannFan(double extremum, datetime extremumTime)
{
    // Define el ángulo de Gann y el nombre correspondiente.
    double angles[] = { 82.5, 75, 71.25, 63.75, 45, 26.25, 18.75, 15, 7.5};
    string angleNames[] = { "1x8", "1x4", "1x3", "1x2", "1x1", "2x1", "3x1", "4x1", "8x1"};

    // Calcular la hora final de la línea de sector (hora actual)
    datetime endTime = TimeCurrent();

    // Dibuja líneas de sector para cada ángulo
    for (int i = 0; i < ArraySize(angles); i++)
    {
        string label = "OppositeGannFan_" + angleNames[i];  // Etiquetas de objetos
        double angle = angles[i];                          // Ángulo actual

        // Calcular la diferencia de precio (en función de la diferencia horaria)
        double secondsDiff = endTime - extremumTime;
        double priceShift = MathTan(angle * M_PI / 180.0) * secondsDiff / PeriodSeconds();
        double endPrice;

        // Cálculo del precio final basado en la dirección de la tendencia opuesta
        if (!isTrendUp) // Invertir la tendencia
        {
            endPrice = extremum + priceShift;
        }
        else {
            endPrice = extremum - priceShift;
            angle = -angle; // Ángulo de inversión en tendencia bajista
        }

        // Crear un objeto línea de tendencia
        if (ObjectCreate(0, label, OBJ_TREND, 0, extremumTime, extremum, endTime, endPrice)) {
            // Establecer las propiedades de la línea de tendencia
            ObjectSetInteger(0, label, OBJPROP_COLOR, GannFanColor);
            ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSetInteger(0, label, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, true);
            ObjectSetString(0, label, OBJPROP_TOOLTIP, "Opposite Gann Fan " + angleNames[i]);
        }
        else {
            Print("Failed to create Opposite Gann Fan line: ", GetLastError());
        }
    }
}

//+------------------------------------------------------------------+
//| Funciones del Manejador de Eventos de Gráficos &nbsp nbsp; & & nbsp; |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,                  // ID del evento
const long & lparam,            // Parámetros enteros largos
                  const double & dparam,          // Parámetros de doble precisión
                  const string & sparam)         // Parámetros de cadena
{
    // Redibujar objetos cuando cambia el gráfico
    if (id == CHARTEVENT_CHART_CHANGE || id == CHARTEVENT_CLICK) {
        // Vuelve a encontrar los extremos y traza la línea de abanico de Venn.
        int rates_total = Bars(_Symbol, PERIOD_CURRENT);
        double high[], low[];
        datetime time[];
        ArraySetAsSeries(high, true);
        ArraySetAsSeries(low, true);
        ArraySetAsSeries(time, true);
        CopyHigh(_Symbol, PERIOD_CURRENT, 0, rates_total, high);
        CopyLow(_Symbol, PERIOD_CURRENT, 0, rates_total, low);
        CopyTime(_Symbol, PERIOD_CURRENT, 0, rates_total, time);

        FindExtremums(rates_total, high, low, time);
        DrawGannFan(extremumPrice, extremumTime);
        DrawOppositeGannFan(oppositeExtremumPrice, oppositeExtremumTime);
    }
}
Del básico al intermedio: Array (III) Del básico al intermedio: Array (III)
En este artículo, veremos cómo trabajar con arrays en MQL5, hasta el punto de transferir información entre funciones y procedimientos mediante arrays. El objetivo es prepararte para lo que se verá y explicará en artículos futuros. No obstante, es extremadamente recomendable que estudies muy bien lo que se mostrará en este artículo.
Del básico al intermedio: Array (II) Del básico al intermedio: Array (II)
En este artículo, veremos qué es un array dinámico y un array estático. ¿Existe diferencia entre usar uno u otro? ¿O ambos son siempre lo mismo? ¿Cuándo debo usar uno y cuándo usar el otro? ¿Y los arrays constantes? ¿Por qué existen y cuál es el riesgo que corro, cuando no inicializo todos los valores de un array? Suponiendo que serán iguales a cero. El contenido expuesto aquí tiene un propósito puramente didáctico. En ningún caso debe considerarse como una aplicación final, si el objetivo no es el estudio de los conceptos mostrados aquí.
Del básico al intermedio: Array (IV) Del básico al intermedio: Array (IV)
En este artículo, veremos cómo podemos hacer algo muy parecido a lo que se encuentra en lenguajes como C, C++ y Java. Se trata de enviar un número casi infinito de parámetros dentro de una función o procedimiento. Aunque, aparentemente, se trate de un tema avanzado. En mi opinión, lo que se verá aquí puede ser implementado con facilidad por cualquier persona que haya comprendido los conceptos anteriores. Siempre y cuando se hayan comprendido los conceptos vistos anteriormente. El contenido expuesto aquí tiene un propósito puramente didáctico. En ningún caso debe considerarse una aplicación cuya finalidad no sea aprender y estudiar los conceptos mostrados.
Redes neuronales en el trading: Modelo Universal de Generación de Trayectorias (UniTraj) Redes neuronales en el trading: Modelo Universal de Generación de Trayectorias (UniTraj)
La comprensión del comportamiento de los agentes es importante en distintos ámbitos, pero la mayoría de los métodos se centran en una única tarea (comprensión, eliminación del ruido, predicción), lo cual reduce su eficacia en escenarios del mundo real. En este artículo, propongo al lector introducir un modelo capaz de adaptarse a diferentes tareas.