Solo gli utenti che hanno acquistato o noleggiato il prodotto possono lasciare commenti
12
Crispin Tibilla  
Please leave comments, reviews and suggestions
Oleg Pokhilko  
Crispin Tibilla #:
Please leave comments, reviews and suggestions

sure. i think smth doesn't work. 

filled gaps do not vanish. alos, not all sweeped gaps alert. please check that

Crispin Tibilla  
Олег Похилько #:

sure. i think smth doesn't work. 

filled gaps do not vanish. alos, not all sweeped gaps alert. please check that

sure

will check that

can i see a screenshot of a case where the gap did not alert?

Oleg Pokhilko  
Crispin Tibilla #:

sure

will check that

can i see a screenshot of a case where the gap did not alert?

I suggest to make some imrovement. For now it alerts when the thin fvg line is swept by the price. Can you make an alert, when the price pullbacks from the fvg. For example, like on screenshot. The candle touched the FVG and then changed its direction. So a good sign for alert would be the situation when a candle first rise or fall, then it touches the FVG, changes its direction and closes with a body bigger than a wick. Is that ok to understand? English is not my native :)



Crispin Tibilla  
Олег Похилько #:

I suggest to make some imrovement. For now it alerts when the thin fvg line is swept by the price. Can you make an alert, when the price pullbacks from the fvg. For example, like on screenshot. The candle touched the FVG and then changed its direction. So a good sign for alert would be the situation when a candle first rise or fall, then it touches the FVG, changes its direction and closes with a body bigger than a wick. Is that ok to understand? English is not my native :)



Thank you for your comment

But this is a personal setting you will like for yourself, for your own strategy

If you need an indicator for your personal strategy, please chat me privately and we will work on it

szkovacs  
Not receveing alerts in push message on mobile. Can you solve it? Thank you.
Crispin Tibilla  
szkovacs #:
Not receveing alerts in push message on mobile. Can you solve it? Thank you.

Sorry for the inconvenience. I will fix it

Crispin Tibilla  
Crispin Tibilla #:

Sorry for the inconvenience. I will fix it

Push messages on mobile is not included in the current version

i will make sure to include it in a new update

thanks

Crispin Tibilla  
szkovacs #:
Not receveing alerts in push message on mobile. Can you solve it? Thank you.

Thanks for your review. I have included the feature

Please check for update

BlackArmor  
Hello Crispin, good indicator, the only problem that I see is that when an FVG is filled and no longer Valid it still shows even with selecting the "Delete Filled Gaps" option.
Please check attachments. Thank you.
File:
No_Fill.JPG  215 kb
No_Fill-2.JPG  119 kb
Crispin Tibilla  

BlackArmor #:
Hello Crispin, good indicator, the only problem that I see is that when an FVG is filled and no longer Valid it still shows even with selecting the "Delete Filled Gaps" option.
Please check attachments. Thank you

Sorry for the inconvenience.

There seems to be a misunderstanding on what "filled gaps" mean

For the indicator, gaps have to be '"filled" by the body of the candle

Hope we understand each other now  

BlackArmor  
Crispin Tibilla #:

Sorry for the inconvenience.

There seems to be a misunderstanding on what "filled gaps" mean

For the indicator, gaps have to be '"filled" by the body of the candle

Hope we understand each other now  

OK Thank you. Maybe in the future we can have the option to not see the ones that are no longer valid.  Thank you again for your response.

Crispin Tibilla  
BlackArmor #:

OK Thank you. Maybe in the future we can have the option to not see the ones that are no longer valid.  Thank you again for your response.

Okay

You can check out my FVG Watcher indicator below that allows you to select the type of sweep

https://www.mql5.com/en/market/product/110482

Evolved  
Hello Crispin,

I would like to know if it's possible to add FVG run alert as well?  Like FVG sweeps, runs happen all the time.
I think it would be a good addition to this indicator?
Crispin Tibilla  
Evolved #:
Hello Crispin,

I would like to know if it's possible to add FVG run alert as well?  Like FVG sweeps, runs happen all the time.
I think it would be a good addition to this indicator?

Sure. I am not familiar with FVG runs

Can you show me what they are so I see if it can be implemented?

Evolved  

FVG runs/continuations are the complete opposite of sweeps. So price breaks through an FVG, hovers around for some time, test the just broken FVG and continues in the direction of the break.


https://www.youtube.com/watch?v=ICdvUHoh4UM  this is about liquidity sweeps and runs, but is basically the same principle

https://www.youtube.com/watch?v=1W3oEBtGC1g  around 3:00 there is some explanation about FVG runs

It's not so easy to find good info about FVG runs, but i hope i did give you an idea?

Crispin Tibilla  
Evolved #:

FVG runs/continuations are the complete opposite of sweeps. So price breaks through an FVG, hovers around for some time, test the just broken FVG and continues in the direction of the break.


https://www.youtube.com/watch?v=ICdvUHoh4UM  this is about liquidity sweeps and runs, but is basically the same principle

https://www.youtube.com/watch?v=1W3oEBtGC1g  around 3:00 there is some explanation about FVG runs

It's not so easy to find good info about FVG runs, but i hope i did give you an idea?

Thanks for the input

I think this is more of a feature for your personal use

You can private message me so I can try to work on it for you

Elect_ed Keepers  


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);
   }
}


Crispin Tibilla  
Elect_ed Keepers #:


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


You can message me privately

eriano  
Whenever I click on download, I get a window with a link and then when I click on it, it opens MT4. There I can login to my MQL4 account, but no download is offered? Please, can someone send me the mql4 file. I will even pay for it via paypal: elias.riano@yahoo.de Thx a lot in advance! Kind Regards
Solo gli utenti che hanno acquistato o noleggiato il prodotto possono lasciare commenti
12