//------------------------------------------------------------------ #property copyright "mladen" #property link "mladenfx@gmail.com" //------------------------------------------------------------------ #property indicator_separate_window #property indicator_buffers 5 #property indicator_color1 LimeGreen #property indicator_color2 PaleVioletRed #property indicator_color3 DarkSlateGray #property indicator_color4 Aqua #property indicator_color5 Red #property indicator_width1 2 #property indicator_width2 2 #property indicator_width3 2 #property indicator_minimum -1 #property indicator_maximum 1 #property indicator_levelcolor DarkGray // // // // // extern string TimeFrame = "Current time frame"; extern int Length = 14; extern int Price = PRICE_TYPICAL; extern bool drawDivergences = true; extern bool ShowClassicalDivergence = true; extern bool ShowHiddenDivergence = true; extern bool divergenceOnValuesVisible = true; extern bool divergenceOnChartVisible = false; extern color divergenceBullishColor = Aqua; extern color divergenceBearishColor = Magenta; extern string drawLinesIdentificator = "RSXdiverge1"; extern string ___ = "Divergence Alerts"; extern bool divergenceAlert = true; extern bool divergenceAlertsMessage = true; extern bool divergenceAlertsSound = true; extern bool divergenceAlertsNotify = true; extern bool divergenceAlertsEmail = false; extern string divergenceAlertsSoundName = "alert1.wav"; extern double levelOs = -0.5; extern double levelOb = 0.5; // // // // // double rsx[]; double rsxDa[]; double rsxDb[]; double bullishDivergence[]; double bearishDivergence[]; double slope[]; // // // // // string shortName; string labelNames; string indicatorFileName; bool calculateValue; bool returnBars; int timeFrame; double pipMultiplier = 1; //------------------------------------------------------------------- // //------------------------------------------------------------------- // // // // // int init() { IndicatorBuffers(6); SetIndexBuffer(0,rsxDa); SetIndexStyle(0,DRAW_HISTOGRAM); SetIndexBuffer(1,rsxDb); SetIndexStyle(1,DRAW_HISTOGRAM); SetIndexBuffer(2,rsx); SetIndexBuffer(3,bullishDivergence); SetIndexStyle(3,DRAW_ARROW); SetIndexArrow(3,233); SetIndexBuffer(4,bearishDivergence); SetIndexStyle(4,DRAW_ARROW); SetIndexArrow(4,234); SetIndexBuffer(5,slope); SetLevelValue(0,levelOb); SetLevelValue(1,levelOs); SetLevelValue(2,0); // // // // // timeFrame = stringToTimeFrame(TimeFrame); labelNames = "RSX_DivergenceLine "+drawLinesIdentificator+":"; shortName = timeFrameToString(timeFrame)+" RSX ("+Length+")"; IndicatorShortName(shortName); // // // // // indicatorFileName = WindowExpertName(); calculateValue = (TimeFrame=="calculateValue"); if (calculateValue) return(0); returnBars = (TimeFrame=="returnBars"); if (returnBars) return(0); return(0); } // // // // // int deinit() { int length=StringLen(labelNames); for(int i=ObjectsTotal()-1; i>=0; i--) { string name = ObjectName(i); if(StringSubstr(name,0,length) == labelNames) ObjectDelete(name); } return(0); } //------------------------------------------------------------------- // //------------------------------------------------------------------- // // // // // double wrkBuffer[][13]; int start() { int i,r,counted_bars=IndicatorCounted(); if(counted_bars<0) return(-1); if(counted_bars>0) counted_bars--; int limit = MathMin(Bars-counted_bars,Bars-1); if (returnBars) { rsxDa[0] = limit+1; return(0); } if (Digits==3 || Digits==5) pipMultiplier = 10; else pipMultiplier = 1; // // // // // if (calculateValue || timeFrame==Period()) { double Kg = (3.0)/(2.0+Length); double Hg = 1.0-Kg; if (ArrayRange(wrkBuffer,0) != Bars) ArrayResize(wrkBuffer,Bars); for(i=limit, r=Bars-i-1; i>=0; i--, r++) { wrkBuffer[r][12] = iMA(NULL,0,1,0,MODE_SMA,Price,i); if (i==(Bars-1)) { for (int c=0; c<12; c++) wrkBuffer[r][c] = 0; continue; } // // // // // double mom = wrkBuffer[r][12]-wrkBuffer[r-1][12]; double moa = MathAbs(mom); for (int k=0; k<3; k++) { int kk = k*2; wrkBuffer[r][kk+0] = Kg*mom + Hg*wrkBuffer[r-1][kk+0]; wrkBuffer[r][kk+1] = Kg*wrkBuffer[r][kk+0] + Hg*wrkBuffer[r-1][kk+1]; mom = 1.5*wrkBuffer[r][kk+0] - 0.5 * wrkBuffer[r][kk+1]; wrkBuffer[r][kk+6] = Kg*moa + Hg*wrkBuffer[r-1][kk+6]; wrkBuffer[r][kk+7] = Kg*wrkBuffer[r][kk+6] + Hg*wrkBuffer[r-1][kk+7]; moa = 1.5*wrkBuffer[r][kk+6] - 0.5 * wrkBuffer[r][kk+7]; } if (moa != 0) rsx[i] = MathMax(MathMin((mom/moa+1.0)*50.0,100.00),0.00)/(50)-1; else rsx[i] = 0; // // // // // rsxDa[i] = EMPTY_VALUE; rsxDb[i] = EMPTY_VALUE; slope[i] = slope[i+1]; if (rsx[i]>rsx[i+1]) slope[i] = 1; if (rsx[i]=0; i--) { int y = iBarShift(NULL,timeFrame,Time[i]); rsx[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",Length,Price,drawDivergences,ShowClassicalDivergence,ShowHiddenDivergence,divergenceOnValuesVisible,divergenceOnChartVisible,divergenceBullishColor,divergenceBearishColor,drawLinesIdentificator,"",divergenceAlert,divergenceAlertsMessage,divergenceAlertsSound,divergenceAlertsNotify,divergenceAlertsEmail,divergenceAlertsSoundName,2,y); slope[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",Length,Price,drawDivergences,ShowClassicalDivergence,ShowHiddenDivergence,divergenceOnValuesVisible,divergenceOnChartVisible,divergenceBullishColor,divergenceBearishColor,drawLinesIdentificator,"",divergenceAlert,divergenceAlertsMessage,divergenceAlertsSound,divergenceAlertsNotify,divergenceAlertsEmail,divergenceAlertsSoundName,5,y); rsxDa[i] = EMPTY_VALUE; rsxDb[i] = EMPTY_VALUE; bullishDivergence[i] = EMPTY_VALUE; bearishDivergence[i] = EMPTY_VALUE; int firstBar = iBarShift(NULL,0,iTime(NULL,timeFrame,y)); if (i==firstBar) { bullishDivergence[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",Length,Price,drawDivergences,ShowClassicalDivergence,ShowHiddenDivergence,divergenceOnValuesVisible,divergenceOnChartVisible,divergenceBullishColor,divergenceBearishColor,drawLinesIdentificator,"",divergenceAlert,divergenceAlertsMessage,divergenceAlertsSound,divergenceAlertsNotify,divergenceAlertsEmail,divergenceAlertsSoundName,3,y); bearishDivergence[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",Length,Price,drawDivergences,ShowClassicalDivergence,ShowHiddenDivergence,divergenceOnValuesVisible,divergenceOnChartVisible,divergenceBullishColor,divergenceBearishColor,drawLinesIdentificator,"",divergenceAlert,divergenceAlertsMessage,divergenceAlertsSound,divergenceAlertsNotify,divergenceAlertsEmail,divergenceAlertsSoundName,4,y); } if (slope[i]== 1) rsxDa[i] = rsx[i]; if (slope[i]==-1) rsxDb[i] = rsx[i]; } return(0); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // // // // // void CatchBullishDivergence(int shift) { shift++; bullishDivergence[shift] = EMPTY_VALUE; ObjectDelete(labelNames+"l"+DoubleToStr(Time[shift],0)); ObjectDelete(labelNames+"l"+"os" + DoubleToStr(Time[shift],0)); if(!IsIndicatorLow(shift)) return; // // // // // int currentLow = shift; int lastLow = GetIndicatorLastLow(shift+1); if(rsx[currentLow] > rsx[lastLow] && Low[currentLow] < Low[lastLow]) { if (ShowClassicalDivergence) { bullishDivergence[currentLow] = rsx[currentLow] - Point*pipMultiplier; if(divergenceOnChartVisible) DrawPriceTrendLine("l",Time[currentLow],Time[lastLow],Low[currentLow],Low[lastLow], divergenceBullishColor, STYLE_SOLID); if(divergenceOnValuesVisible) DrawIndicatorTrendLine("l",Time[currentLow],Time[lastLow],rsx[currentLow],rsx[lastLow],divergenceBullishColor,STYLE_SOLID); if(divergenceAlert) DisplayAlert("Classical bullish divergence",currentLow); } } // // // // // if(rsx[currentLow] < rsx[lastLow] && Low[currentLow] > Low[lastLow]) { if (ShowHiddenDivergence) { bullishDivergence[currentLow] = rsx[currentLow] - Point*pipMultiplier; if(divergenceOnChartVisible) DrawPriceTrendLine("l",Time[currentLow],Time[lastLow],Low[currentLow],Low[lastLow], divergenceBullishColor, STYLE_DOT); if(divergenceOnValuesVisible) DrawIndicatorTrendLine("l",Time[currentLow],Time[lastLow],rsx[currentLow],rsx[lastLow],divergenceBullishColor,STYLE_DOT); if(divergenceAlert) DisplayAlert("Reverse bullish divergence",currentLow); } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // // // // // void CatchBearishDivergence(int shift) { shift++; bearishDivergence[shift] = EMPTY_VALUE; ObjectDelete(labelNames+"h"+DoubleToStr(Time[shift],0)); ObjectDelete(labelNames+"h"+"os" + DoubleToStr(Time[shift],0)); if(IsIndicatorPeak(shift) == false) return; // // // // // int currentPeak = shift; int lastPeak = GetIndicatorLastPeak(shift+1); if(rsx[currentPeak] < rsx[lastPeak] && High[currentPeak]>High[lastPeak]) { if (ShowClassicalDivergence) { bearishDivergence[currentPeak] = rsx[currentPeak] + Point*pipMultiplier; if (divergenceOnChartVisible) DrawPriceTrendLine("h",Time[currentPeak],Time[lastPeak],High[currentPeak],High[lastPeak], divergenceBearishColor,STYLE_SOLID); if (divergenceOnValuesVisible) DrawIndicatorTrendLine("h",Time[currentPeak],Time[lastPeak],rsx[currentPeak],rsx[lastPeak],divergenceBearishColor,STYLE_SOLID); if (divergenceAlert) DisplayAlert("Classical bearish divergence",currentPeak); } } // // // // // if(rsx[currentPeak] > rsx[lastPeak] && High[currentPeak] < High[lastPeak]) { if (ShowHiddenDivergence) { bearishDivergence[currentPeak] = rsx[currentPeak] + Point*pipMultiplier; if (divergenceOnChartVisible) DrawPriceTrendLine("h",Time[currentPeak],Time[lastPeak],High[currentPeak],High[lastPeak], divergenceBearishColor,STYLE_DOT); if (divergenceOnValuesVisible) DrawIndicatorTrendLine("h",Time[currentPeak],Time[lastPeak],rsx[currentPeak],rsx[lastPeak],divergenceBearishColor,STYLE_DOT); if (divergenceAlert) DisplayAlert("Reverse bearish divergence",currentPeak); } } } // // // // // bool IsIndicatorPeak(int shift) { if(rsx[shift] >= rsx[shift+1] && rsx[shift] > rsx[shift+2] && rsx[shift] > rsx[shift-1]) return(true); else return(false); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // // bool IsIndicatorLow(int shift) { if(rsx[shift] <= rsx[shift+1] && rsx[shift] < rsx[shift+2] && rsx[shift] < rsx[shift-1]) return(true); else return(false); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // // int GetIndicatorLastPeak(int shift) { for(int i = shift+5; i < Bars; i++) { if(rsx[i] >= rsx[i+1] && rsx[i] > rsx[i+2] && rsx[i] >= rsx[i-1] && rsx[i] > rsx[i-2]) return(i); } return(-1); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // // int GetIndicatorLastLow(int shift) { for (int i = shift+5; i < Bars; i++) { if (rsx[i] <= rsx[i+1] && rsx[i] < rsx[i+2] && rsx[i] <= rsx[i-1] && rsx[i] < rsx[i-2]) return(i); } return(-1); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // // // // // void DrawPriceTrendLine(string first,datetime t1, datetime t2, double p1, double p2, color lineColor, double style) { string label = labelNames+first+"os"+DoubleToStr(t1,0); ObjectDelete(label); ObjectCreate(label, OBJ_TREND, 0, t1, p1, t2, p2, 0, 0); ObjectSet(label, OBJPROP_RAY, 0); ObjectSet(label, OBJPROP_COLOR, lineColor); ObjectSet(label, OBJPROP_STYLE, style); } // // // // // void DrawIndicatorTrendLine(string first,datetime t1, datetime t2, double p1, double p2, color lineColor, double style) { int indicatorWindow = WindowFind(shortName); if (indicatorWindow < 0) return; string label = labelNames+first+DoubleToStr(t1,0); ObjectDelete(label); ObjectCreate(label, OBJ_TREND, indicatorWindow, t1, p1, t2, p2, 0, 0); ObjectSet(label, OBJPROP_RAY, 0); ObjectSet(label, OBJPROP_COLOR, lineColor); ObjectSet(label, OBJPROP_STYLE, style); } // // // // // void DisplayAlert(string doWhat, int shift) { string dmessage; static datetime lastAlertTime; if(shift <= 2 && Time[0] != lastAlertTime) { dmessage = StringConcatenate(Symbol()," ",timeFrameToString(timeFrame)," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," RSX ",doWhat); if (divergenceAlertsMessage) Alert(dmessage); if (divergenceAlertsNotify) SendNotification(StringConcatenate(Symbol(), Period() ," RSX " +" "+dmessage)); if (divergenceAlertsEmail) SendMail(StringConcatenate(Symbol()," RSX "),dmessage); if (divergenceAlertsSound) PlaySound(divergenceAlertsSoundName); lastAlertTime = Time[0]; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // // // // // string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"}; int iTfTable[] = {1,5,15,30,60,240,1440,10080,43200}; // // // // // int stringToTimeFrame(string tfs) { tfs = StringUpperCase(tfs); for (int i=ArraySize(iTfTable)-1; i>=0; i--) if (tfs==sTfTable[i] || tfs==""+iTfTable[i]) return(MathMax(iTfTable[i],Period())); return(Period()); } string timeFrameToString(int tf) { for (int i=ArraySize(iTfTable)-1; i>=0; i--) if (tf==iTfTable[i]) return(sTfTable[i]); return(""); } // // // // // string StringUpperCase(string str) { string s = str; for (int length=StringLen(str)-1; length>=0; length--) { int tchar = StringGetChar(s, length); if((tchar > 96 && tchar < 123) || (tchar > 223 && tchar < 256)) s = StringSetChar(s, length, tchar - 32); else if(tchar > -33 && tchar < 0) s = StringSetChar(s, length, tchar + 224); } return(s); }