diff --git a/Classes/x-saherelm.x-poi.class.mq5 b/Classes/x-saherelm.x-poi.class.mq5 index 19097101..71cd35f9 100644 --- a/Classes/x-saherelm.x-poi.class.mq5 +++ b/Classes/x-saherelm.x-poi.class.mq5 @@ -1309,10 +1309,59 @@ class XCPOI : public XSCBaseAlert X_MOMENTUM_BAR_DETECTED, state // ); - OnMomentumBarDetected(pBar); - NotifyMomentumBarEventListeners(pBar); + OnMomentumBarDetected(cBar); + NotifyMomentumBarEventListeners(cBar); } + // + // Rejection Bars ... + int rejectionBarsCount = ArraySize(mRejectionBars); + int rejectionBarLoopBackBarIndex = RejectionBarLoopBack() + 1; + XOHCL iRBar; + bool isIRBarInited = iRBar.Init( + Symbol(), + Period(), + rejectionBarLoopBackBarIndex // + ); + if (isIRBarInited) + { + // + bool isRejectionBar = + iRBar.HasStrongLowShadow( + RejectionBarPercent(), + RejectionBarLoopBack(), + RejectionBarSharpRatio() // + ) || + iRBar.HasStrongHighShadow( + RejectionBarPercent(), + RejectionBarLoopBack(), + RejectionBarSharpRatio() // + ); + if (isRejectionBar) + { + // + AddRef( + iRBar, + mRejectionBars // + ); + rejectionBarsCount = ArraySize(mRejectionBars); + + // + DrawRejectionBars(); + + // + Add( + X_REJECTION_BAR_DETECTED, + state // + ); + OnRejectionBarDetected(iRBar); + NotifyRejectionBarEventListeners(iRBar); + } + } + + // + // ... + // mBarTracker.Waits(); @@ -1728,7 +1777,6 @@ class XCPOI : public XSCBaseAlert // bool canContinue = true; - int maxAllowedScanPrevBars = 2000; while (canContinue) { // @@ -1961,8 +2009,36 @@ class XCPOI : public XSCBaseAlert if (rejectionBarsCount < requiredPOIs) { // + bool isRejectionBar = + cBar.HasStrongLowShadow( + RejectionBarPercent(), + RejectionBarLoopBack(), + RejectionBarSharpRatio() // + ) || + cBar.HasStrongHighShadow( + RejectionBarPercent(), + RejectionBarLoopBack(), + RejectionBarSharpRatio() // + ); + + // + if (isRejectionBar) + { + // + AddRef( + cBar, + mRejectionBars // + ); + + // + rejectionBarsCount = ArraySize(mRejectionBars); + } } + // + // Detect Required Conditions for Loop ... + // + // bool isNeedMoreMarketSessions = (!IsValidSize(sessionsCount) ? true @@ -1976,7 +2052,9 @@ class XCPOI : public XSCBaseAlert swingHighsCount < requiredPOIs || swingLowsCount < requiredPOIs || // - momentumBarsCount < requiredPOIs + momentumBarsCount < requiredPOIs || + // + rejectionBarsCount < requiredPOIs // ; if (canContinue) @@ -1985,6 +2063,14 @@ class XCPOI : public XSCBaseAlert } } + // + int errorArr[]; + if (canContinue) + { + // + int t = errorArr[5]; + } + // // Complete Calculations ... @@ -2062,6 +2148,23 @@ class XCPOI : public XSCBaseAlert ); Clean(tmpBars); + // + // Reverse Rejection Bars ... + Copy( + mRejectionBars, + tmpBars // + ); + Clean(mRejectionBars); + ArrayReverse(tmpBars); + Copy( + tmpBars, + mRejectionBars // + ); + Clean(tmpBars); + + // + // ... + // Unlock(); DrawPOIs(); @@ -2335,7 +2438,39 @@ class XCPOI : public XSCBaseAlert void DrawRejectionBars() { // - // TODO: Implement Rejection Bars ... + bool allow = AllowDrawRejectionBars(); + if (!allow) + { + return; + } + + // + int count = ArraySize(mRejectionBars); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = mRejectionBars[i]; + + // + string iName = iBar.GetTag(ToString(X_POI_REJECTION_BAR)); + int iIDX = HasObject( + iName, + mRejectionBarObjects // + ); + if (IsValidIndex(iIDX)) + { + continue; + } + + // + CreateRejectionBarObject(iBar, iName); + } } /** @@ -3085,7 +3220,7 @@ class XCPOI : public XSCBaseAlert iObj.ToStyle(mSessions[sessionIDX].endStyle); // - mMarketSessionObjects.Add(iObj); + mMarketSessionObjects.Add(iObj); } // @@ -3297,6 +3432,69 @@ class XCPOI : public XSCBaseAlert CArrayObj mRejectionBarObjects; // Rejection Bar Chart Objects ... TXOHCLEventHandler mRejectionBarEventListeners[]; // Rejection Bars Event Listeners ... + /** + * Create an Object to Represent Rejection Bar on Chart ... + * + * @param bar: XOHCL instance ... + * @param name: String ... + */ + void CreateRejectionBarObject( + XOHCL &bar, + string name // + ) + { + // + if (!bar.IsValid() || + !IsValid(name)) + { + return; + } + + // + bool isBullish = bar.GetLowShadow() > bar.GetHighShadow(); + double price = + isBullish + ? bar.low + : bar.high; + char arrowCode = + isBullish + ? RejectionBarBullishArrowCode() + : RejectionBarBearishArrowCode(); + color clr = + isBullish + ? RejectionBarBullishColor() + : RejectionBarBearishColor(); + ENUM_ARROW_ANCHOR anchor = + isBullish + ? ANCHOR_TOP + : ANCHOR_BOTTOM; + + // + CChartObjectArrow *iObj; + iObj = new CChartObjectArrow(); + bool isCreated = iObj.Create( + ChartID(), + name, + Window(), + bar.time, + price, + arrowCode // + ); + if (!isCreated) + { + return; + } + + // + // Configure Object ... + iObj.Width(RejectionBarWidth()); + iObj.Color(clr); + iObj.Anchor(anchor); + + // + mRejectionBarObjects.Add(iObj); + } + // }; diff --git a/Experts/x-saherelm.x-121.smc.ea.mq5 b/Experts/x-saherelm.x-121.smc.ea.mq5 index ba025e17..7ab56f78 100644 --- a/Experts/x-saherelm.x-121.smc.ea.mq5 +++ b/Experts/x-saherelm.x-121.smc.ea.mq5 @@ -433,6 +433,7 @@ bool InitEA() eaPOI.EnableDrawPOIs(); eaPOI.AllowDrawSwingHighs(false); eaPOI.AllowDrawSwingLows(false); + eaPOI.AllowDrawMomentumBars(false); eaPOI.Init(); // // diff --git a/Libraries/x-saherelm.common.lib.mq5 b/Libraries/x-saherelm.common.lib.mq5 index 3d21b9f1..0dd9620f 100644 --- a/Libraries/x-saherelm.common.lib.mq5 +++ b/Libraries/x-saherelm.common.lib.mq5 @@ -1277,6 +1277,508 @@ struct XOHCL return result; } + // + bool HasStrongLowShadow( + double percent = 50, // Percent of Body + int __loopback = 2, + double _sharpRatio = 2.5 // + ) + { + // + bool result = false; + + // + result = IsValid() && Index() > 0; + if (!result) + { + return result; + } + + // + result = + (GetRange() * percent) / 100 <= GetLowShadow(); + if (!result) + { + return result; + } + + // + if (__loopback < 0) + { + __loopback = 2; + } + + // + if (_sharpRatio < 0) + { + _sharpRatio = 2.5; + } + + // + result = Index() > __loopback; + if (!result) + { + return result; + } + + // + // Get Highest High and Lowest Low in loopback Range ... + int startIndex = Index() - __loopback; + int endIndex = Index() + __loopback; + int requiredBars = MathAbs(endIndex - startIndex); + + // + // Highs ... + double highs[]; + int copiedHighs = CopyHigh( + symbol, + period, + startIndex, + requiredBars, + highs // + ); + + // + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + int highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + double highestHigh = highs[highestHighIDX]; + + // + // Lows ... + double lows[]; + int copiedLows = CopyLow( + symbol, + period, + startIndex, + requiredBars, + lows // + ); + + // + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + int lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + double lowestLow = lows[lowestLowIDX]; + + // + result = low == lowestLow && + highestHigh > high; + if (!result) + { + return result; + } + + // + // Try to Validate Sharp Ratio ... + + // + Clean(highs); + Clean(lows); + + // + // Left Side ... + startIndex = Index() + 1; + endIndex = startIndex + (__loopback / 2) - 1; + requiredBars = MathAbs(endIndex - startIndex); + + // + copiedHighs = CopyHigh( + symbol, + period, + startIndex, + requiredBars, + highs // + ); + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + highestHigh = highs[highestHighIDX]; + + // + copiedLows = CopyLow( + symbol, + period, + startIndex, + requiredBars, + lows // + ); + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + lowestLow = lows[lowestLowIDX]; + + // + double leftDiff = highestHigh - lowestLow; + + // + Clean(highs); + Clean(lows); + + // + // Right Side ... + startIndex = Index() - 1; + endIndex = startIndex - (__loopback / 2) + 1; + requiredBars = MathAbs(endIndex - startIndex); + + // + copiedHighs = CopyHigh( + symbol, + period, + startIndex, + requiredBars, + highs // + ); + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + highestHigh = highs[highestHighIDX]; + + // + copiedLows = CopyLow( + symbol, + period, + startIndex, + requiredBars, + lows // + ); + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + lowestLow = lows[lowestLowIDX]; + + // + double rightDiff = highestHigh - lowestLow; + double diff = MathMax(leftDiff, rightDiff); + result = GetLowShadow() >= (diff / 100) * _sharpRatio; + + // + return result; + } + + // + bool HasStrongHighShadow( + double percent = 50, // Percent of Body + int __loopback = 2, + double _sharpRatio = 2.5 // + ) + { + // + bool result = false; + + // + result = IsValid() && Index() > 0; + if (!result) + { + return result; + } + + // + result = + (GetRange() * percent) / 100 <= GetHighShadow(); + if (!result) + { + return result; + } + + // + if (__loopback < 0) + { + __loopback = 2; + } + + // + if (_sharpRatio < 0) + { + _sharpRatio = 2.5; + } + + // + result = Index() > __loopback; + if (!result) + { + return result; + } + + // + // Get Highest High and Lowest Low in loopback Range ... + int startIndex = Index() - __loopback; + int endIndex = Index() + __loopback; + int requiredBars = MathAbs(endIndex - startIndex); + + // + // Highs ... + double highs[]; + int copiedHighs = CopyHigh( + symbol, + period, + startIndex, + requiredBars, + highs // + ); + + // + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + int highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + double highestHigh = highs[highestHighIDX]; + + // + // Lows ... + double lows[]; + int copiedLows = CopyLow( + symbol, + period, + startIndex, + requiredBars, + lows // + ); + + // + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + int lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + double lowestLow = lows[lowestLowIDX]; + + // + result = high == highestHigh && + lowestLow < low; + if (!result) + { + return result; + } + + // + // Try to Validate Sharp Ratio ... + + // + Clean(highs); + Clean(lows); + + // + // Left Side ... + startIndex = Index() + 1; + endIndex = startIndex + (__loopback / 2) - 1; + requiredBars = MathAbs(endIndex - startIndex); + + // + copiedHighs = CopyHigh( + symbol, + period, + startIndex, + requiredBars, + highs // + ); + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + highestHigh = highs[highestHighIDX]; + + // + copiedLows = CopyLow( + symbol, + period, + startIndex, + requiredBars, + lows // + ); + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + lowestLow = lows[lowestLowIDX]; + + // + double leftDiff = highestHigh - lowestLow; + + // + Clean(highs); + Clean(lows); + + // + // Right Side ... + startIndex = Index() - 1; + endIndex = startIndex - (__loopback / 2) + 1; + requiredBars = MathAbs(endIndex - startIndex); + + // + copiedHighs = CopyHigh( + symbol, + period, + startIndex, + requiredBars, + highs // + ); + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + highestHigh = highs[highestHighIDX]; + + // + copiedLows = CopyLow( + symbol, + period, + startIndex, + requiredBars, + lows // + ); + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + lowestLow = lows[lowestLowIDX]; + + // + double rightDiff = highestHigh - lowestLow; + double diff = MathMax(leftDiff, rightDiff); + result = GetHighShadow() >= (diff / 100) * _sharpRatio; + + // + return result; + } + // bool IsStrongBullish( double percent = 50 // Percent of Body @@ -8038,7 +8540,8 @@ datetime GetUTCTime( int gmtOffset = TimeGMTOffset(); int offsetDelte = gmtOffset + cLocalOffset; int requiredUTCOffset = GetUTCRequiredTimeOffset(); - if (requiredUTCOffset > 0) { + if (requiredUTCOffset > 0) + { requiredUTCOffset = -1 * requiredUTCOffset; }