Desarrollamos un indicador Heiken Ashi personalizado utilizando MQL5

Mohamed Abdelmaaboud | 6 octubre, 2023

Introducción

Todos necesitamos interpretar gráficos. Las herramientas que ayudarnos en esta tarea incluyen indicadores calculados según los precios, el volumen, otro indicador técnico o una combinación de estos. Tenemos muchos indicadores listos para usar integrados en el terminal comercial, pero si necesitamos añadir algunas funciones que se adapten a nuestro estilo comercial, tendremos que recurrir a soluciones personalizadas.

En este artículo, usaremos la función iCustom y crearemos un indicador personalizado según nuestras condiciones y preferencias. También crearemos un indicador técnico Heiken Ashi personalizado y lo usaremos en sistemas comerciales. Así, hoy abarcaremos los siguientes temas:

El material del artículo se puede utilizar como muestra para crear indicadores personalizados propios. Usaremos el lenguaje MQL5 (MetaQuotes Language) integrado en la plataforma comercial MetaTrader 5 para escribir los códigos para los indicadores y asesores creados. Si no sabe cómo descargarlos y utilizarlos, lea la sección "Escribiendo el código MQL5 en el MetaEditor" de artículos anteriores.

¡Atención! Toda la información del presente artículo se ofrece «tal cual», únicamente con fines ilustrativos, y no supone ningún tipo de recomendación. El artículo no garantiza ningún resultado en absoluto. Todo lo que ponga en práctica usando este artículo como base, lo hará bajo su propia cuenta y riesgo; el autor no garantiza resultado alguno.

Indicador personalizado y definición de Heiken Ashi

Como mencioné en la introducción de la sección anterior, un indicador personalizado es una herramienta de análisis técnico que puede crear el usuario usando el lenguaje de programación MQL5. Puede utilizarse en MetaTrader 5 para analizar y comprender los movimientos del mercado y ayudar a tomar decisiones de inversión informadas. Existen muchos indicadores técnicos incorporados de gran utilidad, pero a veces necesitamos analizar y comprender cómo se está desempeñando el mercado según algunas ideas matemáticas, estadísticas o técnicas adicionales cuyos principios no están cubiertos por los indicadores existentes. En estos casos, deberemos crear dicho indicador nosotros mismos, y esta es una de las características más destacadas de la plataforma MetaTrader 5: su capacidad para ayudar al usuario a crear herramientas analíticas o comerciales propias que se adapten a sus preferencias y objetivos específicos.

Veamos los pasos necesarios para crear nuestro propio indicador:

Abra el MetaEditor y seleccione la carpeta Indicators en el Navegador.

Carpeta Indicators

Clique en el botón "Crear" para crear un nuevo programa como se muestra en la siguiente imagen

Botón New

Después de esto, se abrirá una ventana en la que deberá seleccionar el tipo de programa a crear. Seleccione "Indicador personalizado"

Seleccionar el tipo de programa

Después de clicar en el botón "Siguiente", se abrirá la siguiente ventana con información sobre el indicador. Introduzca el nombre del indicador personalizado aquí y clique en Siguiente.

Información sobre el indicador

En las siguientes ventanas ofrecemos información más detallada sobre el indicador.

Información sobre el indicador 2

Información sobre el indicador 3

Tras completar todas las configuraciones y clicar en el botón "Finalizar", se abrirá la ventana del editor.

Veremos cómo desarrollar un indicador propio usando Heiken Ashi como ejemplo. Como es lógico, primero necesitaremos aprender más sobre él. Heiken Ashi supone una técnica de gráficos de velas que se puede utilizar para representar y analizar los movimientos del mercado, y puede usarse en combinación con otras herramientas para proporcionar información detallada sobre la que tomar decisiones comerciales informadas.

Los gráficos Heiken Ashi son similares a los gráficos de velas normales, pero los métodos para calcular las velas son distintos. Como ya sabemos, un gráfico de velas normal calcula los precios basándose en una serie de precios reales (apertura, máximo, mínimo y cierre) de un periodo determinado, pero Heiken Ashi tiene en cuenta los precios similares anteriores (apertura, máximo, mínimo y cierre) al calcular sus velas.

Así es como se calculan los valores de Heiken Ashi:

Según el cálculo, el indicador construye velas alcistas y bajistas. Los colores de estas velas indicarán la dirección correspondiente del mercado: alcista o bajista. A modo de comparación, a continuación le mostramos las velas japonesas tradicionales y el Heiken Ashi.

 Heiken Ashi

La sección superior muestra las velas tradicionales, mientras que la sección inferior muestra el indicador Heiken Ashi, representado como velas azules y rojas que determinan la dirección del mercado. El objetivo del indicador consiste en filtrar y eliminar parte del ruido en los movimientos del mercado suavizando los datos para evitar señales falsas.


Indicador Heiken Ashi simple

Vamos a crear un indicador Heiken Ashi simple para usarlo en MetaTrader 5. El indicador debe verificar constantemente los precios (apertura, máximo, mínimo y cierre) y realizar cálculos para generar los valores haOpen, haHigh, haLow y haClose. Según los cálculos, el indicador debería mostrar los valores en el gráfico como velas de diferentes colores: azul para el movimiento alcista y rojo para el movimiento bajista. Las velas deberán mostrarse en una ventana aparte debajo del gráfico tradicional en forma de subventana.

Veamos todos los pasos que deberemos seguir para crear este indicador personalizado.

Primero definiremos la configuración del indicador especificando los parámetros adicionales a través de los valores #property y el identificador:

#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrBlue, clrRed
#property indicator_width1  2
#property indicator_label1  "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"

Luego crearemos cinco arrays para cinco búferes del indicador (haOpen, haHigh, haLow, haClose, haColor) de tipo double.

double haOpen[];
double haHigh[];
double haLow[];
double haClose[];
double haColor[];

Dentro de OnInit() esta función se utilizará para inicializar un indicador en ejecución.

int OnInit()

A continuación clasificaremos los búferes del indicador usando un array dinámico unidimensional de tipo double usando la función (SetIndexBuffer). Los parámetros serán los siguientes:

   SetIndexBuffer(0,haOpen,INDICATOR_DATA);
   SetIndexBuffer(1,haHigh,INDICATOR_DATA);
   SetIndexBuffer(2,haLow,INDICATOR_DATA);
   SetIndexBuffer(3,haClose,INDICATOR_DATA);
   SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);

Luego estableceremos el valor de la propiedad del indicador correspondiente usando la función (IndicatorSetInteger) con una variante de llamada en la que especificaremos el identificador de la propiedad. Los parámetros serán los siguientes:

IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

A continuación, estableceremos el valor de propiedad correspondiente de tipo string con la opción de llamada en la que también especificaremos el identificador de la propiedad. Los parámetros serán los siguientes:

   IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");

Luego estableceremos el valor de la propiedad double correspondiente del indicador necesario usando la función (PlotIndexSetDouble). Los parámetros serán los siguientes:

   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);

Luego retornaremos (INIT_SUCCEEDED) como parte de la función OnInit() para finalizarla retornando la inicialización exitosa.

   return(INIT_SUCCEEDED);

Dentro de la función OnCalculate, que se llama en el indicador para procesar los datos de precio, el tipo de cálculo cambiará según la serie temporal del periodo actual.

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

Ahora crearemos la variable entera start. Le asignaremos el valor más adelante:

int start;

Después usaremos una declaración if para retornar los valores del índice (bajo, alto, abierto y cerrado) y start=1 si prev_calculated es 0, o retornar el valor inicial asignado a (prev_calculated-1):

   if(prev_calculated==0)
     {
      haLow[0]=low[0];
      haHigh[0]=high[0];
      haOpen[0]=open[0];
      haClose[0]=close[0];
      start=1;
     }
   else
      start=prev_calculated-1;

La función for se usa en el ciclo de cálculo principal. La declaración for consta de tres expresiones y declaraciones ejecutables.

Tres expresiones:

Las operaciones que deberemos realizar cada vez durante el ciclo son:

Cálculo para las cuatro variables de tipo double.

La asignación de los valores calculados en el paso anterior será similar a la siguiente:

Ahora comprobaremos si el valor de apertura de Heiken Ashi es inferior al valor de cierre. En caso afirmativo, el indicador debería dibujar una vela azul y, en caso contrario, una roja.

   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
      double haCloseVal=(open[i]+high[i]+low[i]+close[i])/4;
      double haHighVal =MathMax(high[i],MathMax(haOpenVal,haCloseVal));
      double haLowVal  =MathMin(low[i],MathMin(haOpenVal,haCloseVal));

      haLow[i]=haLowVal;
      haHigh[i]=haHighVal;
      haOpen[i]=haOpenVal;
      haClose[i]=haCloseVal;

      //--- set candle color
      if(haOpenVal<haCloseVal)
         haColor[i]=0.0;
      else
         haColor[i]=1.0;
     }

Luego finalizaremos la función retornando (rates_total) como prev_calculated para la siguiente llamada,

return(rates_total);

y compilaremos el código para asegurarnos de que no haya errores. El código completo tendrá el aspecto que sigue:

//+------------------------------------------------------------------+
//|                                             simpleHeikenAshi.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrBlue, clrRed
#property indicator_width1  2
#property indicator_label1  "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
double haOpen[];
double haHigh[];
double haLow[];
double haClose[];
double haColor[];
int OnInit()
  {
   SetIndexBuffer(0,haOpen,INDICATOR_DATA);
   SetIndexBuffer(1,haHigh,INDICATOR_DATA);
   SetIndexBuffer(2,haLow,INDICATOR_DATA);
   SetIndexBuffer(3,haClose,INDICATOR_DATA);
   SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
   IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
   return(INIT_SUCCEEDED);
  }
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[])
  {
   int start;
   if(prev_calculated==0)
     {
      haLow[0]=low[0];
      haHigh[0]=high[0];
      haOpen[0]=open[0];
      haClose[0]=close[0];
      start=1;
     }
   else
      start=prev_calculated-1;
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
      double haCloseVal=(open[i]+high[i]+low[i]+close[i])/4;
      double haHighVal =MathMax(high[i],MathMax(haOpenVal,haCloseVal));
      double haLowVal  =MathMin(low[i],MathMin(haOpenVal,haCloseVal));

      haLow[i]=haLowVal;
      haHigh[i]=haHighVal;
      haOpen[i]=haOpenVal;
      haClose[i]=haCloseVal;
      if(haOpenVal<haCloseVal)
         haColor[i]=0.0;
      else
         haColor[i]=1.0;
     }
   return(rates_total);
  }

Después realizar la compilación con éxito, el indicador estará disponible en la carpeta "Indicadores" en la ventana "Navegador", como se muestra a continuación.

simpleHA nav

Vamos a iniciarlo. Se abrirá una ventana de configuración estándar:

 simpleHA win

La pestaña "Colores" mostrará la configuración por defecto: azul para movimiento ascendente, rojo para movimiento descendente. Los valores se pueden modificar.

 simpleHA win2

Después de clicar en OK, el indicador se adjuntará al gráfico y tendrá el aspecto siguiente:

iniciando simpleHA

Como podemos ver, el indicador funcionará en una subventana separada. Las velas azules y rojas indicarán la dirección del precio (alcista y bajista). Ahora tenemos nuestro propio indicador creado en MetaTrader 5, y podemos usarlo en cualquier sistema comercial. Esto es exactamente lo que haremos ahora.


Asesor experto basado en el indicador personalizado Heiken Ashi

En este apartado aprenderemos a utilizar los indicadores personalizados en un asesor experto. Para ello, crearemos un sistema Heiken Ashi simple que pueda mostrarnos los precios del indicador (apertura, máximo, mínimo y cierre) ya que sabemos que estos son diferentes de los precios reales calculados por el indicador.

Vamos a crear un asesor. Código completo:

//+------------------------------------------------------------------+
//|                                             heikenAshiSystem.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
int heikenAshi;
int OnInit()
  {
   heikenAshi=iCustom(_Symbol,_Period,"My Files\\Heiken Ashi\\simpleHeikenAshi");
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("Heiken Ashi System Removed");
  }
void OnTick()
  {
   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];
   CopyBuffer(heikenAshi,0,0,1,heikenAshiOpen);
   CopyBuffer(heikenAshi,1,0,1,heikenAshiHigh);
   CopyBuffer(heikenAshi,2,0,1,heikenAshiLow);
   CopyBuffer(heikenAshi,3,0,1,heikenAshiClose);
   Comment("heikenAshiOpen ",DoubleToString(heikenAshiOpen[0],_Digits),
           "\n heikenAshiHigh ",DoubleToString(heikenAshiHigh[0],_Digits),
           "\n heikenAshiLow ",DoubleToString(heikenAshiLow[0],_Digits),
           "\n heikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
  }

Diferencias en este código:

Tipo de programa: asesor. El diseño del programa será diferente porque consta de tres partes, concretamente:

Fuera de las funciones anteriores y antes de las mismas, crearemos una variable entera (heikenAshi)

int heikenAshi;

Dentro del ámbito de OnInit(), asignaremos el valor de la función iCustom a la variable heikenAshi. La función iCustom retornará el identificador del indicador personalizado, que aquí será Simple Heiken Ashi, pero puede usar cualquier indicador personalizado en la carpeta Indicadores. Parámetros:

Luego finalizaremos la función retornando (INIT_SUCCEEDED) para una inicialización exitosa.

int OnInit()
  {
   heikenAshi=iCustom(_Symbol,_Period,"My Files\\Heiken Ashi\\simpleHeikenAshi");
   return(INIT_SUCCEEDED);
  }

Dentro de la función OnDeinit(), usaremos la función print para indicar que el asesor ha sido eliminado.

void OnDeinit(const int reason)
  {
   Print("Heiken Ashi System Removed");
  }

Dentro de la función OnTick(), hemos hecho lo siguiente para finalizar nuestro código:

Hemos creado cuatro variables de tipo doble para los precios de Heiken Ashi (Open, High, Low y Close).

   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];

Luego hemos obtenido los datos de los búferes del indicador personalizado utilizando la función CopyBuffer. Parámetros:

Luego hemos recibido un comentario en el gráfico con los precios actuales de Heiken Ashi (apertura, máximo, mínimo y cierre) utilizando la función de comentario:

   Comment("heikenAshiOpen ",DoubleToString(heikenAshiOpen[0],_Digits),
           "\n heikenAshiHigh ",DoubleToString(heikenAshiHigh[0],_Digits),
           "\n heikenAshiLow ",DoubleToString(heikenAshiLow[0],_Digits),
           "\n heikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));

Tras compilar y ejecutar este código sin errores, podemos encontrar el asesor adjunto al gráfico. Es posible obtener la misma señal en el siguiente ejemplo:

 haSystem

Como podemos ver, los precios de los indicadores se muestran como un comentario en la esquina superior izquierda del gráfico.


Heiken Ashi - Sistema EMA

En este apartado añadiremos otra herramienta técnica para ver si el resultado es mejor o no. La idea consiste en filtrar las señales de los indicadores personalizados utilizando una media móvil exponencial con precios. Existen muchas formas de hacer esto: podemos crear otro indicador personalizado para EMA si queremos añadir más funciones a esta. Luego podremos usarlo en el asesor como iCustom de la misma manera que lo hemos hecho para obtener las señales deseadas. También podemos crear un indicador suavizado, realizando para ello el suavizado de los valores del indicador y luego usando nuestras señales. Podemos usar la función iMA incorporada en nuestro asesor para obtener señales del mismo. Por su simplicidad, aquí usaremos este método.

Necesitamos permitir que el asesor verifique continuamente los valores de las dos EMA actuales (rápida y lenta), la EMA rápida anterior y el precio de cierre de Heiken Ash para determinar las posiciones de cada valor. Si el valor anterior de heikenAshiClose es mayor que el array fastEMA anterior, y el valor fastEMA actual es mayor que el valor actual de SlowEMA, el asesor debería retornar una señal de compra y estos valores deberían mostrarse en el gráfico. Si el anterior valor de heikenAshiClose está por debajo del array fastEMA anterior y el valor de fastEMA actual está por debajo del valor actual de SlowEMA, el asesor debería retornar una señal de venta y estos valores deberían mostrarse en el gráfico.

Aquí tenemos el código completo para crear un asesor:

//+------------------------------------------------------------------+
//|                                          heikenAsh-EMASystem.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
input int fastEMASmoothing=9; // Fast EMA Period
input int slowEMASmoothing=18; // Slow EMA Period
int heikenAshi;
double fastEMAarray[], slowEMAarray[];
int OnInit()
  {
   heikenAshi=iCustom(_Symbol,_Period,"My Files\\Heiken Ashi\\simpleHeikenAshi");
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("Heiken Ashi-EMA System Removed");
  }
void OnTick()
  {
   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];
   CopyBuffer(heikenAshi,0,0,3,heikenAshiOpen);
   CopyBuffer(heikenAshi,1,0,3,heikenAshiHigh);
   CopyBuffer(heikenAshi,2,0,3,heikenAshiLow);
   CopyBuffer(heikenAshi,3,0,3,heikenAshiClose);
   int fastEMA = iMA(_Symbol,_Period,fastEMASmoothing,0,MODE_SMA,PRICE_CLOSE);
   int slowEMA = iMA(_Symbol,_Period,slowEMASmoothing,0,MODE_SMA,PRICE_CLOSE);
   ArraySetAsSeries(fastEMAarray,true);
   ArraySetAsSeries(slowEMAarray,true);
   CopyBuffer(fastEMA,0,0,3,fastEMAarray);
   CopyBuffer(slowEMA,0,0,3,slowEMAarray);
   if(heikenAshiClose[1]>fastEMAarray[1])
     {
      if(fastEMAarray[0]>slowEMAarray[0])
        {
         Comment("Buy Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nprevHeikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }
     }
   if(heikenAshiClose[1]<fastEMAarray[1])
     {
      if(fastEMAarray[0]<slowEMAarray[0])
        {
         Comment("Sell Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nheikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }
     }
  }

Qué ha cambiado en el código con respecto al anterior:

Crearemos datos de entrada personalizados para establecer el periodo de la EMA rápida y el periodo de la EMA lenta según las preferencias del usuario.

input int fastEMASmoothing=9; // Fast EMA Period
input int slowEMASmoothing=18; // Slow EMA Period

Luego crearemos dos arrays para fastEMA y slowEMA,

double fastEMAarray[], slowEMAarray[];

y estableceremos en 3 la cantidad de datos copiados en CopyBuffer para obtener los valores de cierre anteriores del indicador Heiken Ashi.

   CopyBuffer(heikenAshi,0,0,3,heikenAshiOpen);
   CopyBuffer(heikenAshi,1,0,3,heikenAshiHigh);
   CopyBuffer(heikenAshi,2,0,3,heikenAshiLow);
   CopyBuffer(heikenAshi,3,0,3,heikenAshiClose);

Determinaremos la EMA rápida y lenta usando la función iMA incorporada, que devuelve el identificador del indicador de media móvil. Parámetros:

   int fastEMA = iMA(_Symbol,_Period,fastEMASmoothing,0,MODE_SMA,PRICE_CLOSE);
   int slowEMA = iMA(_Symbol,_Period,slowEMASmoothing,0,MODE_SMA,PRICE_CLOSE);

Utilizaremos la función ArraySetAsSeries para configurar el indicador AS_SERIES. Parámetros:

   ArraySetAsSeries(fastEMAarray,true);
   ArraySetAsSeries(slowEMAarray,true);

Luego obtendremos los datos del búfer del indicador EMA usando la función CopyBuffer.

   CopyBuffer(fastEMA,0,0,3,fastEMAarray);
   CopyBuffer(slowEMA,0,0,3,slowEMAarray);

Condiciones para retornar señales usando la declaración if:

En caso de una señal de compra

Si heikenAshiClose anterior > el array fastEMA anterior y el array fastEMA actual > el array slowEMA actual, el asesor debería retornar una señal de compra y los siguientes valores:

   if(heikenAshiClose[1]>fastEMAarray[1])
     {
      if(fastEMAarray[0]>slowEMAarray[0])
        {
         Comment("Buy Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nprevHeikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }

Con una señal de venta:

Si heikenAshiClose anterior < el array fastEMA anterior y el array fastEMA actual < el array slowEMA actual, el asesor debería retornar una señal de venta y los valores de precio:

   if(heikenAshiClose[1]<fastEMAarray[1])
     {
      if(fastEMAarray[0]<slowEMAarray[0])
        {
         Comment("Sell Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nheikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }
     }

Tras compilar el código y ejecutarlo, podremos obtener nuestras señales como se muestra en los siguientes ejemplos de prueba.

Si hay una señal de compra:

HA con 2EMA - señal de compra

Como podemos ver en el gráfico anterior, en la esquina superior izquierda tenemos como comentario la siguiente señal:

Si hay una señal de venta:

HA con 2EMA - señal de venta

Como señal en el gráfico tenemos los valores siguientes:

Conclusión

Si ha entendido todo lo que hemos comentado en este artículo, podrá crear su propio indicador Heiken Ashi o incluso añadir algunas características adicionales según sus preferencias. Esto hará más fácil leer los gráficos y tomar decisiones efectivas. Además, podrá utilizar el indicador creado en sus sistemas comerciales como parte de los asesores, ya que lo hemos mencionado y utilizado en dos sistemas comerciales como ejemplo.

Espero que este artículo le resulte útil y le ayude a alcanzar sus objetivos comerciales. También espero que intente aplicar lo aprendido en este artículo, ya que le será de gran ayuda para entrenar sus habilidades de programación, y la práctica supone un factor esencial en el aprendizaje. Tenga en cuenta que debe probar todo lo aprendido en este artículo u otros recursos antes de usar sus conocimientos en el comercio real. Este artículo tiene fines exclusivamente educativos, por lo que el lector deberá tener cuidado y mostrar prudencia.

En mi perfil podrá encontrar los enlaces a mis otros artículos. Espero que también los encuentre útiles.