forextastic: , but I don't see any reason why this for loop code shouldn't work, but I don't have much experience.
Use the debugger or print out your variables, including _LastError and prices and find out why. Do you really expect us to debug your code for you?
Code debugging - Developing programs - MetaEditor Help
Error Handling and Logging in MQL5 - MQL5 Articles (2015)
Tracing, Debugging and Structural Analysis of Source Code - MQL5 Articles (2011)
Introduction to MQL5: How to write simple Expert Advisor and Custom Indicator - MQL5 Articles (2010)
No, I don't expect that. I just asked because I've been banging my head on it for days and for several hours so if anyone has had a similar experience it can help.
As I already wrote, the problem happens in the for loop and I sent the code. If I insert a print immediately after the for when it happens the problem , the print is not executed.
What is the point of the forum otherwise ? 😉
Resolved. The problem was that I was comparing the visible bars in the chart with Mathmin in the oninit and this sometimes returned a negative value.
By removing that line, the problem does not occur.
By removing that line, the problem does not occur.
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); } }
You are missing trading opportunities:
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
Registration
Log in
You agree to website policy and terms of use
If you do not have an account, please register
I wrote an indicator that, based on the opening and closing conditions of the past bars, creates rectangles in the chart.
The indicator works well most of the time and updates correctly on the chart.
The problem occurs when I try to change assets or timeframes several times: if an asset hasn't been used before, often the indicator seems not to appear on the chart (i.e. no objects are drawn) until I reload the indicator or I switch between timeframes.
I tried inserting some print to debug and when this happens, the on init is initialized correctly but the print inside the for loop that loops the bars is not printed. This leaves me thinking that the problem is in the loop.
This is how I try to cycle the bars :
I've tried searching the forum, but I don't see any reason why this for loop code shouldn't work, but I don't have much experience.