Gap indicator - page 2

 
Hamzah:
Hey Guys

Where can I find Gap Indicator that will show arrow in the direction of the gaps. The gap should be between previous M5 candle lowest price and its next M5 candle highest price when in downtrend and vise versa. The gap can be a small as 1 pip.

Thanks for sharing.

Please guys if anybody have this kind of gap indicator. I'm trading gap and this indicator will be very useful. Thanks in advance to those who is willing to share.

 

Hidden gap indicator

wrb-hidden-gap.mq4

 

Can you help with this indicator cant seem to get it to draw the second timeframe fvg correctly and also not getting alerts for the second time frame

//+------------------------------------------------------------------+
//|                                               Fair_Value_Gap.mq5 |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_plots 0

//--- input parameters
input color             InpColorToUP   =  clrGreen;      // Color of the gap up
input color             InpColorToDN   =  clrRed;        // Color of the gap down

input color             HtfInpColorToUP   =  clrBlue;      // Color of the gap up
input color             HtfInpColorToDN   =  clrBlue;        // Color of the gap down

input int maxbars = 100;                                  // How many bars to look back

input ENUM_TIMEFRAMES   TimeFrame2 = PERIOD_H4;          // Second timeframe for FVG

input bool              EnableNativeAlerts = true;       // Enable native alerts
input bool              EnableSoundAlerts   = true;      // Enable sound alerts
input string            SoundFileName       = "alert.wav";  // Sound file name
input bool              EnableEmailAlerts   = false;     // Enable email alerts
input string            AlertEmailSubject   = "Fair Value Gap Alert"; // Email subject
input bool              EnablePushAlerts    = true;      // Enable push notifications

string prefix;
double price;
const int MAX_ALERTS = 1; // Max number of alerts per gap

// Structure to store gap information and alert count
struct GapAlert {
    datetime gap_time;
    double price_up;
    double price_dn;
    bool is_active;
    int alert_count;
    int Return_alert_count;
    int dir;
    ENUM_TIMEFRAMES timeframe; // Timeframe for the gap
};

GapAlert gap_alerts[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit() {
    prefix = MQLInfoString(MQL_PROGRAM_NAME) + "_";
    return(INIT_SUCCEEDED);
}

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

//+------------------------------------------------------------------+
//| 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 < 4) return 0;

    price = close[0];
    ArraySetAsSeries(open, true);
    ArraySetAsSeries(high, true);
    ArraySetAsSeries(low, true);
    ArraySetAsSeries(close, true);
    ArraySetAsSeries(time, true);

    // Process current timeframe
    FindFVG(rates_total, prev_calculated, time, high, low, close, time, InpColorToUP, InpColorToDN, maxbars, PERIOD_CURRENT);

    // Process second timeframe using iBarShift to match bars
    int limit = Bars(NULL, TimeFrame2); // Get number of bars for the second timeframe
    if (limit > 0) {
        datetime TimeFrame2_time[];
        double TimeFrame2_high[], TimeFrame2_low[], TimeFrame2_close[];
        
        // Get high and low values from the second timeframe
        CopyHigh(NULL, TimeFrame2, 0, limit, TimeFrame2_high);
        CopyLow(NULL, TimeFrame2, 0, limit, TimeFrame2_low);
        CopyTime(NULL, TimeFrame2, 0, limit, TimeFrame2_time);
        CopyClose(NULL, TimeFrame2, 0, limit, TimeFrame2_close);
        
        ArraySetAsSeries(TimeFrame2_high, true);
        ArraySetAsSeries(TimeFrame2_low, true);
        ArraySetAsSeries(TimeFrame2_time, true);
        ArraySetAsSeries(TimeFrame2_close, true);
        
        // Look for FVG on the second timeframe
        FindFVG(limit, prev_calculated, TimeFrame2_time, TimeFrame2_high, TimeFrame2_low, TimeFrame2_close, time, HtfInpColorToUP, HtfInpColorToDN, maxbars, TimeFrame2);
    }

    // Return the number of bars processed
    return rates_total;
}

//+------------------------------------------------------------------+
//| Find Fair Value Gap (FVG) function                               |
//+------------------------------------------------------------------+
void FindFVG(const int rates_total,
             const int prev_calculated,
             const datetime &time[],
             const double &high[],
             const double &low[],
             const double &close[],
             const datetime &time_main[],
             const color color_up,
             const color color_dn,
             const int bars_lookback,
             ENUM_TIMEFRAMES timeframe) {
   
   int limit = rates_total - prev_calculated;
   if (limit > 1) {
      limit = rates_total - 5;
   }
   
   // Check for new gaps only if a new bar has formed
   if (limit > 0) {
      int end_index = MathMin(rates_total - 4, bars_lookback); // Ensure at least 4 bars available
      for (int i = end_index; i >= 0 && !IsStopped(); i--) {

         if (low[i + 1] - high[i + 3] >= Point()) {
            double up = fmin(high[i + 1], low[i + 1]);
            double dn = fmax(high[i + 3], low[i + 3]);

            DrawArea(i, up, dn, time_main, high, low, close, color_up, 1, timeframe);
         }

         if (low[i + 3] - high[i + 1] >= Point()) {
            double up = fmin(high[i + 3], low[i + 3]);
            double dn = fmax(high[i + 1], low[i + 1]);

            DrawArea(i, up, dn, time_main, high, low, close, color_dn, 0, timeframe);
         }
      }
   }
   
   // Check for price return to active gaps
   for (int i = ArraySize(gap_alerts) - 1; i >= 0; i--) {
      if (gap_alerts[i].is_active && gap_alerts[i].timeframe == timeframe) {
         if (gap_alerts[i].dir == 1) { // Bullish gap
            if (low[0] < gap_alerts[i].price_up) {
               if (ShouldTriggerReturnAlert(gap_alerts[i].gap_time, gap_alerts[i].price_up, gap_alerts[i].price_dn, timeframe)) {
                  string msg = "Price returned to bullish gap on " + Symbol() +
                               " with Low: " + DoubleToString(gap_alerts[i].price_dn, 5) +
                               " and High: " + DoubleToString(gap_alerts[i].price_up, 5) + " on " + EnumToString(timeframe);
                  TriggerAlerts(msg);
                  Print("Price returned to bullish gap");
               }
            }
         } else { // Bearish gap
            if (high[0] > gap_alerts[i].price_dn) {
               if (ShouldTriggerReturnAlert(gap_alerts[i].gap_time, gap_alerts[i].price_up, gap_alerts[i].price_dn, timeframe)) {
                  string msg = "Price returned to bearish gap on " + Symbol() +
                               " with Low: " + DoubleToString(gap_alerts[i].price_dn, 5) +
                               " and High: " + DoubleToString(gap_alerts[i].price_up, 5) + " on " + EnumToString(timeframe);
                  TriggerAlerts(msg);
                  Print("Price returned to bearish gap");
               }
            }
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Function to manage alerts and prevent sending more than 2 alerts |
//+------------------------------------------------------------------+
bool ShouldTriggerAlert(datetime gap_time, double price_up, double price_dn, int dir, ENUM_TIMEFRAMES timeframe) {
   for (int i = 0; i < ArraySize(gap_alerts); i++) {
      if (gap_alerts[i].gap_time == gap_time && 
          gap_alerts[i].price_up == price_up && 
          gap_alerts[i].price_dn == price_dn && 
          gap_alerts[i].timeframe == timeframe) {
         
         if (gap_alerts[i].alert_count < MAX_ALERTS) {
            gap_alerts[i].alert_count++;
            return true;
         } else {
            return false; // Max alerts reached, don't trigger any more
         }
      }
   }

   // New gap, add to the array
   int new_size = ArraySize(gap_alerts) + 1;
   ArrayResize(gap_alerts, new_size);

   GapAlert new_gap;
   new_gap.gap_time = gap_time;
   new_gap.price_up = price_up;
   new_gap.price_dn = price_dn;
   new_gap.is_active = true;
   new_gap.alert_count = 1; // First alert
   new_gap.Return_alert_count = 0;
   new_gap.dir = dir;
   new_gap.timeframe = timeframe;
   gap_alerts[new_size - 1] = new_gap;

   return true;
}

//+------------------------------------------------------------------+
//| Function to check if price return alert should be triggered      |
//+------------------------------------------------------------------+
bool ShouldTriggerReturnAlert(datetime gap_time, double price_up, double price_dn, ENUM_TIMEFRAMES timeframe) {
   for (int i = 0; i < ArraySize(gap_alerts); i++) {
      if (gap_alerts[i].gap_time == gap_time && 
          gap_alerts[i].price_up == price_up && 
          gap_alerts[i].price_dn == price_dn && 
          gap_alerts[i].timeframe == timeframe) {
         
         if (gap_alerts[i].Return_alert_count < MAX_ALERTS) {
            gap_alerts[i].Return_alert_count++;
            return true;
         } else {
            return false; // Max alerts reached, don't trigger any more
         }
      }
   }
   return false;
}

//+------------------------------------------------------------------+
//| Function to draw gap area on the chart                          |
//+------------------------------------------------------------------+
void DrawArea(int index, double price_up, double price_dn, const datetime &time[], const double &high[], const double &low[], const double &close[], color color_area, int dir, ENUM_TIMEFRAMES timeframe) {
   string name = prefix + IntegerToString(index);
   // Check if the rectangle already exists; if not, create it
   if (ObjectFind(0, name) < 0) {
      ObjectCreate(0, name, OBJ_RECTANGLE, 0, 0, 0, 0);
   }

   // Set rectangle properties
   ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
   ObjectSetInteger(0, name, OBJPROP_FILL, false);
   ObjectSetInteger(0, name, OBJPROP_BACK, true);
   ObjectSetString(0, name, OBJPROP_TOOLTIP, "\n");

   // Set rectangle color
   ObjectSetInteger(0, name, OBJPROP_COLOR, color_area);

   // Set the starting time point (time[index + 3])
   ObjectSetInteger(0, name, OBJPROP_TIME, 0, time[index + 3]);

   // Continuously update the ending time point to the current last bar (time[0])
   ObjectSetInteger(0, name, OBJPROP_TIME, 1, time[0]);

   // Set the price levels for the rectangle
   ObjectSetDouble(0, name, OBJPROP_PRICE, 0, price_up);
   ObjectSetDouble(0, name, OBJPROP_PRICE, 1, price_dn);

   // Check if the gap is fully filled and delete the rectangle
   for (int j = index; j >= 0; j--) {
      if (dir > 0 && low[j] <= price_dn) {
         ObjectDelete(0, name);
         // Mark gap as inactive
         for (int k = 0; k < ArraySize(gap_alerts); k++) {
             if (gap_alerts[k].price_up == price_up && gap_alerts[k].price_dn == price_dn) {
                 gap_alerts[k].is_active = false;
                 break;
             }
         }
         break;
      }

      if (dir == 0 && high[j] >= price_up) {
         ObjectDelete(0, name);
         // Mark gap as inactive
         for (int k = 0; k < ArraySize(gap_alerts); k++) {
             if (gap_alerts[k].price_up == price_up && gap_alerts[k].price_dn == price_dn) {
                 gap_alerts[k].is_active = false;
                 break;
             }
         }
         break;
      }
   }

   // Check if the gap exceeds the maxbars limit and delete the rectangle if it's too old
   if (TimeCurrent() - time[index + 2] > PeriodSeconds() * maxbars) {
      ObjectDelete(0, name);  // Delete the rectangle if it's older than the look-back period
      // Mark gap as inactive
      for (int k = 0; k < ArraySize(gap_alerts); k++) {
          if (gap_alerts[k].price_up == price_up && gap_alerts[k].price_dn == price_dn) {
              gap_alerts[k].is_active = false;
              break;
          }
      }
   }

   // Trigger alert if the gap is new or has fewer than 2 alerts
   if (ShouldTriggerAlert(time[index + 2], price_up, price_dn, dir, timeframe)) {
       string msg = "Gap detected on " + Symbol() +
                             " with Low: " + DoubleToString(price_dn, 5) +
                             " and High: " + DoubleToString(price_up, 5) + " on " + EnumToString(timeframe);
       TriggerAlerts(msg);
       Print("The third candlestick has closed.");
   }
}

//+------------------------------------------------------------------+
//| Function to trigger alerts                                     |
//+------------------------------------------------------------------+
void TriggerAlerts(string message) {
   if (EnableNativeAlerts) {
      Alert(message);
   }
   if (EnableSoundAlerts) {
      PlaySound(SoundFileName);
   }
   if (EnableEmailAlerts) {
      SendMail(AlertEmailSubject, message);
   }
   if (EnablePushAlerts) {
      SendNotification(message);
   }
}



Documentation on MQL5: Common Functions / Alert
Documentation on MQL5: Common Functions / Alert
  • www.mql5.com
Displays a message in a separate window. Parameters argument [in]  Any values separated by commas. To split the information output in several...
Files: