//+------------------------------------------------------------------+ //| FX5_Divergence.mq4 | //| FX5 | //| hazem@uk2.net | //| Linuxser 2007 for TSD http://www.forex-tsd.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2007, FX5" #property link "hazem@uk2.net" //---- #property indicator_separate_window #property indicator_buffers 6 #property indicator_color1 LimeGreen #property indicator_color2 Red #property indicator_color3 Green #property indicator_color4 Red #property indicator_color5 Red #property indicator_color6 CLR_NONE #property indicator_maximum 325.0 #property indicator_minimum -325.0 #property indicator_level1 200 #property indicator_level2 100 #property indicator_level3 0.0 #property indicator_level4 -100 #property indicator_level5 -200 //---- input parameters extern string separator1 = "*** CCI Settings ***"; extern int CCI_Period = 14; extern string separator2 = "*** Indicator Settings ***"; extern double positiveSensitivity = 0.0001; extern double negativeSensitivity = -0.0001; extern double historyBarsCount = 0; extern bool drawDivergenceLines = true; extern bool displayAlert = true; //---- buffers double upCCIdiv[]; double downCCIdiv[]; double bullishDivergence[]; double bearishDivergence[]; double CCIdiv[]; double CCI[]; double Signal[]; double alertBuffer[]; //---- int chartBarsCount; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- indicators IndicatorBuffers(8); SetIndexStyle(0, DRAW_HISTOGRAM, STYLE_SOLID); SetIndexBuffer(0, upCCIdiv); SetIndexStyle(1, DRAW_HISTOGRAM, STYLE_SOLID); SetIndexBuffer(1, downCCIdiv); SetIndexStyle(2, DRAW_ARROW); SetIndexBuffer(2, bullishDivergence); SetIndexArrow(2, 233); SetIndexStyle(3, DRAW_ARROW); SetIndexBuffer(3, bearishDivergence); SetIndexArrow(3, 234); SetIndexStyle(4, DRAW_NONE); SetIndexBuffer(4, CCIdiv); SetIndexStyle(0, DRAW_HISTOGRAM, STYLE_SOLID); SetIndexBuffer(0, upCCIdiv); // additional buffers SetIndexBuffer(5, CCI); SetIndexStyle(6, DRAW_LINE, STYLE_SOLID); SetIndexBuffer(6, Signal); SetIndexBuffer(7, alertBuffer); //---- SetIndexLabel(0,NULL); SetIndexLabel(1,NULL); SetIndexLabel(2,NULL); SetIndexLabel(3,NULL); SetIndexLabel(4,NULL); SetIndexDrawBegin(0, CCI_Period); //---- IndicatorDigits(Digits + 2); IndicatorShortName("CCI_Divergence(" + CCI_Period + ")"); //---- return(0); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ 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); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { if(historyBarsCount <= 0 || historyBarsCount > Bars) chartBarsCount = Bars; else chartBarsCount = historyBarsCount; int countedBars = IndicatorCounted(); if(countedBars < 0) countedBars = 0; CalculateCCIdiv(countedBars); CalculateDivergence(countedBars); return(0); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CalculateDivergence(int countedBars) { double arrowSeparation = 1 / MathPow(10, Digits + 2) * 50; for(int i = chartBarsCount - countedBars; i >= 0; i--) { bearishDivergence[i] = EMPTY_VALUE; bullishDivergence[i] = EMPTY_VALUE; //---- int firstPeakOrTroughShift = GetFirstPeakOrTrough(i); double firstPeakOrTroughCCIdiv = CCIdiv[firstPeakOrTroughShift]; if(firstPeakOrTroughCCIdiv > 0) { int peak_0 = GetIndicatorLastPeak(i); int trough_0 = GetIndicatorLastTrough(peak_0); int peak_1 = GetIndicatorLastPeak(trough_0); int trough_1 = GetIndicatorLastTrough(peak_1); } else { trough_0 = GetIndicatorLastTrough(i); peak_0 = GetIndicatorLastPeak(trough_0); trough_1 = GetIndicatorLastTrough(peak_0); peak_1 = GetIndicatorLastPeak(trough_1); } if(peak_0 == -1 || peak_1 == -1 || trough_0 == -1 || trough_1 == -1) continue; double indicatorLastPeak = CCIdiv[peak_0]; double indicatorThePeakBefore = CCIdiv[peak_1]; double indicatorLastTrough = CCIdiv[trough_0]; double indicatorTheTroughBefore = CCIdiv[trough_1]; /* int pricePeak_0 = GetPriceLastPeak(peak_0); int pricePeak_1 = GetPriceLastPeak(peak_1); int priceTrough_0 = GetPriceLastTrough(trough_0); int priceTrough_1 = GetPriceLastTrough(trough_1); */ int pricePeak_0 = peak_0; int pricePeak_1 = peak_1; int priceTrough_0 = trough_0; int priceTrough_1 = trough_1; //---- double priceLastPeak = High[pricePeak_0]; double priceThePeakBefore = High[pricePeak_1]; double priceLastTrough = Low[priceTrough_0]; double priceTheTroughBefore = Low[priceTrough_1]; // Classic bearish divergence condition if(priceLastPeak > priceThePeakBefore && indicatorLastPeak < indicatorThePeakBefore) { DisplayAlert("Classic bearish divergence on: ", i, pricePeak_0); bearishDivergence[peak_0] = upCCIdiv[peak_0] + arrowSeparation; if(drawDivergenceLines) { PriceDrawLine(Time[pricePeak_0], Time[pricePeak_1], priceLastPeak, priceThePeakBefore, Red, STYLE_SOLID); IndicatorDrawLine(Time[peak_0], Time[peak_1], indicatorLastPeak, indicatorThePeakBefore, Red, STYLE_SOLID); } continue; } // Reverse bearsih divergence condition if(priceLastPeak < priceThePeakBefore && indicatorLastPeak > indicatorThePeakBefore) { DisplayAlert("Reverse bearish divergence on: ", i, pricePeak_0); bearishDivergence[peak_0] = upCCIdiv[peak_0] + arrowSeparation; if(drawDivergenceLines) { PriceDrawLine(Time[pricePeak_0], Time[pricePeak_1], priceLastPeak, priceThePeakBefore, Red, STYLE_DOT); IndicatorDrawLine(Time[peak_0], Time[peak_1], indicatorLastPeak, indicatorThePeakBefore, Red, STYLE_DOT); } continue; } // Classic bullish divergence condition if(priceLastTrough < priceTheTroughBefore && indicatorLastTrough > indicatorTheTroughBefore) { DisplayAlert("Classic bullish divergence on: ", i, priceTrough_0); bullishDivergence[trough_0] = downCCIdiv[trough_0] - arrowSeparation; if(drawDivergenceLines) { PriceDrawLine(Time[priceTrough_0], Time[priceTrough_1], priceLastTrough, priceTheTroughBefore, Green, STYLE_SOLID); IndicatorDrawLine(Time[trough_0], Time[trough_1], indicatorLastTrough, indicatorTheTroughBefore, Green, STYLE_SOLID); } continue; } // Hidden bullish divergence condition if(priceLastTrough > priceTheTroughBefore && indicatorLastTrough < indicatorTheTroughBefore) { DisplayAlert("Reverse bullish divergence on: ", i, priceTrough_0); bullishDivergence[trough_0] = downCCIdiv[trough_0] - arrowSeparation; if(drawDivergenceLines) { PriceDrawLine(Time[priceTrough_0], Time[priceTrough_1], priceLastTrough, priceTheTroughBefore, Green, STYLE_DOT); IndicatorDrawLine(Time[trough_0], Time[trough_1], indicatorLastTrough, indicatorTheTroughBefore, Green, STYLE_DOT); } continue; } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void DisplayAlert(string message, int barIndex, int signalIndex) { if(displayAlert == true && barIndex == 0 && alertBuffer[signalIndex] != 1) { Alert(message, Symbol(), " , at: ", Bid); alertBuffer[signalIndex] = 1; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CalculateCCIdiv(int countedBars) { for(int i = Bars - countedBars; i >= 0; i--) { CCI[i]=iCCI(NULL, 0, CCI_Period, PRICE_TYPICAL, i); } for(i = Bars - countedBars; i >= 0; i--) { Signal[i]=iCCI(NULL, 0, CCI_Period, PRICE_TYPICAL, i); CCIdiv[i] = CCI[i]; //---- if (CCIdiv[i] > 0) { upCCIdiv[i] = CCIdiv[i]; downCCIdiv[i] = 0; } else if(CCIdiv[i] < 0) { downCCIdiv[i] = CCIdiv[i]; upCCIdiv[i] = 0; } else { upCCIdiv[i] = 0; downCCIdiv[i] = 0; } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int GetPositiveRegionStart(int index) { int regionStart; for(int i = index + 1; i < Bars; i++) { if(CCIdiv[i] >= CCIdiv[i-1] && CCIdiv[i] >= CCIdiv[i+1] && CCIdiv[i] >= CCIdiv[i+2] && CCIdiv[i] > positiveSensitivity) return(i); } return(-1); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int GetNegativeRegionStart(int index) { for(int i = index + 1; i < Bars; i++) { if(CCIdiv[i] <= CCIdiv[i-1] && CCIdiv[i] <= CCIdiv[i+1] && CCIdiv[i] <= CCIdiv[i+2] && CCIdiv[i] < negativeSensitivity) return(i); } return(-1); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int GetFirstPeakOrTrough(int index) { for(int i = index + 1; i < Bars; i++) { if ((CCIdiv[i] >= CCIdiv[i-1] && CCIdiv[i] >= CCIdiv[i+1] && CCIdiv[i] >= CCIdiv[i+2] && CCIdiv[i] > positiveSensitivity) || (CCIdiv[i] <= CCIdiv[i-1] && CCIdiv[i] <= CCIdiv[i+1] && CCIdiv[i] <= CCIdiv[i+2] && CCIdiv[i] < negativeSensitivity)) return(i); } return(-1); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int GetIndicatorLastPeak(int index) { int regionStart = GetPositiveRegionStart(index); //---- if(regionStart == -1) return(-1); int peakShift = 0; double peakValue = 0; //---- for(int i = regionStart; i < Bars; i++) { if(CCIdiv[i] > peakValue && CCIdiv[i] >= CCIdiv[i-1] && CCIdiv[i] >= CCIdiv[i+1] && CCIdiv[i] >= CCIdiv[i+2] && CCIdiv[i] > positiveSensitivity) { peakValue = CCIdiv[i]; peakShift = i; } if(CCIdiv[i] < 0) break; } return(peakShift); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int GetIndicatorLastTrough(int index) { int regionStart = GetNegativeRegionStart(index); //---- if(regionStart == -1) return(-1); int troughShift = 0; double troughValue = 0; //---- for(int i = regionStart; i < Bars; i++) { if(CCIdiv[i] < troughValue && CCIdiv[i] <= CCIdiv[i-1] && CCIdiv[i] <= CCIdiv[i+1] && CCIdiv[i] <= CCIdiv[i+2] && CCIdiv[i] < negativeSensitivity) { troughValue = CCIdiv[i]; troughShift = i; } if(CCIdiv[i] > 0) break; } return(troughShift); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void PriceDrawLine(datetime x1, datetime x2, double y1, double y2, color lineColor, double style) { string label = "DivergenceLine# " + DoubleToStr(x1, 0); ObjectDelete(label); ObjectCreate(label, OBJ_TREND, 0, x1, y1, x2, y2, 0, 0); ObjectSet(label, OBJPROP_RAY, 0); ObjectSet(label, OBJPROP_COLOR, lineColor); ObjectSet(label, OBJPROP_STYLE, style); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void IndicatorDrawLine(datetime x1, datetime x2, double y1, double y2, color lineColor, double style) { int indicatorWindow = WindowFind("FX5_Divergence(" + CCI_Period + ""); if(indicatorWindow < 0) return; string label = "DivergenceLine$# " + DoubleToStr(x1, 0); ObjectDelete(label); ObjectCreate(label, OBJ_TREND, indicatorWindow, x1, y1, x2, y2, 0, 0); ObjectSet(label, OBJPROP_RAY, 0); ObjectSet(label, OBJPROP_COLOR, lineColor); ObjectSet(label, OBJPROP_STYLE, style); } //+------------------------------------------------------------------+