← К каталогу
Исходный код · ID 4295

SHK Pro Heikin Ashi Signals

shk professional heikin ashi 1.00.mq5
Вы автор или правообладатель?

Сообщите нам, если считаете, что материал размещён без разрешения.

Краткий обзор

О программе

SHK Pro Heikin Ashi Signals — индикатор для MetaTrader 5, реализующий аналитическую систему на основе свечей Хайкин Аши. Он рассчитывает значения HA Open, HA High, HA Low и HA Close, отображая их на графике с помощью графических объектов с цветовой индикацией направления тренда.

Индикатор поддерживает три режима цветового кодирования: стандартный, основанный на тренде и основанный на моментуме. Визуализация включает сигнальные круги моментов и подтверждённые стрелки BUY/SELL, которые формируются при совпадении изменения цвета HA-свечей с дивергенцией MACD.

Система сигналов предусматривает несколько уровней подтверждения: количество подтверждающих свечей, проверку по закрытию и фильтрацию по силе тел свечей. Настраиваемые уведомления включают всплывающие окна, push-уведомления, электронную почту и звуковые сигналы с возможностью задания периода охлаждения.

Режим работы с закрытыми свечами обеспечивает отсутствие перерисовки, а параметр MaxBarsToCalculate ограничивает объём обрабатываемой истории для оптимизации производительности.

Настройки программы

НастройкаОписание
MaxBarsToCalculate Максимальное количество баров для расчёта индикатора.
ShowHeikinAshiCandles Включает отображение HA-свечей на графике.
ShowOriginalCandlesFaint Отображает исходные свечи графика приглушённым цветом на фоне HA-свечей.
EnableSignals Включает или отключает генерацию торговых сигналов.
UseClosedBarsOnly Использует только закрытые свечи для расчёта сигналов, исключая перерисовку на формирующемся баре.
CandleMode Режим цветового кодирования HA-свечей: стандартный, основанный на тренде или на моментуме.
BullColor Цвет для отрисовки бычьих HA-свечей.
BearColor Цвет для отрисовки медвежьих HA-свечей.
StrongBullColor Цвет для отрисовки сильных бычьих HA-свечей.
StrongBearColor Цвет для отрисовки сильных медвежьих HA-свечей.
NeutralColor Цвет для отрисовки нейтральных HA-свечей (уравновешенных).
ConfirmationCandles Количество свечей, необходимых для подтверждения изменения цвета HA.
SignalLookbackBars Количество баров назад от текущего бара для сканирования сигналов при полном пересчёте.
MinBodyPercent Минимальный процент тела свечи относительно диапазона для формирования сигналов.
SignalOnHAColorChange При активации сигналы формируются при подтверждённом изменении цвета HA-свечей.
RequireMACDDivergenceConfirmation Требует наличия дивергенции MACD для формирования подтверждённых стрелок.
MACDFastEMA Период быстрой скользящей средней для расчёта MACD.
MACDSlowEMA Период медленной скользящей средней для расчёта MACD.
MACDSignalEMA Период сигнальной линии MACD.
DivergencePivotLookback Количество баров для поиска пивотов при определении дивергенции MACD.
DivergenceSearchBars Количество баров назад для поиска предыдущего пивота при определении дивергенции MACD.
DivergenceConfirmWindow Количество баров назад, в пределах которых ищется подтверждённая дивергенция MACD.
RequireStrongCandleForCircle Требует повышенной силы свечи (короткая тень или большой объём тела) для формирования круга момента.
CancelSignalOnOppositeHA Отменяет ожидающий сигнал при появлении свечи противоположного направления HA.
ConfirmByCloseBreak При подтверждении сигнала проверяет пробой уровня закрытием свечи, а не максимумом/минимумом.
ArrowOffsetATR Смещение стрелок BUY/SELL от уровня свечи в единицах ATR.
CircleOffsetATR Смещение сигнальных кругов моментов от уровня свечи в единицах ATR.
VisualATRPeriod Период расчёта ATR для визуального смещения стрелок и кругов.
EnablePopupAlert Включает всплывающие оповещения на графике.
EnablePushAlert Включает push-уведомления на мобильное устройство.
EnableEmailAlert Включает отправку оповещений по электронной почте.
EnableSoundAlert Включает звуковые оповещения при появлении сигналов.
BuySoundFile Путь к звуковому файлу для оповещения о покупке.
SellSoundFile Путь к звуковому файлу для оповещения о продаже.
AlertCooldownSeconds Период охлаждения между последовательными оповещениями одного направления в секундах.
AlertOnlyRealtime Ограничивает отправку оповещений только для закрытых свечей в реальном времени.
Получить полный код

Поиск по коду файла

#property version   "1.12"
#property description "Professional Heikin Ashi candle engine with HA color change plus MACD divergence confirmed BUY/SELL arrows. Closed bar, EA integration friendly."
#property strict

#property indicator_chart_window
#property indicator_buffers 10

#property indicator_color1 clrNONE
#property indicator_color2 clrNONE
#property indicator_color3 clrNONE
#property indicator_color4 clrNONE
#property indicator_color5 clrNONE

enum CandleColorMode
{
   COLOR_STANDARD       = 0,
   COLOR_TREND_BASED    = 1,
   COLOR_MOMENTUM_BASED = 2
};

input int    MaxBarsToCalculate                 = 3000;
input bool   ShowHeikinAshiCandles              = true;
input bool   ShowOriginalCandlesFaint           = false;
input bool   EnableSignals                      = true;
input bool   UseClosedBarsOnly                  = true;
input CandleColorMode CandleMode                = COLOR_STANDARD;

input color  BullColor                          = clrLime;
input color  BearColor                          = clrRed;
input color  StrongBullColor                   = clrDodgerBlue;
input color  StrongBearColor                   = clrOrange;
input color  NeutralColor                      = clrGray; 

input int    ConfirmationCandles                = 1;
input int    SignalLookbackBars                 = 1000;
input double MinBodyPercent                     = 0.0;
input bool   SignalOnHAColorChange              = true;

input bool   RequireMACDDivergenceConfirmation  = true;
input int    MACDFastEMA                        = 12;
input int    MACDSlowEMA                        = 26;
input int    MACDSignalEMA                      = 5;
input int    DivergencePivotLookback            = 2;
input int    DivergenceSearchBars               = 200;
input int    DivergenceConfirmWindow            = 30;

input bool   RequireStrongCandleForCircle       = false;
input bool   CancelSignalOnOppositeHA           = true;
input bool   ConfirmByCloseBreak                = true;

input double ArrowOffsetATR                     = 0.25;
input double CircleOffsetATR                   = 0.15;
input int    VisualATRPeriod                    = 14;

input bool   EnablePopupAlert                   = true;
input bool   EnablePushAlert                    = false;
input bool   EnableEmailAlert                   = false;
input bool   EnableSoundAlert                   = false;

input string BuySoundFile                       = "alert.wav";
input string SellSoundFile                      = "alert2.wav";

input int    AlertCooldownSeconds               = 120;
input bool   AlertOnlyRealtime                  = true;

double HAOpen[];
double HAHigh[];
double HALow[];
double HAClose[];
double HAColor[];

double BuyCircle[];
double SellCircle[];
double BuyArrow[];
double SellArrow[];

double ATRBuf[];

double MacdFastBuf[];
double MacdSlowBuf[];
double MacdSignalBuf[];
double MacdHistBuf[];

bool BullDivConfirmed[];
bool BearDivConfirmed[];

double TRBuf[];
double TRPrefix[];
double HABodyBuf[];
double HABodyPrefix[];

#define COL_BULL           0
#define COL_BEAR           1
#define COL_STRONG_BULL    2
#define COL_STRONG_BEAR    3
#define COL_NEUTRAL        4

#define MOM_BODY_WINDOW    14
#define STRONG_WICK_FRAC  0.10
#define CIRCLE_WICK_FRAC  0.15

#define ARROW_BUY_CODE     233
#define ARROW_SELL_CODE    234
#define CIRCLE_CODE        108

int g_firstBar    = 1;
int g_confCandles = 3;

bool   g_buyPending  = false;
double g_buyRefHigh  = 0.0;
int    g_buyBarsLeft = 0;

bool   g_sellPending  = false;
double g_sellRefLow   = 0.0;
int    g_sellBarsLeft = 0;

datetime g_lastClosedTime = 0;

datetime g_lastAlertTime = 0;
int      g_lastAlertDir  = 0;
datetime g_lastAlertWall = 0;

int g_macdCalcStart = 0;
int g_prevFirstBar  = -1;

int g_draw_first = -1;
int g_draw_last  = -1;

bool IsBullishHA(const int i)
{
   return(HAClose[i] > HAOpen[i]);
}

bool IsBearishHA(const int i)
{
   return(HAClose[i] < HAOpen[i]);
}

double GetBodyPercent(const int i)
{
   double range = HAHigh[i] - HALow[i];

   if(range <= 0.0)
      return(0.0);

   return(MathAbs(HAClose[i] - HAOpen[i]) / range * 100.0);
}

void ComputeHABodyCache(const int i)
{
   double body = MathAbs(HAClose[i] - HAOpen[i]);

   HABodyBuf[i] = body;

   if(i == g_firstBar)
      HABodyPrefix[i] = body;
   else
      HABodyPrefix[i] =
         HABodyPrefix[i - 1] + body;
}

double AvgHABody(const int i,
                 const int win,
                 const int firstBar)
{
   int w = win;
   if(w < 1) w = 1;

   int st = i - w;

   if(st < firstBar)
      return(0.0);

   double sum = HABodyPrefix[i - 1];

   if(st > firstBar)
      sum -= HABodyPrefix[st - 1];

   return(sum / w);
}

int GetCandleColorIndex(const int i)
{
   double range = HAHigh[i] - HALow[i];

   bool bull = IsBullishHA(i);
   bool bear = IsBearishHA(i);

   if(!bull && !bear)
      return(COL_NEUTRAL);

   if(CandleMode == COLOR_STANDARD)
      return(bull ? COL_BULL : COL_BEAR);

   if(CandleMode == COLOR_TREND_BASED)
   {
      if(range <= 0.0)
         return(bull ? COL_BULL : COL_BEAR);

      double lowerWick =
         MathMin(HAOpen[i], HAClose[i]) - HALow[i];

      double upperWick =
         HAHigh[i] - MathMax(HAOpen[i], HAClose[i]);

      if(bull)
      {
         return(lowerWick <= STRONG_WICK_FRAC * range
                ? COL_STRONG_BULL
                : COL_BULL);
      }

      return(upperWick <= STRONG_WICK_FRAC * range
             ? COL_STRONG_BEAR
             : COL_BEAR);
   }

   double body = MathAbs(HAClose[i] - HAOpen[i]);
   double avgBody =
      AvgHABody(i, MOM_BODY_WINDOW, g_firstBar);

   if(avgBody > 0.0 && body >= 1.2 * avgBody)
      return(bull ? COL_STRONG_BULL : COL_STRONG_BEAR);

   return(bull ? COL_BULL : COL_BEAR);
}

void ComputeHABar(const int i,
                  const double &open[],
                  const double &high[],
                  const double &low[],
                  const double &close[])
{
   double haClose =
      (open[i] + high[i] + low[i] + close[i]) / 4.0;

   double haOpen =
      (HAOpen[i - 1] + HAClose[i - 1]) / 2.0;

   double haHigh =
      MathMax(high[i], MathMax(haOpen, haClose));

   double haLow =
      MathMin(low[i], MathMin(haOpen, haClose));

   HAOpen[i]  = haOpen;
   HAClose[i] = haClose;
   HAHigh[i]  = haHigh;
   HALow[i]   = haLow;
}

void InitHASeed(const int firstBar,
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[])
{
   double haClose =
      (open[firstBar] +
       high[firstBar] +
       low[firstBar] +
       close[firstBar]) / 4.0;

   double haOpen =
      (open[firstBar] + close[firstBar]) / 2.0;

   HAClose[firstBar] = haClose;
   HAOpen[firstBar]  = haOpen;

   HAHigh[firstBar] =
      MathMax(high[firstBar],
              MathMax(haOpen, haClose));

   HALow[firstBar] =
      MathMin(low[firstBar],
              MathMin(haOpen, haClose));
}

void ComputeTR(const int i,
               const double &high[],
               const double &low[],
               const double &close[],
               const int firstBar)
{
   double tr = high[i] - low[i];

   if(i > firstBar)
   {
      double a = MathAbs(high[i] - close[i - 1]);
      double b = MathAbs(low[i]  - close[i - 1]);

      if(a > tr) tr = a;
      if(b > tr) tr = b;
   }

   TRBuf[i] = tr;

   if(i == firstBar)
      TRPrefix[i] = tr;
   else
      TRPrefix[i] = TRPrefix[i - 1] + tr;
}

double GetVisualATR(const int i,
                    const double &high[],
                    const double &low[],
                    const double &close[],
                    const int firstBar)
{
   int p = VisualATRPeriod;

   if(p < 1)
      p = 1;

   int st = i - p + 1;

   if(st < firstBar)
      st = firstBar;

   ComputeTR(i, high, low, close, firstBar);

   double sum = TRPrefix[i];

   if(st > firstBar)
      sum -= TRPrefix[st - 1];

   int count = i - st + 1;

   double atr =
      count > 0
      ? sum / count
      : TRBuf[i];

   ATRBuf[i] = atr;

   return(atr);
}

bool IsMacdPeak(const int i,
                const int lookback,
                const int firstBar,
                const int lastBar)
{
   if(i - lookback < firstBar ||
      i + lookback > lastBar)
      return(false);

   for(int k = 1; k <= lookback; k++)
   {
      if(MacdHistBuf[i] <= MacdHistBuf[i - k] ||
         MacdHistBuf[i] <= MacdHistBuf[i + k])
         return(false);
   }

   return(true);
}

bool IsMacdTrough(const int i,
                  const int lookback,
                  const int firstBar,
                  const int lastBar)
{
   if(i - lookback < firstBar ||
      i + lookback > lastBar)
      return(false);

   for(int k = 1; k <= lookback; k++)
   {
      if(MacdHistBuf[i] >= MacdHistBuf[i - k] ||
         MacdHistBuf[i] >= MacdHistBuf[i + k])
         return(false);
   }

   return(true);
}

void ComputeMACDDivergence(const int rates_total,
                           const int firstBar,
                           const int lastClosed,
                           const double &high[],
                           const double &low[],
                           const double &close[])
{

   if(ArraySize(MacdFastBuf) < rates_total)
   {
      ArrayResize(MacdFastBuf, rates_total);
      ArrayResize(MacdSlowBuf, rates_total);
      ArrayResize(MacdSignalBuf, rates_total);
      ArrayResize(MacdHistBuf, rates_total);

      ArrayResize(BullDivConfirmed, rates_total);
      ArrayResize(BearDivConfirmed, rates_total);

      ArrayInitialize(MacdFastBuf, 0.0);
      ArrayInitialize(MacdSlowBuf, 0.0);
      ArrayInitialize(MacdSignalBuf, 0.0);
      ArrayInitialize(MacdHistBuf, 0.0);
      ArrayInitialize(BullDivConfirmed, false);
      ArrayInitialize(BearDivConfirmed, false);

      g_macdCalcStart = firstBar;
   }

   if(!RequireMACDDivergenceConfirmation)
      return;

   int fast          = MACDFastEMA;
   int slow          = MACDSlowEMA;
   int signal        = MACDSignalEMA;
   int pivotLookback = DivergencePivotLookback;
   int searchBars    = DivergenceSearchBars;

   if(fast < 1) fast = 1;
   if(slow < 1) slow = 1;
   if(signal < 1) signal = 1;
   if(pivotLookback < 1) pivotLookback = 1;
   if(searchBars < 1) searchBars = 1;

   if(lastClosed < firstBar + pivotLookback * 2 + 2)
      return;

   double fastAlpha   = 2.0 / ((double)fast + 1.0);
   double slowAlpha   = 2.0 / ((double)slow + 1.0);
   double signalAlpha = 2.0 / ((double)signal + 1.0);

   int macdStart = (g_macdCalcStart < firstBar) ? firstBar : g_macdCalcStart;
   if(macdStart > lastClosed) macdStart = lastClosed;

   if(macdStart == firstBar)
   {
      ArrayInitialize(BullDivConfirmed, false);
      ArrayInitialize(BearDivConfirmed, false);
   }

   for(int i = macdStart; i <= lastClosed; i++)
   {
      double price = close[i];

      if(i == firstBar)
      {
         MacdFastBuf[i]   = price;
         MacdSlowBuf[i]   = price;
         MacdSignalBuf[i] = 0.0;
         MacdHistBuf[i]   = 0.0;
         continue;
      }

      MacdFastBuf[i] =
         fastAlpha * price +
         (1.0 - fastAlpha) * MacdFastBuf[i - 1];

      MacdSlowBuf[i] =
         slowAlpha * price +
         (1.0 - slowAlpha) * MacdSlowBuf[i - 1];

      double macdMain =
         MacdFastBuf[i] - MacdSlowBuf[i];

      MacdSignalBuf[i] =
         signalAlpha * macdMain +
         (1.0 - signalAlpha) * MacdSignalBuf[i - 1];

      MacdHistBuf[i] =
         macdMain - MacdSignalBuf[i];
   }

   g_macdCalcStart = lastClosed + 1;

   int lastPivot = lastClosed - pivotLookback;
   int pivotCheckStart = (macdStart - pivotLookback < firstBar + pivotLookback) ? firstBar + pivotLookback : macdStart - pivotLookback;

   for(int i = pivotCheckStart; i <= lastPivot; i++)
   {
      int confirmationBar = i + pivotLookback;

      if(confirmationBar < rates_total)
      {
         BullDivConfirmed[confirmationBar] = false;
         BearDivConfirmed[confirmationBar] = false;
      }

      if(IsMacdTrough(i, pivotLookback, firstBar, lastClosed))
      {
         int prevTrough = -1;
         int oldest = i - searchBars;
         if(oldest < firstBar + pivotLookback) oldest = firstBar + pivotLookback;

         for(int j = i - 1; j >= oldest; j--)
         {
            if(IsMacdTrough(j, pivotLookback, firstBar, lastClosed))
            {
               prevTrough = j;
               break;
            }
         }

         if(prevTrough >= 0 &&
            low[i] < low[prevTrough] &&
            MacdHistBuf[i] > MacdHistBuf[prevTrough])
         {
            if(confirmationBar < rates_total)
               BullDivConfirmed[confirmationBar] = true;
         }
      }

      if(IsMacdPeak(i, pivotLookback, firstBar, lastClosed))
      {
         int prevPeak = -1;
         int oldest = i - searchBars;
         if(oldest < firstBar + pivotLookback) oldest = firstBar + pivotLookback;

         for(int j = i - 1; j >= oldest; j--)
         {
            if(IsMacdPeak(j, pivotLookback, firstBar, lastClosed))
            {
               prevPeak = j;
               break;
            }
         }

         if(prevPeak >= 0 &&
            high[i] > high[prevPeak] &&
            MacdHistBuf[i] < MacdHistBuf[prevPeak])
         {
            if(confirmationBar < rates_total)
               BearDivConfirmed[confirmationBar] = true;
         }
      }
   }
}

bool RecentMACDDivergenceConfirmed(const int i,
                                   const bool bullish)
{
   if(!RequireMACDDivergenceConfirmation)
      return(true);

   int window = DivergenceConfirmWindow;
   if(window < 0) window = 0;

   int first = i - window;
   if(first < g_firstBar) first = g_firstBar;

   for(int k = i; k >= first; k--)
   {
      if(bullish && BullDivConfirmed[k]) return(true);
      if(!bullish && BearDivConfirmed[k]) return(true);
   }

   return(false);
}

void ClearSignalBuffers(const int from,
                        const int to)
{
   for(int i = from; i <= to; i++)
   {
      BuyCircle[i]  = EMPTY_VALUE;
      SellCircle[i] = EMPTY_VALUE;
      BuyArrow[i]   = EMPTY_VALUE;
      SellArrow[i]  = EMPTY_VALUE;
   }
}

void ClearAllBuffers(const int total)
{
   for(int i = 0; i < total; i++)
   {
      HAOpen[i]  = EMPTY_VALUE;
      HAHigh[i]  = EMPTY_VALUE;
      HALow[i]   = EMPTY_VALUE;
      HAClose[i] = EMPTY_VALUE;
      HAColor[i] = 0.0;

      ATRBuf[i] = 0.0;

      BuyCircle[i]  = EMPTY_VALUE;
      SellCircle[i] = EMPTY_VALUE;
      BuyArrow[i]   = EMPTY_VALUE;
      SellArrow[i]  = EMPTY_VALUE;

      TRBuf[i] = 0.0;
      TRPrefix[i] = 0.0;
      HABodyBuf[i] = 0.0;
      HABodyPrefix[i] = 0.0;
   }
}

void ResetSignalState()
{
   g_buyPending  = false;
   g_buyRefHigh  = 0.0;
   g_buyBarsLeft = 0;

   g_sellPending  = false;
   g_sellRefLow   = 0.0;
   g_sellBarsLeft = 0;
}

void FireAlert(const int dir,
               const string typeText,
               const double price,
               const datetime candleTime)
{
   if(!(EnablePopupAlert ||
        EnablePushAlert ||
        EnableEmailAlert ||
        EnableSoundAlert))
      return;

   if(candleTime == g_lastAlertTime &&
      dir == g_lastAlertDir)
      return;

   if(g_lastAlertWall > 0 &&
      dir == g_lastAlertDir &&
      (TimeCurrent() - g_lastAlertWall) < AlertCooldownSeconds)
      return;

   string tf = IntegerToString(Period());

   string msg =
      "SHK Heikin Ashi Signals | " +
      Symbol() + " " +
      tf + " | " +
      typeText +
      " | Price: " +
      DoubleToString(price, Digits) +
      " | Time: " +
      TimeToString(candleTime, TIME_DATE | TIME_MINUTES);

   if(EnablePopupAlert)
      Alert(msg);

   if(EnablePushAlert)
      SendNotification(msg);

   if(EnableEmailAlert)
      SendMail("SHK Heikin Ashi Signal", msg);

   if(EnableSoundAlert)
   {
      if(dir > 0)
         PlaySound(BuySoundFile);
      else
         PlaySound(SellSoundFile);
   }

   g_lastAlertTime = candleTime;
   g_lastAlertDir  = dir;
   g_lastAlertWall = TimeCurrent();
}

bool HasConfirmedHAColorChange(const int i,
                               const bool bullish)
{
   int candles = g_confCandles;
   if(candles < 1) candles = 1;

   int runStart = i - candles + 1;
   int previous = runStart - 1;

   if(runStart < g_firstBar + 1 ||
      previous < g_firstBar)
      return(false);

   for(int k = runStart; k <= i; k++)
   {
      if(bullish && !IsBullishHA(k)) return(false);
      if(!bullish && !IsBearishHA(k)) return(false);
      if(GetBodyPercent(k) < MinBodyPercent) return(false);
   }

   if(bullish)
      return(IsBearishHA(previous));

   return(IsBullishHA(previous));
}

void ProcessColorChangeArrow(const int i,
                             const datetime &time[],
                             const double atr,
                             const bool allowAlert)
{
   if(HasConfirmedHAColorChange(i, true) &&
      RecentMACDDivergenceConfirmed(i, true))
   {
      BuyArrow[i] =
         HALow[i] - ArrowOffsetATR * atr;

      if(allowAlert)
      {
         FireAlert(+1,
                   "STRONG BUY HA + MACD Div

Показано первые 50% кода (символов: 22824)

Открыть по тарифу

Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.

Разовая покупка файла

На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.

Чтобы оформить заказ, введите email и перейдите к оплате.

Стоимость полного кода
2 282,40₽ ≈ $27.90