#property description "Divergence" //---- номер версии индикатора #property version "1.00" //+----------------------------------------------+ //| Параметры отрисовки индикатора | //+----------------------------------------------+ //---- отрисовка индикатора в главном окне #property indicator_chart_window //---- для расчета и отрисовки индикатора использовано 10 буферов #property indicator_buffers 10 //---- использовано всего одно графическое построение #property indicator_plots 1 //---- в качестве способа отображения использованы цветные свечи #property indicator_type1 DRAW_COLOR_CANDLES #property indicator_color1 clrRed,clrMagenta,clrBlue,clrLime //---- отображение метки индикатора #property indicator_label1 "Divergence Candles Open";"Divergence Candles High";"Divergence Candles Low";"Divergence Candles Close" //+----------------------------------------------+ //| Объявление констант | //+----------------------------------------------+ #define RESET 0 // константа для возврата терминалу команды на пересчет индикатора //+----------------------------------------------+ //| объявление перечислений | //+----------------------------------------------+ enum INDMODE { MODE_MACD, // MACD MODE_RSI, // RSI MODE_ADX, // ADX MODE_Momentum // Momentum }; //+----------------------------------------------+ //| объявление перечислений | //+----------------------------------------------+ enum PRICEMODE { MODE_CLOSE, // Close MODE_HIGHLOW // High/Low }; //+----------------------------------------------+ //| Входные параметры индикатора | //+----------------------------------------------+ input INDMODE ind=MODE_MACD; //индикатор input uint pds=10; //indicator periods input PRICEMODE f=MODE_CLOSE; //price field input double dCh=0; //peak/trough depth minimum (0-1) input uint xshift=0; //shift signals back to match divergences input int Shift=0; //сдвиг индикатора по горизонтали в барах input bool swAlert = true; // Alert input bool swPush = true; // Push input bool swMail = true; // Mail //+----------------------------------------------+ //---- объявление динамических массивов, которые в дальнейшем //---- будут использованы в качестве индикаторных буферов double ExtOpenBuffer[]; double ExtHighBuffer[]; double ExtLowBuffer[]; double ExtCloseBuffer[]; double ExtColorBuffer[]; double R1[],R2[],y[],xd[],xu[]; double Ch,fCh; //---- Объявление глобальных переменных int min_rates_total; //---- Объявление целых переменных для хендлов индикаторов int Ind_Handle; static datetime TimeN=0; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ void OnInit() { //---- инициализация глобальных переменных min_rates_total=int(pds); Ch=MathMax(MathMin(dCh,1),0); fCh=Ch/100.0; if(ind!=MODE_MACD) min_rates_total=int(pds+2); else min_rates_total=int(12+26+9+2); //---- получение хендла индикатора switch(ind) { case MODE_MACD: Ind_Handle=iMACD(NULL,0,12,26,9,PRICE_CLOSE); if(Ind_Handle==INVALID_HANDLE) Print(" Не удалось получить хендл индикатора iMACD"); break; case MODE_RSI: Ind_Handle=iRSI(NULL,0,pds,PRICE_CLOSE); if(Ind_Handle==INVALID_HANDLE) Print(" Не удалось получить хендл индикатора iRSI"); break; case MODE_ADX: Ind_Handle=iADX(NULL,0,pds); if(Ind_Handle==INVALID_HANDLE) Print(" Не удалось получить хендл индикатора iADX"); break; case MODE_Momentum: Ind_Handle=iMomentum(NULL,0,pds,PRICE_CLOSE); if(Ind_Handle==INVALID_HANDLE) Print(" Не удалось получить хендл индикатора iMomentum"); break; } //---- превращение динамических массивов в индикаторные буферы SetIndexBuffer(0,ExtOpenBuffer,INDICATOR_DATA); SetIndexBuffer(1,ExtHighBuffer,INDICATOR_DATA); SetIndexBuffer(2,ExtLowBuffer,INDICATOR_DATA); SetIndexBuffer(3,ExtCloseBuffer,INDICATOR_DATA); //---- превращение динамического массива в цветовой, индексный буфер SetIndexBuffer(4,ExtColorBuffer,INDICATOR_COLOR_IN DEX); //---- превращение динамических массивов в буферы для расчётов SetIndexBuffer(5,R1,INDICATOR_CALCULATIONS); SetIndexBuffer(6,R2,INDICATOR_CALCULATIONS); SetIndexBuffer(7,y,INDICATOR_CALCULATIONS); SetIndexBuffer(8,xd,INDICATOR_CALCULATIONS); SetIndexBuffer(9,xu,INDICATOR_CALCULATIONS); //---- индексация элементов в буфере, как в таймсерии ArraySetAsSeries(ExtOpenBuffer,true); ArraySetAsSeries(ExtHighBuffer,true); ArraySetAsSeries(ExtLowBuffer,true); ArraySetAsSeries(ExtCloseBuffer,true); ArraySetAsSeries(ExtColorBuffer,true); ArraySetAsSeries(R1,true); ArraySetAsSeries(R2,true); ArraySetAsSeries(y,true); ArraySetAsSeries(xd,true); ArraySetAsSeries(xu,true); //ArrayInitialize(ExtColorBuffer,-5); //---- осуществление сдвига индикатора по горизонтали на Shift PlotIndexSetInteger(0,PLOT_SHIFT,Shift); //---- осуществление сдвига начала отсчёта отрисовки индикатора PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_to tal); //---- установка значений индикатора, которые не будут видимы на графике PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); //---- установка формата точности отображения индикатора IndicatorSetInteger(INDICATOR_DIGITS,_Digits); //---- имя для окон данных и метка для подокон string short_name="Divergence Candles"; IndicatorSetString(INDICATOR_SHORTNAME,short_name) ; //---- } //+------------------------------------------------------------------+ //| 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(BarsCalculated(Ind_Handle)<rates_total || rates_total<min_rates_total) return(RESET); //---- объявления локальных переменных int limit,to_copy,bar,CNmb1,CNmb2,CNmb3,CNmb4; double Pkx1,Pkx2,Trx1,Trx2,Pky1,Pky2,Try1,Try2; bool Trx,Pkx,Try,Pky; //---- расчёты необходимого количества копируемых данных и //стартового номера limit для цикла пересчёта баров if(prev_calculated>rates_total || prev_calculated<=0)// проверка на первый старт расчёта индикатора { limit=rates_total-1-min_rates_total-3; // стартовый номер для расчёта всех баров } else { limit=rates_total-prev_calculated; // стартовый номер для расчёта новых баров } to_copy=limit+1; //---- копируем вновь появившиеся данные в массивы if(CopyBuffer(Ind_Handle,MAIN_LINE,0,to_copy,y)<=0 ) return(RESET); //---- индексация элементов в массивах как в таймсериях ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArraySetAsSeries(close,true); ArraySetAsSeries(open,true); for(bar=limit; bar>=0 && !IsStopped(); bar--) { if(f==MODE_CLOSE) { xu[bar]=close[bar]; xd[bar]=close[bar]; } else { xu[bar]=high[bar]; xd[bar]=low[bar]; } ExtOpenBuffer [bar]=0.0; ExtCloseBuffer[bar]=0.0; ExtHighBuffer [bar]=0.0; ExtLowBuffer [bar]=0.0; } //---- основной цикл расчета индикатора for(bar=limit; bar>=2 && !IsStopped(); bar--) { CNmb1=0; CNmb2=0; CNmb3=0; CNmb4=0; for(int kkk=bar; kkk<rates_total; kkk++) { Pkx=xu[kkk]<xu[kkk-1] && xu[kkk-1]>xu[kkk-2] && xu[kkk-1]>xu[kkk]+xu[kkk-2])/2.0*(1.0+fCh); if(Pkx) CNmb1++; if(Pkx && CNmb1==1) Pkx1=xu[kkk-1]; if(Pkx && CNmb1==2) Pkx2=xu[kkk-1]; Trx=xd[kkk]>xd[kkk-1] && xd[kkk-1]<xd[kkk-2] && xd[kkk-1]<xd[kkk]+xd[kkk-2])/2.0*(1.0-fCh); if(Trx) CNmb2++; if(Trx && CNmb2==1) Trx1=xd[kkk-1]; if(Trx && CNmb2==2) Trx2=xd[kkk-1]; Pky=y[kkk]<y[kkk-1] && y[kkk-1]>y[kkk-2] && y[kkk-1]>y[kkk]+y[kkk-2])/2.0*(1.0+fCh); if(Pky) CNmb3++; if(Pky && CNmb3==1) Pky1=y[kkk-1]; if(Pky && CNmb3==2) Pky2=y[kkk-1]; Try=y[kkk]>y[kkk-1] && y[kkk-1]<y[kkk-2] && y[kkk-1]<y[kkk]+y[kkk-2])/2.0*(1.0-fCh); if(Try) CNmb4++; if(Try && CNmb4==1) Try1=y[kkk-1]; if(Try && CNmb4==2) Try2=y[kkk-1]; if(CNmb1>=2 && CNmb2>=2 && CNmb3>=2 && CNmb4>=2) break; } Pkx=xu[bar]<xu[bar-1] && xu[bar-1]>xu[bar-2] && xu[bar-1]>xu[bar]+xu[bar-2])/2.0*(1.0+fCh); Trx=xd[bar]>xd[bar-1] && xd[bar-1]<xd[bar-2] && xd[bar-1]<xd[bar]+xd[bar-2])/2.0*(1.0-fCh); Pky=y[bar]<y[bar-1] && y[bar-1]>y[bar-2] && y[bar-1]>y[bar]+y[bar-2])/2.0*(1.0+fCh); Try=y[bar]>y[bar-1] && y[bar-1]<y[bar-2] && y[bar-1]<y[bar]+y[bar-2])/2.0*(1.0-fCh); R1[bar]=0; if(Trx && Try && Trx1<Trx2 && Try1>Try2) R1[bar]=1; R2[bar]=0; if(Pkx && Pky && Pkx1>Pkx2 && Pky1<Pky2) R2[bar]=1; if(R1[bar]-R2[bar]>0) { ExtOpenBuffer[bar]=open[bar]; ExtCloseBuffer[bar]=close[bar]; ExtHighBuffer[bar]=high[bar]; ExtLowBuffer[bar]=low[bar]; if(close[bar]>open[bar]) ExtColorBuffer[bar]=3; else ExtColorBuffer[bar]=2; } if(R1[bar]-R2[bar]<0) { ExtOpenBuffer[bar]=open[bar]; ExtCloseBuffer[bar]=close[bar]; ExtHighBuffer[bar]=high[bar]; ExtLowBuffer[bar]=low[bar]; if(open[bar]>close[bar]) ExtColorBuffer[bar]=0; else ExtColorBuffer[bar]=1; } //Print(rates_total," ",high[0]," ",ExtColorBuffer[0]," ",ExtColorBuffer[1]," ",ExtColorBuffer[3]); } datetime TimeC=iTimeMQL4(NULL,Period(),0); if (TimeN==0)TimeN=TimeC; if(TimeN!=TimeC){//clrRed,clrMagenta,clrBlue,clrLime Print(ExtColorBuffer[1]); if (MathAbs(ExtColorBuffer[1]-0.00)<0.001){ string strsignal="Div:"+Symbol()+" Red Signal "; if(swAlert)Alert(strsignal); if(swPush)fPush(strsignal); if(swMail)fSendMail(strsignal); } if (MathAbs(ExtColorBuffer[1]-1.00)<0.001){ string strsignal="Div:"+Symbol()+" Magenta Signal "; if(swAlert)Alert(strsignal); if(swPush)fPush(strsignal); if(swMail)fSendMail(strsignal); } if (MathAbs(ExtColorBuffer[1]-2.00)<0.001){ string strsignal="Div:"+Symbol()+" Blue Signal "; if(swAlert)Alert(strsignal); if(swPush)fPush(strsignal); if(swMail)fSendMail(strsignal); } if (MathAbs(ExtColorBuffer[1]-3.00)<0.001){ string strsignal="Div:"+Symbol()+" Lime Signal "; if(swAlert)Alert(strsignal); if(swPush)fPush(strsignal); if(swMail)fSendMail(strsignal); } TimeN=TimeC; } //---- return(rates_total); } //+------------------------------------------------------------------+ void fPush(string text){ if(!SendNotification(text)) { Print("Не удалось отправить PUSH-уведомление на смартфон!!!"); switch(GetLastError()) { case ERR_NOTIFICATION_SEND_FAILED : Print("Не удалось отправить уведомление!"); break; case ERR_NOTIFICATION_WRONG_PARAMETER : Print("Неверный параметр для отправки уведомления - пустая строка!"); break; case ERR_NOTIFICATION_WRONG_SETTINGS : Print("Неверные настройки уведомлений в терминале (не указан ID или не выставлено разрешение!)"); break; case ERR_NOTIFICATION_TOO_FREQUENT : Print("Слишком частая отправка уведомлений!"); break; default : Print("Неизвестная ошибка!"); } ResetLastError(); } else { Print("PUSH-уведомление успешно отправлено!"); GlobalVariableSet("Push",double(TimeCurrent())); } } void fSendMail(string text){ if(!SendMail("StdDevInformer",text)) { Print("Не удалось отправить уведомление на почту!!!"); ResetLastError(); } else { Print("Уведомление на почту успешно отправлено!"); }} datetime iTimeMQL4(string symbol,int tf,int index) { if(index < 0) return(-1); ENUM_TIMEFRAMES timeframe=TFMigrate(tf); datetime Arr[]; if(CopyTime(symbol, timeframe, index, 1, Arr)>0) return(Arr[0]); else return(-1); } ENUM_TIMEFRAMES TFMigrate(int tf) { switch(tf) { case 0: return(PERIOD_CURRENT); case 1: return(PERIOD_M1); case 5: return(PERIOD_M5); case 15: return(PERIOD_M15); case 30: return(PERIOD_M30); case 60: return(PERIOD_H1); case 240: return(PERIOD_H4); case 1440: return(PERIOD_D1); case 10080: return(PERIOD_W1); case 43200: return(PERIOD_MN1); case 2: return(PERIOD_M2); case 3: return(PERIOD_M3); case 4: return(PERIOD_M4); case 6: return(PERIOD_M6); case 10: return(PERIOD_M10); case 12: return(PERIOD_M12); case 20: return(PERIOD_M20); case 16385: return(PERIOD_H1); case 16386: return(PERIOD_H2); case 16387: return(PERIOD_H3); case 16388: return(PERIOD_H4); case 16390: return(PERIOD_H6); case 16392: return(PERIOD_H8); case 16396: return(PERIOD_H12); case 16408: return(PERIOD_D1); case 32769: return(PERIOD_W1); case 49153: return(PERIOD_MN1); default: return(PERIOD_CURRENT); } }