//+-------------------------------------------------------------------------------------------------------------------+ //| kosma-2.02.mq4 | //| pu6ka@mail.ru | //+-------------------------------------------------------------------------------------------------------------------+ #property indicator_separate_window #property indicator_buffers 7 #property indicator_color1 Magenta #property indicator_color4 Yellow #property indicator_color5 Yellow #property indicator_color6 Green #property indicator_color7 Red extern int fast = 12; extern int slow = 26; extern int sig = 9; extern int k = 1; // коэф.умножения параметров OsMA extern int n = 2; // кол-во баров справа/слева начиная с которого считается пик/впадина extern bool drawDivergenceLines = true; // отображать или нет линии дивергенции, стрелки на основном графике int history=15000; double OsMA[]; double bullishDivergence[]; double bearishDivergence[]; double peak[]; double trough[]; double bulliShift[]; double beariShift[]; //+-------------------------------------------------------------------------------------------------------------------+ //| | //+-------------------------------------------------------------------------------------------------------------------+ int init() { //---- indicators SetIndexStyle(0,DRAW_LINE,0,1); SetIndexStyle(3,DRAW_ARROW); SetIndexStyle(4,DRAW_ARROW); SetIndexStyle(5,DRAW_ARROW); SetIndexStyle(6,DRAW_ARROW); //---- SetIndexBuffer(0, OsMA); // Буфер индикатора для массива OsMA[] SetIndexBuffer(1, bullishDivergence); // заносятся значения для отражения стрелки "вверх" SetIndexBuffer(2, bearishDivergence); // заносятся значения для отражения стрелки "вниз" SetIndexBuffer(3, peak); // заносим значения изгибов наверху SetIndexBuffer(4, trough); // заносим значения изгибов снизу SetIndexBuffer(5, bulliShift); // заносятся значения для отражения стрелки "вверх" со смещением SetIndexBuffer(6, beariShift); // заносятся значения для отражения стрелки "вниз" со смещением //---- SetIndexArrow(5, 233); // Назначение значка "стрелка вверх" для bullishDivergence SetIndexArrow(6, 234); // Назначение значка "стрелка вниз" для bearishDivergence SetIndexArrow(3, 116); // Назначение значка изгибов наверху SetIndexArrow(4, 116); // Назначение значка изгибов снизу //---- IndicatorDigits(Digits+2); IndicatorShortName("kosma-2.02 ("+fast+","+slow+","+sig+")"+" k"+k+" n"+n); return(0); } //+-------------------------------------------------------------------------------------------------------------------+ //| | //+-------------------------------------------------------------------------------------------------------------------+ int deinit() { for(int i=ObjectsTotal()-1; i>=0; i--) { string label=ObjectName(i); if(StringSubstr(label,0,14)!="DivergenceLine") continue; ObjectDelete(label); } return(0); } //+-------------------------------------------------------------------------------------------------------------------+ //| | //+-------------------------------------------------------------------------------------------------------------------+ int start() { int countedBars = IndicatorCounted(); // Кол-во неизмененных баров if(countedBars < 0) countedBars = 0; // Обнулим, если значение меньше 0. CalculateIndicator(countedBars); return(0); } //+-------------------------------------------------------------------------------------------------------------------+ //| | //+-------------------------------------------------------------------------------------------------------------------+ void CalculateIndicator(int countedBars) { int j=Bars-countedBars; // Индекс первого непосчитанного бара if(countedBars==0) j-=2*n+1; for(int i=j; i>=0; i--) { CalculateOsMA(i); CatchBullishDivergence(i+n); CatchBearishDivergence(i+n); } } //+-------------------------------------------------------------------------------------------------------------------+ //| Заполнение значениями буферного массива OsMA[] | //+-------------------------------------------------------------------------------------------------------------------+ void CalculateOsMA(int i) { OsMA[i]=iOsMA(NULL,0,fast*k,slow*k,sig*k,PRICE_WEIGHTED,i); } //+-------------------------------------------------------------------------------------------------------------------+ //| Дивергенция указывающая стрелку "вверх" | //+-------------------------------------------------------------------------------------------------------------------+ void CatchBullishDivergence(int shift) // shift = i+n { int idTrough=IsIndicatorTrough(shift); // индекс горба, получаем по перебору влево от найденой впадины if(idTrough < 0) return; // впадина отсутствует int currentTrough = shift; // индекс ямы, раз дошли сюда, n-й бар самый низкий int lastTrough = GetIndicatorLastTrough(idTrough); // Получили индекс предпоследней впадины // Если тек.яма выше предыдущей и цена Low тек.ямы ниже цены Low предыдущей ямы индикатора - такой дивер > if(OsMA[currentTrough]>OsMA[lastTrough] && Low[currentTrough]Low[lastTrough]) { bullishDivergence[currentTrough]=OsMA[currentTrough]; // передаем знач.OsMA в массив со стрелочным буфером bulliShift[currentTrough-n]=OsMA[currentTrough]; // передаем знач.OsMA в массив со стрелочным буфером if(drawDivergenceLines) DrawArrowOnChart(currentTrough,1); //trough[shift] = EMPTY_VALUE; // уберем наложение на один индекс двух значков if(drawDivergenceLines==true) // прорисовка линий, если выбрано true в глоб.переменной { DrawPriceTrendLine(Time[currentTrough],Time[lastTrough],Low[currentTrough], Low[lastTrough],Green,STYLE_DOT); DrawIndicatorTrendLine(Time[currentTrough],Time[lastTrough],OsMA[currentTrough], OsMA[lastTrough],Green,STYLE_DOT); } } } //+-------------------------------------------------------------------------------------------------------------------+ //| Дивергенция указывающая стрелку "вниз" | //+-------------------------------------------------------------------------------------------------------------------+ void CatchBearishDivergence(int shift) // shift = i+n { int idPeak=IsIndicatorPeak(shift); // индекс впадины, получаем по перебору влево от найденого пика if(idPeak<0) return; // пик отсутствует int currentPeak = shift; // индекс пика, раз дошли сюда, n-й бар самый высокий int lastPeak = GetIndicatorLastPeak(idPeak); // получили индекс предпоследнего пика // Если тек.пик ниже предыдущего и цена тек.пика выше цены предыдущего пика индикатора - такой дивер < if(lastPeak>=0&&OsMA[currentPeak]High[lastPeak]) { bearishDivergence[currentPeak]=OsMA[currentPeak]; // записываем в массив значение ОсМА beariShift[currentPeak-n]=OsMA[currentPeak]; // записываем в массив значение ОсМА if(drawDivergenceLines) DrawArrowOnChart(currentPeak,2); //peak[shift] = EMPTY_VALUE; // уберем наложение на один индекс двух значков if(drawDivergenceLines==true) // прорисовка линий, если выбрано true в глоб.переменной { DrawPriceTrendLine(Time[currentPeak],Time[lastPeak],High[currentPeak], High[lastPeak],Red,STYLE_SOLID); DrawIndicatorTrendLine(Time[currentPeak],Time[lastPeak],OsMA[currentPeak], OsMA[lastPeak],Red,STYLE_SOLID); } } // Если тек.пик выше предыдущего и цена тек.пика ниже цены предыдущего пика индикатора - такой дивер > if(lastPeak>=0&&OsMA[currentPeak]>OsMA[lastPeak] && High[currentPeak]OsMA[shift+i+1] && OsMA[shift-i]>OsMA[shift-i-1]) || (OsMA[shift]>OsMA[shift+i+1] && OsMA[shift]>OsMA[shift-i-1])) { m++; continue; } else return(-1); // вернем значение тек.функции "false" } if(m==n) { peak[shift] = OsMA[shift]; // заносим в массив получившийся изгиб for(i = shift + n; i < Bars; i++) // пересчитываем все бары OsMA падает назад в историю if(OsMA[i] < OsMA[i+1]) // OsMA изогнулась, тек.знач меньше i+1 return(i); // получим индекс бара на котором изгиб-впадина } return(-1); // вернем значение тек.функции "false" } //+-------------------------------------------------------------------------------------------------------------------+ //| Ф-я в первом цикле for опр-ет наличие впадины V перебирая указанное число n-баров слева и справа от искомой свечи.| //| Искомая свеча определяется от текущего бара, как правило нулевого (а на истории от i-го), на n-баров влево. | //| Далее, если впадина, отвечающая условиям, существует, делаем перебор вглубь истории. ОсМА вглубь растет, если по- | //| является изгиб вниз, тогда возвращаем этот индекс бара. Во всех остальных случаях функция возвращает (-1) | //| Во втором цикле for можно искать изгибы ОсМА не на 1 бар, а на больше, чтоб игнорировать незначительные колебания | //+-------------------------------------------------------------------------------------------------------------------+ int IsIndicatorTrough(int shift) // ищем изгиб V на shift = i + n { int i,m=0; for(i=0; i OsMA[i+1]) // OsMA изогнулась, тек.знач больше i+1 return(i); // получим индекс бара на котором изгиб-горб } } return(-1); // вернем значение тек.функции "false" } //+-------------------------------------------------------------------------------------------------------------------+ //| Нахождение предпоследнего пика | //| Высчитывается, как два соседних бара слева и справа ниже искомого | //+-------------------------------------------------------------------------------------------------------------------+ int GetIndicatorLastPeak(int idPeak) { for(int i=idPeak+1; i