//+------------------------------------------------------------------+ //| MACD_Div.mqh | //| Majid Namnabat | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Majid Namnabat" #property link "https://www.mql5.com" #property version "1.00" #property strict #include #include enum ENUM_ALLOW_DIVERGENCE_DETECTION { ENUM_ALLOW_DIVERGENCE_T1 = 1, //In One Wave Between Highest & Current ENUM_ALLOW_DIVERGENCE_T2 = 2, //In One Wave Between Nearest High & Current ENUM_ALLOW_DIVERGENCE_NONSTANDARD = 4, // In Two Wave ENUM_ALLOW_DIVERGENCE_EXTENTION1 = 8, ENUM_ALLOW_DIVERGENCE_RSI_T1 = 16 }; // two bit : positive or negative // six bit : types enum ENUM_DIVERGENCE_CLASS { ENUM_DIVERGENCE_NONE = 0, ENUM_DIVERGENCE_UNKNOWN = -1, ENUM_DIVERGENCE_NEGATIVE_T1 = char(1) | (1 << 3),//0x01001 ENUM_DIVERGENCE_POSITIVE_T1 = char(2) | (1 << 3),//0x1010 , 0x010110 // return 24 ENUM_DIVERGENCE_NEGATIVE_T2 = char(1) | (1 << 4), ENUM_DIVERGENCE_POSITIVE_T2 = char(2) | (1 << 4), ENUM_DIVERGENCE_NONSTANDARD_NEGATIVE = (char(1) | (1 << 5)), ENUM_DIVERGENCE_NONSTANDARD_POSITIVE = (char(2) | (1 << 5)), ENUM_DIVERGENCE_NEGATIVE_EXT1 = (char(1) | (1 << 6)), //The indicator is decreasing ENUM_DIVERGENCE_POSITIVE_EXT1 = (char(2) | (1 << 6)), //The indicator is increasing //return 80 01001110 64+8+4+2 ENUM_DIVERGENCE_NEGATIVE_RSI_T1 = (char(1) | (1 << 7)), ENUM_DIVERGENCE_POSITIVE_RSI_T1 = (char(2) | (1 << 7)) }; #define nCheckBarsMax 102 // number of bars to check divergence + 2 candle of prv and prvprv const int Extremum_LeftBarSize = 4; const int Extremum_RightBarSize = 4; const int INVALID_VALUE = -999999999; const double MACD_THRESHOLD_RATIO_MAX = 0.0f; struct SExtremum { int PriceBar; int ExtremumBar; datetime ExtremumTime; double IndicatorValue; double PriceValue; int IndicatorWaveEndBar; int IndicatorWaveStartBar; }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class EA_MACD_Div { private: int macd_fast; int macd_slow; int macd_signal; //double div_oscErr; // allowable error along divergence line (oscilator) //double div_priceErr; // allowable error along divergence line (PPS), iATR(nCheckBars)*err SExtremum m_extremums[]; double m_fMACD[nCheckBarsMax]; double m_fMACD_MinimumLevel ; double m_fMACD_MaximumLevel ; int m_nExtCount; int m_nSelTimeFrame ; int m_nAllowCheckTypes ; double m_fMACD_Point; void AddExtremum(double indval, double pval, int indbar, int pbar, datetime et, int wstart, int wend ) { if(m_nExtCount>=ArraySize(m_extremums)) { ArrayResize(m_extremums,ArraySize(m_extremums)+5); } m_extremums[m_nExtCount].IndicatorValue=indval; m_extremums[m_nExtCount].PriceValue=pval; m_extremums[m_nExtCount].ExtremumBar=indbar; m_extremums[m_nExtCount].PriceBar=pbar; m_extremums[m_nExtCount].ExtremumTime=et; m_extremums[m_nExtCount].IndicatorWaveEndBar = wend; m_extremums[m_nExtCount].IndicatorWaveStartBar = wstart; m_nExtCount++; }; bool IsArrayMinimum(const double& arr[], int leftwin, int rightwin, int center) ; bool IsLocalExtremum(const double& arr[], int leftwin, int rightwin, int center) ; double GetCandleValue(const double& arr[],int index); bool FindExtermums(); bool IsExistAndDrawNegativeDiv(int nExtIndex,ENUM_DIVERGENCE_CLASS divClass); bool IsExistAndDrawPositiveDiv(int nExtIndex,ENUM_DIVERGENCE_CLASS divClass); int IsExistAndValidNearExtremum(); void FillPriceTimeExtremum(int nExtInd,ENUM_WAVE_TREND trendDirection); ENUM_DIVERGENCE_CLASS CheckDivergenceExtention(ENUM_WAVE_TREND trendDirection); ENUM_DIVERGENCE_CLASS CheckDivergenceRSI(int nExtIndex, ENUM_WAVE_TREND trendDirection); bool IsAllowCheck(ENUM_DIVERGENCE_CLASS divClass); void DrawExtermum(ENUM_WAVE_TREND trendDirection,int nExtInd); bool m_bIsCheckRSI ; public: EA_MACD_Div(); ~EA_MACD_Div(); bool Init(ENUM_WAVE_TREND & trendDirection); bool Reset(); ENUM_DIVERGENCE_CLASS Check(ENUM_WAVE_TREND trendDirection); void SetPeriod(int nPeriod) {m_nSelTimeFrame = nPeriod ; } void SetAllowCheckTypes(int nAllowType) { m_nAllowCheckTypes = nAllowType;} double GetMACD_Prv2(); void Set_IsCheckRSI(bool bIsCheckRSI) { m_bIsCheckRSI = bIsCheckRSI;} }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ EA_MACD_Div::EA_MACD_Div() { macd_fast = 5; // fast EMA macd_slow = 34; // slow EMA macd_signal = 5; // signal SMA //div_oscErr = 4.0; // allowable error along divergence line (oscilator) //div_priceErr = 0.4; // allowable error along divergence line (PPS), iATR(nCheckBars)*err m_nExtCount = 0 ; ArraySetAsSeries(m_fMACD,true); ArrayFill(m_fMACD,0,ArraySize(m_fMACD),INVALID_VALUE); m_nSelTimeFrame = LowerPeriod(); m_nAllowCheckTypes = 0; m_fMACD_MinimumLevel = INVALID_VALUE; m_fMACD_MaximumLevel = INVALID_VALUE ; m_fMACD_Point = 0.0f; m_bIsCheckRSI = false ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ EA_MACD_Div::~EA_MACD_Div() { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool EA_MACD_Div::Reset() { macd_fast = 5; // fast EMA macd_slow = 34; // slow EMA macd_signal = 5; // signal SMA //div_oscErr = 4.0; // allowable error along divergence line (oscilator) //div_priceErr = 0.4; // allowable error along divergence line (PPS), iATR(nCheckBars)*err m_nExtCount = 0 ; ArraySetAsSeries(m_fMACD,true); ArrayFill(m_fMACD,0,ArraySize(m_fMACD),INVALID_VALUE); m_nSelTimeFrame = LowerPeriod(); m_nAllowCheckTypes = 0; m_fMACD_MaximumLevel = INVALID_VALUE ; m_fMACD_MinimumLevel = INVALID_VALUE ; m_fMACD_Point = 0.0f; m_bIsCheckRSI = false ; return true; } //+------------------------------------------------------------------+ //|first work with PrvPrv Candle : Experience // second : Candle or MACD must be Pick in local one neighbour , may be two candle or two MACD toghether mark Pick , but another must be determine this is Pick | //+------------------------------------------------------------------+ bool EA_MACD_Div::Init(ENUM_WAVE_TREND & trendDirection) { double fMACDVal; int nMaxIndex; bool bIsPositive ; bool bIsAccept_Analysing = false; ////////////////////// /*datetime datePrvPrv = iTime(NULL,m_nSelTimeFrame , 2 ); int YY=TimeYear( datePrvPrv ); // Year int MN=TimeMonth( datePrvPrv ); // Month int DD=TimeDay( datePrvPrv ); // Day int HH=TimeHour( datePrvPrv ); // Hour if(YY == 2021 && MN == 3 && ( DD >= 17 || DD <= 25 ) ) { DrawArrowCheckCandle(120,trendDirection == ENUM_TREND_BULLISH ? ENUM_OBJECT_ABOVE_CANDLE : ENUM_OBJECT_BELOW_CANDLE,2,m_nSelTimeFrame); }*/ ////////////////// int nAllBarCount = iBars(NULL,m_nSelTimeFrame); int nBarIntervalCount = 0 ; if(nAllBarCount < macd_slow + 1) return false; m_fMACD[0] = INVALID_VALUE; m_fMACD[1] = iMACD(NULL, m_nSelTimeFrame, macd_fast, macd_slow, macd_signal, PRICE_CLOSE, MODE_MAIN, 1); m_fMACD[2] = iMACD(NULL, m_nSelTimeFrame, macd_fast, macd_slow, macd_signal, PRICE_CLOSE, MODE_MAIN, 2); m_fMACD[3] = iMACD(NULL, m_nSelTimeFrame, macd_fast, macd_slow, macd_signal, PRICE_CLOSE, MODE_MAIN, 3); nMaxIndex = 2; if(m_fMACD[2] < INVALID_VALUE + 1) return false; if(m_fMACD[2] > 0 && trendDirection == ENUM_TREND_UNKNOWN ) { trendDirection = ENUM_TREND_BULLISH ; } else if(m_fMACD[2] < 0 && trendDirection == ENUM_TREND_UNKNOWN) { trendDirection = ENUM_TREND_BEARISH ; } /*&& && */ if(m_fMACD[2] > 0 && trendDirection == ENUM_TREND_BEARISH) { return false; } else if(m_fMACD[2] < 0 && trendDirection == ENUM_TREND_BULLISH) { return false; } if(m_fMACD[2] > 0) { bIsPositive = true; //Shadow not very important , body is more important // but not very tight , work with high /*if( iHigh(NULL,m_nSelTimeFrame,2) < iHigh(NULL,m_nSelTimeFrame,1)- 1*_Point) return false; if( iHigh(NULL,m_nSelTimeFrame,2) < iHigh(NULL,m_nSelTimeFrame,3)- 1*_Point) return false; */ //High Between Two Candle , Consecutive , not important bIsAccept_Analysing = false ; if(iHigh(NULL,m_nSelTimeFrame,3) <= iHigh(NULL,m_nSelTimeFrame,2) && iHigh(NULL,m_nSelTimeFrame,2) >= iHigh(NULL,m_nSelTimeFrame,1)) bIsAccept_Analysing = true ; /*if(iHigh(NULL,m_nSelTimeFrame,3) > iHigh(NULL,m_nSelTimeFrame,2) && iHigh(NULL,m_nSelTimeFrame,2) > iHigh(NULL,m_nSelTimeFrame,1)) return false; */ if( m_fMACD[3] <= m_fMACD[2] && m_fMACD[2] >= m_fMACD[1] && iHigh(NULL,m_nSelTimeFrame,2) >= iHigh(NULL,m_nSelTimeFrame,1) ) bIsAccept_Analysing = true ; if(!bIsAccept_Analysing) return false; /* Experience : make mistanke MACD lagging , next macd show influence of Previous Candle if( m_fMACD[3] > m_fMACD[2] && m_fMACD[2] > m_fMACD_Candle1 ) return false; */ //except macd prvprv peak } else if (m_fMACD[2] < 0) { bIsPositive = false; //باید حداقل مینیمم کندل پایین تر یا کوچکتر از کندل بعدی باشد. کندل بعدی بالاتر یا بزرگتر باز شود //next candle must open or low must greater or above /* if( iLow(NULL,m_nSelTimeFrame,2) > iLow(NULL,m_nSelTimeFrame,1) + 1 * _Point) //Shadow not very important , body is more important // but not very tight , work with high return false; if( iLow(NULL,m_nSelTimeFrame,2) > iLow(NULL,m_nSelTimeFrame,3) + 1 * _Point) //Shadow not very important , body is more important // but not very tight , work with high return false; */ //Low Between Two Candles , Trend bIsAccept_Analysing = false ; if(iLow(NULL,m_nSelTimeFrame,3) >= iLow(NULL,m_nSelTimeFrame,2) && iLow(NULL,m_nSelTimeFrame,2) <= iLow(NULL,m_nSelTimeFrame,1) ) bIsAccept_Analysing = true; /*if(iLow(NULL,m_nSelTimeFrame,3) < iLow(NULL,m_nSelTimeFrame,2) && iLow(NULL,m_nSelTimeFrame,2) < iLow(NULL,m_nSelTimeFrame,1) ) return false; */ if( MathAbs(m_fMACD[3]) <= MathAbs(m_fMACD[2]) && MathAbs(m_fMACD[2]) >= MathAbs(m_fMACD[1]) && iLow(NULL,m_nSelTimeFrame,2) <= iLow(NULL,m_nSelTimeFrame,1) ) bIsAccept_Analysing = true; /*if( MathAbs(m_fMACD[3]) > MathAbs(m_fMACD[2]) && MathAbs(m_fMACD[2]) > MathAbs(m_fMACD_Candle1) ) return false; */ if(!bIsAccept_Analysing) return false; } //Print ("EA_MACD_Div::Init " , bIsPositive ); m_fMACD_MinimumLevel = MathAbs(m_fMACD[2]); m_fMACD_MaximumLevel = MathAbs(m_fMACD[2]); for(int n=3; n < nCheckBarsMax ; n++) { nBarIntervalCount = Bars(NULL,m_nSelTimeFrame, iTime(NULL, m_nSelTimeFrame,nAllBarCount -1), iTime(NULL, m_nSelTimeFrame,n)); if(nBarIntervalCount < (macd_slow + 1)) break; fMACDVal = iMACD(NULL, m_nSelTimeFrame, macd_fast, macd_slow, macd_signal, PRICE_CLOSE, MODE_MAIN, n); if(bIsPositive) { if(fMACDVal > 0 || MathAbs(fMACDVal) < (MACD_THRESHOLD_RATIO_MAX * m_fMACD_MaximumLevel)) { m_fMACD[n] = fMACDVal; if(MathAbs(fMACDVal) > m_fMACD_MaximumLevel) { m_fMACD_MaximumLevel = MathAbs(fMACDVal); nMaxIndex = n; } if(MathAbs(fMACDVal) < m_fMACD_MinimumLevel) { m_fMACD_MinimumLevel = MathAbs(fMACDVal) ; } } else break; } else { if(fMACDVal < 0 || (fMACDVal > 0 && MathAbs(fMACDVal) < (MACD_THRESHOLD_RATIO_MAX * m_fMACD_MaximumLevel))) { m_fMACD[n] = fMACDVal; if(MathAbs(fMACDVal) > m_fMACD_MaximumLevel) { m_fMACD_MaximumLevel = MathAbs(fMACDVal); nMaxIndex = n; } if(MathAbs(fMACDVal) < m_fMACD_MinimumLevel) { m_fMACD_MinimumLevel = MathAbs(fMACDVal) ; } } else break; } } /////////////////////////////////// // MACD Levels are different in different TimeFrames , So I assume window size is 4 cm or 40 mm , so half of it is positive m_fMACD_Point = (m_fMACD_MaximumLevel / 2 ) / 40 ; //Print ("MACD_Div : Init , m_fMACD_Point : ", m_fMACD_Point , " m_fMACD_MaximumLevel " , m_fMACD_MaximumLevel); /* if(m_fMACD[2] > 0 && m_fMACD[2] < m_fMACD_Candle1-15*m_fMACD_Point && m_fMACD_Candle1 > INVALID_VALUE + 1) return false; //except macd prvprv peak if(m_fMACD[2] < 0 && MathAbs(m_fMACD[2]) < MathAbs(m_fMACD_Candle1)-15*m_fMACD_Point && m_fMACD_Candle1 > INVALID_VALUE + 1) return false; if(m_fMACD[2] > 0 && m_fMACD[2] < m_fMACD[3]-15*m_fMACD_Point) return false; //except macd prvprv peak if(m_fMACD[2] < 0 && MathAbs(m_fMACD[2]) < MathAbs(m_fMACD[3])-15*m_fMACD_Point ) return false; */ // DrawArrowCheckCandle(120,trendDirection == ENUM_TREND_BULLISH ? ENUM_OBJECT_ABOVE_CANDLE : ENUM_OBJECT_BELOW_CANDLE,2,m_nSelTimeFrame); //Print ("EA_MACD_Div::Init FindExtermums"); FindExtermums(); return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double EA_MACD_Div::GetMACD_Prv2() { double fMACD = iMACD(NULL, m_nSelTimeFrame, macd_fast, macd_slow, macd_signal, PRICE_CLOSE, MODE_MAIN, 2); return fMACD; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ ENUM_DIVERGENCE_CLASS EA_MACD_Div::Check(ENUM_WAVE_TREND trendDirection) { int LocalStart = 0 ; int nMaxIndex = 0, nMinIndex = 0; ENUM_DIVERGENCE_CLASS nDivergenceClass = ENUM_DIVERGENCE_NONE; bool isValid_Div_T1 = false; //Print ("MACD_DIv : Check " , trendDirection , " " , m_fMACD[2] , " " , m_nExtCount ); switch(trendDirection) { case ENUM_TREND_BULLISH : //search for Negative Divergence , Expect MACD positive , RSI Negative if(m_fMACD[2] < INVALID_VALUE + 1) { //if(IS_ENABLE_LOG) Print("DivCheck2 ENUM_TREND_BULLISH: Lower Time MACD inaccessible "); return ENUM_DIVERGENCE_NONE; } if(m_fMACD[2] < 0) { //if(IS_ENABLE_LOG) Print("DivCheck2 ENUM_TREND_BULLISH: m_fMACD[2] < 0 !important! : ", m_fMACD[2]); return ENUM_DIVERGENCE_NONE; } if(m_nExtCount == 0) return ENUM_DIVERGENCE_NONE; //Print ("MACD:Check Before If 1 "); if((m_extremums[0].IndicatorValue > m_fMACD[2])) //Search Negative Divergence , Negative is possible is first extremum { //Check Extremum is valid or not //Print ("DivCheck ENUM_TREND_BULLISH: First Valid Check : " ,m_extremums[0].ExtremumBar ," " , m_extremums[0].IndicatorWaveStartBar ," " ,m_extremums[0].IndicatorWaveEndBar ); isValid_Div_T1 = m_extremums[0].ExtremumBar > m_extremums[0].IndicatorWaveStartBar+1 && m_extremums[0].ExtremumBar < m_extremums[0].IndicatorWaveEndBar-1 ; if(isValid_Div_T1) //Maximum Bar is valid in this Extremum , { //So First Check Tak Maximum of this Extremum ( Possible Wave 3 ) for Div FillPriceTimeExtremum(0,trendDirection); //if(IS_ENABLE_LOG) Print("DivCheck : Second Valid Check : ",m_extremums[0].PriceBar," ", m_extremums[0].PriceValue," ",m_extremums[0].ExtremumTime); if(IsAllowCheck(ENUM_DIVERGENCE_NEGATIVE_T1) && IsExistAndDrawNegativeDiv(0,ENUM_DIVERGENCE_NEGATIVE_T1)) { return ENUM_DIVERGENCE_NEGATIVE_T1; } //No Elliot Principle search For Other Max in Window From Highest Wave 1 to Current Bar in Extremum 0 if(IsAllowCheck(ENUM_DIVERGENCE_NEGATIVE_T2)) { //Print ("ENUM_TREND_BULLISH:Check Before If 2 "); int extremumNewIndex = IsExistAndValidNearExtremum() ; if(extremumNewIndex > 0) { FillPriceTimeExtremum(extremumNewIndex,trendDirection); DrawExtermum(trendDirection,extremumNewIndex); //if(IS_ENABLE_LOG) Print("DivCheck2 : Find NearExtremum ", extremumNewIndex, "Time : ", m_extremums[extremumNewIndex].ExtremumTime); if(IsExistAndDrawNegativeDiv(extremumNewIndex,ENUM_DIVERGENCE_NEGATIVE_T2)) { return ENUM_DIVERGENCE_NEGATIVE_T2; } } } } //Now Analyse between Max Prv Wave Max with This if(IsAllowCheck(ENUM_DIVERGENCE_NONSTANDARD_NEGATIVE) && m_nExtCount > 1 && m_extremums[1].IndicatorWaveStartBar > m_extremums[0].IndicatorWaveEndBar) { if(IsExistAndDrawNegativeDiv(1,ENUM_DIVERGENCE_NONSTANDARD_NEGATIVE)) { return ENUM_DIVERGENCE_NONSTANDARD_NEGATIVE; } } } break; case ENUM_TREND_BEARISH : //search for Positive Divergence , Expect MACD negative if(m_fMACD[2] < INVALID_VALUE + 1) { //if(IS_ENABLE_LOG) Print("DivCheck2 ENUM_TREND_BEARISH : Lower Time MACD inaccessible "); return ENUM_DIVERGENCE_NONE; } if(m_fMACD[2] > 0) { //if(IS_ENABLE_LOG) Print("DivCheck2 ENUM_TREND_BEARISH : m_fMACD[2] > 0 !important! ", m_fMACD[2]); return ENUM_DIVERGENCE_NONE; } if(m_nExtCount == 0) return ENUM_DIVERGENCE_NONE; if((m_fMACD[2] < 0 && MathAbs(m_extremums[0].IndicatorValue) > MathAbs(m_fMACD[2]))) //Search Negative Divergence , Negative is possible is first extremum { //Check Extremum is valid or not //Print ("DivCheck ENUM_TREND_BEARISH: First Valid Check : " ,m_extremums[0].ExtremumBar ," " , m_extremums[0].IndicatorWaveStartBar ," " ,m_extremums[0].IndicatorWaveEndBar ); isValid_Div_T1 = m_extremums[0].ExtremumBar > m_extremums[0].IndicatorWaveStartBar+1 && m_extremums[0].ExtremumBar < m_extremums[0].IndicatorWaveEndBar-1 ; if(isValid_Div_T1) //Maximum Bar is valid in this Extremum , { //So First Check Tak Maximum of this Extremum ( Possible Wave 3 ) for Div FillPriceTimeExtremum(0,trendDirection); //if(IS_ENABLE_LOG) Print("DivCheck ENUM_TREND_BEARISH: Second Valid Check : ",m_extremums[0].PriceBar," ", m_extremums[0].PriceValue," ",m_extremums[0].ExtremumTime); if(IsAllowCheck(ENUM_DIVERGENCE_POSITIVE_T1) && IsExistAndDrawPositiveDiv(0,ENUM_DIVERGENCE_POSITIVE_T1)) { //Print ("EA_MACD_Div::Check Allow Check ENUM_DIVERGENCE_POSITIVE_T1 " ); return ENUM_DIVERGENCE_POSITIVE_T1; } //No Elliot Principle search For Other Max in Window From Highest Wave 1 to Current Bar in Extremum 0 if(IsAllowCheck(ENUM_DIVERGENCE_POSITIVE_T2)) { int extremumNewIndex = IsExistAndValidNearExtremum() ; if(extremumNewIndex > 0) { FillPriceTimeExtremum(extremumNewIndex,trendDirection); //DrawExtermum(trendDirection,extremumNewIndex); //if(IS_ENABLE_LOG) Print("DivCheck2 ENUM_TREND_BEARISH: Find NearExtremum ", extremumNewIndex, "Time : ", m_extremums[extremumNewIndex].ExtremumTime); if(IsExistAndDrawPositiveDiv(extremumNewIndex,ENUM_DIVERGENCE_POSITIVE_T2)) { return ENUM_DIVERGENCE_POSITIVE_T2; } } } } //Now Analyse between Max Prv Wave Max with This if(IsAllowCheck(ENUM_DIVERGENCE_NONSTANDARD_POSITIVE) && m_nExtCount > 1 && m_extremums[1].IndicatorWaveStartBar > m_extremums[0].IndicatorWaveEndBar) { if(IsExistAndDrawPositiveDiv(1,ENUM_DIVERGENCE_NONSTANDARD_POSITIVE)) { return ENUM_DIVERGENCE_NONSTANDARD_POSITIVE; } } } break; } //Print (" Check: CheckDivergenceExtention" ); nDivergenceClass = CheckDivergenceExtention(trendDirection) ; if(nDivergenceClass != ENUM_DIVERGENCE_NONE) return nDivergenceClass ; //Print (" Check: " , isValid_Div_T1 ); if(isValid_Div_T1) { nDivergenceClass = CheckDivergenceRSI(0,trendDirection) ; if(nDivergenceClass != ENUM_DIVERGENCE_NONE) return nDivergenceClass ; } return nDivergenceClass; } //+------------------------------------------------------------------+ //| Search For Local Extremum , Different Than | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int EA_MACD_Div::IsExistAndValidNearExtremum() { bool bIsLocalExtremum = false; for(int n=3 + Extremum_RightBarSize ; n <= m_extremums[0].ExtremumBar - Extremum_LeftBarSize ; n++) { bIsLocalExtremum = IsLocalExtremum(m_fMACD,Extremum_LeftBarSize,Extremum_RightBarSize,n); if(bIsLocalExtremum) // not = because last Max is better { //if(IS_ENABLE_LOG) Print("IsExistAndValidNearExtremum Find"); AddExtremum(m_fMACD[n],-1.f,n,-1,-1,m_extremums[0].IndicatorWaveStartBar,m_extremums[0].IndicatorWaveEndBar); return m_nExtCount-1; } } return -1; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool EA_MACD_Div::IsLocalExtremum(const double& arr[], int leftwin, int rightwin, int center) { for(int n=center-1; n MathAbs(arr[center])) return false; } for(int n=center+1; n MathAbs(arr[center])) return false; } return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool EA_MACD_Div::IsArrayMinimum(const double& arr[], int leftwin, int rightwin, int center) { for(int n=center+leftwin; n 0) { AddExtremum(fMaxVal,-1.f,nMaxBarIndex,-1,-1,nWaveStartBar, nWaveEndBar); //if(IS_ENABLE_LOG) Print("Wave End : MaxBar :" , nMaxBarIndex , " MaxValue " ,fMaxVal , " nWaStartBar : ",nWaveStartBar , " EndBar : ",nWaveEndBar , " Time " , iTime(NULL, m_nSelTimeFrame ,nWaveEndBar) ); nWaveStartBar = -1; } break ; } if(MathAbs(m_fMACD[n]) > fMaxVal) // not = because last Max is better { fMaxVal = MathAbs(m_fMACD[n]); nMaxBarIndex = n ; } if(((m_fMACD[2] > 0 && m_fMACD[n] < 0) || (m_fMACD[2] < 0 && m_fMACD[n] > 0)) && nWaveStartBar > 0 && n > nWaveStartBar) //One Wave Finished { nWaveEndBar = n-1 ; AddExtremum(fMaxVal,-1.f,nMaxBarIndex,-1,-1,nWaveStartBar, nWaveEndBar); //if(IS_ENABLE_LOG) Print("Wave Direct: MaBar :" , nMaxBarIndex , " MaxValue " ,fMaxVal , " StartBar : ",nWaveStartBar , " EndBar : ",nWaveEndBar , " Time " , iTime(NULL, m_nSelTimeFrame , nWaveEndBar)); nMaxBarIndex = -1; fMaxVal = 0.f; nWaveStartBar = -1; if(m_nExtCount>=2) // Maximum Two Consecutive MACD Wave is enough break; } else if(nWaveStartBar == -1 && ((m_fMACD[2] > 0 && m_fMACD[n] > 0) || (m_fMACD[2] < 0 && m_fMACD[n] < 0))) { nWaveStartBar = n; } } return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void EA_MACD_Div::FillPriceTimeExtremum(int nExtInd, ENUM_WAVE_TREND trendDirection) { int nExtremem_Period = Extremum_LeftBarSize+Extremum_RightBarSize+1 ; if(trendDirection == ENUM_TREND_BULLISH) { m_extremums[nExtInd].PriceBar = iHighest(NULL,m_nSelTimeFrame,MODE_HIGH,nExtremem_Period,m_extremums[nExtInd].ExtremumBar-Extremum_LeftBarSize-1); m_extremums[nExtInd].PriceValue = iHigh(NULL,m_nSelTimeFrame,m_extremums[nExtInd].PriceBar); m_extremums[nExtInd].ExtremumTime =iTime(NULL,m_nSelTimeFrame,m_extremums[nExtInd].PriceBar); } else if(trendDirection == ENUM_TREND_BEARISH) { m_extremums[nExtInd].PriceBar = iLowest(NULL,m_nSelTimeFrame,MODE_LOW,nExtremem_Period,m_extremums[nExtInd].ExtremumBar-Extremum_LeftBarSize-1); m_extremums[nExtInd].PriceValue = iLow(NULL,m_nSelTimeFrame,m_extremums[nExtInd].PriceBar); m_extremums[nExtInd].ExtremumTime =iTime(NULL,m_nSelTimeFrame,m_extremums[nExtInd].PriceBar); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool EA_MACD_Div::IsExistAndDrawNegativeDiv(int nExtIndex,ENUM_DIVERGENCE_CLASS divClass) { string objName; if(m_extremums[nExtIndex].IndicatorValue >= m_fMACD[2] && m_extremums[nExtIndex].PriceValue < iHigh(NULL,m_nSelTimeFrame,2) /* && (m_fMACD[2] > m_fMACD_Candle1 || m_fMACD_Candle1 < INVALID_VALUE + 1) */ ) //Negative Divergence { // Check RSI //Print ("IsExistAndDrawNegativeDiv RSI Value : ", m_bIsCheckRSI , " " ); if(m_bIsCheckRSI) { double fRSIExtremum = iRSI(NULL,m_nSelTimeFrame,14,PRICE_CLOSE,m_extremums[nExtIndex].ExtremumBar); //Print ("IsExistAndDrawNegativeDiv RSI Value : ", fRSIExtremum); if(fRSIExtremum < 78 ) return false; } // Find Max MACD beteen three last Candle int nMACDValueMaxIndex = 2 ; if(MathAbs(m_fMACD[1]) > MathAbs(m_fMACD[2]) && MathAbs(m_fMACD[1]) > MathAbs(m_fMACD[3])) nMACDValueMaxIndex = 1 ; if(MathAbs(m_fMACD[3]) > MathAbs(m_fMACD[2]) && MathAbs(m_fMACD[3]) > MathAbs(m_fMACD[1])) nMACDValueMaxIndex = 3 ; if(IsLocalExtremum(m_fMACD,Extremum_LeftBarSize,Extremum_RightBarSize,nMACDValueMaxIndex)) { //if(IS_ENABLE_LOG) Print("DivCheck2 : FindDivergence : ", EnumToString(divClass)," PriceBar :", m_extremums[nExtIndex].PriceBar, " ExtremumTime ", m_extremums[nExtIndex].ExtremumTime); if(IS_DRAW_DIVERGENCE) { objName = "Text"+IntegerToString(MathRand())+IntegerToString(MathRand()); if(!ObjectCreate(0,objName,OBJ_TEXT,0,iTime(NULL,m_nSelTimeFrame,m_extremums[nExtIndex].PriceBar),iHigh(NULL,m_nSelTimeFrame,m_extremums[nExtIndex].PriceBar)+20*_Point)) { Print(__FUNCTION__, ": failed to create \"OBJ_TEXT\" sign! Error code = ",GetLastError()); } //--- set anchor type ObjectSetString(0,objName,OBJPROP_TEXT,"X"); //--- set a sign color ObjectSetInteger(0,objName,OBJPROP_COLOR,clrYellow); //--- set the slope angle of the text ObjectSetDouble(0,objName,OBJPROP_ANGLE,-90.0); } return true; } } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool EA_MACD_Div::IsExistAndDrawPositiveDiv(int nExtIndex, ENUM_DIVERGENCE_CLASS divClass) { string objName; if(MathAbs(m_extremums[nExtIndex].IndicatorValue) >= MathAbs(m_fMACD[2]) && m_extremums[nExtIndex].PriceValue > iLow(NULL,m_nSelTimeFrame,2) /* && (MathAbs(m_fMACD[2]) >= MathAbs(m_fMACD_Candle1) || m_fMACD_Candle1 < INVALID_VALUE + 1)*/) //Positive Divergence { if(m_bIsCheckRSI) { double fRSIExtremum = iRSI(NULL,m_nSelTimeFrame,14,PRICE_CLOSE,m_extremums[nExtIndex].ExtremumBar); //Print ("IsExistAndDrawPositiveDiv RSI Value : ", fRSIExtremum); if(fRSIExtremum > 22 ) return false; } //if(IS_ENABLE_LOG) Print("DivCheck2 : FindDivergence : ", EnumToString(divClass)," PriceBar :", m_extremums[nExtIndex].PriceBar, " ExtremumTime ", m_extremums[nExtIndex].ExtremumTime); int nMACDValueMaxIndex = 2 ; if(MathAbs(m_fMACD[1]) > MathAbs(m_fMACD[2]) && MathAbs(m_fMACD[1]) > MathAbs(m_fMACD[3])) nMACDValueMaxIndex = 1 ; if(MathAbs(m_fMACD[3]) > MathAbs(m_fMACD[2]) && MathAbs(m_fMACD[3]) > MathAbs(m_fMACD[1])) nMACDValueMaxIndex = 3 ; if(IsLocalExtremum(m_fMACD,Extremum_LeftBarSize,Extremum_RightBarSize,nMACDValueMaxIndex)) { if(IS_DRAW_DIVERGENCE) { objName = "Text"+IntegerToString(MathRand())+IntegerToString(MathRand()); if(!ObjectCreate(0,objName,OBJ_TEXT,0,iTime(NULL,m_nSelTimeFrame,m_extremums[nExtIndex].PriceBar),iLow(NULL,m_nSelTimeFrame,m_extremums[nExtIndex].PriceBar)-20*_Point)) { Print(__FUNCTION__, ": failed to create \"OBJ_TEXT\" sign! Error code = ",GetLastError()); } //--- set anchor type ObjectSetString(0,objName,OBJPROP_TEXT,"X"); //--- set a sign color ObjectSetInteger(0,objName,OBJPROP_COLOR,clrYellow); //--- set the slope angle of the text ObjectSetDouble(0,objName,OBJPROP_ANGLE,-90.0); } return true; } } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double EA_MACD_Div::GetCandleValue(const double& arr[],int index) { if(m_fMACD[index] > INVALID_VALUE + 1) return MathAbs(m_fMACD[index]); //m_fHLCAMedian[index] = (High[index]+ Close[index] + Low[index]) / 3; //m_fHLCAMedian[index] = (High[index]+ Close[index] + Low[index]) / 3; return m_fMACD[index]; } //+------------------------------------------------------------------+ //| Decrease Increasing MACDs in Main FrameTime | //+------------------------------------------------------------------+ ENUM_DIVERGENCE_CLASS EA_MACD_Div::CheckDivergenceExtention(ENUM_WAVE_TREND trendDirection) { if(trendDirection == ENUM_TREND_BULLISH && !IsAllowCheck(ENUM_DIVERGENCE_NEGATIVE_EXT1)) return ENUM_DIVERGENCE_NONE; if(trendDirection == ENUM_TREND_BEARISH && !IsAllowCheck(ENUM_DIVERGENCE_POSITIVE_EXT1)) return ENUM_DIVERGENCE_NONE; double fMainMacd[4]; ENUM_DIVERGENCE_CLASS divClass = ENUM_DIVERGENCE_NONE; fMainMacd[1] = iMACD(NULL, 0, macd_fast, macd_slow, macd_signal, PRICE_CLOSE, MODE_MAIN, 1); fMainMacd[2] = iMACD(NULL, 0, macd_fast, macd_slow, macd_signal, PRICE_CLOSE, MODE_MAIN, 2); fMainMacd[3] = iMACD(NULL, 0, macd_fast, macd_slow, macd_signal, PRICE_CLOSE, MODE_MAIN, 3); double fObjPosition = 0.f; string objName; switch(trendDirection) { case ENUM_TREND_BULLISH : //search for Negative Divergence , Expect MACD positive if(fMainMacd[1] > 0 && fMainMacd[2] > 0 && fMainMacd[3] > 0 && fMainMacd[3] > fMainMacd[2] && fMainMacd[2] > fMainMacd[1] && High[1] > High[3]) // High Last Balatar az Before { divClass = ENUM_DIVERGENCE_NEGATIVE_EXT1; fObjPosition = High[1]+20*_Point; } break; case ENUM_TREND_BEARISH : if(fMainMacd[1] < 0 && fMainMacd[2] < 0 && fMainMacd[3] < 0 && MathAbs(fMainMacd[3]) > MathAbs(fMainMacd[2]) && MathAbs(fMainMacd[2]) > MathAbs(fMainMacd[1]) && Low[1] < Low[3]) // Low Last Payin tar az Before { divClass = ENUM_DIVERGENCE_POSITIVE_EXT1; fObjPosition = Low[1]-20*_Point; } break; } if(divClass != ENUM_DIVERGENCE_NONE) { //if(IS_ENABLE_LOG) Print("DivCheck2 : FindDivergence : ", EnumToString(divClass)," PriceBar :", 1, " ExtremumTime ",Time[2]); if(IS_DRAW_DIVERGENCE) { objName = "Text"+IntegerToString(MathRand())+IntegerToString(MathRand()); if(!ObjectCreate(0,objName,OBJ_TEXT,0,Time[2],fObjPosition)) { Print(__FUNCTION__, ": failed to create \"OBJ_TEXT\" sign! Error code = ",GetLastError()); } //--- set anchor type ObjectSetString(0,objName,OBJPROP_TEXT,"E1"); //--- set a sign color ObjectSetInteger(0,objName,OBJPROP_COLOR,clrYellow); //--- set the slope angle of the text ObjectSetDouble(0,objName,OBJPROP_ANGLE,-90.0); } } return divClass; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ ENUM_DIVERGENCE_CLASS EA_MACD_Div::CheckDivergenceRSI(int nExtIndex, ENUM_WAVE_TREND trendDirection) { if(trendDirection == ENUM_TREND_BULLISH && !IsAllowCheck(ENUM_DIVERGENCE_NEGATIVE_RSI_T1)) { //if(IS_ENABLE_LOG) Print("NotAllowed :" , m_nSelTimeFrame , " " , m_nAllowCheckTypes , " " , (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_RSI_T1) == 1 ); return ENUM_DIVERGENCE_NONE; } if(trendDirection == ENUM_TREND_BEARISH && !IsAllowCheck(ENUM_DIVERGENCE_POSITIVE_RSI_T1)) { //if(IS_ENABLE_LOG) Print("NotAllowed :" , m_nSelTimeFrame , " " , m_nAllowCheckTypes , " " , (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_RSI_T1) == 1 ); return ENUM_DIVERGENCE_NONE; } ENUM_DIVERGENCE_CLASS divClass = ENUM_DIVERGENCE_NONE; double fRSI_Prv = iRSI(NULL, 0, 14,PRICE_CLOSE, 2); double fRSI_Extremum = iRSI(NULL, 0, 14,PRICE_CLOSE, m_extremums[nExtIndex].PriceBar); //Print ("CheckDivergenceRSI : RSI_Prv : " , (int)fRSI_Prv , " fRSI_Extremum : " , (int)fRSI_Extremum , " PriceBar " , m_extremums[nExtIndex].PriceBar , " " , EnumToString(trendDirection) , " Extremum Price Value : " , m_extremums[nExtIndex].PriceValue , " LowOrHigh[2] : " , trendDirection == ENUM_TREND_BULLISH ? High[2] : Low[2] ); double fObjPosition = 0.f; string objName; switch(trendDirection) { case ENUM_TREND_BULLISH : //search for Negative Divergence , Expect MACD positive if(fRSI_Extremum >= fRSI_Prv && m_extremums[nExtIndex].PriceValue < High[2]) //Negative Divergence { divClass = ENUM_DIVERGENCE_NEGATIVE_RSI_T1; fObjPosition = High[2]+20*_Point; } break; case ENUM_TREND_BEARISH : if(fRSI_Extremum <= fRSI_Prv && m_extremums[nExtIndex].PriceValue > Low[2]) //Positive Divergence { divClass = ENUM_DIVERGENCE_POSITIVE_RSI_T1; fObjPosition = Low[2]-20*_Point; } break; } if(divClass != ENUM_DIVERGENCE_NONE) { //if(IS_ENABLE_LOG) Print("CheckDivergenceRSI : FindDivergence : ", EnumToString(divClass)," PriceBar :", m_extremums[nExtIndex].PriceValue, " ExtremumTime ",Time[2]); if(IS_DRAW_DIVERGENCE) { objName = "Text"+IntegerToString(MathRand())+IntegerToString(MathRand()); if(!ObjectCreate(0,objName,OBJ_TEXT,0,Time[2],fObjPosition)) { Print(__FUNCTION__, ": failed to create \"OBJ_TEXT\" sign! Error code = ",GetLastError()); } //--- set anchor type ObjectSetString(0,objName,OBJPROP_TEXT,"RS"); //--- set a sign color ObjectSetInteger(0,objName,OBJPROP_COLOR,clrYellow); //--- set the slope angle of the text ObjectSetDouble(0,objName,OBJPROP_ANGLE,-90.0); } } return divClass; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool EA_MACD_Div::IsAllowCheck(ENUM_DIVERGENCE_CLASS divClass) { //Print (" EA_MACD_Div::IsAllowCheck " , EnumToString(divClass), " " , divClass , " " , m_nAllowCheckTypes , " " , (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_T1)); switch(divClass) { case ENUM_DIVERGENCE_NEGATIVE_T1: case ENUM_DIVERGENCE_POSITIVE_T1: { //Print (" EA_MACD_Div::IsAllowCheck :" , (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_T1) != 0); return (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_T1) != 0 ; break; } case ENUM_DIVERGENCE_NEGATIVE_T2: case ENUM_DIVERGENCE_POSITIVE_T2: { //Print (" EA_MACD_Div::IsAllowCheck :" , (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_T2) != 0); return (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_T2) != 0; break; } case ENUM_DIVERGENCE_NEGATIVE_EXT1: case ENUM_DIVERGENCE_POSITIVE_EXT1: { //Print (" EA_MACD_Div::IsAllowCheck :" , (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_EXTENTION1) != 0 ); return (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_EXTENTION1) != 0; break; } case ENUM_DIVERGENCE_NONSTANDARD_NEGATIVE: case ENUM_DIVERGENCE_NONSTANDARD_POSITIVE: { //Print (" EA_MACD_Div::IsAllowCheck : " , (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_NONSTANDARD) != 0); return (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_NONSTANDARD) != 0; break; } case ENUM_DIVERGENCE_NEGATIVE_RSI_T1: case ENUM_DIVERGENCE_POSITIVE_RSI_T1: { //Print (" EA_MACD_Div::IsAllowCheck : " , (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_RSI_T1) != 0); return (m_nAllowCheckTypes & ENUM_ALLOW_DIVERGENCE_RSI_T1) != 0; break; } default : if(IS_ENABLE_LOG) Print("Not Detectable divClass "); break; } return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void EA_MACD_Div::DrawExtermum(ENUM_WAVE_TREND trendDirection,int nExtInd) { if(!IS_DRAW_TEXT) return ; string objName = "Text"+IntegerToString(MathRand())+IntegerToString(MathRand()); double fObjPosition = 0.f; switch(trendDirection) { case ENUM_TREND_BULLISH : //search for Negative Divergence , Expect MACD positive fObjPosition = iHigh(NULL,m_nSelTimeFrame,m_extremums[nExtInd].ExtremumBar) + 20 * _Point ; break; case ENUM_TREND_BEARISH : fObjPosition = iLow(NULL,m_nSelTimeFrame,m_extremums[nExtInd].ExtremumBar) - 20 * _Point ; break; } if(!ObjectCreate(0,objName,OBJ_TEXT,0,iTime(NULL,m_nSelTimeFrame,m_extremums[nExtInd].PriceBar),fObjPosition)) { Print(__FUNCTION__, ": failed to create \"OBJ_TEXT\" sign! Error code = ",GetLastError()); } //--- set anchor type ObjectSetString(0,objName,OBJPROP_TEXT,"X"); //--- set a sign color ObjectSetInteger(0,objName,OBJPROP_COLOR,clrYellow); //--- set the slope angle of the text ObjectSetDouble(0,objName,OBJPROP_ANGLE,-90.0); } ///////////////////study{ /* https://www.mql5.com/en/articles/3460 This article is good , mathmatical and serious . But : only continuous peaks are investigate I guess ? Are hamintor hast. https://www.mql5.com/en/articles/3686 use it accelerator of Bill Willimas , Profit Factor and Draw Down is very good , But : in chart it has problem Some wave not ertebat ba ham , but determine as devergence , I want to determine and Trend and pass it to this class , Also Candle Stick Patterns is first alarm . خودم فکر می کنم باید واگرایی در یک تایم پایین تر بررسی شود تجربه ترید خود این می گوید. نشان دهنده ضعف است که می تواند در تایم بالاتر بعدا ظاهر شود. Both have an Extremum function get one index and two count from left and right determine extermum is or not. also ArrayMinimum and ArrayMaximum that return highest and lowest in a range index about MACD oscillator IMPORTANT : IMPORTANT : One of the rules for determining the divergence using MACD is the following: the oscillator bars must not cross the zero level. The below screenshot shows that in this case divergence is not obvious, so chances of having a profitable trade are low. Unlike the previous indicators, this one generates fewer signals. But it is a trend indicator, and therefore it informs about global changes in the market. Despite all advantages, the market entry needs to be confirmed by the Price Action analysis or candlestick patterns. https://www.mql5.com/en/articles/5703 Classification of Divergence is good and necessary Using ADX Custom , really its chart is very good , check in different TimeFrame and Symbols and Profit Factor is good and Positive I think it is interesting , really investigate , the programming is weak but Deeply analyse and underestand of Indicators. اجنه می گویند حرف گوش کنم این را استفاده نمایم. فکر می کنم برنامه نویسی آن هم ساده هست کار سختی نیست. S1 : I must read this paper carefully. */ //+------------------------------------------------------------------+ /* بنظرم حالت اکستنشن یعنی اینکه کاهنده یا افزاینده باشد باید در تایم فریم خود اصلی بررسی شود نه پایین تر ببین می خواهم یک نقاط مناسب خروج پیدا کن اما الان فقط یک سری نقاط مناسب نوسانگیری دارد د دستم را می گیرد باید اگر مدیریت سرمایه اجازه داد در سود مناسبی بودم (این درست هست یا نه نمی دونم) اما مثلا پله ای در این نقطه بفروشم. بعد چنددرصد پایین تر دوباره سوار شوم این نوسانگیری هست ببین من در الیوت از مکد برای تعیین نقاط اکسترموم درجه امواج شناسایی امواج استفاده می کنم الان هم باید همینطور باشد مکد را بزنم نقاط ماکزیمم مینیمم در بیاورم بهینه سازی ابتدا بر روی کندل قبلی کار می کردم اما بنظرم اشتباه است باید کندل قبلی که بسته شد کندل قبلش مشخص باشد که یک اکسترمم هست یا نه هم از نظر اندیکاتور هم از نظر قیمتی برای همین بنظرم کلا سیستم را روی دو تا کندل قبل بردم درستش هم همین هستم واگرایی تاخیر دارد و روی دو تا کندل قبل مشخص می گردد نه فقط یکی */ //+------------------------------------------------------------------+