English Русский 中文 Deutsch 日本語
preview
Introducción a MQL5 (Parte 12): Guía para principiantes sobre cómo crear indicadores personalizados

Introducción a MQL5 (Parte 12): Guía para principiantes sobre cómo crear indicadores personalizados

MetaTrader 5Trading |
354 2
Israel Pelumi Abioye
Israel Pelumi Abioye

Introducción

¡Bienvenido nuevamente a nuestra serie MQL5! Hasta ahora, hemos cubierto mucho, incluido el manejo de indicadores integrados, la creación de asesores expertos, la exploración de conceptos fundamentales de MQL5 y la puesta en práctica de nuestro conocimiento a través de proyectos prácticos. Es hora de avanzar aprendiendo cómo crear un indicador personalizado desde cero. Obtendremos una comprensión más profunda de cómo funcionan los indicadores internamente, lo que nos permitirá tener un control total sobre su funcionamiento y diseño en lugar de depender de funciones integradas. ¿Alguna vez te has preguntado cómo se crean la media móvil o el MACD, dos de los indicadores integrados en MQL5? Si no existieran funciones como iRSI o iMA, ¿aún se podrían crear indicadores? 

Utilizando un enfoque basado en proyectos, dividiremos el proceso en dos partes principales. Primero, sin utilizar la función iMA, construiremos un indicador de media móvil completamente desde cero. A continuación, iremos un paso más allá y transformaremos la media móvil de la forma de línea convencional a un indicador de estilo vela. Además, este método práctico abrirá nuevas vías para desarrollar herramientas comerciales que se adapten específicamente a sus necesidades.

Media móvil en formato de línea

Figura 1. Formato de línea MA

Media móvil en formato de vela

Figura 2. Formato de vela MA

En este artículo aprenderás:

  • Cómo crear indicadores personalizados desde cero en MQL5.
  • La diferencia entre trazar indicadores en formato de línea y formato de vela.
  • Uso de buffers indicadores para almacenar y mostrar valores calculados.
  • Establecer correctamente las propiedades del indicador.
  • Creación de un indicador de media móvil personalizado en MQL5.
  • Mapeo de buffers de indicadores usando SetIndexBuffer().
  • Procesamiento de datos de precios mediante la función OnCalculate().
  • Cómo determinar los colores de las velas según el movimiento de precios.

Incluso si eres nuevo en MQL5, puedes seguirlo sin sentirte abrumado porque este artículo está pensado para principiantes. Cada línea de código se explicará detalladamente, diseccionando ideas complejas en pasos manejables. Al final de este tutorial, debería tener una comprensión sólida de cómo funcionan los indicadores personalizados en MQL5, ya que mantendré las cosas sencillas y útiles.


1. Indicadores personalizados

1.1. ¿Qué son los indicadores personalizados?

Los indicadores personalizados son aquellos que no están disponibles en MQL5 de forma predeterminada. A diferencia de los indicadores incorporados que trae MetaTrader 5, como las medias móviles (MA), el índice de fuerza relativa (RSI) o MACD, los usuarios pueden crear sus propios indicadores para realizar cálculos particulares, proporcionar señales o presentar datos del mercado como mejor les parezca.

Es sencillo incorporar indicadores integrados en las estrategias comerciales porque se puede acceder a ellos directamente mediante funciones como iMA(), iRSI() e iMACD(). Pero cuando se trata de personalizar, son limitados. Por otro lado, los indicadores personalizados proporcionan un control completo sobre los cálculos, la lógica y la visualización de gráficos, lo que le permite crear herramientas adaptadas a sus requisitos comerciales particulares. Los comerciantes que deseen realizar análisis de mercado con métodos no admitidos por indicadores integrados encontrarán estos indicadores especialmente útiles. Puede diseñar indicadores únicos que proporcionen una comprensión más completa del movimiento de precios, las tendencias y las posibles oportunidades comerciales utilizando la programación MQL5.

Analogía

Considere colocar una estantería en su espacio vital. Los indicadores incorporados son comparables a las tiendas con estanterías premontadas. Estas estanterías tienen tamaños, formas y características predeterminadas y están disponibles en diseños estándar. Para la mayoría de las personas, son fáciles de usar, convenientes y efectivos. Sin embargo, es posible que la estantería premontada no se ajuste con precisión ni satisfaga sus necesidades si su espacio tiene una forma irregular o si necesita estanterías especiales para volúmenes raros.

Por otro lado, los indicadores personalizados son como una estantería que tú mismo haces. Se pueden elegir las medidas exactas, el número de estantes y los materiales para crear una estantería que se adapte a tu espacio y organice tus libros de la forma que elijas. De la misma manera, en el trading, los indicadores personalizados le brindan la precisión y flexibilidad que los indicadores integrados no pueden ofrecer, lo que le permite diseñar soluciones que se adapten a su estrategia única.

1.2. Diferencias entre asesores expertos e indicadores

Aunque los indicadores y los asesores expertos evalúan los datos del mercado de maneras bastante similares, sus funciones son bastante distintas. Debido a que los EA están hechos para automatizar el comercio, además de analizar el mercado, también realizan transacciones de acuerdo con reglas preestablecidas. Son capaces de gestionar el riesgo, modificar el stop-loss, determinar los niveles de take-profit y abrir y cerrar órdenes. Cada vez que hay una nueva actualización de precio, se llama OnTick(), una de las funciones más importantes en un EA. Con la ayuda de esta función, el EA puede vigilar los movimientos de precios en tiempo real y verificar si se cumplen los criterios comerciales antes de realizar un pedido.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

//

  }

Por el contrario, los indicadores no tienen el poder de ejecutar operaciones; sólo se concentran en el análisis del mercado. Los indicadores utilizan el método OnCalculate(), que analiza datos históricos y actuales para producir indicaciones comerciales, en lugar de OnTick(). OnCalculate() se encarga del cálculo de valores de indicadores, la actualización de elementos del gráfico y la presentación de señales visuales como líneas de tendencia o velas codificadas por colores.

Los indicadores simplemente ofrecen información útil; los traders deben tomar la decisión final, a diferencia de los EA, que están diseñados para actuar. Aunque ambos examinan datos del mercado, los indicadores y los EA tienen propósitos diferentes. Mientras que los indicadores ayudan a los traders a interpretar manualmente el mercado y tomar decisiones comerciales bien informadas, los EA actúan sobre las oportunidades comerciales.

//+------------------------------------------------------------------+
//| 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[])
  {
//
  }

Analogía

Considere los indicadores y los asesores expertos como dos herramientas comerciales distintas. Un EA analiza el mercado, toma decisiones y ejecuta operaciones de forma autónoma, de forma muy similar a un automóvil autónomo. Sin intervención humana, aplica técnicas comerciales, monitorea continuamente las fluctuaciones del mercado y controla el riesgo.

Un indicador, por otro lado, funciona más como un GPS en el sentido de que ofrece dirección pero no logra nada. Analiza datos del mercado, identifica patrones y ayuda a los comerciantes a comprender los cambios en los precios. Una media móvil, por ejemplo, puede indicar si el mercado está subiendo o bajando, pero no puede iniciar ni finalizar operaciones. Un indicador solo ofrece información; la elección final depende de usted, pero un EA opera por usted.


2. Configuración del proyecto

Ahora que sabemos qué son los indicadores personalizados y en qué se diferencian de los Asesores Expertos y los indicadores integrados, veamos cómo crear y modificar nuestros indicadores en MQL5. Exploraremos el procedimiento en detalle en esta sección para asegurarnos de que tenga una buena idea de cómo crear un indicador desde el principio. Sin utilizar rutinas de indicadores preexistentes, como MA, construiremos dos indicadores únicos desde cero en este tutorial.

2.1. Línea MA

El primer indicador será un indicador de promedio móvil simple que calcula y muestra tres promedios móviles diferentes:

  • Periodo 200 aplicado al Precio Alto.
  • Periodo 100 aplicado al precio de Cierre.
  • Periodo 50 aplicado al precio de apertura.

Para crear un indicador personalizado, es esencial comprender primero la lógica detrás de su funcionalidad. Antes de escribir cualquier código, debemos definir cómo el indicador procesará los datos del mercado y mostrará información relevante. Este paso garantiza que nuestro enfoque esté bien estructurado y sea fácil de implementar. Redactar un pseudocódigo es un paso esencial además de comprender su lógica. Crear un pseudocódigo facilita la división de la implementación en partes más pequeñas y manejables. Reduce la posibilidad de errores y aumenta la eficiencia del proceso de codificación al delinear claramente lo que debe hacerse.

En esta sección se examinará primero la lógica necesaria para determinar y mostrar tres promedios móviles utilizando varias fuentes de precios. Antes de escribir el código real, primero redactaremos un pseudocódigo que servirá como guía para nuestra implementación. Este enfoque estructurado nos ayudará a construir un indicador personalizado bien definido y al mismo tiempo reforzará los conceptos de programación clave en MQL5.

Pseudocódigo:

// SETUP INDICATOR

1. Establezca el indicador para que se muestre en la ventana del gráfico.

2. Define 3 buffers para almacenar datos para los promedios móviles (MA200, MA100, MA50).

3. Define 3 gráficos para mostrar los promedios móviles en el gráfico.

// SETUP PLOT PROPERTIES

4. Para MA200:

  • Etiqueta: "MA 200"
  • Tipo: Línea
  • Estilo: Dash-Dot-Dot
  • Ancho: 1
  • Color: Azul

5. Para MA100:

  • Etiqueta: "MA 100"
  • Tipo: Línea
  • Estilo: Dash
  • Ancho: 1
  • Color: Marrón

6. Para MA50:

  • Etiqueta: "MA 50"
  • Tipo: Línea
  • Estilo: Dot
  • Ancho: 1
  • Color: Morado

// DEFINE BUFFERS

7. Crear buffers para almacenar los valores calculados para:

  • MA200
  • MA100
  • MA50

// DEFINE INPUT PARAMETERS

8. Permitir al usuario establecer el período para cada promedio móvil:

  • MA200: Periodo predeterminado = 200
  • MA100: Periodo predeterminado = 100
  • MA50: Periodo predeterminado = 50

// INITIALIZATION FUNCTION

9. Cuando se inicializa el indicador:

  • Asigna cada buffer a su parcela correspondiente.
  • Establezca el número de barras iniciales a omitir para cada promedio móvil:
  • MA200: Omite las primeras 200 barras
  • MA100: Omite las primeras 100 barras
  • MA50: Omite las primeras 50 barras

// CALCULATION FUNCTION

10. Para cada nueva vela o cuando se actualiza el gráfico:

Los precios máximos, de cierre y de apertura de las 200, 100 y 50 barras anteriores se sumarán para cada barra, se dividirán por el tiempo correspondiente y los resultados se almacenarán en los buffers apropiados para determinar la MA200, MA100 y MA50.

2.2. Vela MA

A continuación, crearemos un indicador de media móvil diferente que represente las tendencias de precios en formato de vela. Este indicador utilizará un promedio móvil con un período de 5 y representará visualmente sus valores utilizando velas en lugar de líneas. Al mostrar los datos de promedio móvil de esta manera, podemos resaltar las tendencias a corto plazo y filtrar el ruido del mercado de manera más efectiva. Esto proporcionará una perspectiva única sobre el movimiento de precios manteniendo los principios de los cálculos de promedio móvil.

Cada proyecto se explicará detalladamente, asegurándose de que cada línea de código sea lo suficientemente simple para que los principiantes puedan entenderla. Al finalizar esta parte, tendrá experiencia práctica en la creación y modificación de indicadores desde cero, lo que le proporcionará habilidades útiles para proyectos futuros.

Pseudocódigo:

// SETUP INDICATOR

1. Configure el indicador para que se muestre en una ventana separada.

2. Crea 5 matrices (buffers) para almacenar:

  • precios apertura (OpenBuffer)
  • precios altos (HighBuffer)
  • precios bajos (LowBuffer)
  • precios de cierre (CloseBuffer)
  • Colores de las velas (ColorBuffer: 0 = verde, 1 = rojo)

3. Define 1 gráfica para mostrar las velas.

// SETUP PLOT PROPERTIES

4. Para el dibujo:

  • Etiqueta: "Candles"
  • Tipo: Velas de colores (DRAW_COLOR_CANDLES)
  • Colores: Verde para alcista, rojo para bajista
  • Estilo: Sólido
  • Ancho: 1

// DEFINE INPUT PARAMETERS

5. Permitir al usuario establecer el período de suavizado (predeterminado = 5).

// INITIALIZATION FUNCTION

6. Cuando se inicializa el indicador:

  • Asigne a cada buffer su dato o índice de color correspondiente.
  • Establezca el número de barras iniciales a omitir (igual al período de suavizado).

// CALCULATION FUNCTION

7. Para cada nueva vela o cuando se actualiza el gráfico:

  • Compruebe si hay suficientes barras para calcular (al menos barras de "período").
  • En caso contrario, imprima un mensaje de error y deténgase.

8. Para cada barra desde la barra del "período 1" hasta la última barra:

Calcule los precios suavizados de apertura, máximo, mínimo y cierre:

  • Sume los precios de apertura, máximo, mínimo y cierre de las últimas barras del "período".
  • Divida cada suma por "período" para obtener el promedio.
  • Almacene los resultados en OpenBuffer, HighBuffer, LowBuffer y CloseBuffer.

Establezca el color de la vela:

  • Si el precio de cierre suavizado >= precio de apertura suavizado, establezca el color en verde (0).
  • De lo contrario, establezca el color en rojo (1).


3. Creación y personalización de indicadores personalizados

Ahora podemos crear y modificar nuestros indicadores personalizados, ya que hemos escrito un pseudocódigo. Con una estrategia bien definida, comenzaremos a poner en práctica la lógica gradualmente, asegurándonos de que el indicador funcione como lo previsto. Podemos visualizar eficientemente los movimientos del mercado y modificar el indicador para adaptarlo a nuestras necesidades organizando adecuadamente nuestro código.

3.1. Creación de un indicador de media móvil en formato de línea

El primer paso para crear un indicador es imaginar cómo quiere que se vea y funcione. Es fundamental plantearse algunas preguntas cruciales para ayudarle a comprender el diseño y la implementación antes de crear cualquier código:

  • ¿El indicador debe mostrarse en la ventana principal del gráfico o en una ventana separada?
  • ¿Cuántos buffers requerirá el indicador para almacenar y mostrar datos?
  • ¿Qué tipo de gráfico se debe utilizar: línea, histograma, velas u otro?
  • ¿Qué colores deben asignarse a los diferentes elementos para una mejor visibilidad?
  • ¿El indicador utilizará múltiples fuentes de datos, como precios máximos, mínimos, de apertura o de cierre?

Al responder estas preguntas, puede crear un plan claro para su indicador, lo que hará que el proceso de desarrollo sea más fluido y estructurado.

Ejemplo:

//INDICATOR IN CHART WINDOW
#property indicator_chart_window

//SET INDICATOR BUFFER TO STORE DATA
#property indicator_buffers 3

//SET NUMBER FOR INDICATOR PLOTS
#property indicator_plots   3

Explicación:

Indicador en la ventana del gráfico
#property indicator_chart_window

En lugar de mostrar el indicador personalizado en una ventana separada, esta directiva indica a MetaTrader 5 que lo muestre inmediatamente en el gráfico principal, que muestra la acción del precio. Para trazar el indicador en una ventana diferente (como el RSI o el MACD), usaríamos:

#property indicator_separate_window

Esta directiva garantiza que el indicador se muestre en una ventana separada debajo del gráfico principal, en lugar de trazarse directamente en el gráfico de precios.

Configuración de búferes de indicadores para almacenar datos

#property indicator_buffers 3

Los valores calculados que se representarán en el gráfico se almacenan en matrices llamadas buffers de indicadores. Cada buffer representa un elemento distinto del indicador. En este caso, almacenaremos tres conjuntos distintos de valores, ya que construimos tres buffers de indicadores. Se requieren tres buffers para contener los valores de cada promedio móvil de forma independiente porque estamos construyendo un indicador de promedio móvil con tres períodos distintos (50, 100 y 200).

Configuración del número de gráficos indicadores

#property indicator_plots   3

Esto especifica cuántas gráficas mostrará el indicador. Una representación gráfica distintiva en el gráfico se llama diagrama. Se requieren tres gráficos ya que estamos dibujando tres promedios móviles: uno para cada uno de los promedios móviles de 50, 100 y 200 períodos.

Se pueden personalizar el color, el estilo y el formato (como línea, histograma o velas) para cada gráfico. Aquí, cada uno de los tres gráficos se mostrará como una línea que representa un promedio móvil distinto.

Resumen

  • El indicador se mostrará en el gráfico principal (#property indicator_chart_window).
  • Almacenará tres conjuntos de valores utilizando buffers de indicadores (#property indicator_buffers 3).
  • Trazará tres promedios móviles diferentes (#property indicator_plots 3).

Esta configuración garantiza que el indicador calcule y muestre correctamente los tres promedios móviles en el gráfico de precios.

Figura 3. Gráficos y gráficos de ventana

La configuración de las propiedades del gráfico viene a continuación de definir las características fundamentales de nuestro indicador. Para especificar cómo aparecerá el indicador en el gráfico, es esencial proporcionar atributos de gráfico al construir un indicador personalizado en MQL5. El tipo de dibujo, el estilo de línea, el grosor, el color y las etiquetas están determinados por estos parámetros. Comprender estos parámetros le ayudará a crear y modificar indicadores para diversos casos de uso, ya que este artículo se centra en enseñar cómo diseñar indicadores personalizados utilizando un enfoque basado en proyectos.

Ejemplos:

//INDICATOR IN CHART WINDOW
#property indicator_chart_window

//SET INDICATOR BUFFER TO STORE DATA
#property indicator_buffers 3

//SET NUMBER FOR INDICATOR PLOTS
#property indicator_plots   3

//SETTING PLOTS PROPERTIES
//PROPERTIES OF THE FIRST MA (MA200)
#property indicator_label1  "MA 200"    //GIVE PLOT ONE A NAME
#property indicator_type1   DRAW_LINE  //TYPE OF PLOT THE FIRST MA 
#property indicator_style1  STYLE_DASHDOTDOT  //STYLE OF SPOT THE FIRST MA
#property indicator_width1  1         //LINE THICKNESS THE FIRST MA
#property indicator_color1  clrBlue    //LINE COLOR THE FIRST MA

//PROPERTIES OF THE SECOND MA (MA100)
#property indicator_label2  "MA 100"   //GIVE PLOT TWO A NAME
#property indicator_type2   DRAW_LINE  //TYPE OF PLOT THE SECOND MA
#property indicator_style2  STYLE_DASH  //STYLE OF SPOT THE SECOND MA
#property indicator_width2  1          //LINE THICKNESS THE SECOND MA
#property indicator_color2  clrBrown    //LINE COLOR THE SECOND MA

//PROPERTIES OF THE THIRD MA (MA50)
#property indicator_label3  "MA 50"    //GIVE PLOT TWO A NAME
#property indicator_type3   DRAW_LINE  //TYPE OF PLOT THE THIRD MA
#property indicator_style3  STYLE_DOT  //STYLE OF SPOT THE THIRD MA
#property indicator_width3  1          //LINE THICKNESS THE THIRD MA
#property indicator_color3  clrPurple    //LINE COLOR THE THIRD MA

Explicación:

Promedio móvil inicial (MA 200)

#property indicator_label1  "MA 200"    //GIVE PLOT ONE A NAME
#property indicator_type1   DRAW_LINE  //TYPE OF PLOT THE FIRST MA 
#property indicator_style1  STYLE_DASHDOTDOT  //STYLE OF SPOT THE FIRST MA
#property indicator_width1  1         //LINE THICKNESS THE FIRST MA
#property indicator_color1  clrBlue    //LINE COLOR THE FIRST MA

La primera media móvil (MA200) aparecerá como una línea de puntos discontinuos de color azul con un grosor de 1.

Segunda media móvil (MA 100)

#property indicator_label2  "MA 100"   //GIVE PLOT TWO A NAME
#property indicator_type2   DRAW_LINE  //TYPE OF PLOT THE SECOND MA
#property indicator_style2  STYLE_DASH  //STYLE OF SPOT THE SECOND MA
#property indicator_width2  1          //LINE THICKNESS THE SECOND MA
#property indicator_color2  clrBrown    //LINE COLOR THE SECOND MA

La segunda media móvil (MA100) se mostrará como una línea discontinua marrón con un grosor de 1.

Tercera media móvil (MA 50)

#property indicator_label3  "MA 50"    //GIVE PLOT TWO A NAME
#property indicator_type3   DRAW_LINE  //TYPE OF PLOT THE THIRD MA
#property indicator_style3  STYLE_DOT  //STYLE OF SPOT THE THIRD MA
#property indicator_width3  1          //LINE THICKNESS THE THIRD MA
#property indicator_color3  clrPurple    //LINE COLOR THE THIRD MA

La tercera media móvil (MA50) se mostrará como una línea punteada violeta con un grosor de 1.

Comprensión de la relación entre las propiedades del gráfico en MQL5

Cada gráfico (línea, histograma, flecha, etc.) requiere un conjunto de características que determinan su apariencia al determinar cómo debe mostrarse un indicador en un gráfico. Los sufijos numerados, como indicator_label1, indicator_type1, indicator_style1, etc., se utilizan en MQL5 para asignar las propiedades.

Gracias a esta numeración se garantiza que todas las propiedades de una determinada parcela pertenecen juntas. Vamos a explorarlo:

  • indicator_label1 asigna un nombre al primer gráfico, lo que facilita su identificación.
  • indicator_type1 especifica cómo se dibujará este primer gráfico (por ejemplo, como una línea).
  • indicator_style1 determina el estilo de línea para este primer gráfico (sólida, discontinua, punteada, etc.).
  • indicator_width1 controla el grosor del primer gráfico.
  • indicator_color1 establece el color para este primer gráfico.

Ejemplo para aclarar la relación

Piense en estas propiedades como un conjunto coincidente para cada promedio móvil:

Propiedad Lo que controla
Primer MA (200)
Segunda MA (100) Tercera MA (50)
indicator_labelX
Nombre de la MA
"MA 200"
"MA 100"
"MA 50"
indicator_typeX
Tipo de dibujo
DRAW_LINE
DRAW_LINE
DRAW_LINE
indicator_styleX
Line Style
STYLE_DASHDOTDOT
STYLE_DASH
STYLE_DOT
indicator_widthX Thickness 1 1 1
indicator_colorX
Color
clrBlue
clrBrown
clrPurple

Este enfoque garantiza que cada propiedad coincida con el promedio móvil apropiado y nos permite especificar muchas parcelas de manera organizada. Por lo tanto, solo la segunda MA se verá afectada si se cambia indicator_style2. Solo el color de la tercera MA cambiará si se cambia indicator_color3. Podemos gestionar la aparición de cada media móvil en el gráfico sin crear confusión manteniendo la consistencia y organización de estas características.

Además de los muchos tipos de gráficos, estilos de línea y colores que empleamos en nuestro indicador de promedio móvil, MQL5 ofrece una variedad de otras posibilidades de personalización para los gráficos de indicadores. Los desarrolladores pueden diseñar varios tipos de indicaciones utilizando estos parámetros, desde líneas simples hasta visualizaciones más complejas como bandas, flechas e histogramas. Utilizamos un enfoque basado en proyectos, concentrándonos en un solo indicador y presentando ideas esenciales que pueden usarse para otros indicadores personalizados porque hay demasiadas variables para discutir en un solo artículo. Sin embargo, es útil saber que hay más opciones.

En general, se pueden analizar diferentes estilos de trama utilizando la misma lógica utilizada en este artículo. Pero esto no siempre es así para todo tipo de tramas. Por ejemplo, mientras que DRAW_LINE solo necesita un buffer por gráfico, DRAW_CANDLES necesita cuatro buffers para trazar una sola vela. Puedes consultar la Documentación de MQL5 para una descripción completa de los muchos tipos de parcelas disponibles, junto con sus necesidades particulares.

La declaración de variables dobles para almacenar los buffers de indicadores se realiza después de configurar los atributos del gráfico. Dado que almacenan los valores calculados que se mostrarán en el gráfico, estos buffers son cruciales. La función SetIndexBuffer() debe utilizarse para vincular las variables a los buffers indicadores después de que hayan sido declarados. Esta etapa garantiza que los datos almacenados en estos buffers se puedan mostrar con precisión y se asignen adecuadamente a las parcelas correspondientes.

Ejemplo:

//INDICATOR IN CHART WINDOW
#property indicator_chart_window

//SET INDICATOR BUFFER TO STORE DATA
#property indicator_buffers 3

//SET NUMBER FOR INDICATOR PLOTS
#property indicator_plots   3

//SETTING PLOTS PROPERTIES
//PROPERTIES OF THE FIRST MA (MA200)
#property indicator_label1  "MA 200"   //GIVE PLOT ONE A NAME
#property indicator_type1   DRAW_LINE  //TYPE OF PLOT THE FIRST MA 
#property indicator_style1  STYLE_DASHDOTDOT  //STYLE OF SPOT THE FIRST MA
#property indicator_width1  1         //LINE THICKNESS THE FIRST MA
#property indicator_color1  clrBlue    //LINE COLOR THE FIRST MA

//PROPERTIES OF THE SECOND MA (MA100)
#property indicator_label2  "MA 100"   //GIVE PLOT TWO A NAME
#property indicator_type2   DRAW_LINE  //TYPE OF PLOT THE SECOND MA
#property indicator_style2  STYLE_DASH  //STYLE OF SPOT THE SECOND MA
#property indicator_width2  1          //LINE THICKNESS THE SECOND MA
#property indicator_color2  clrBrown    //LINE COLOR THE SECOND MA

//PROPERTIES OF THE THIRD MA (MA50)
#property indicator_label3  "MA 50"    //GIVE PLOT TWO A NAME
#property indicator_type3   DRAW_LINE  //TYPE OF PLOT THE THIRD MA
#property indicator_style3  STYLE_DOT  //STYLE OF SPOT THE THIRD MA
#property indicator_width3  1          //LINE THICKNESS THE THIRD MA
#property indicator_color3  clrPurple    //LINE COLOR THE THIRD MA

//SET MA BUFFER TO STORE DATA
double buffer_mA200[];  //BUFFER FOR THE FIRST MA
double buffer_mA100[];  //BUFFER FOR THE SECOND MA
double buffer_mA50[];   //BUFFER FOR THE THIRD MA

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {

//SETTING BUFFER
   SetIndexBuffer(0, buffer_mA200, INDICATOR_DATA);  //INDEX 0 FOR MA200
   SetIndexBuffer(1, buffer_mA100, INDICATOR_DATA);  //INDEX 1 FOR MA100
   SetIndexBuffer(2, buffer_mA50, INDICATOR_DATA);   //INDEX 1 FOR MA50

//---
   return(INIT_SUCCEEDED);
  }

Explicación:

//SET MA BUFFER TO STORE DATA
double buffer_mA200[];  //BUFFER FOR THE FIRST MA
double buffer_mA100[];  //BUFFER FOR THE SECOND MA
double buffer_mA50[];   //BUFFER FOR THE THIRD MA

Estas matrices (buffer_mA200, buffer_mA100, buffer_mA50) sirven como almacenamiento para los valores calculados de cada media móvil (MA).

Cada buffer corresponde a un MA específico:

  • buffer_mA200 → Almacena valores para MA 200
  • buffer_mA100 → Almacena valores para MA 100
  • buffer_mA50 → Almacena valores para MA 50

Al mostrar el indicador, los valores guardados en estos búferes se representarán en el gráfico. Para almacenar los valores calculados de un indicador en MQL5, se requieren búferes de indicador. Sería imposible guardar y mostrar los resultados sin buffers.

//SETTING BUFFER
SetIndexBuffer(0, buffer_mA200, INDICATOR_DATA);  //INDEX 0 FOR MA200
SetIndexBuffer(1, buffer_mA100, INDICATOR_DATA);  //INDEX 1 FOR MA100
SetIndexBuffer(2, buffer_mA50, INDICATOR_DATA);   //INDEX 2 FOR MA50

SetIndexBuffer() se utiliza para vincular cada búfer al sistema de trazado del indicador.

Se necesitan tres parámetros:

  • Índice de búfer → Determina el orden en que se utilizan los búferes (comenzando desde 0).
  • La variable Buffer → El buffer que almacenará los valores para ese índice.
  • Tipo de búfer → INDICATOR_DATA especifica que el búfer contiene valores de indicador.

Desglose de cada línea:

  • SetIndexBuffer(0, buffer_mA200, INDICATOR_DATA); → Asigna buffer_mA200 al índice 0 (primer MA).
  • SetIndexBuffer(1, buffer_mA100, INDICATOR_DATA); → Asigna buffer_mA100 al índice 1 (segunda media móvil).
  • SetIndexBuffer(2, buffer_mA50, INDICATOR_DATA); → Asigna buffer_mA50 al índice 2 (tercer MA).

Esto garantiza que el sistema indicador MQL5 reconozca y trace correctamente cada búfer. El indicador no funcionaría correctamente sin este paso.

Tener una comprensión profunda de las matemáticas o el razonamiento que subyacen a un indicador es crucial para su creación. Sólo cuando un indicador evalúa con precisión los cambios de precios utilizando una base matemática o lógica sólida puede considerarse útil. Debes comprender cómo funciona un indicador y qué entradas se necesitan para calcularlo de manera eficiente antes de ponerlo en práctica en MQL5.

Por ejemplo, tomemos la media móvil:

Al reducir las oscilaciones de precios, el promedio móvil hace más sencillo detectar patrones de mercado sin verse influenciado por cambios transitorios.

Para calcular una media móvil, debemos considerar:

Período

La cantidad de velas históricas que se utilizan para calcular la media móvil depende del período de tiempo. Por ejemplo, las últimas 200 velas están promediadas por una MA de 200 períodos. Si bien la media móvil responde mejor a los movimientos recientes cuando el período es más corto, un período más largo produce una línea más suave que responde a los cambios de precios más lentamente.

Tipo de precio

La MA se puede calcular utilizando diferentes tipos de precios, como:

  • Precio de cierre → Utiliza el precio de cierre de cada vela.
  • Precio de apertura → Utiliza el precio de apertura de cada vela.
  • Precio alto → Utiliza el precio más alto de cada vela.
  • Precio bajo → Utiliza el precio más bajo de cada vela.

En este proyecto, trabajaremos con tres medias móviles diferentes:

  • MA 200 (aplicado al precio alto)
  • MA 100 (aplicado al precio de cierre)
  • MA 50 (aplicado al precio de apertura)

Comprender estos conceptos básicos garantiza que podamos calcular y visualizar correctamente el promedio móvil sin depender de funciones MQL5 integradas como iMA().

Ejemplo:

//INDICATOR IN CHART WINDOW
#property indicator_chart_window

//SET INDICATOR BUFFER TO STORE DATA
#property indicator_buffers 3

//SET NUMBER FOR INDICATOR PLOTS
#property indicator_plots   3

//SETTING PLOTS PROPERTIES
//PROPERTIES OF THE FIRST MA (MA200)
#property indicator_label1  "MA 200"   //GIVE PLOT ONE A NAME
#property indicator_type1   DRAW_LINE  //TYPE OF PLOT THE FIRST MA 
#property indicator_style1  STYLE_DASHDOTDOT  //STYLE OF SPOT THE FIRST MA
#property indicator_width1  1         //LINE THICKNESS THE FIRST MA
#property indicator_color1  clrBlue    //LINE COLOR THE FIRST MA

//PROPERTIES OF THE SECOND MA (MA100)
#property indicator_label2  "MA 100"   //GIVE PLOT TWO A NAME
#property indicator_type2   DRAW_LINE  //TYPE OF PLOT THE SECOND MA
#property indicator_style2  STYLE_DASH  //STYLE OF SPOT THE SECOND MA
#property indicator_width2  1          //LINE THICKNESS THE SECOND MA
#property indicator_color2  clrBrown    //LINE COLOR THE SECOND MA

//PROPERTIES OF THE THIRD MA (MA50)
#property indicator_label3  "MA 50"    //GIVE PLOT TWO A NAME
#property indicator_type3   DRAW_LINE  //TYPE OF PLOT THE THIRD MA
#property indicator_style3  STYLE_DOT  //STYLE OF SPOT THE THIRD MA
#property indicator_width3  1          //LINE THICKNESS THE THIRD MA
#property indicator_color3  clrPurple    //LINE COLOR THE THIRD MA

//SET MA BUFFER TO STORE DATA
double buffer_mA200[];  //BUFFER FOR THE FIRST MA
double buffer_mA100[];  //BUFFER FOR THE SECOND MA
double buffer_mA50[];   //BUFFER FOR THE THIRD MA

//SET MA PERIOD
input int period_ma200 = 200;  //PERIOD FOR THE FIRST MA
input int period_ma100 = 100;  //PERIOD FOR THE SECOND MA
input int period_ma50  = 50;   //PERIOD FOR THE THIRD MA

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {

//SETTING BUFFER
   SetIndexBuffer(0, buffer_mA200, INDICATOR_DATA);  //INDEX 0 FOR MA200
   SetIndexBuffer(1, buffer_mA100, INDICATOR_DATA);  //INDEX 1 FOR MA100
   SetIndexBuffer(2, buffer_mA50, INDICATOR_DATA);   //INDEX 1 FOR MA50

//SETTING BARS TO START PLOTTING
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, period_ma200);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, period_ma100);
   PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, period_ma50);

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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[])
  {

//CALCULATE THE MOVING AVERAGE FOR THE THE First MA (MA200)
   for(int i = period_ma200 - 1; i < rates_total; i++)
     {

      double sum = 0.0;
      for(int j = 0; j < period_ma200; j++)
        {
         sum += high[i - j];
        }

      buffer_mA200[i] = sum / period_ma200;

     }

//CALCULATE THE MOVING AVERAGE FOR THE THE SECOND MA (MA100)
   for(int i = period_ma100 - 1; i < rates_total; i++)
     {

      double sum = 0.0;
      for(int j = 0; j < period_ma100; j++)
        {
         sum += close[i - j];
        }
      buffer_mA100[i] = sum / period_ma100;

     }

//CALCULATE THE MOVING AVERAGE FOR THE THE THIRD MA (MA50)
   for(int i = period_ma50 - 1; i < rates_total; i++)
     {
      double sum = 0.0;
      for(int j = 0; j < period_ma50; j++)
        {
         sum += open[i - j];
        }
      buffer_mA50[i] = sum / period_ma50;
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

Explicación:

//SET MA PERIOD
input int period_ma200 = 200;  //PERIOD FOR THE FIRST MA
input int period_ma100 = 100;  //PERIOD FOR THE SECOND MA
input int period_ma50  = 50;   //PERIOD FOR THE THIRD MA

  • Estas variables de entrada definen el período de cada media móvil (MA).
  • El período determina cuántas velas pasadas utilizará la MA para su cálculo.
  • period_ma200 = 200 significa que la MA200 utilizará las últimas 200 velas para calcular el precio promedio.
  • period_ma100 = 100 significa que la MA100 utilizará las últimas 100 velas para calcular el promedio.
  • period_ma50 = 50 significa que la MA50 utilizará las últimas 50 velas para calcular el promedio.
  • Dado que se trata de variables de entrada, los operadores pueden modificarlas en la configuración del indicador sin cambiar el código.

//SETTING BARS TO START PLOTTING
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, period_ma200);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, period_ma100);
   PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, period_ma50);

¿Por qué es esto necesario?

  • Dado que una media móvil con un período de 200 necesita 200 velas anteriores para calcular su valor, no puede graficar nada antes de las primeras 200 velas.
  • PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, period_ma200); le dice a MetaTrader que comience a dibujar MA200 solo después de que haya 200 velas disponibles.
  • PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, period_ma100); hace lo mismo para MA100 (comienza después de 100 velas).
  • PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, period_ma50); garantiza que MA50 comience después de 50 velas.

Figura 4. Comienzo del dibujo

//+------------------------------------------------------------------+
//| 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[])

La función central de cada indicador personalizado, OnCalculate(), se llama automáticamente cada vez que se recibe un nuevo tick o se actualizan datos históricos. Es crucial para los cálculos de indicadores ya que procesa datos de precios y modifica los buffers del indicador. OnCalculate() está hecho especialmente para indicadores y ofrece acceso directo a datos de precios históricos sin la necesidad de otros procedimientos como CopyOpen(), CopyClose() o ArraySetAsSeries(), a diferencia de OnTick(), que se utiliza en Asesores Expertos.

Diferencia entre OnCalculate() y OnTick()

Característica
OnCalculate()
OnTick()
Utilizado en
Indicators
Expert Advisors
Llamado cuando Llega un nuevo tick o se actualiza el gráfico
Llega una nueva garrapata
Acceso a datos de precios
Utiliza matrices integradas (open[], close[], etc.)
Requiere funciones como CopyClose() para obtener datos
Objetivo
Calcula y actualiza los valores de los indicadores
Ejecuta la lógica comercial y coloca órdenes.
Comprensión de los parámetros en OnCalculate()
Parámetro
Descripción
rates_total
El número total de velas (barras) disponibles en el gráfico.
prev_calculated
El número de barras calculadas previamente (ayuda a optimizar el rendimiento).
time[]
La marca de tiempo de cada vela (por ejemplo, 2024.02.02 12:30).
open[]
El precio de apertura de cada vela.
high[]
El precio más alto de cada vela
low[]
El precio más bajo de cada vela.
close[]
El precio de cierre de cada vela.
tick_volume[]
El número de ticks (actualizaciones de precios) dentro de una vela.
volume[]
El volumen total negociado dentro de una vela.
spread[]
El spread (diferencia entre el precio de oferta y el de demanda) para cada vela.
// CALCULATE THE MOVING AVERAGE FOR THE FIRST MA (MA200)
for(int i = period_ma200 - 1; i < rates_total; i++)
  {
   double sum = 0.0;
   for(int j = 0; j < period_ma200; j++)
     {
      sum += high[i - j];  // SUM OF HIGH PRICES OVER THE PERIOD
     }
   buffer_mA200[i] = sum / period_ma200;  // CALCULATE THE AVERAGE
  }

Se utiliza un bucle for que itera a través de los datos de precios para calcular la media móvil (MA) para la primera MA (MA200). Tenemos suficientes puntos de datos previos para calcular el promedio porque el bucle comienza en period_ma200 - 1. Continúa hasta rates_total, que es la cantidad total de puntos de datos de precios que se proporcionan. Este método evita errores que podrían ocurrir si intentamos acceder a puntos de datos inexistentes (como valores de índice negativos). Cada barra del gráfico tiene su media móvil determinada sistemáticamente por el bucle, que luego actualiza el buffer del indicador apropiadamente.

Para mantener la suma acumulada de los precios altos durante el período de tiempo dado (en este caso, 200), inicializamos una suma variable dentro del bucle. Un bucle for anidado itera a través de las últimas 200 barras desde 0 hasta period_ma200. Suma += alto[i - j]; se utiliza en cada iteración para agregar el precio alto de una determinada barra a la variable suma. Al avanzar hacia atrás desde el índice actual i, la fórmula i – j garantiza que estamos sumando los precios altos de las últimas 200 barras. Este procedimiento suma eficientemente todos los precios altos para el período de tiempo especificado.

Una vez que tenemos el total de los precios altos en los 200 períodos, dividimos esa cantidad por la longitud del período para obtener el promedio: buffer_mA200[i] = suma / periodo_ma200; El valor MA calculado para cada barra se representa posteriormente mediante este valor final, que luego se guarda en el índice apropiado de buffer_mA200. Al tomar el promedio de los últimos 200 precios altos, el promedio móvil equilibra las oscilaciones de precios y permite a los operadores detectar patrones a largo plazo. Aunque los otros promedios móviles emplean diferentes tipos de precios (cierre y apertura) y períodos (100 y 50), el mismo razonamiento es válido para ellos.

Figura 5. Línea MA

3.2. Construyendo un indicador de media móvil en formato de vela

En esta sección, desarrollaremos un tipo diferente de indicador de media móvil que utiliza el formato de vela para mostrar los movimientos de precios. Este indicador empleará un promedio móvil de cinco períodos y utilizará velas en lugar de líneas para mostrar gráficamente sus valores. Podemos filtrar con mayor éxito el ruido del mercado y resaltar las tendencias a corto plazo al presentar datos de promedio móvil de esta manera. Esto preservará los fundamentos de los cálculos de promedio móvil y al mismo tiempo ofrecerá un punto de vista distintivo sobre el movimiento de precios.

El precio de apertura, el precio de cierre, el precio máximo y el precio mínimo son los cuatro componentes esenciales del precio que forman una vela. El formato de vela requiere cálculos de promedio móvil independientes para estos cuatro valores, a diferencia del estilo de línea, que solo requiere un valor de precio por período (como el cierre o la apertura). En consecuencia, necesitamos un mínimo de cuatro buffers para un solo gráfico, uno para cada uno de los valores de promedio móvil que representan los precios de apertura, cierre, máximo y mínimo. La estructura de este indicador garantiza que los datos del promedio móvil se presenten de una manera que imita de cerca los patrones de velas reales, lo que facilita el análisis de la tendencia de precios utilizando señales visuales bien conocidas.

Ejemplo:

#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1

//---- plot ColorCandles
#property indicator_label1  "Candles"
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrGreen, clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- indicator buffers
double OpenBuffer[];
double HighBuffer[];
double LowBuffer[];
double CloseBuffer[];
double ColorBuffer[];

int period = 5;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0, OpenBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, HighBuffer, INDICATOR_DATA);
   SetIndexBuffer(2, LowBuffer, INDICATOR_DATA);
   SetIndexBuffer(3, CloseBuffer, INDICATOR_DATA);
   SetIndexBuffer(4, ColorBuffer, INDICATOR_COLOR_INDEX);

   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, period);

   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| 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 < period)
     {
      Print("Error: Not enough bars to calculate.");
      return 0;
     }

   for(int i = period - 1; i < rates_total; i++)
     {

      if(i - period + 1 < 0)
         continue;

      double sumClose = 0.0;
      double sumOpen = 0.0;
      double sumHigh = 0.0;
      double sumLow = 0.0;

      for(int j = 0; j < period; j++)
        {
         int index = i - j;
         if(index < 0)
            continue; // Prevent out-of-bounds access

         sumClose += close[index];
         sumOpen += open[index];
         sumHigh += high[index];
         sumLow += low[index];
        }

      if(period > 0)
        {
         OpenBuffer[i] = sumOpen / period;
         HighBuffer[i] = sumHigh / period;
         LowBuffer[i] = sumLow / period;
         CloseBuffer[i] = sumClose / period;
        }
      else
        {
         Print("Error: Division by zero prevented.");
         return 0;
        }

      ColorBuffer[i] = (CloseBuffer[i] >= OpenBuffer[i]) ? 0 : 1;
     }

   return rates_total;
  }

Explicación:

#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1

//---- plot ColorCandles
#property indicator_label1  "Candles"
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrGreen, clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- indicator buffers
double OpenBuffer[];
double HighBuffer[];
double LowBuffer[];
double CloseBuffer[];
double ColorBuffer[];

int period = 5;

Este código define las propiedades y los buffers de un indicador personalizado que muestra un promedio móvil en formato de vela. Una vela normalmente necesita cuatro amortiguadores: uno para los componentes de precio de apertura, máximo, mínimo y cierre. Sin embargo, debido a que se necesita un buffer adicional (ColorBuffer) para identificar y almacenar el color de cada vela, este indicador necesita cinco buffers.

Propiedades del indicador

  • #property indicator_separate_window garantiza que el indicador se muestre en una ventana separada en lugar de trazarse en el gráfico principal.
  • #property indicator_buffers 5 Define el número de buffers utilizados. Aunque una vela requiere solo cuatro buffers (Apertura, Alto, Bajo y Cierre), se necesita un quinto buffer para asignar un color a cada vela.
  • #property indicator_plots 1 especifica que el indicador solo tiene un gráfico, que utilizará velas de colores.

Configuración de gráficos y visualización

  • indicator_label1 "Candles" nombra el dibujo.
  • indicator_type1 DRAW_COLOR_CANDLES establece el tipo de gráfico en velas de colores. A diferencia de DRAW_LINE, este tipo requiere valores de apertura, alto, bajo y cierre, además de un índice de color.
  • indicator_color1 clrGreen, clrRed asigna verde a las velas alcistas y rojo a las velas bajistas.
  • indicator_style1 STYLE_SOLID garantiza bordes de velas sólidos.
  • indicator_width1 1 define el grosor de los contornos de las velas.

¿Por qué cinco buffers en lugar de cuatro?

Una estructura de vela típica requiere cuatro buffers:

  • OpenBuffer[]: almacena los precios de apertura promedio móviles.
  • HighBuffer[]: almacena los precios altos promedio móviles.
  • LowBuffer[]: almacena los precios bajos promedio móviles.
  • CloseBuffer[]: almacena los precios de cierre promedio móviles.

Sin embargo, dado que el indicador utiliza velas de colores, también necesita un quinto búfer:

  • ColorBuffer[]: Almacena el índice de color (0 para verde, 1 para rojo). Al proporcionar un buffer adicional, la media móvil se representa gráficamente mediante velas bajistas (rojas) y alcistas (verdes), lo que facilita la identificación de patrones de precios.
//--- indicator buffers mapping
SetIndexBuffer(0, OpenBuffer, INDICATOR_DATA);
SetIndexBuffer(1, HighBuffer, INDICATOR_DATA);
SetIndexBuffer(2, LowBuffer, INDICATOR_DATA);
SetIndexBuffer(3, CloseBuffer, INDICATOR_DATA);
SetIndexBuffer(4, ColorBuffer, INDICATOR_COLOR_INDEX);

PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, period);

Para guardar los valores de promedio móvil determinados en formato de vela, esta sección de código asigna los buffers del indicador. Esta variante de velas del promedio móvil utiliza cuatro buffers (OpenBuffer, HighBuffer, LowBuffer y CloseBuffer) para almacenar el equivalente del promedio móvil de los precios de apertura, máximo, mínimo y cierre, a diferencia de la versión convencional basada en líneas, que solo necesita un buffer para contener los valores calculados para el gráfico.

También se utiliza un quinto búfer, llamado ColorBuffer, para identificar el color de cada vela, diferenciando entre velas bajistas (rojas) y alcistas (verdes). Para garantizar que el indicador procese y muestre los datos adecuadamente, la función SetIndexBuffer() asocia cada búfer con un índice de gráfico distinto. Para evitar gráficos incompletos o engañosos, PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, period); se asegura de que el indicador solo comience a trazar después de que haya suficientes barras disponibles.

if(rates_total < period)
  {
   Print("Error: Not enough bars to calculate.");
   return 0;
  }

for(int i = period - 1; i < rates_total; i++)
  {

   if(i - period + 1 < 0)
      continue;

   double sumClose = 0.0;
   double sumOpen = 0.0;
   double sumHigh = 0.0;
   double sumLow = 0.0;

   for(int j = 0; j < period; j++)
     {
      int index = i - j;
      if(index < 0)
         continue; // Prevent out-of-bounds access

      sumClose += close[index];
      sumOpen += open[index];
      sumHigh += high[index];
      sumLow += low[index];
     }

   if(period > 0)
     {
      OpenBuffer[i] = sumOpen / period;
      HighBuffer[i] = sumHigh / period;
      LowBuffer[i] = sumLow / period;
      CloseBuffer[i] = sumClose / period;
     }
   else
     {
      Print("Error: Division by zero prevented.");
      return 0;
     }

   ColorBuffer[i] = (CloseBuffer[i] >= OpenBuffer[i]) ? 0 : 1;
  }

return rates_total;

Este segmento de código comienza determinando si hay suficientes barras de precios para que el cálculo continúe. Hay suficientes puntos de datos históricos (o "barras") para calcular el promedio móvil en función del período definido por el usuario gracias a la condición if (rates_total < period). La función devuelve 0 y escribe un mensaje de error si no hay suficientes barras. Este paso es esencial ya que no se puede realizar un cálculo de promedio móvil significativo sin datos suficientes, y tratar de hacerlo puede generar estadísticas inexactas o engañosas.

El bucle for itera sobre los datos de precios, comenzando en el índice del período - 1 y llegando hasta rates_total, después de que se haya verificado que hay suficientes barras. Cada barra es procesada por el bucle, que comienza en el momento designado y continúa. En este bucle, el índice de barra actual está representado por la variable i. Utilizando la información de precios de las barras del período anterior, este bucle determina el promedio móvil de cada barra. El bucle garantiza que el cálculo solo comience cuando esté disponible el número necesario de barras y continúe con la siguiente iteración si el índice i - período + 1 es menor que 0.

Cuatro variables se inicializan a 0.0 dentro del bucle: sumClose, sumOpen, sumHigh y sumLow. Las sumas acumuladas de los datos de precios correspondientes para el período de tiempo especificado se almacenarán en estas variables. La información de precios de cada barra dentro del período se recopila utilizando un segundo bucle for, esta vez iterando desde 0 hasta el período -1. Al deducir j del índice actual i, el bucle interno recupera cada una de las barras anteriores y calcula la suma de los precios de cierre, apertura, máximo y mínimo durante el período especificado. El bucle evita datos defectuosos al usar la condición if(index < 0) para evitar acceder a entradas fuera de los límites en las matrices.

Para evitar problemas de división por cero, el código determina si el período es mayor que cero después de recopilar los datos de precios del período. El código determina el promedio de los precios de apertura, máximo, mínimo y cierre durante el período y guarda el resultado en los buffers OpenBuffer, HighBuffer, LowBuffer y CloseBuffer, si el período es válido. Los valores calculados para el gráfico de velas se almacenan en estos búferes. Por último, el color de la vela se establece actualizando el ColorBuffer. La vela es de color verde (valor 0) cuando el precio de cierre es mayor o igual al precio de apertura, lo que significa una tendencia alcista; si el precio de cierre es menor o igual al precio de apertura, la vela es de color rojo (valor 1), lo que significa una tendencia bajista.

El valor de rates_total, que indica a MetaTrader cuántas barras se procesaron correctamente, se devuelve al final de la función OnCalculate. Para llamadas posteriores al método OnCalculate, este valor es crucial porque realiza un seguimiento de la cantidad de barras que se han procesado y garantiza que las actualizaciones de datos en tiempo real se manejen correctamente.

Figura 6. Vela MA

Al trabajar con formatos de velas, también sentamos las bases para indicadores más avanzados como los gráficos Heikin Ashi, que se explorarán en futuros artículos.


Conclusión

En conclusión, este artículo presentó conceptos básicos como la creación de indicadores personalizados, el uso de promedios móviles y la visualización de datos en diferentes formatos, como estilos de línea y vela. También exploramos cómo utilizar buffers y configurar gráficos para representar datos. De ahora en adelante nos centraremos en proyectos más interesantes en futuros artículos. La mejor manera de aprender como principiante es a través de un enfoque basado en proyectos, que divide el aprendizaje en pasos manejables en lugar de abrumarlo con detalles innecesarios en esta etapa. Este método garantiza un progreso gradual y una comprensión más profunda de los conceptos clave.

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

Archivos adjuntos |
dhermanus
dhermanus | 30 may 2025 en 07:12

Gracias por el esfuerzo. Isreal. Se lo agradezco.

Me gustaría comentar en esta parte de la serie para personalizar el indicador.
No utilizaste el prev_calculated. Eso significa que para cada tick en ejecución
tu código recalcularía cada barra calculada anterior otra vez.

Israel Pelumi Abioye
Israel Pelumi Abioye | 30 may 2025 en 09:27
dhermanus personalizar indicador.
No utilizaste el prev_calculated. Eso significa que para cada tick en ejecución
tu código recalcularía cada barra calculada anterior otra vez.
Hola.
Su comentario es muy apreciada, voy a mirar en eso.

Gracias.
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 12): Flujo externo (III) TrendMap Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 12): Flujo externo (III) TrendMap
El flujo del mercado está determinado por las fuerzas entre alcistas y bajistas. Hay niveles específicos que el mercado respeta debido a las fuerzas que actúan sobre ellos. Los niveles de Fibonacci y VWAP son especialmente poderosos a la hora de influir en el comportamiento del mercado. Acompáñame en este artículo mientras exploramos una estrategia basada en los niveles VWAP y Fibonacci para la generación de señales.
Pruebas de robustez en asesores expertos Pruebas de robustez en asesores expertos
En el desarrollo de una estrategia hay muchos detalles complejos a tener en cuenta, muchos de los cuales no se destacan para los traders principiantes. Como resultado, muchos comerciantes, incluido yo mismo, hemos tenido que aprender estas lecciones a las duras penas. Este artículo se basa en mis observaciones de errores comunes que la mayoría de los traders principiantes encuentran al desarrollar estrategias en MQL5. Ofrecerá una variedad de consejos, trucos y ejemplos para ayudar a identificar la descalificación de un EA y probar la solidez de nuestros propios EA de una manera fácil de implementar. El objetivo es educar a los lectores, ayudándolos a evitar futuras estafas al comprar EA, así como a prevenir errores en el desarrollo de su propia estrategia.
Automatización de estrategias de trading en MQL5 (Parte 6): Dominar la detección de bloques de órdenes para el comercio inteligente con dinero Automatización de estrategias de trading en MQL5 (Parte 6): Dominar la detección de bloques de órdenes para el comercio inteligente con dinero
En este artículo, automatizamos la detección de bloques de órdenes en MQL5 utilizando análisis de acción de precios puro. Definimos bloques de órdenes, implementamos su detección e integramos la ejecución automatizada de operaciones. Por último, realizamos una prueba retrospectiva de la estrategia para evaluar su rendimiento.
Dominando los registros (Parte 5): Optimizar el controlador con caché y rotación Dominando los registros (Parte 5): Optimizar el controlador con caché y rotación
Este artículo mejora la biblioteca de registro agregando formateadores en los controladores, la clase CIntervalWatcher para administrar ciclos de ejecución, optimización con almacenamiento en caché y rotación de archivos, pruebas de rendimiento y ejemplos prácticos. Con estas mejoras, aseguramos un sistema de registro eficiente, escalable y adaptable a diferentes escenarios de desarrollo.