//+------------------------------------------------------------------+
//|                                            FXP_EmaCloudTrend.mq5 |
//|                                                     FXPIPS ONLINE |
//+------------------------------------------------------------------+
#property copyright "FXPIPS ONLINE"
#property link      "https://fxpips.online/mt5-indicators/ema-cloud-trend/"
#property version   "1.00"
#property description "Two EMA clouds (default 8/21 and 50/200) filled by direction."
#property description "Arrows when the fast cloud flips in the direction of the slow cloud."
/*
   License: MIT. Copyright (c) 2026 FXPIPS ONLINE.
   Permission is hereby granted, free of charge, to any person obtaining a copy of this
   software, to use, copy, modify, merge, publish and distribute it, provided this notice
   is included. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.

   Educational tool - not financial advice. Trading involves substantial risk of loss.
*/
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots   4

#property indicator_label1  "Fast EMA A;Fast EMA B"
#property indicator_type1   DRAW_FILLING
#property indicator_color1  C'60,170,90',C'200,80,80'

#property indicator_label2  "Slow EMA A;Slow EMA B"
#property indicator_type2   DRAW_FILLING
#property indicator_color2  C'150,210,165',C'225,160,160'

#property indicator_label3  "Aligned bullish flip"
#property indicator_type3   DRAW_ARROW
#property indicator_color3  clrGreen
#property indicator_width3  2

#property indicator_label4  "Aligned bearish flip"
#property indicator_type4   DRAW_ARROW
#property indicator_color4  clrCrimson
#property indicator_width4  2

input group "Fast cloud"
input int  InpFastA   = 8;     // Fast cloud EMA A
input int  InpFastB   = 21;    // Fast cloud EMA B
input group "Slow cloud"
input int  InpSlowA   = 50;    // Slow cloud EMA A
input int  InpSlowB   = 200;   // Slow cloud EMA B
input group "Signals"
input bool InpNeedAlign = true;  // Only signal fast flips that agree with the slow cloud
input group "Alerts"
input bool InpAlerts  = false; // Pop-up alert on new signal
input bool InpPush    = false; // Push notification on new signal

double g_fa[], g_fb[], g_sa[], g_sb[], g_buy[], g_sell[];
double g_kFa, g_kFb, g_kSa, g_kSb;
int g_begin;
datetime g_lastAlert = 0;

//+------------------------------------------------------------------+
int OnInit()
{
   g_kFa = 2.0 / (MathMax(1, InpFastA) + 1.0);
   g_kFb = 2.0 / (MathMax(1, InpFastB) + 1.0);
   g_kSa = 2.0 / (MathMax(1, InpSlowA) + 1.0);
   g_kSb = 2.0 / (MathMax(1, InpSlowB) + 1.0);
   g_begin = MathMax(MathMax(InpSlowA, InpSlowB), MathMax(InpFastA, InpFastB));

   SetIndexBuffer(0, g_fa,   INDICATOR_DATA);
   SetIndexBuffer(1, g_fb,   INDICATOR_DATA);
   SetIndexBuffer(2, g_sa,   INDICATOR_DATA);
   SetIndexBuffer(3, g_sb,   INDICATOR_DATA);
   SetIndexBuffer(4, g_buy,  INDICATOR_DATA);
   SetIndexBuffer(5, g_sell, INDICATOR_DATA);

   ArraySetAsSeries(g_fa, false); ArraySetAsSeries(g_fb, false);
   ArraySetAsSeries(g_sa, false); ArraySetAsSeries(g_sb, false);
   ArraySetAsSeries(g_buy, false); ArraySetAsSeries(g_sell, false);

   for(int p = 0; p < 4; p++)
      PlotIndexSetDouble(p, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(InpFastA, InpFastB));
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(InpSlowA, InpSlowB));
   PlotIndexSetInteger(2, PLOT_ARROW, 233);
   PlotIndexSetInteger(3, PLOT_ARROW, 234);

   IndicatorSetString(INDICATOR_SHORTNAME,
      StringFormat("FXP EMA Cloud Trend (%d/%d, %d/%d)", InpFastA, InpFastB, InpSlowA, InpSlowB));
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
   return(INIT_SUCCEEDED);
}

void Notify(const datetime barTime, const string msg)
{
   if(barTime == g_lastAlert) return;
   g_lastAlert = barTime;
   string text = StringFormat("%s %s: %s", _Symbol, EnumToString((ENUM_TIMEFRAMES)_Period), msg);
   if(InpAlerts) Alert(text);
   if(InpPush)   SendNotification(text);
}

//+------------------------------------------------------------------+
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 <= g_begin + 2) return(0);

   int start = (prev_calculated > 0) ? prev_calculated - 1 : 0;

   for(int i = start; i < rates_total; i++)
   {
      g_buy[i] = EMPTY_VALUE; g_sell[i] = EMPTY_VALUE;

      if(i == 0)
      {
         g_fa[i] = close[i]; g_fb[i] = close[i];
         g_sa[i] = close[i]; g_sb[i] = close[i];
         continue;
      }
      g_fa[i] = g_fa[i - 1] + g_kFa * (close[i] - g_fa[i - 1]);
      g_fb[i] = g_fb[i - 1] + g_kFb * (close[i] - g_fb[i - 1]);
      g_sa[i] = g_sa[i - 1] + g_kSa * (close[i] - g_sa[i - 1]);
      g_sb[i] = g_sb[i - 1] + g_kSb * (close[i] - g_sb[i - 1]);

      if(i > g_begin && i < rates_total - 1)
      {
         bool fastUp   = g_fa[i] > g_fb[i] && g_fa[i - 1] <= g_fb[i - 1];
         bool fastDown = g_fa[i] < g_fb[i] && g_fa[i - 1] >= g_fb[i - 1];
         bool slowBull = g_sa[i] > g_sb[i];
         double off = (high[i] - low[i]) * 0.5;
         if(fastUp && (!InpNeedAlign || slowBull))    g_buy[i]  = low[i] - off;
         if(fastDown && (!InpNeedAlign || !slowBull)) g_sell[i] = high[i] + off;
      }
   }

   if(prev_calculated > 0 && (InpAlerts || InpPush))
   {
      int b = rates_total - 2;
      if(g_buy[b] != EMPTY_VALUE)  Notify(time[b], "Fast EMA cloud turned bullish");
      if(g_sell[b] != EMPTY_VALUE) Notify(time[b], "Fast EMA cloud turned bearish");
   }
   return(rates_total);
}

void OnDeinit(const int reason)
{
   // No handles or chart objects are created by this indicator.
}
//+------------------------------------------------------------------+
