//+------------------------------------------------------------------+ //| Fractal.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_chart_window #property copyright "2025" #property version "1.40" #property indicator_chart_window #property indicator_plots 2 #property indicator_buffers 2 //--- Swing High #property indicator_label1 "SwingHigh" #property indicator_type1 DRAW_ARROW #property indicator_color1 clrCrimson #property indicator_width1 1 //--- Swing Low #property indicator_label2 "SwingLow" #property indicator_type2 DRAW_ARROW #property indicator_color2 clrMediumSeaGreen #property indicator_width2 1 input int InpLeftRightBars = 3; // swing detection size input int InpLeftRightBars0 = 1; // between-point minimum swing size input ushort code = 170; // Arrow symbol double SwingHighBuffer[]; double SwingLowBuffer[]; int lastHighIndex = -1; int lastLowIndex = -1; datetime last_bar_time = 0; //------------------------------------------------------------ inline bool IsSwingHigh_L(const double &high[], int i, int L) { for(int j = 1; j <= L; j++) if(high[i] <= high[i - j] || high[i] <= high[i + j]) return false; return true; } //------------------------------------------------------------ inline bool IsSwingLow_L(const double &low[], int i, int L) { for(int j = 1; j <= L; j++) if(low[i] >= low[i - j] || low[i] >= low[i + j]) return false; return true; } //------------------------------------------------------------ int OnInit() { SetIndexBuffer(0, SwingHighBuffer, INDICATOR_DATA); SetIndexBuffer(1, SwingLowBuffer, INDICATOR_DATA); ArrayInitialize(SwingHighBuffer, 0.0); ArrayInitialize(SwingLowBuffer, 0.0); PlotIndexSetInteger(0, PLOT_ARROW, code); PlotIndexSetInteger(1, PLOT_ARROW, code); return(INIT_SUCCEEDED); } //------------------------------------------------------------ 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 < InpLeftRightBars*2 + 1) return 0; if(rates_total > 0 && time[rates_total - 1] == last_bar_time) return rates_total; ArrayInitialize(SwingHighBuffer, 0.0); ArrayInitialize(SwingLowBuffer, 0.0); lastHighIndex = -1; lastLowIndex = -1; int start = InpLeftRightBars; int end = rates_total - 1 - InpLeftRightBars; for(int i = start; i <= end; i++) { bool isHigh = IsSwingHigh_L(high, i, InpLeftRightBars); bool isLow = IsSwingLow_L(low, i, InpLeftRightBars); // --- Swing High --- if(isHigh) { SwingHighBuffer[i] = high[i]; if(lastHighIndex != -1 && lastHighIndex > lastLowIndex) { int a = lastHighIndex; int b = i; if(a > b) { int tmp = a; a = b; b = tmp; } double minVal = DBL_MAX; int minIndex = -1; for(int k = a + 1; k < b; k++) { // only consider swing lows with L = InpLeftRightBars0 if(IsSwingLow_L(low, k, InpLeftRightBars0)) { if(low[k] < minVal) { minVal = low[k]; minIndex = k; } } } if(minIndex != -1) SwingLowBuffer[minIndex] = minVal; // draw in SwingLowBuffer } lastHighIndex = i; } // --- Swing Low --- if(isLow) { SwingLowBuffer[i] = low[i]; if(lastLowIndex != -1 && lastLowIndex > lastHighIndex) { int a = lastLowIndex; int b = i; if(a > b) { int tmp = a; a = b; b = tmp; } double maxVal = -DBL_MAX; int maxIndex = -1; for(int k = a + 1; k < b; k++) { // only consider swing highs with L = InpLeftRightBars0 if(IsSwingHigh_L(high, k, InpLeftRightBars0)) { if(high[k] > maxVal) { maxVal = high[k]; maxIndex = k; } } } if(maxIndex != -1) SwingHighBuffer[maxIndex] = maxVal; // draw in SwingHighBuffer } lastLowIndex = i; } } last_bar_time = time[rates_total - 1]; return rates_total; }