//+------------------------------------------------------------------+ //| XXX.mq5 | //| Copyright 2009-2021, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "XXX" #property link "XXX" #property version "XXX" #property strict #property tester_everytick_calculate #property indicator_chart_window //--- init indicator buffers #property indicator_buffers 2 #property indicator_plots 2 #define INDICATORNAME "XXX" // имя файла индикатора //--- plot fractal line #property indicator_label1 "frPriceshigh" #property indicator_type1 DRAW_LINE #property indicator_color1 clrGreen #property indicator_style1 STYLE_SOLID #property indicator_width1 2 #property indicator_label2 "frPriceslow" #property indicator_type2 DRAW_LINE #property indicator_color2 clrDeepPink #property indicator_style2 STYLE_SOLID #property indicator_width2 2 //--- input parameters sinput string _01 = "XXX"; // === Настройка индикатора === input bool Top = true; // Фрактал Сверху? input int baseSize_point = 200; // Значение, пунктов, минимального размера движения (КОНСТАНТА) input double Right = 1; // Коэф Правой стороны input double Left = 1; // Коэф Левой стороны input int MaxBarsRight = 10000; // Максимум баров справа input int MaxBarsLeft = 10000; // Максимум баров слева input int History = 10; // История, дней //--- indicator buffers double frPriceshigh[]; double frPriceslow[]; //--- глобальные массивы и переменные double fractals[]; // здесь храним ценовое значение фрактала double baseSize; // здесь храним размер диапазона отсчета размера int extremBarNum = 0; double currentMax = 0.0; double currentMin = 0.0; int extremBarNum2 = 0; double currentMax2 = 0.0; double currentMin2 = 0.0; bool moveDone = false; bool moveDone2 = false; int startBarNum = 0; int bar, bar2, limit; int j; // переменные для циклов bool FirstStartFlag; // флаг первого запуска индикатора int cnt_bars; // счетчик баров int HistoryCandle; int fractals_Count; // счетчик фракталов //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- инициализация переменных и массивов ArrayInitialize(fractals,EMPTY_VALUE); ArraySetAsSeries(fractals,true); extremBarNum = 0; currentMax = 0.0; currentMin = 0.0; extremBarNum2 = 0; currentMax2 = 0.0; currentMin2 = 0.0; moveDone = false; moveDone2 = false; startBarNum = 0; j = 0; FirstStartFlag = true; bar = 0; bar2 = 0; limit = 0; fractals_Count = 0; HistoryCandle = History*24*60*60/PeriodSeconds(PERIOD_CURRENT); cnt_bars = HistoryCandle; // Кол-во баров для подсчета сигналов //--- indicator buffers mapping SetIndexBuffer (0,frPriceshigh,INDICATOR_DATA); SetIndexBuffer (1,frPriceslow,INDICATOR_DATA); ArraySetAsSeries (frPriceshigh,true); ArraySetAsSeries (frPriceslow,true); PlotIndexSetInteger (0,PLOT_DRAW_TYPE,DRAW_LINE); PlotIndexSetInteger (1,PLOT_DRAW_TYPE,DRAW_LINE); PlotIndexSetInteger (0,PLOT_LINE_COLOR,clrGreen); PlotIndexSetInteger (1,PLOT_LINE_COLOR,clrDeepPink); PlotIndexSetString (0,PLOT_LABEL,"Prices high"); PlotIndexSetString (1,PLOT_LABEL,"Prices low"); //--- number of digits of indicator value IndicatorSetInteger(INDICATOR_DIGITS,_Digits); //--- имя для окон данных и метки для подокон IndicatorSetString(INDICATOR_SHORTNAME,INDICATORNAME); ChartRedraw(0); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Получаем сообщение о причине деинициализации reason_answer(reason); //Comment(""); //--- } //+------------------------------------------------------------------+ //| 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[]) { //--- //--- устанавливаем массивы данных как таймсерии ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); if(HistoryCandle>=rates_total) cnt_bars=rates_total-1; else cnt_bars=HistoryCandle; //----+ проверка количества баров на достаточность для корректного расчёта индикатора if(rates_total<=cnt_bars) { Print("Недостаточно истории. Есть "+IntegerToString(rates_total-1)+" надо "+IntegerToString(cnt_bars)); return(0); } //--- первый запуск if(FirstStartFlag) { int out; out = ArrayInitialize(frPriceshigh,EMPTY_VALUE); if(out>0) Print("OnCalculate: Количество инициализированных элементов массива frPriceshigh = "+IntegerToString(out)); out = ArrayInitialize(frPriceslow,EMPTY_VALUE); if(out>0) Print("OnCalculate: Количество инициализированных элементов массива frPriceslow = "+IntegerToString(out)); ArrayResize(fractals,cnt_bars+1,cnt_bars+1); for(int x=cnt_bars; x>0 && !IsStopped(); x--) { frPriceshigh[x] = EMPTY_VALUE; frPriceslow[x] = EMPTY_VALUE; fractals[x] = EMPTY_VALUE; } FirstStartFlag = false; ChartRedraw(0); } limit=cnt_bars-1; // стартовый номер для расчёта всех баров //--- решение проблемы 0 буфера при сдвиге графика if (rates_total != prev_calculated) // Every shift { frPriceshigh[0] = EMPTY_VALUE; frPriceslow[0] = EMPTY_VALUE; } //--- рассчет индикатора //--- если выбрано построение по верхним фракталам if(Top) { fractals_Count = 0; for(bar=0; bar currentMax) { currentMax = high[bar2]; } } if(low[bar2] < currentMin2) { currentMin2 = low[bar2]; currentMax2 = low[bar2]; } else { if(high[bar2] > currentMax2) { currentMax2 = high[bar2]; } } if(currentMax - currentMin >= Left * baseSize && !moveDone) { moveDone = true; extremBarNum = bar; } if(high[bar2] > high[limit-extremBarNum]) { extremBarNum = bar; } if(currentMax2 - currentMin2 >= Left * baseSize) { moveDone2 = true; extremBarNum2 = bar; currentMin2 = low[bar2]; currentMax2 = low[bar2]; } if(high[bar2] > high[limit-extremBarNum2]) { extremBarNum2 = bar; } //--- if(high[limit-extremBarNum] - low[bar2] >= Right * baseSize && bar != extremBarNum && moveDone) { if (high[limit-extremBarNum2] - low[bar2] >= Right * baseSize) { extremBarNum = extremBarNum2; } startBarNum = 0; for(j = extremBarNum - 1; j >= 0; j--) { if (high[limit-extremBarNum] - low[limit-j] >= Left * baseSize) { startBarNum = j; break; } } if(extremBarNum - startBarNum <= MaxBarsLeft && bar - extremBarNum <= MaxBarsRight) { fractals[fractals_Count] = high[limit-extremBarNum]; fractals_Count++; } currentMin = low[bar2]; currentMax = low[bar2]; extremBarNum = bar; moveDone = false; } else { if(high[limit-extremBarNum2] - low[bar2] >= Right * baseSize && bar != extremBarNum2 && moveDone2) { startBarNum = 0; for (j = extremBarNum2 - 1; j >= 0; j--) { if (high[limit-extremBarNum2] - low[limit-j] >= Left * baseSize) { startBarNum = j; break; } } if (extremBarNum2 - startBarNum <= MaxBarsLeft && bar - extremBarNum2 <= MaxBarsRight) { fractals[fractals_Count] = high[limit-extremBarNum2]; fractals_Count++; } currentMin2 = low[bar2]; currentMax2 = low[bar2]; extremBarNum2 = bar; moveDone2 = false; } } if (fractals_Count < 1) { frPriceshigh[bar2] = EMPTY_VALUE; } else { frPriceshigh[bar2] = fractals[fractals_Count - 1]; } } } } //--- если выбрано построение по нижним фракталам if(!Top) { fractals_Count = 0; for(bar=0; bar currentMax) { currentMin = high[bar2]; currentMax = high[bar2]; } else { if (low[bar2] < currentMin) { currentMin = low[bar2]; } } if(high[bar2] > currentMax2) { currentMin2 = high[bar2]; currentMax2 = high[bar2]; } else { if(low[bar2] < currentMin2) { currentMin2 = low[bar2]; } } if(currentMax - currentMin >= Left * baseSize && !moveDone) { moveDone = true; extremBarNum = bar; } if(low[bar2] > low[limit-extremBarNum]) { extremBarNum = bar; } if(currentMax2 - currentMin2 >= Left * baseSize) { moveDone2 = true; extremBarNum2 = bar; currentMin2 = high[bar2]; currentMax2 = high[bar2]; } if(low[bar2] < low[limit-extremBarNum2]) { extremBarNum2 = bar; } if(high[bar2] - low[limit-extremBarNum] >= Right * baseSize && bar != extremBarNum && moveDone) { if(high[bar2] - low[limit-extremBarNum2] >= Right * baseSize) { extremBarNum = extremBarNum2; } startBarNum = 0; for(j = extremBarNum - 1; j >= 0; j--) { if(high[limit-j] - low[limit-extremBarNum] >= Left * baseSize) { startBarNum = j; break; } } if(extremBarNum - startBarNum <= MaxBarsLeft && bar - extremBarNum <= MaxBarsRight) { fractals[fractals_Count] = low[limit-extremBarNum]; fractals_Count++; } currentMin = high[bar2]; currentMax = high[bar2]; extremBarNum = bar; moveDone = false; } else { if(high[bar2] - low[limit-extremBarNum2] >= Right * baseSize && bar != extremBarNum2 && moveDone2) { startBarNum = 0; for(j = extremBarNum2 - 1; j >= 0; j--) { if(high[limit-j] - low[limit-extremBarNum2] >= Left * baseSize) { startBarNum = j; break; } } if(extremBarNum2 - startBarNum <= MaxBarsLeft && bar - extremBarNum2 <= MaxBarsRight) { fractals[fractals_Count] = low[limit-extremBarNum2]; fractals_Count++; } currentMin2 = high[bar2]; currentMax2 = high[bar2]; extremBarNum2 = bar; moveDone2 = false; } } if (fractals_Count < 1) frPriceslow[bar2] = EMPTY_VALUE; else { frPriceslow[bar2] = fractals[fractals_Count - 1]; } } } } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Получаем сообщение о причине деинициализации | //+------------------------------------------------------------------+ void reason_answer(int vol_reason) { if(vol_reason == 0) Print("Deinit: Эксперт прекратил свою работу, вызвав функцию ExpertRemove()"); if(vol_reason == 1) Print("Deinit: Программа удалена с графика"); if(vol_reason == 2) Print("Deinit: Программа перекомпилирована"); if(vol_reason == 3) Print("Deinit: Символ или период графика был изменен"); if(vol_reason == 4) Print("Deinit: График закрыт"); if(vol_reason == 5) Print("Deinit: Входные параметры были изменены пользователем"); if(vol_reason == 6) Print("Deinit: Активирован другой счет либо произошло переподключение к торговому серверу вследствие изменения настроек счета"); if(vol_reason == 7) Print("Deinit: Применен другой шаблон графика"); if(vol_reason == 8) Print("Deinit: Признак того, что обработчик OnInit() вернул ненулевое значение"); if(vol_reason == 9) Print("Deinit: Терминал был закрыт"); } //+------------------------------------------------------------------+