diff --git a/Classes/x-saherelm.x-poi.class.mq5 b/Classes/x-saherelm.x-poi.class.mq5 index 92745a0b..be134d9f 100644 --- a/Classes/x-saherelm.x-poi.class.mq5 +++ b/Classes/x-saherelm.x-poi.class.mq5 @@ -573,15 +573,15 @@ class XCPOIDetector : public XCBaseAlert // // Swings ... - int swingRange = SwingRange(); - if (swingRange > 0) + int iSwingRange = SwingRange(); + if (iSwingRange > 0) { // XOHCL swingBar; isInited = swingBar.Init( symbol, period, - zIndex + swingRange // + zIndex + iSwingRange // ); if (isInited) { @@ -2453,8 +2453,8 @@ class XCPOIDetector : public XCBaseAlert { // // Swings ... - int swingRange = SwingRange(); - if (swingRange > 0) + int iSwingRange = SwingRange(); + if (iSwingRange > 0) { // // Swing Highs ... @@ -2610,11 +2610,11 @@ class XCPOIDetector : public XCBaseAlert // // Swings ... bool canContinueSwingHighs = - swingRange > 0 + iSwingRange > 0 ? swingHighsCount < requiredPOIs : false; bool canContinueSwingLows = - swingRange > 0 + iSwingRange > 0 ? swingLowsCount < requiredPOIs : false; diff --git a/Classes/x-saherelm.x-poi.drawer.class.mq5 b/Classes/x-saherelm.x-poi.drawer.class.mq5 index f0b0cb65..6d76f2ef 100644 --- a/Classes/x-saherelm.x-poi.drawer.class.mq5 +++ b/Classes/x-saherelm.x-poi.drawer.class.mq5 @@ -2793,8 +2793,8 @@ class XCPOIDrawer : public XCBase int width = BarWidth(); // - color bullishColor = BarBullishColor(); - color bearishColor = BarBearishColor(); + color mBullishColor = BarBullishColor(); + color mBearishColor = BarBearishColor(); // bool fillBody = BarFillBody(); @@ -2835,16 +2835,16 @@ class XCPOIDrawer : public XCBase if (isBullish) { // - object.BodyColor(bullishColor); - object.LowShadowColor(bullishColor); - object.HighShadowColor(bullishColor); + object.BodyColor(mBullishColor); + object.LowShadowColor(mBullishColor); + object.HighShadowColor(mBullishColor); } else { // - object.BodyColor(bearishColor); - object.LowShadowColor(bearishColor); - object.HighShadowColor(bearishColor); + object.BodyColor(mBearishColor); + object.LowShadowColor(mBearishColor); + object.HighShadowColor(mBearishColor); } // diff --git a/Documents/BKP/1/1.coes.mq5 b/Documents/BKP/1/1.coes.mq5 index 55c74e19..a662e6f8 100644 --- a/Documents/BKP/1/1.coes.mq5 +++ b/Documents/BKP/1/1.coes.mq5 @@ -492,3 +492,1045 @@ //////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Detect Order Blocks Breaker Bar ... + * + * @param breakerBar: XOHCL instance Reference ... + * + * @return ( bool ) + */ + bool DetectBreakerBar(XOHCL &breakerBar) + { + // + bool result = false; + + // + breakerBar.Clean(); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL fromBar; + result = FillBar(fromBar); + if (!result) + { + return result; + } + + // + int fromIndex = fromBar.Index(); + result = fromIndex > 0; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(); + ENUM_X_DIRECTION dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + double value = + isBullish + ? Upper() + : Lower(); + + // + for (int i = fromIndex - 1; i >= 0; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + fromBar.symbol, + fromBar.period, + i // + ); + if (!isInited) + { + continue; + } + + // + isInited = IsBarBreak( + value, + dir, + iBar // + ); + if (isInited) + { + // + breakerBar = iBar; + break; + } + } + + // + result = breakerBar.IsValid(); + + // + return result; + } + + /** + * Check Order Block is Hunted or not ... + * + * @param huntedBar: XOHCL instance Reference ... + * + * @return ( bool ) + */ + bool IsHunted(XOHCL &huntedBar) + { + // + bool result = false; + + // + huntedBar.Clean(); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL breakerBar; + result = DetectBreakerBar(breakerBar); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(); + + // + int breakerIndex = breakerBar.Index(); + for (int i = breakerIndex - 1; i >= 0; i--) + { + // + XOHCL iBar; + result = iBar.Init( + breakerBar.symbol, + breakerBar.period, + i // + ); + + // + double price = + isBullish + ? iBar.low + : iBar.high; + + // + result = IsPriceInsideZone( + price, + Upper(), + Lower() // + ); + if (result) + { + // + huntedBar = iBar; + break; + } + } + + // + result = huntedBar.IsValid(); + + // + return result; + } + + /** + * Check Order Block Validation ... + * + * @return ( bool ) + */ + bool IsValidOrderBlock() + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL breakerBar; + result = DetectBreakerBar(breakerBar); + if (!result) + { + return result; + } + int breakerBarIndex = breakerBar.Index(); + + // + XOHCL huntedBar; + bool isHunted = IsHunted(huntedBar); + result = !isHunted; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(); + + // + for (int i = breakerBarIndex - 1; i >= 0; i--) + { + // + XOHCL iBar; + result = iBar.Init( + breakerBar.symbol, + breakerBar.period, + i // + ); + if (!result) + { + continue; + } + + // + double price = + isBullish + ? iBar.low + : iBar.high; + + // + result = + isBullish + ? price > Upper() + : price < Lower(); + if (!result) + { + return result; + } + } + + // + return result; + } + + +//////////////////////////////////////////////////////////////////////////////////////////// + + // XCOrderBlock *tmp[]; + // Copy( + // mBullishOrderBlocks, + // tmp // + // ); + + // // + // for (int i = 0; i <= bullOBsCount; i++) + // { + // // + // XCOrderBlock *iOB = tmp[i]; + + // // + // // Validate ... + // bool isValid = iOB.IsValid(); + // if (!isValid) + // { + // // + // ArrayRemove( + // mBullishOrderBlocks, + // i, + // 1 // + // ); + // } + // } + +///////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Test Market for Detect Order Block FVG ... + * + * @param forDir: Direction + * @param bullishOrderBlocks: Detected Bullish Order Blocks ... + * @param bearishOrderBlocks: Detected Bearish Order Blocks ... + * @param orderBlockState: Order Block Detection POIState ... + * @param fairValueGapState: Fair Value Gap Detection POIState ... + * @param barIndex: Bar Index ... + * + * @return ( bool ) + */ +bool DetectFVGOB( + ENUM_X_DIRECTION &forDir, // Test For Specified Direction ... + XFVGOrderBlock &bullishOrderBlocks[], // Bullish Order Blocks ... + XFVGOrderBlock &bearishOrderBlocks[], // Bearish Order Blocks ... + XPOIState &orderBlockState, // Order Block Detection TF POI(s) ... + XPOIState &fairValueGapState, // Fair Value Gap Detection TF POI(s) ... + int barIndex = 0 // Bar Index ... +) +{ + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + forDir = X_DIRECTION_NONE; + + // + // Validate Args ... + result = + orderBlockState.HasChild() && + fairValueGapState.HasChild(); + if (!result) + { + return result; + } + + // + string symbol = orderBlockState.symbol; + ENUM_TIMEFRAMES period = orderBlockState.period; + + // + // Retrieve Bars ... + XOHCL triggerCBar; + result = triggerCBar.Init( + symbol, + period, + barIndex // + ); + + // + // Select Order Blocks Which Has Big Changes ... + int count = 0; + datetime cTime = TimeCurrent(); + + // + XOHCL jBar; + result = jBar.Init( + fairValueGapState.symbol, + fairValueGapState.period, + barIndex // + ); + if (!result) + { + return result; + } + double jBarLL = jBar.FindLowest(3, MODE_LOW); + double jBarHH = jBar.FindHighest(3, MODE_HIGH); + + // + // Bullish ... + int bullishOrderBlocksCount = orderBlockState.CountBullishOrderBlocks(); + count = bullishOrderBlocksCount; + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCFVG *iFVG = NULL; + XStateZones iStateZones; + XCOrderBlock *iOb = orderBlockState.bullishOrderBlocks[i]; + iOb.To(cTime); + + // + // Find Exit Bar of Bullish OrderBlock Upper ... + XOHCL breakerBar; + bool hasBreakerBar = iOb.DetectBreakerBar(breakerBar); + if (!hasBreakerBar) + { + continue; + } + + // + // Detect Order Block is Hunted Or Not ... + XOHCL huntedBar; + bool isHunted = iOb.IsHunted(huntedBar); + if (isHunted) + { + continue; + } + + // + // Check Validation of Order Block ... + bool isValid = iOb.IsValidOrderBlock(); + if (!isValid) + { + continue; + } + + // + // Check Order Block Has Fair Value Gap ... + int fvgsCount = fairValueGapState.CountBullishFairValueGaps(); + bool hasFVG = IsValidSize(fvgsCount); + if (!hasFVG) + { + continue; + } + + // + // Detect an FVG for Order Block ... + for (int j = fvgsCount - 1; j >= 0; j--) + { + // + XCFVG *jFVG = fairValueGapState.bullishFairValueGaps[j]; + + // + bool isValid = + // + jFVG.IsBullish() && + jBarLL > jFVG.Upper() && + jBar.low > jFVG.Upper() && + jFVG.From() >= iOb.From() && + ((jFVG.Upper() > iOb.Upper() && + jFVG.Lower() <= iOb.Upper()) || + (jFVG.Upper() <= iOb.Upper() && + jFVG.Lower() >= iOb.Lower())) + // + ; + if (isValid) + { + // + jFVG.To(cTime); + iFVG = jFVG; + break; + } + } + + // + hasFVG = iFVG != NULL; + result = hasFVG; + if (!result) + { + continue; + } + + // // + // double upper = MathMax(iOb.Upper(), iFVG.Upper()); + // double lower = MathMin(iOb.Lower(), iFVG.Lower()); + // datetime from = iFVG.From(); + + // // + // // Detect Price Zones ... + // // Based On Decision State ... + // bool hasStateZones = CalculateStateZones( + // iStateZones, + // decisionState, + // upper, + // lower, + // from // + // ); + // result = hasStateZones; + // if (!result) + // { + // continue; + // } + + // + XFVGOrderBlock iModel; + iModel.orderBlock = iOb; + iModel.fairValueGap = iFVG; + // iModel.stateZones = iStateZones; + + // + AddRef( + iModel, + bullishOrderBlocks // + ); + } + } + + // + // Bearish ... + int bearishOrderBlocksCount = orderBlockState.CountBearishOrderBlocks(); + count = bearishOrderBlocksCount; + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCFVG *iFVG = NULL; + XStateZones iStateZones; + XCOrderBlock *iOb = orderBlockState.bearishOrderBlocks[i]; + iOb.To(cTime); + + // + // Find Exit Bar of Bullish OrderBlock Upper ... + XOHCL breakerBar; + bool hasBreakerBar = iOb.DetectBreakerBar(breakerBar); + if (!hasBreakerBar) + { + continue; + } + + // + // Detect Order Block is Hunted Or Not ... + XOHCL huntedBar; + bool isHunted = iOb.IsHunted(huntedBar); + if (isHunted) + { + continue; + } + + // + // Check Validation of Order Block ... + bool isValid = iOb.IsValidOrderBlock(); + if (!isValid) + { + continue; + } + + // + // Check Order Block Has Fair Value Gap ... + int fvgsCount = fairValueGapState.CountBearishFairValueGaps(); + bool hasFVG = IsValidSize(fvgsCount); + if (!hasFVG) + { + continue; + } + + // + // Detect an FVG for Order Block ... + for (int j = fvgsCount - 1; j >= 0; j--) + { + // + XCFVG *jFVG = fairValueGapState.bearishFairValueGaps[j]; + + // + bool isValid = + // + jFVG.IsBearish() && + jBarHH < jFVG.Lower() && + jBar.high < jFVG.Lower() && + jFVG.From() >= iOb.From() && + ((jFVG.Upper() > iOb.Lower() && + jFVG.Lower() <= iOb.Lower()) || + (jFVG.Upper() <= iOb.Upper() && + jFVG.Lower() >= iOb.Lower())) + // + ; + if (isValid) + { + // + jFVG.To(cTime); + iFVG = jFVG; + break; + } + } + + // + hasFVG = iFVG != NULL; + result = hasFVG; + if (!result) + { + continue; + } + + // + double upper = MathMax(iOb.Upper(), iFVG.Upper()); + double lower = MathMin(iOb.Lower(), iFVG.Lower()); + datetime from = iFVG.From(); + + // // + // // Detect Price Zones ... + // // Based On Decision State ... + // bool hasStateZones = CalculateStateZones( + // iStateZones, + // decisionState, + // upper, + // lower, + // from // + // ); + // result = hasStateZones; + // if (!result) + // { + // continue; + // } + + // + XFVGOrderBlock iModel; + iModel.orderBlock = iOb; + iModel.fairValueGap = iFVG; + // iModel.stateZones = iStateZones; + + // + AddRef( + iModel, + bearishOrderBlocks // + ); + } + } + + // + // Check Order Blocks ... + bullishOrderBlocksCount = ArraySize(bullishOrderBlocks); + bool hasBullishOrderBlocks = IsValidSize(bullishOrderBlocksCount); + + // + // Check Order Blocks ... + bearishOrderBlocksCount = ArraySize(bearishOrderBlocks); + bool hasBearishOrderBlocks = IsValidSize(bearishOrderBlocksCount); + + // + result = + // + hasBullishOrderBlocks || + hasBearishOrderBlocks + // + ; + if (!result) + { + return result; + } + + // + bool isBullish = hasBullishOrderBlocks && !hasBearishOrderBlocks; + bool isBearish = hasBearishOrderBlocks && !hasBullishOrderBlocks; + + // + forDir = + isBullish + ? X_DIRECTION_BULLISH + : isBearish + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + + // + result = forDir != X_DIRECTION_NONE; + if (!result) + { + return result; + } + + // + return result; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Handle POI Recieved ... + * + * @param event: ENUM_XPOI_EVENTS member ... + */ +// void OnPOIEvent( +// ENUM_XPOI_EVENTS event, +// XCBasePOI *param // +// ) +// { +// // +// Print("POI Recieved: " + ToString(event)); + +// // +// if (param == NULL) +// { +// return; +// } + +// switch (event) +// { +// // +// // Bullish Order Block ... +// case X_BULLISH_ORDERBLOCK_DETECTED: { +// // +// XCOrderBlock *ob = (XCOrderBlock *)param; +// Add( +// ob, +// mBullishOrderBlocks // +// ); +// break; +// } + +// // +// // Bearish Order Block ... +// case X_BEARISH_ORDERBLOCK_DETECTED: { +// // +// XCOrderBlock *ob = (XCOrderBlock *)param; +// Add( +// ob, +// mBearishOrderBlocks // +// ); +// break; +// } + +// // +// // Bullish Fair Value Gap ... +// case X_BULLISH_FVG_DETECTED: { +// // +// XCFVG *fvg = (XCFVG *)param; +// Add( +// fvg, +// mBullishFairValueGaps // +// ); +// break; +// } + +// // +// // Bearish Fair Value Gap ... +// case X_BEARISH_FVG_DETECTED: { +// // +// XCFVG *fvg = (XCFVG *)param; +// Add( +// fvg, +// mBearishFairValueGaps // +// ); +// break; +// } + +// // +// // Support Zone ... +// case X_SUPPORT_ZONE_DETECTED: { +// // +// XCSupportZone *zone = (XCSupportZone *)param; +// Add( +// zone, +// mSupportZones // +// ); +// break; +// } + +// // +// // Resistance Zone ... +// case X_RESISTANCE_ZONE_DETECTED: { +// // +// XCResistanceZone *zone = (XCResistanceZone *)param; +// Add( +// zone, +// mResistanceZones // +// ); +// break; +// } + +// // +// // Supply Zone ... +// case X_SUPPLY_ZONE_DETECTED: { +// // +// XCSupplyZone *zone = (XCSupplyZone *)param; +// Add( +// zone, +// mSupplyZones // +// ); +// break; +// } + +// // +// // Demand Zone ... +// case X_DEMAND_ZONE_DETECTED: { +// // +// XCDemandZone *zone = (XCDemandZone *)param; +// Add( +// zone, +// mDemandZones // +// ); +// break; +// } + +// // +// } +// } + +///////////////////////////////////////////////////////////////////////////////////////////////////// + + + // else + // { + // // + // mPOIDetector.GetState(state); + // bool isStateValid = state.IsValid() && + // state.HasChild(); + // if (isStateValid) + // { + // // + // // Order Blocks ... + + // // + // // Bullish ... + // int bullishOBsCount = state.CountBullishOrderBlocks(); + // bool hasBullishOBs = IsValidSize(bullishOBsCount); + // if (hasBullishOBs && + // !IsValidSize(ArraySize(mBullishOrderBlocks))) + // { + // // + // for (int i = 0; i < bullishOBsCount; i++) + // { + // // + // Add( + // state.bullishOrderBlocks[i], + // mBullishOrderBlocks // + // ); + // } + // } + + // // + // // Bearish ... + // int bearishOBsCount = state.CountBearishOrderBlocks(); + // bool hasBearishOBs = IsValidSize(bearishOBsCount); + // if (hasBearishOBs && + // !IsValidSize(ArraySize(mBearishOrderBlocks))) + // { + // // + // for (int i = 0; i < bearishOBsCount; i++) + // { + // // + // Add( + // state.bearishOrderBlocks[i], + // mBearishOrderBlocks // + // ); + // } + // } + + // // + // // Fair Value Gaps ... + + // // + // // Bullish ... + // int bullishFVGsCount = state.CountBullishFairValueGaps(); + // bool hasBullishFVGs = IsValidSize(bullishFVGsCount); + // if (hasBullishFVGs && + // !IsValidSize(ArraySize(mBullishFairValueGaps))) + // { + // // + // for (int i = 0; i < bullishFVGsCount; i++) + // { + // // + // Add( + // state.bullishFairValueGaps[i], + // mBullishFairValueGaps // + // ); + // } + // } + + // // + // // Bearish ... + // int bearishFVGsCount = state.CountBearishFairValueGaps(); + // bool hasBearishFVGs = IsValidSize(bearishFVGsCount); + // if (hasBearishFVGs && + // !IsValidSize(ArraySize(mBearishFairValueGaps))) + // { + // // + // for (int i = 0; i < bearishFVGsCount; i++) + // { + // // + // Add( + // state.bearishFairValueGaps[i], + // mBearishFairValueGaps // + // ); + // } + // } + + // // + // // Support and Resistance ... + + // // + // // Support ... + // int supportZonesCount = state.CountSupportZones(); + // bool hasSupportZones = IsValidSize(supportZonesCount); + // if (hasSupportZones && + // !IsValidSize(ArraySize(mSupportZones))) + // { + // // + // for (int i = 0; i < supportZonesCount; i++) + // { + // // + // Add( + // state.supportZones[i], + // mSupportZones // + // ); + // } + // } + + // // + // // Resistance ... + // int resistanceZonesCount = state.CountResistanceZones(); + // bool hasResistanceZones = IsValidSize(resistanceZonesCount); + // if (hasResistanceZones && + // !IsValidSize(ArraySize(mResistanceZones))) + // { + // // + // for (int i = 0; i < resistanceZonesCount; i++) + // { + // // + // Add( + // state.resistanceZones[i], + // mResistanceZones // + // ); + // } + // } + + // // + // // Supply and Demand ... + + // // + // // Supply ... + // int supplyZonesCount = state.CountSupplyZones(); + // bool hasSupplyZones = IsValidSize(supplyZonesCount); + // if (hasSupplyZones && + // !IsValidSize(ArraySize(mSupplyZones))) + // { + // // + // for (int i = 0; i < supplyZonesCount; i++) + // { + // // + // Add( + // state.supplyZones[i], + // mSupplyZones // + // ); + // } + // } + + // // + // // Demand ... + // int demandZonesCount = state.CountDemandZones(); + // bool hasDemandZones = IsValidSize(demandZonesCount); + // if (hasDemandZones && + // !IsValidSize(ArraySize(mDemandZones))) + // { + // // + // for (int i = 0; i < demandZonesCount; i++) + // { + // // + // Add( + // state.demandZones[i], + // mDemandZones // + // ); + // } + // } + + // // + // // + // // + + // // + // // Swings ... + + // // + // // Low ... + // int swingLowsCount = state.CountSwingLows(); + // bool hasSwingLows = IsValidSize(swingLowsCount); + // if (hasSwingLows && + // !IsValidSize(ArraySize(mSwingLows))) + // { + // // + // for (int i = 0; i < swingLowsCount; i++) + // { + // // + // Add( + // state.swingLows[i], + // mSwingLows // + // ); + // } + // } + + // // + // // Highs... + // int swingHighsCount = state.CountSwingHighs(); + // bool hasSwingHighs = IsValidSize(swingHighsCount); + // if (hasSwingHighs && + // !IsValidSize(ArraySize(mSwingHighs))) + // { + // // + // for (int i = 0; i < swingHighsCount; i++) + // { + // // + // Add( + // state.swingHighs[i], + // mSwingHighs // + // ); + // } + // } + + // // + // // Momentum Bars ... + + // // + // // Bullish ... + // int bullishMomentumBarsCount = state.CountBullishMomentumBars(); + // bool hasBullishMomentumBars = IsValidSize(bullishMomentumBarsCount); + // if (hasBullishMomentumBars && + // !IsValidSize(ArraySize(mBullishMomentumBars))) + // { + // // + // for (int i = 0; i < bullishMomentumBarsCount; i++) + // { + // // + // Add( + // state.bullishMomentumBars[i], + // mBullishMomentumBars // + // ); + // } + // } + + // // + // // Bearish ... + // int bearishMomentumBarsCount = state.CountBearishMomentumBars(); + // bool hasBearishMomentumBars = IsValidSize(bearishMomentumBarsCount); + // if (hasBearishMomentumBars && + // !IsValidSize(ArraySize(mBearishMomentumBars))) + // { + // // + // for (int i = 0; i < bearishMomentumBarsCount; i++) + // { + // // + // Add( + // state.bearishMomentumBars[i], + // mBearishMomentumBars // + // ); + // } + // } + + // // + // // Rejection Bars ... + + // // + // // Bullish ... + // int bullishRejectionBarsCount = state.CountBullishRejectionBars(); + // bool hasBullishRejectionBars = IsValidSize(bullishRejectionBarsCount); + // if (hasBullishRejectionBars && + // !IsValidSize(ArraySize(mBullishRejectionBars))) + // { + // // + // for (int i = 0; i < bullishRejectionBarsCount; i++) + // { + // // + // Add( + // state.bullishRejectionBars[i], + // mBullishRejectionBars // + // ); + // } + // } + + // // + // // Bearish ... + // int bearishRejectionBarsCount = state.CountBearishRejectionBars(); + // bool hasBearishRejectionBars = IsValidSize(bearishRejectionBarsCount); + // if (hasBearishRejectionBars && + // !IsValidSize(ArraySize(mBearishRejectionBars))) + // { + // // + // for (int i = 0; i < bearishRejectionBarsCount; i++) + // { + // // + // Add( + // state.bearishRejectionBars[i], + // mBearishRejectionBars // + // ); + // } + // } + + // // + // } + // } + diff --git a/Documents/BKP/1/x-saherelm.x121.xpoi.mq5 b/Documents/BKP/1/x-saherelm.x121.xpoi.mq5 new file mode 100644 index 00000000..375c4df8 --- /dev/null +++ b/Documents/BKP/1/x-saherelm.x121.xpoi.mq5 @@ -0,0 +1,2063 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121 XPOI +// Description: XPOI ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XPOI Indicator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121 XPOI" + +// +// Includes Common Library ... +#include "../Classes/x-saherelm.x-poi.class.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Libraries/x-saherelm.draw.lib.mq5" + +// +// Inputs ... + +// +// Market ... +input group "Market"; +input int maxNumberOfPOIs = 50; // Max Number Of Holding POI(s) +input int maxNumberOfRequiredPOIs = 50; // Max Number of Required POI(s) +input int swingRange = 7; // Swing Detection Range +input int orderBlocksSameBars = 3; // Order Block Same Bars +input int ticksRangeZoneLevel = 10; // Number of Ticks Zone's Levels +input int ticksRangeZoneRange = 144; // Lenght of Tick Zones Calculation +input int fairValueGapsSameBars = 3; // Fair Value Gaps Same Bars +input int momentumBarExtendRange = 2; // Momentum Bars Extends Range +input int supplyAndDemandRange = 144; // Supply and Demand Range +input int rejectionBarExtendRange = 2; // Rejection Bars Extends Range +input int supportAndResistanceRange = 7; // Support and Resistance Range +input double momentumBarBodyPercent = 70; // Momentum Bars Body Range +input double rejectionBarShadowPercent = 70; // Rejection Bars Body Range + +// +// Presentation ... +input group "Presentation"; + +// +input int startCalculationForLastBars = 2000; // Calculate Last n Bars + +// +input int swingLowsArrowCode = 159; // Swing Lows Arrow Code +input int swingHighsArrowCode = 159; // Swing Highs Arrow Code +input int bullishMomentumBarsArrowCode = 233; // Bullish Momentum Bars Arrow Code +input int bearishMomentumBarsArrowCode = 234; // Bearish Momentum Bars Arrow Code +input int bullishRejectionBarsArrowCode = 241; // Bullish Rejection Bars Arrow Code +input int bearishRejectionBarsArrowCode = 242; // Bearish Rejection Bars Arrow Code + +// +input color bullishColor = clrAqua; // Bullish Color +input color bearishColor = clrMagenta; // Bearish Color + +// +input ENUM_LINE_STYLE orderBlockStyle = STYLE_SOLID; // Order Block Style +input ENUM_LINE_STYLE fairValueGapStyle = STYLE_DASH; // Fair Value Gap Style +input ENUM_LINE_STYLE supResStyle = STYLE_DASHDOT; // Support and Resistance Style +input ENUM_LINE_STYLE supDemStyle = STYLE_DASHDOTDOT; // Supply and Demand Style + +// +input bool drawSwingLows = false; // Draw Swing Lows +input bool drawSwingHighs = false; // Draw Swing Highs +input bool drawSupplyZones = false; // Draw Supply Zones +input bool drawDemandZones = false; // Draw Demand Zones +input bool drawSupportZones = false; // Draw Support Zones +input bool drawResistanceZones = false; // Draw Resistance Zones +input bool drawBullishOrderBlocks = true; // Draw Bullish Order Blocks +input bool drawBearishOrderBlocks = true; // Draw Bearish Order Blocks +input bool drawBullishFairValueGaps = true; // Draw Bullish Fair Vlue Gaps +input bool drawBearishFairValueGaps = true; // Draw Bearish Fair Vlue Gaps +input bool drawBullishMomentumBars = true; // Draw Bullish Momentum Bars +input bool drawBearishMomentumBars = true; // Draw Bearish Momentum Bars +input bool drawBullishRejectionBars = true; // Draw Bullish Rejection Bars +input bool drawBearishRejectionBars = true; // Draw Bearish Rejection Bars + +// +#property indicator_chart_window + +// +#property indicator_buffers 6 +#property indicator_plots 6 + +// +// Plot Buffers ... + +// +// XSWING ... + +// +// HIGH ... +#define swingHighsBufferIndex 0 +double swingHighsBuffer[]; + +// +#property indicator_label1 "X121 XPOI SWH" +#property indicator_type1 DRAW_ARROW +#property indicator_color1 clrMagenta +#property indicator_width1 3 + +// +// LOW ... +#define swingLowsBufferIndex 1 +double swingLowsBuffer[]; + +// +#property indicator_label2 "X121 XPOI SWL" +#property indicator_type2 DRAW_ARROW +#property indicator_color2 clrAqua +#property indicator_width2 3 + +// +// MOMENTUM ... + +// +// BULLISH ... +#define bullishMomentumBarsBufferIndex 2 +double bullishMomentumBarsBuffer[]; + +// +#property indicator_label3 "X121 XPOI BULLMNTM" +#property indicator_type3 DRAW_ARROW +#property indicator_color3 clrAqua +#property indicator_width3 3 + +// +// BEARISH ... +#define bearishMomentumBarsBufferIndex 3 +double bearishMomentumBarsBuffer[]; + +// +#property indicator_label4 "X121 XPOI BEARNTM" +#property indicator_type4 DRAW_ARROW +#property indicator_color4 clrMagenta +#property indicator_width4 3 + +// +// REJECTION ... + +// +// BULLISH ... +#define bullishRejectionBarsBufferIndex 4 +double bullishRejectionBarsBuffer[]; + +// +#property indicator_label5 "X121 XPOI BULLMRJCT" +#property indicator_type5 DRAW_ARROW +#property indicator_color5 clrAqua +#property indicator_width5 3 + +// +// BEARISH ... +#define bearishRejectionBarsBufferIndex 5 +double bearishRejectionBarsBuffer[]; + +// +#property indicator_label6 "X121 XPOI BEARRJCT" +#property indicator_type6 DRAW_ARROW +#property indicator_color6 clrMagenta +#property indicator_width6 3 + +// +// Data Buffers ... + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +bool isPOIRequested = false; +string iPrefix = ShortName + "_" + ToString(_Period); + +// +XCPOIDrawer *mPOIDrawer; +XCPOIDetector *mPOIDetector; + +// +// Supported POIS ... + +// +// Swings ... +XCSwing *mSwingHighs[]; +XCSwing *mSwingLows[]; + +// +// Rejections ... +XCRejectionBar *mBullishRejectionBars[]; +XCRejectionBar *mBearishRejectionBars[]; + +// +// Momentums ... +XCMomentumBar *mBullishMomentumBars[]; +XCMomentumBar *mBearishMomentumBars[]; + +// +// Order Block ... +XCOrderBlock *mBullishOrderBlocks[]; +XCOrderBlock *mBearishOrderBlocks[]; + +// +// Fair Value Gap ... +XCFVG *mBullishFairValueGaps[]; +XCFVG *mBearishFairValueGaps[]; + +// +// Support and Resistances ... +XCSupportZone *mSupportZones[]; +XCResistanceZone *mResistanceZones[]; + +// +// Supply and Demand ... +XCSupplyZone *mSupplyZones[]; +XCDemandZone *mDemandZones[]; + +// +XCBaseObject *mPOIObjects[]; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize POI Detector ... + InitialiDetector(); + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + IndicatorSetInteger(INDICATOR_DIGITS, 2); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + Clean(mSupplyZones); + Clean(mDemandZones); + Clean(mSupportZones); + Clean(mResistanceZones); + Clean(mBullishOrderBlocks); + Clean(mBearishOrderBlocks); + Clean(mBullishFairValueGaps); + Clean(mBearishFairValueGaps); + + // + Clean(mSwingLows); + Clean(mSwingHighs); + Clean(mBullishMomentumBars); + Clean(mBearishMomentumBars); + Clean(mBullishRejectionBars); + Clean(mBearishRejectionBars); + + // + CleanChart(); + + // + mPOIDetector.Destroy(); + + // + ZeroMemory(mPOIDrawer); + ZeroMemory(mPOIDetector); +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +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[] // +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + true + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(result, result); + + // + return result; +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // SWING ... + + // + // LOW ... + ENUM_DRAW_TYPE swingLowsDrawType = drawSwingLows ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(swingLowsBuffer, true); + SetIndexBuffer(swingLowsBufferIndex, swingLowsBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(swingLowsBufferIndex, PLOT_SHOW_DATA, drawSwingLows); + PlotIndexSetInteger(swingLowsBufferIndex, PLOT_DRAW_TYPE, swingLowsDrawType); + + // + PlotIndexSetDouble(swingLowsBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(swingLowsBufferIndex, PLOT_ARROW, swingLowsArrowCode); + + // + // LOW ... + ENUM_DRAW_TYPE swingHighsDrawType = drawSwingLows ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(swingHighsBuffer, true); + SetIndexBuffer(swingHighsBufferIndex, swingHighsBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(swingHighsBufferIndex, PLOT_SHOW_DATA, drawSwingLows); + PlotIndexSetInteger(swingHighsBufferIndex, PLOT_DRAW_TYPE, swingHighsDrawType); + + // + PlotIndexSetDouble(swingHighsBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(swingHighsBufferIndex, PLOT_ARROW, swingHighsArrowCode); + + // + // REJECTION ... + + // + // BULLISH ... + ENUM_DRAW_TYPE bullishRejectionBarsDrawType = drawSwingLows ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bullishRejectionBarsBuffer, true); + SetIndexBuffer(bullishRejectionBarsBufferIndex, bullishRejectionBarsBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bullishRejectionBarsBufferIndex, PLOT_SHOW_DATA, drawSwingLows); + PlotIndexSetInteger(bullishRejectionBarsBufferIndex, PLOT_DRAW_TYPE, bullishRejectionBarsDrawType); + + // + PlotIndexSetDouble(bullishRejectionBarsBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bullishRejectionBarsBufferIndex, PLOT_ARROW, bullishRejectionBarsArrowCode); + + // + // BEARISH ... + ENUM_DRAW_TYPE bearishRejectionBarsDrawType = drawSwingLows ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bearishRejectionBarsBuffer, true); + SetIndexBuffer(bearishRejectionBarsBufferIndex, bearishRejectionBarsBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bearishRejectionBarsBufferIndex, PLOT_SHOW_DATA, drawSwingLows); + PlotIndexSetInteger(bearishRejectionBarsBufferIndex, PLOT_DRAW_TYPE, bearishRejectionBarsDrawType); + + // + PlotIndexSetDouble(bearishRejectionBarsBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bearishRejectionBarsBufferIndex, PLOT_ARROW, bearishRejectionBarsArrowCode); + + // + // MOMENTUM ... + + // + // BULLISH ... + ENUM_DRAW_TYPE bullishMomentumBarsDrawType = drawSwingLows ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bullishMomentumBarsBuffer, true); + SetIndexBuffer(bullishMomentumBarsBufferIndex, bullishMomentumBarsBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bullishMomentumBarsBufferIndex, PLOT_SHOW_DATA, drawSwingLows); + PlotIndexSetInteger(bullishMomentumBarsBufferIndex, PLOT_DRAW_TYPE, bullishMomentumBarsDrawType); + + // + PlotIndexSetDouble(bullishMomentumBarsBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bullishMomentumBarsBufferIndex, PLOT_ARROW, bullishMomentumBarsArrowCode); + + // + // BEARISH ... + ENUM_DRAW_TYPE bearishMomentumBarsDrawType = drawSwingLows ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bearishMomentumBarsBuffer, true); + SetIndexBuffer(bearishMomentumBarsBufferIndex, bearishMomentumBarsBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bearishMomentumBarsBufferIndex, PLOT_SHOW_DATA, drawSwingLows); + PlotIndexSetInteger(bearishMomentumBarsBufferIndex, PLOT_DRAW_TYPE, bearishMomentumBarsDrawType); + + // + PlotIndexSetDouble(bearishMomentumBarsBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bearishMomentumBarsBufferIndex, PLOT_ARROW, bearishMomentumBarsArrowCode); + + // + // Data Buffers ... +} + +/** + * Initialize POI Detector ... + */ +void InitialiDetector() +{ + // + ArraySetAsSeries(mSwingLows, true); + ArraySetAsSeries(mSwingHighs, true); + ArraySetAsSeries(mBullishMomentumBars, true); + ArraySetAsSeries(mBearishMomentumBars, true); + ArraySetAsSeries(mBullishRejectionBars, true); + ArraySetAsSeries(mBearishRejectionBars, true); + + // + ArraySetAsSeries(mSupplyZones, true); + ArraySetAsSeries(mDemandZones, true); + ArraySetAsSeries(mSupportZones, true); + ArraySetAsSeries(mResistanceZones, true); + ArraySetAsSeries(mBullishOrderBlocks, true); + ArraySetAsSeries(mBearishOrderBlocks, true); + ArraySetAsSeries(mBullishFairValueGaps, true); + ArraySetAsSeries(mBearishFairValueGaps, true); + + // + mPOIDetector = new XCPOIDetector( + _Symbol, + _Period // + ); + + // + // Configure POI Detector ... + mPOIDetector.SwingRange(swingRange); + mPOIDetector.MaxNumberOfPOIs(maxNumberOfPOIs); + mPOIDetector.OrderBlocksSameBars(orderBlocksSameBars); + mPOIDetector.TicksRangeZoneLevel(ticksRangeZoneLevel); + mPOIDetector.TicksRangeZoneRange(ticksRangeZoneRange); + mPOIDetector.SupplyAndDemandRange(supplyAndDemandRange); + mPOIDetector.FairValueGapsSameBars(fairValueGapsSameBars); + mPOIDetector.MomentumBarExtendRange(momentumBarExtendRange); + mPOIDetector.MomentumBarBodyPercent(momentumBarBodyPercent); + mPOIDetector.MaxNumberOfRequiredPOIs(maxNumberOfRequiredPOIs); + mPOIDetector.RejectionBarExtendRange(rejectionBarExtendRange); + mPOIDetector.RejectionBarShadowPercent(rejectionBarShadowPercent); + mPOIDetector.SupportAndResistanceRange(supportAndResistanceRange); + + // + mPOIDrawer = new XCPOIDrawer(); + + // + // Configure Drawer ... + mPOIDrawer.Prefix(iPrefix); + + // + mPOIDrawer.BarBullishColor(bullishColor); + mPOIDrawer.BarBearishColor(bearishColor); + + // + mPOIDrawer.DemandZoneColor(bullishColor); + mPOIDrawer.BullishFVGColor(bullishColor); + mPOIDrawer.SupportZoneColor(bullishColor); + mPOIDrawer.BullishOrderBlockColor(bullishColor); + + // + mPOIDrawer.SupplyZoneColor(bearishColor); + mPOIDrawer.BearishFVGColor(bearishColor); + mPOIDrawer.ResistanceZoneColor(bearishColor); + mPOIDrawer.BearishOrderBlockColor(bearishColor); + + // + mPOIDrawer.SupplyZoneStyle(supDemStyle); + mPOIDrawer.DemandZoneStyle(supDemStyle); + mPOIDrawer.SupportZoneStyle(supResStyle); + mPOIDrawer.ResistanceZoneStyle(supResStyle); + mPOIDrawer.BullishFVGStyle(fairValueGapStyle); + mPOIDrawer.BearishFVGStyle(fairValueGapStyle); + mPOIDrawer.BullishOrderBlockStyle(orderBlockStyle); + mPOIDrawer.BearishOrderBlockStyle(orderBlockStyle); + + // +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + if (bar_index == 0) + { + // + XPOIState state; + ENUM_XPOI_EVENTS events[]; + int numberOfEvents = mPOIDetector.Update(events); + bool hasEvents = IsValidSize(numberOfEvents); + if (hasEvents) + { + // + mPOIDetector.GetState(state); + bool isStateValid = state.IsValid() && + state.HasChild(); + if (isStateValid) + { + // + // Order Blocks ... + + // + // Bullish ... + bool hasBullOB = Contains( + X_BULLISH_ORDERBLOCK_DETECTED, + events // + ); + if (hasBullOB) + { + // + int count = state.CountBullishOrderBlocks(); + if (IsValidSize(count)) + { + // + Add( + state.bullishOrderBlocks[count - 1], + mBullishOrderBlocks // + ); + } + } + + // + // Bearish ... + bool hasBearOB = Contains( + X_BEARISH_ORDERBLOCK_DETECTED, + events // + ); + if (hasBearOB) + { + // + int count = state.CountBearishOrderBlocks(); + if (IsValidSize(count)) + { + // + Add( + state.bearishOrderBlocks[count - 1], + mBearishOrderBlocks // + ); + } + } + + // + // Fair Value Gaps ... + + // + // Bullish ... + bool hasBullFVG = Contains( + X_BULLISH_FVG_DETECTED, + events // + ); + if (hasBullFVG) + { + // + int count = state.CountBullishFairValueGaps(); + if (IsValidSize(count)) + { + // + Add( + state.bullishFairValueGaps[count - 1], + mBullishFairValueGaps // + ); + } + } + + // + // Bearish ... + bool hasBearFVG = Contains( + X_BEARISH_FVG_DETECTED, + events // + ); + if (hasBearFVG) + { + // + int count = state.CountBearishFairValueGaps(); + if (IsValidSize(count)) + { + // + Add( + state.bearishFairValueGaps[count - 1], + mBearishFairValueGaps // + ); + } + } + + // + // Support and Resistance ... + + // + // Support ... + bool hasSupportZone = Contains( + X_SUPPORT_ZONE_DETECTED, + events // + ); + if (hasSupportZone) + { + // + int count = state.CountSupportZones(); + if (IsValidSize(count)) + { + // + Add( + state.supportZones[count - 1], + mSupportZones // + ); + } + } + + // + // Resistance ... + bool hasResistanceZone = Contains( + X_RESISTANCE_ZONE_DETECTED, + events // + ); + if (hasResistanceZone) + { + // + int count = state.CountResistanceZones(); + if (IsValidSize(count)) + { + // + Add( + state.resistanceZones[count - 1], + mResistanceZones // + ); + } + } + + // + // Supply and Demand ... + + // + // Supply ... + bool hasSupplyZone = Contains( + X_SUPPLY_ZONE_DETECTED, + events // + ); + if (hasSupplyZone) + { + // + int count = state.CountSupplyZones(); + if (IsValidSize(count)) + { + // + Add( + state.supplyZones[count - 1], + mSupplyZones // + ); + } + } + + // + // Demand ... + bool hasDemandZone = Contains( + X_DEMAND_ZONE_DETECTED, + events // + ); + if (hasDemandZone) + { + // + int count = state.CountDemandZones(); + if (IsValidSize(count)) + { + // + Add( + state.demandZones[count - 1], + mDemandZones // + ); + } + } + + // + // + // + + // + // Swings ... + + // + // Low ... + bool hasSwingLow = Contains( + X_SWING_LOW_DETECTED, + events // + ); + if (hasSwingLow) + { + // + int count = state.CountSwingLows(); + if (IsValidSize(count)) + { + // + Add( + state.swingLows[count - 1], + mSwingLows // + ); + } + } + + // + // High ... + bool hasSwingHigh = Contains( + X_SWING_HIGH_DETECTED, + events // + ); + if (hasSwingHigh) + { + // + int count = state.CountSwingHighs(); + if (IsValidSize(count)) + { + // + Add( + state.swingHighs[count - 1], + mSwingHighs // + ); + } + } + + // + // Momentum ... + + // + // Bullish ... + bool hasBullishMomentumBar = Contains( + X_BULLISH_MOMENTUM_BAR_DETECTED, + events // + ); + if (hasBullishMomentumBar) + { + // + int count = state.CountBullishMomentumBars(); + if (IsValidSize(count)) + { + // + Add( + state.bullishMomentumBars[count - 1], + mBullishMomentumBars // + ); + } + } + + // + // Bearish ... + bool hasBearishMomentumBar = Contains( + X_BEARISH_MOMENTUM_BAR_DETECTED, + events // + ); + if (hasBearishMomentumBar) + { + // + int count = state.CountBearishMomentumBars(); + if (IsValidSize(count)) + { + // + Add( + state.bearishMomentumBars[count - 1], + mBearishMomentumBars // + ); + } + } + + // + // Rejection ... + + // + // Bullish ... + bool hasBullishRejectionBar = Contains( + X_BULLISH_REJECTION_BAR_DETECTED, + events // + ); + if (hasBullishRejectionBar) + { + // + int count = state.CountBullishRejectionBars(); + if (IsValidSize(count)) + { + // + Add( + state.bullishRejectionBars[count - 1], + mBullishRejectionBars // + ); + } + } + + // + // Bearish ... + bool hasBearishRejectionBar = Contains( + X_BEARISH_REJECTION_BAR_DETECTED, + events // + ); + if (hasBearishRejectionBar) + { + // + int count = state.CountBearishRejectionBars(); + if (IsValidSize(count)) + { + // + Add( + state.bearishRejectionBars[count - 1], + mBearishRejectionBars // + ); + } + } + + // + } + } + + // + if (bar_index == 0 && !isPOIRequested) + { + // + mPOIDetector.Init(); + isPOIRequested = true; + } + + // + if (isPOIRequested && + bar_index == 0 && + !mPOIDetector.IsLocked()) + { + // + mPOIDetector.GetState(state); + bool isStateValid = state.IsValid() && + state.HasChild(); + if (isStateValid) + { + // + // Order Blocks ... + + // + // Bullish ... + int bullishOBsCount = state.CountBullishOrderBlocks(); + bool hasBullishOBs = IsValidSize(bullishOBsCount); + if (hasBullishOBs) + { + // + for (int i = 0; i < bullishOBsCount; i++) + { + // + XOHCL activatedBar; + ENUM_X_DIRECTION activatedDir; + bool isActivated = state.bullishOrderBlocks[i].IsActivated( + activatedBar, + activatedDir // + ); + if (!isActivated) + { + // + Add( + state.bullishOrderBlocks[i], + mBullishOrderBlocks // + ); + } + } + } + + // + // Bearish ... + int bearishOBsCount = state.CountBearishOrderBlocks(); + bool hasBearishOBs = IsValidSize(bearishOBsCount); + if (hasBearishOBs) + { + // + for (int i = 0; i < bearishOBsCount; i++) + { + // + XOHCL activatedBar; + ENUM_X_DIRECTION activatedDir; + bool isActivated = state.bearishOrderBlocks[i].IsActivated( + activatedBar, + activatedDir // + ); + if (!isActivated) + { + // + Add( + state.bearishOrderBlocks[i], + mBearishOrderBlocks // + ); + } + } + } + + // + // Fair Value Gaps ... + + // + // Bullish ... + int bullishFVGsCount = state.CountBullishFairValueGaps(); + bool hasBullishFVGs = IsValidSize(bullishFVGsCount); + if (hasBullishFVGs) + { + // + for (int i = 0; i < bullishFVGsCount; i++) + { + // + XOHCL activatedBar; + ENUM_X_DIRECTION activatedDir; + bool isActivated = state.bullishFairValueGaps[i].IsActivated( + activatedBar, + activatedDir // + ); + if (!isActivated) + { + // + Add( + state.bullishFairValueGaps[i], + mBullishFairValueGaps // + ); + } + } + } + + // + // Bearish ... + int bearishFVGsCount = state.CountBearishFairValueGaps(); + bool hasBearishFVGs = IsValidSize(bearishFVGsCount); + if (hasBearishFVGs) + { + // + for (int i = 0; i < bearishFVGsCount; i++) + { + // + XOHCL activatedBar; + ENUM_X_DIRECTION activatedDir; + bool isActivated = state.bearishFairValueGaps[i].IsActivated( + activatedBar, + activatedDir // + ); + if (!isActivated) + { + // + Add( + state.bearishFairValueGaps[i], + mBearishFairValueGaps // + ); + } + } + } + + // + // Support and Resistance ... + + // + // Support ... + int supportZonesCount = state.CountSupportZones(); + bool hasSupportZones = IsValidSize(supportZonesCount); + if (hasSupportZones) + { + // + for (int i = 0; i < supportZonesCount; i++) + { + // + Add( + state.supportZones[i], + mSupportZones // + ); + } + } + + // + // Resistance ... + int resistanceZonesCount = state.CountResistanceZones(); + bool hasResistanceZones = IsValidSize(resistanceZonesCount); + if (hasResistanceZones) + { + // + for (int i = 0; i < resistanceZonesCount; i++) + { + // + Add( + state.resistanceZones[i], + mResistanceZones // + ); + } + } + + // + // Supply and Demand ... + + // + // Supply ... + int supplyZonesCount = state.CountSupplyZones(); + bool hasSupplyZones = IsValidSize(supplyZonesCount); + if (hasSupplyZones) + { + // + for (int i = 0; i < supplyZonesCount; i++) + { + // + Add( + state.supplyZones[i], + mSupplyZones // + ); + } + } + + // + // Demand ... + int demandZonesCount = state.CountDemandZones(); + bool hasDemandZones = IsValidSize(demandZonesCount); + if (hasDemandZones) + { + // + for (int i = 0; i < demandZonesCount; i++) + { + // + Add( + state.demandZones[i], + mDemandZones // + ); + } + } + + // + // + // + + // + // Swings ... + + // + // Low ... + int swingLowsCount = state.CountSwingLows(); + bool hasSwingLows = IsValidSize(swingLowsCount); + if (hasSwingLows) + { + // + for (int i = 0; i < swingLowsCount; i++) + { + // + Add( + state.swingLows[i], + mSwingLows // + ); + } + } + + // + // Highs... + int swingHighsCount = state.CountSwingHighs(); + bool hasSwingHighs = IsValidSize(swingHighsCount); + if (hasSwingHighs) + { + // + for (int i = 0; i < swingHighsCount; i++) + { + // + Add( + state.swingHighs[i], + mSwingHighs // + ); + } + } + + // + // Momentum Bars ... + + // + // Bullish ... + int bullishMomentumBarsCount = state.CountBullishMomentumBars(); + bool hasBullishMomentumBars = IsValidSize(bullishMomentumBarsCount); + if (hasBullishMomentumBars) + { + // + for (int i = 0; i < bullishMomentumBarsCount; i++) + { + // + Add( + state.bullishMomentumBars[i], + mBullishMomentumBars // + ); + } + } + + // + // Bearish ... + int bearishMomentumBarsCount = state.CountBearishMomentumBars(); + bool hasBearishMomentumBars = IsValidSize(bearishMomentumBarsCount); + if (hasBearishMomentumBars) + { + // + for (int i = 0; i < bearishMomentumBarsCount; i++) + { + // + Add( + state.bearishMomentumBars[i], + mBearishMomentumBars // + ); + } + } + + // + // Rejection Bars ... + + // + // Bullish ... + int bullishRejectionBarsCount = state.CountBullishRejectionBars(); + bool hasBullishRejectionBars = IsValidSize(bullishRejectionBarsCount); + if (hasBullishRejectionBars) + { + // + for (int i = 0; i < bullishRejectionBarsCount; i++) + { + // + Add( + state.bullishRejectionBars[i], + mBullishRejectionBars // + ); + } + } + + // + // Bearish ... + int bearishRejectionBarsCount = state.CountBearishRejectionBars(); + bool hasBearishRejectionBars = IsValidSize(bearishRejectionBarsCount); + if (hasBearishRejectionBars) + { + // + for (int i = 0; i < bearishRejectionBarsCount; i++) + { + // + Add( + state.bearishRejectionBars[i], + mBearishRejectionBars // + ); + } + } + + // + } + } + + // + UpdatePOIs( + bar_index, + prevCalculated // + ); + } + } + else + { + FillBuffersZero(bar_index); + } +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + swingLowsBuffer[barIndex] = 0; + swingHighsBuffer[barIndex] = 0; + bullishMomentumBarsBuffer[barIndex] = 0; + bearishMomentumBarsBuffer[barIndex] = 0; + bullishRejectionBarsBuffer[barIndex] = 0; + bearishRejectionBarsBuffer[barIndex] = 0; +} + +/** + * Update nd Validate POIS ... + */ +void UpdatePOIs( + int barIndex, + const int prevCalculated // +) +{ + // + // CleanChart(); + FillBuffersZero(barIndex); + + // + if (prevCalculated <= 0) + { + return; + } + + // + // CleanChart(); + datetime cTime = TimeCurrent(); + + // + XOHCL iBar; + bool isInited = iBar.Init( + _Symbol, + _Period, + barIndex // + ); + if (!isInited) + { + return; + } + + // + XOHCL iPBar; + isInited = iPBar.Init( + _Symbol, + _Period, + barIndex + 1 // + ); + if (!isInited) + { + return; + } + + // + // Order Blcoks ... + + // + // Bullish ... + int bullOBsCount = ArraySize(mBullishOrderBlocks); + if (IsValidSize(bullOBsCount)) + { + // + for (int i = 0; i < bullOBsCount; i++) + { + // + // Check OB Activation ... + // XOHCL activatedBar; + // ENUM_X_DIRECTION activatedDir; + // bool isActivated = mBullishOrderBlocks[i].IsActivated( + // activatedBar, + // activatedDir // + // ); + + // + // Check OB Breake ... + XOHCL breakerBar; + ENUM_X_DIRECTION breakerDir; + bool isBreaked = mBullishOrderBlocks[i].IsBreaked( + breakerBar, + breakerDir // + ); + if (!isBreaked) + { + mBullishOrderBlocks[i].To(cTime); + } + else + { + mBullishOrderBlocks[i].To(breakerBar.time); + } + + // + if (drawBullishOrderBlocks) + { + // + XCBullishOrderBlockObject *iObj; + bool isCreated = mPOIDrawer.CreateBullishOrderBlock( + mBullishOrderBlocks[i], + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + mPOIObjects // + ); + } + } + } + } + + // + // Bearish ... + int bearOBsCount = ArraySize(mBearishOrderBlocks); + if (IsValidSize(bearOBsCount)) + { + // + for (int i = 0; i < bearOBsCount; i++) + { + // + // Check OB Activation ... + // XOHCL activatedBar; + // ENUM_X_DIRECTION activatedDir; + // bool isActivated = mBearishOrderBlocks[i].IsActivated( + // activatedBar, + // activatedDir // + // ); + + // + // Check OB Breake ... + XOHCL breakerBar; + ENUM_X_DIRECTION breakerDir; + bool isBreaked = mBearishOrderBlocks[i].IsBreaked( + breakerBar, + breakerDir // + ); + if (!isBreaked) + { + mBearishOrderBlocks[i].To(cTime); + } + else + { + mBearishOrderBlocks[i].To(breakerBar.time); + } + + // + if (drawBearishOrderBlocks) + { + // + XCBearishOrderBlockObject *iObj; + bool isCreated = mPOIDrawer.CreateBearishOrderBlock( + mBearishOrderBlocks[i], + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + mPOIObjects // + ); + } + } + } + } + + // + // Fair Value Gap ... + + // + // Bullish ... + int bullFVGsCount = ArraySize(mBullishFairValueGaps); + if (IsValidSize(bullFVGsCount)) + { + // + for (int i = 0; i < bullFVGsCount; i++) + { + // + // Check OB Activation ... + // XOHCL activatedBar; + // ENUM_X_DIRECTION activatedDir; + // bool isActivated = mBullishFairValueGaps[i].IsActivated( + // activatedBar, + // activatedDir // + // ); + + // + // Check OB Breake ... + XOHCL breakerBar; + ENUM_X_DIRECTION breakerDir; + bool isBreaked = mBullishFairValueGaps[i].IsBreaked( + breakerBar, + breakerDir // + ); + if (!isBreaked) + { + mBullishFairValueGaps[i].To(cTime); + } + else + { + mBullishFairValueGaps[i].To(breakerBar.time); + } + + // + if (drawBullishFairValueGaps) + { + // + XCBullishFairValueGapObject *iObj; + bool isCreated = mPOIDrawer.CreateBullishFairValueGap( + mBullishFairValueGaps[i], + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + mPOIObjects // + ); + } + } + } + } + + // + // Bearish ... + int bearFVGsCount = ArraySize(mBearishFairValueGaps); + if (IsValidSize(bearFVGsCount)) + { + // + for (int i = 0; i < bearFVGsCount; i++) + { + // + // Check OB Activation ... + // XOHCL activatedBar; + // ENUM_X_DIRECTION activatedDir; + // bool isActivated = mBearishFairValueGaps[i].IsActivated( + // activatedBar, + // activatedDir // + // ); + + // + // Check OB Breake ... + XOHCL breakerBar; + ENUM_X_DIRECTION breakerDir; + bool isBreaked = mBearishFairValueGaps[i].IsBreaked( + breakerBar, + breakerDir // + ); + if (!isBreaked) + { + mBearishFairValueGaps[i].To(cTime); + } + else + { + mBearishFairValueGaps[i].To(breakerBar.time); + } + + // + if (drawBearishFairValueGaps) + { + // + XCBearishFairValueGapObject *iObj; + bool isCreated = mPOIDrawer.CreateBearishFairValueGap( + mBearishFairValueGaps[i], + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + mPOIObjects // + ); + } + } + } + } + + // + // Support and Resistance Zones ... + + // + // Support Zones ... + int supportZonesCount = ArraySize(mSupportZones); + if (IsValidSize(supportZonesCount)) + { + // + for (int i = 0; i < supportZonesCount; i++) + { + // + // Check OB Activation ... + // XOHCL activatedBar; + // ENUM_X_DIRECTION activatedDir; + // bool isActivated = mSupportZones[i].IsActivated( + // activatedBar, + // activatedDir // + // ); + + // + // Check OB Breake ... + XOHCL breakerBar; + ENUM_X_DIRECTION breakerDir; + bool isBreaked = mSupportZones[i].IsBreaked( + breakerBar, + breakerDir // + ); + if (!isBreaked) + { + mSupportZones[i].To(cTime); + } + else + { + mSupportZones[i].To(breakerBar.time); + } + + // + if (drawSupportZones) + { + // + XCSupportZoneObject *iObj; + bool isCreated = mPOIDrawer.CreateSupportZone( + mSupportZones[i], + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + mPOIObjects // + ); + } + } + } + } + + // + // Resistance Zones ... + int resistanceZonesCount = ArraySize(mResistanceZones); + if (IsValidSize(resistanceZonesCount)) + { + // + for (int i = 0; i < resistanceZonesCount; i++) + { + // + // Check OB Activation ... + // XOHCL activatedBar; + // ENUM_X_DIRECTION activatedDir; + // bool isActivated = mResistanceZones[i].IsActivated( + // activatedBar, + // activatedDir // + // ); + + // + // Check OB Breake ... + XOHCL breakerBar; + ENUM_X_DIRECTION breakerDir; + bool isBreaked = mResistanceZones[i].IsBreaked( + breakerBar, + breakerDir // + ); + if (!isBreaked) + { + mResistanceZones[i].To(cTime); + } + else + { + mResistanceZones[i].To(breakerBar.time); + } + + // + if (drawResistanceZones) + { + // + XCResistanceZoneObject *iObj; + bool isCreated = mPOIDrawer.CreateResistanceZone( + mResistanceZones[i], + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + mPOIObjects // + ); + } + } + } + } + + // + // Supply and Demand Zones ... + + // + // Supply Zones ... + int supplyZonesCount = ArraySize(mSupplyZones); + if (IsValidSize(supplyZonesCount)) + { + // + for (int i = 0; i < supplyZonesCount; i++) + { + // + // Check OB Activation ... + // XOHCL activatedBar; + // ENUM_X_DIRECTION activatedDir; + // bool isActivated = mSupplyZones[i].IsActivated( + // activatedBar, + // activatedDir // + // ); + + // + // Check OB Breake ... + XOHCL breakerBar; + ENUM_X_DIRECTION breakerDir; + bool isBreaked = mSupplyZones[i].IsBreaked( + breakerBar, + breakerDir // + ); + if (!isBreaked) + { + mSupplyZones[i].To(cTime); + } + else + { + mSupplyZones[i].To(breakerBar.time); + } + + // + if (drawSupplyZones) + { + // + XCSupplyZoneObject *iObj; + bool isCreated = mPOIDrawer.CreateSupplyZone( + mSupplyZones[i], + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + mPOIObjects // + ); + } + } + } + } + + // + // Demand Zones ... + int demandZonesCount = ArraySize(mDemandZones); + if (IsValidSize(demandZonesCount)) + { + // + for (int i = 0; i < demandZonesCount; i++) + { + // + // Check OB Activation ... + // XOHCL activatedBar; + // ENUM_X_DIRECTION activatedDir; + // bool isActivated = mDemandZones[i].IsActivated( + // activatedBar, + // activatedDir // + // ); + + // + // Check OB Breake ... + XOHCL breakerBar; + ENUM_X_DIRECTION breakerDir; + bool isBreaked = mDemandZones[i].IsBreaked( + breakerBar, + breakerDir // + ); + if (!isBreaked) + { + mDemandZones[i].To(cTime); + } + else + { + mDemandZones[i].To(breakerBar.time); + } + + // + if (drawDemandZones) + { + // + XCDemandZoneObject *iObj; + bool isCreated = mPOIDrawer.CreateDemandZone( + mDemandZones[i], + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + mPOIObjects // + ); + } + } + } + } + + // + // + // + + // + double swingsDistance = _Point * 5; + double momentumBarsDistance = _Point * 20; + double rejectionBarsDistance = _Point * 40; + + // + // Swings ... + + // + // Lows ... + int swingLowsCount = ArraySize(mSwingLows); + if (IsValidSize(swingLowsCount)) + { + // + for (int i = 0; i < swingLowsCount; i++) + { + // + XCSwing *iSwing = mSwingLows[i]; + + // + double iValue = iSwing.GetValue() - swingsDistance; + int iIDX = iBarShift( + _Symbol, + _Period, + iSwing.GetTime() // + ); + + // + swingLowsBuffer[iIDX] = iValue; + } + } + + // + // Highs ... + int swingHighsCount = ArraySize(mSwingHighs); + if (IsValidSize(swingHighsCount)) + { + // + for (int i = 0; i < swingHighsCount; i++) + { + // + XCSwing *iSwing = mSwingHighs[i]; + + // + double iValue = iSwing.GetValue() + swingsDistance; + int iIDX = iBarShift( + _Symbol, + _Period, + iSwing.GetTime() // + ); + + // + swingHighsBuffer[iIDX] = iValue; + } + } + + // + // Momentum Bars ... + + // + // Bullish ... + int bullishMomentumBarsCount = ArraySize(mBullishMomentumBars); + if (IsValidSize(bullishMomentumBarsCount)) + { + // + for (int i = 0; i < bullishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentumBar = mBullishMomentumBars[i]; + + // + XOHCL iBar; + bool isIBarFilled = iMomentumBar.FillBar(iBar); + + // + double iValue = iBar.low - momentumBarsDistance; + int iIDX = iBar.Index(); + + // + bullishMomentumBarsBuffer[iIDX] = iValue; + } + } + + // + // Bearish ... + int bearishMomentumBarsCount = ArraySize(mBearishMomentumBars); + if (IsValidSize(bearishMomentumBarsCount)) + { + // + for (int i = 0; i < bearishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentumBar = mBearishMomentumBars[i]; + + // + XOHCL iBar; + bool isIBarFilled = iMomentumBar.FillBar(iBar); + + // + double iValue = iBar.high + momentumBarsDistance; + int iIDX = iBar.Index(); + + // + bearishMomentumBarsBuffer[iIDX] = iValue; + } + } + + // + // Rejection Bars ... + + // + // Bullish ... + int bullishRejectionBarsCount = ArraySize(mBullishRejectionBars); + if (IsValidSize(bullishRejectionBarsCount)) + { + // + for (int i = 0; i < bullishRejectionBarsCount; i++) + { + // + XCRejectionBar *iRejectionBar = mBullishRejectionBars[i]; + + // + XOHCL iBar; + bool isIBarFilled = iRejectionBar.FillBar(iBar); + + // + double iValue = iBar.low - rejectionBarsDistance; + int iIDX = iBar.Index(); + + // + bullishRejectionBarsBuffer[iIDX] = iValue; + } + } + + // + // Bearish ... + int bearishRejectionBarsCount = ArraySize(mBearishRejectionBars); + if (IsValidSize(bearishRejectionBarsCount)) + { + // + for (int i = 0; i < bearishRejectionBarsCount; i++) + { + // + XCRejectionBar *iRejectionBar = mBearishRejectionBars[i]; + + // + XOHCL iBar; + bool isIBarFilled = iRejectionBar.FillBar(iBar); + + // + double iValue = iBar.high + rejectionBarsDistance; + int iIDX = iBar.Index(); + + // + bearishRejectionBarsBuffer[iIDX] = iValue; + } + } +} + +/** + * Clear all Drawn Objects ... + */ +void CleanChart() +{ + // + long chartID = mPOIDrawer.ChartIdentification(); + int subWindow = mPOIDrawer.SubWindowIdentification(); + string objName = NULL; + + // + int count = ArraySize(mPOIObjects); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + objName = mPOIObjects[i].ObjName(); + mPOIObjects[i].Delete(); + mPOIObjects[i].Detach(); + + // + RemoveDraw( + objName, + chartID, + subWindow // + ); + } + } + + // + RemoveDraws( + iPrefix, + chartID, + subWindow // + ); + + // + Clean(mPOIObjects); + + // + ZeroMemory(mPOIObjects); +} \ No newline at end of file diff --git a/Indicators/x-saherelm.x121.xtrend.mq5 b/Indicators/x-saherelm.x121.xtrend.mq5 new file mode 100644 index 00000000..7d923f3a --- /dev/null +++ b/Indicators/x-saherelm.x121.xtrend.mq5 @@ -0,0 +1,676 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121 XTREND +// Description: XTREND ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XTREND Indicator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121 XTREND" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +// Market ... +input group "Market"; + +input ENUM_APPLIED_PRICE trendPriceType = PRICE_CLOSE; // Detect Trend Price Type + +input group "MA Detection"; +input int maLength = 50; // MA Length +input ENUM_MA_METHOD maMethod = MODE_EMA; // MA Method +input ENUM_APPLIED_PRICE maAppliedTo; // MA Applied To + +input group "ADX Detection"; +input int adxLength = 14; // ADX Length +input double adxThreshold = 25; // ADX Threshold for Strong Trends + +// +// Presentation ... +input group "Presentation"; + +// +input int startCalculationForLastBars = 1000; // Calculate Last n Bars +input int upTrendArrowCode = 233; // Up Trend Arrow Code +input int downTrendArrowCode = 234; // Down Trend Arrow Code + +// +input bool showOnlyTrendStart = true; // Show Only Trend Start +input bool showUpTrend = true; // Show Up Trend +input bool showDownTrend = true; // Show Down Trend + +// +#property indicator_chart_window + +// +#property indicator_buffers 6 +#property indicator_plots 2 + +// +// Plot Buffers ... + +// +#define upTrendBufferIndex 0 +double upTrendBuffer[]; + +// +#property indicator_label1 "X121 XTREND Up" +#property indicator_type1 DRAW_ARROW +#property indicator_color1 clrAqua +#property indicator_width1 1 + +// +#define downTrendBufferIndex 1 +double downTrendBuffer[]; + +// +#property indicator_label2 "X121 XTREND Down" +#property indicator_type2 DRAW_ARROW +#property indicator_color2 clrMagenta +#property indicator_width2 1 + +// +// Data Buffers ... + +// +int mLastBufferIndex = 1; + +// +#define maBufferIndex mLastBufferIndex + 1 +double maBuffer[]; + +// +#define adxBufferIndex mLastBufferIndex + 2 +double adxBuffer[]; + +// +#define adxPBufferIndex mLastBufferIndex + 3 +double adxPBuffer[]; + +// +#define adxMBufferIndex mLastBufferIndex + 4 +double adxMBuffer[]; + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +double lastValue = 0; +ENUM_X_DIRECTION lastTrendDir = X_DIRECTION_NONE; + +// +// MA Handler ... +int maHandler = INVALID_HANDLE; + +// +// ADX Handler ... +int adxHandler = INVALID_HANDLE; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Indicator Handlers ... + + // + // MA ... + maHandler = iMA( + _Symbol, + _Period, + maLength, + 0, + maMethod, + maAppliedTo // + ); + bool isInited = maHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // ADx ... + adxHandler = iADX( + _Symbol, + _Period, + adxLength // + ); + isInited = maHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + IndicatorSetInteger(INDICATOR_DIGITS, 2); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + IndicatorRelease(maHandler); + IndicatorRelease(adxHandler); +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +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[] // +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // Validate Calculated Bars ... + + // + // MA ... + int maCalculatedBars = BarsCalculated(maHandler); + + // + // ADX ... + int adxCalculatedBars = BarsCalculated(adxHandler); + + // + bool isPassedRequiredCalculatedBars = + // + // MA ... + maCalculatedBars >= maxLength && + // + // ADX ... + adxCalculatedBars >= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // MA ... + int copiedMas = CopyBuffer(maHandler, 0, 0, limit, maBuffer); + + // + // ADX ... + int copiedAdxs = CopyBuffer(adxHandler, MAIN_LINE, 0, limit, adxBuffer); + int copiedAdxPs = CopyBuffer(adxHandler, PLUSDI_LINE, 0, limit, adxPBuffer); + int copiedAdxMs = CopyBuffer(adxHandler, MINUSDI_LINE, 0, limit, adxMBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // MA ... + copiedMas > 0 && + // + // ADX ... + copiedAdxs > 0 && + copiedAdxPs > 0 && + copiedAdxMs > 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + // MA ... + maLength > 0 && + // + // ADX ... + adxLength > 0 && + adxThreshold > 0 + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(maLength, adxLength); + + // + return result; +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // UP Trend ... + + // + ENUM_DRAW_TYPE upTrendDrawType = showUpTrend ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(upTrendBuffer, true); + SetIndexBuffer(upTrendBufferIndex, upTrendBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(upTrendBufferIndex, PLOT_SHOW_DATA, showUpTrend); + PlotIndexSetInteger(upTrendBufferIndex, PLOT_DRAW_TYPE, upTrendDrawType); + + // + PlotIndexSetDouble(upTrendBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(upTrendBufferIndex, PLOT_ARROW, upTrendArrowCode); + + // + // DOWN Trend ... + + // + ENUM_DRAW_TYPE downTrendDrawType = showDownTrend ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(downTrendBuffer, true); + SetIndexBuffer(downTrendBufferIndex, downTrendBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(downTrendBufferIndex, PLOT_SHOW_DATA, showDownTrend); + PlotIndexSetInteger(downTrendBufferIndex, PLOT_DRAW_TYPE, downTrendDrawType); + + // + PlotIndexSetDouble(downTrendBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(downTrendBufferIndex, PLOT_ARROW, downTrendArrowCode); + + // + // Data Buffers ... + + // + ArraySetAsSeries(maBuffer, true); + SetIndexBuffer(maBufferIndex, maBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(adxBuffer, true); + SetIndexBuffer(adxBufferIndex, adxBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(adxPBuffer, true); + SetIndexBuffer(adxPBufferIndex, adxPBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(adxMBuffer, true); + SetIndexBuffer(adxMBufferIndex, adxMBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + CalculateTrend( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + else + { + FillBuffersZero(bar_index); + } +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + upTrendBuffer[barIndex] = 0; + downTrendBuffer[barIndex] = 0; + + // + maBuffer[barIndex] = 0; + adxBuffer[barIndex] = 0; + adxPBuffer[barIndex] = 0; + adxMBuffer[barIndex] = 0; +} + +/** + * Calculate Trends ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateTrend( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + double iPrice = GetAppliedPrice( + trendPriceType, + open, + high, + low, + close, + bar_index // + ); + + // + double iMa = maBuffer[bar_index]; + double iAdx = adxBuffer[bar_index]; + double points = GetPoints(_Symbol); + double points10 = 10 * points; + + // + bool isUpTrend = + iPrice > iMa && + iAdx > adxThreshold; + bool isDownTrend = + iPrice < iMa && + iAdx > adxThreshold; + + // + if (isUpTrend) + { + // + // double iLastValue = + // prevCalculated <= 0 + // ? 0 + // : upTrendBuffer[bar_index + 1]; + // if (iLastValue > 0 && + // iValue > iLastValue) + // { + // iValue = iLastValue; + // } + + // // + // double iValue = low[bar_index] - points10; + + // + double iValue = + !IsBullish(lastTrendDir) ? low[bar_index] - points10 + : !showOnlyTrendStart + ? lastValue + : 0; + + // + upTrendBuffer[bar_index] = iValue; + downTrendBuffer[bar_index] = 0; + + // + lastValue = iValue; + lastTrendDir = X_DIRECTION_BULLISH; + } + else if (isDownTrend) + { + // + // double iLastValue = + // prevCalculated <= 0 + // ? 0 + // : downTrendBuffer[bar_index + 1]; + // if (iLastValue > 0 && + // iValue < iLastValue) + // { + // iValue = iLastValue; + // } + + // // + // double iValue = high[bar_index] + points10; + + // + double iValue = + !IsBearish(lastTrendDir) ? high[bar_index] + points10 + : !showOnlyTrendStart + ? lastValue + : 0; + + // + upTrendBuffer[bar_index] = 0; + downTrendBuffer[bar_index] = iValue; + + // + lastValue = iValue; + lastTrendDir = X_DIRECTION_BEARISH; + } + else + { + // + double iValue = + IsBullish(lastTrendDir) + ? showOnlyTrendStart + ? 0 + : lastValue + : IsBearish(lastTrendDir) + ? showOnlyTrendStart + ? 0 + : lastValue + : 0; + + // + upTrendBuffer[bar_index] = 0; + downTrendBuffer[bar_index] = 0; + + // + lastValue = 0; + lastTrendDir = X_DIRECTION_NONE; + } +} \ No newline at end of file diff --git a/Libraries/x-saherelm.x-poi.lib.mq5 b/Libraries/x-saherelm.x-poi.lib.mq5 index d511a3c2..13ecb198 100644 --- a/Libraries/x-saherelm.x-poi.lib.mq5 +++ b/Libraries/x-saherelm.x-poi.lib.mq5 @@ -843,6 +843,218 @@ class XCBarZone : public XCZone return result; } + /** + * Is Activated Zone or not ... + * + * @param activatedBar: XOHCL instance Reference ... + * @param activatedDir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ + bool IsActivated( + XOHCL &activatedBar, + ENUM_X_DIRECTION &activatedDir // + ) + { + // + bool result = false; + + // + activatedBar.Clean(); + activatedDir = X_DIRECTION_NONE; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + // Detect From Bar Index ... + int fromIndex = iBarShift( + GetSymbol(), + GetPeriod(), + From() // + ); + fromIndex--; + + // + for (int i = fromIndex; i >= 0; i--) + { + // + if (i == fromIndex) + { + continue; + } + + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + GetPeriod(), + i // + ); + result = isInited; + if (!result) + { + continue; + } + + // + XOHCL iPBar; + isInited = iBar + .GetPreviousBar(iPBar); + result = isInited; + if (!result) + { + continue; + } + + // + bool isActivedFromUpper = + // + (iPBar.low > Upper() && + iBar.low <= Upper()) + // + ; + + // + bool isActivedFromLower = + // + (iPBar.high < Lower() && + iBar.high >= Lower()) + // + ; + + // + bool isActivated = + isActivedFromUpper || + isActivedFromLower; + if (isActivated) + { + // + result = isActivated; + activatedBar = iBar; + activatedDir = + isActivedFromUpper + ? X_DIRECTION_BEARISH + : X_DIRECTION_BULLISH; + break; + } + } + + // + return result; + } + + /** + * Is Breaked Zone or not ... + * + * @param breakerBar: XOHCL instance Reference ... + * @param breakerDir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ + bool IsBreaked( + XOHCL &breakerBar, + ENUM_X_DIRECTION &breakerDir // + ) + { + // + bool result = false; + + // + breakerBar.Clean(); + breakerDir = X_DIRECTION_NONE; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL activatedBar; + ENUM_X_DIRECTION activatedDir; + bool isActivated = IsActivated( + activatedBar, + activatedDir // + ); + result = isActivated; + if (!result) + { + return result; + } + + // + int activatedIndex = activatedBar.Index(); + activatedIndex--; + + // + for (int i = activatedIndex; i >= 0; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + GetPeriod(), + i // + ); + result = isInited; + if (!result) + { + continue; + } + + // + XOHCL iPBar; + isInited = iBar + .GetPreviousBar(iPBar); + result = isInited; + if (!result) + { + continue; + } + + // + bool isBreakedFromUpper = + // + (iPBar.high <= Upper() && + iBar.low > Upper()) + // + ; + + // + bool isBreakedFromLower = + // + (iPBar.low >= Lower() && + iBar.low < Lower()) + // + ; + + // + bool isBreaked = + isBreakedFromUpper || + isBreakedFromLower; + if (isBreaked) + { + // + result = isBreaked; + breakerBar = iBar; + breakerDir = + isBreakedFromUpper + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + break; + } + } + + // + return result; + } + // // Overrides ... @@ -1169,6 +1381,218 @@ class XCTwoBarZone : public XCZone return result; } + /** + * Is Activated Zone or not ... + * + * @param activatedBar: XOHCL instance Reference ... + * @param activatedDir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ + bool IsActivated( + XOHCL &activatedBar, + ENUM_X_DIRECTION &activatedDir // + ) + { + // + bool result = false; + + // + activatedBar.Clean(); + activatedDir = X_DIRECTION_NONE; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + // Detect From Bar Index ... + int fromIndex = iBarShift( + GetSymbol(), + GetPeriod(), + From() // + ); + fromIndex--; + + // + for (int i = fromIndex; i >= 0; i--) + { + // + if (i == fromIndex) + { + continue; + } + + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + GetPeriod(), + i // + ); + result = isInited; + if (!result) + { + continue; + } + + // + XOHCL iPBar; + isInited = iBar + .GetPreviousBar(iPBar); + result = isInited; + if (!result) + { + continue; + } + + // + bool isActivedFromUpper = + // + (iPBar.low > Upper() && + iBar.low <= Upper()) + // + ; + + // + bool isActivedFromLower = + // + (iPBar.high < Lower() && + iBar.high >= Lower()) + // + ; + + // + bool isActivated = + isActivedFromUpper || + isActivedFromLower; + if (isActivated) + { + // + result = isActivated; + activatedBar = iBar; + activatedDir = + isActivedFromUpper + ? X_DIRECTION_BEARISH + : X_DIRECTION_BULLISH; + break; + } + } + + // + return result; + } + + /** + * Is Breaked Zone or not ... + * + * @param breakerBar: XOHCL instance Reference ... + * @param breakerDir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ + bool IsBreaked( + XOHCL &breakerBar, + ENUM_X_DIRECTION &breakerDir // + ) + { + // + bool result = false; + + // + breakerBar.Clean(); + breakerDir = X_DIRECTION_NONE; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL activatedBar; + ENUM_X_DIRECTION activatedDir; + bool isActivated = IsActivated( + activatedBar, + activatedDir // + ); + result = isActivated; + if (!result) + { + return result; + } + + // + int activatedIndex = activatedBar.Index(); + activatedIndex--; + + // + for (int i = activatedIndex; i >= 0; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + GetPeriod(), + i // + ); + result = isInited; + if (!result) + { + continue; + } + + // + XOHCL iPBar; + isInited = iBar + .GetPreviousBar(iPBar); + result = isInited; + if (!result) + { + continue; + } + + // + bool isBreakedFromUpper = + // + (iPBar.high <= Upper() && + iBar.low > Upper()) + // + ; + + // + bool isBreakedFromLower = + // + (iPBar.low >= Lower() && + iBar.low < Lower()) + // + ; + + // + bool isBreaked = + isBreakedFromUpper || + isBreakedFromLower; + if (isBreaked) + { + // + result = isBreaked; + breakerBar = iBar; + breakerDir = + isBreakedFromUpper + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + break; + } + } + + // + return result; + } + // // Overrides ... @@ -2123,237 +2547,6 @@ class XCOrderBlock : public XCBarZone return result; } - /** - * Detect Order Blocks Breaker Bar ... - * - * @param breakerBar: XOHCL instance Reference ... - * - * @return ( bool ) - */ - bool DetectBreakerBar(XOHCL &breakerBar) - { - // - bool result = false; - - // - breakerBar.Clean(); - - // - result = IsValid(); - if (!result) - { - return result; - } - - // - XOHCL fromBar; - result = FillBar(fromBar); - if (!result) - { - return result; - } - - // - int fromIndex = fromBar.Index(); - result = fromIndex > 0; - if (!result) - { - return result; - } - - // - bool isBullish = IsBullish(); - ENUM_X_DIRECTION dir = - isBullish - ? X_DIRECTION_BULLISH - : X_DIRECTION_BEARISH; - double value = - isBullish - ? Upper() - : Lower(); - - // - for (int i = fromIndex - 1; i >= 0; i--) - { - // - XOHCL iBar; - bool isInited = iBar.Init( - fromBar.symbol, - fromBar.period, - i // - ); - if (!isInited) - { - continue; - } - - // - isInited = IsBarBreak( - value, - dir, - iBar // - ); - if (isInited) - { - // - breakerBar = iBar; - break; - } - } - - // - result = breakerBar.IsValid(); - - // - return result; - } - - /** - * Check Order Block is Hunted or not ... - * - * @param huntedBar: XOHCL instance Reference ... - * - * @return ( bool ) - */ - bool IsHunted(XOHCL &huntedBar) - { - // - bool result = false; - - // - huntedBar.Clean(); - - // - result = IsValid(); - if (!result) - { - return result; - } - - // - XOHCL breakerBar; - result = DetectBreakerBar(breakerBar); - if (!result) - { - return result; - } - - // - bool isBullish = IsBullish(); - - // - int breakerIndex = breakerBar.Index(); - for (int i = breakerIndex - 1; i >= 0; i--) - { - // - XOHCL iBar; - result = iBar.Init( - breakerBar.symbol, - breakerBar.period, - i // - ); - - // - double price = - isBullish - ? iBar.low - : iBar.high; - - // - result = IsPriceInsideZone( - price, - Upper(), - Lower() // - ); - if (result) - { - // - huntedBar = iBar; - break; - } - } - - // - result = huntedBar.IsValid(); - - // - return result; - } - - /** - * Check Order Block Validation ... - * - * @return ( bool ) - */ - bool IsValidOrderBlock() - { - // - bool result = false; - - // - result = IsValid(); - if (!result) - { - return result; - } - - // - XOHCL breakerBar; - result = DetectBreakerBar(breakerBar); - if (!result) - { - return result; - } - int breakerBarIndex = breakerBar.Index(); - - // - XOHCL huntedBar; - bool isHunted = IsHunted(huntedBar); - result = !isHunted; - if (!result) - { - return result; - } - - // - bool isBullish = IsBullish(); - - // - for (int i = breakerBarIndex - 1; i >= 0; i--) - { - // - XOHCL iBar; - result = iBar.Init( - breakerBar.symbol, - breakerBar.period, - i // - ); - if (!result) - { - continue; - } - - // - double price = - isBullish - ? iBar.low - : iBar.high; - - // - result = - isBullish - ? price > Upper() - : price < Lower(); - if (!result) - { - return result; - } - } - - // - return result; - } - // // Overrides ... @@ -3230,7 +3423,10 @@ class XCTicksZone : public XCTwoBarZone XCTickZone *iZone = mZones.At(i); // - iZone.volumePercent = (double)(iZone.volume * 100 / mVolumes); + if (mVolumes > 0) + { + iZone.volumePercent = (double)(iZone.volume * 100 / mVolumes); + } } // @@ -11533,370 +11729,6 @@ int DetectValidSupplyZones( return result; } -/** - * Test Market for Detect Order Block FVG ... - * - * @param forDir: Direction - * @param bullishOrderBlocks: Detected Bullish Order Blocks ... - * @param bearishOrderBlocks: Detected Bearish Order Blocks ... - * @param orderBlockState: Order Block Detection POIState ... - * @param fairValueGapState: Fair Value Gap Detection POIState ... - * @param barIndex: Bar Index ... - * - * @return ( bool ) - */ -bool DetectFVGOB( - ENUM_X_DIRECTION &forDir, // Test For Specified Direction ... - XFVGOrderBlock &bullishOrderBlocks[], // Bullish Order Blocks ... - XFVGOrderBlock &bearishOrderBlocks[], // Bearish Order Blocks ... - XPOIState &orderBlockState, // Order Block Detection TF POI(s) ... - XPOIState &fairValueGapState, // Fair Value Gap Detection TF POI(s) ... - int barIndex = 0 // Bar Index ... -) -{ - // - bool result = false; - - // - if (barIndex < 0) - { - barIndex = 0; - } - - // - forDir = X_DIRECTION_NONE; - - // - // Validate Args ... - result = - orderBlockState.HasChild() && - fairValueGapState.HasChild(); - if (!result) - { - return result; - } - - // - string symbol = orderBlockState.symbol; - ENUM_TIMEFRAMES period = orderBlockState.period; - - // - // Retrieve Bars ... - XOHCL triggerCBar; - result = triggerCBar.Init( - symbol, - period, - barIndex // - ); - - // - // Select Order Blocks Which Has Big Changes ... - int count = 0; - datetime cTime = TimeCurrent(); - - // - XOHCL jBar; - result = jBar.Init( - fairValueGapState.symbol, - fairValueGapState.period, - barIndex // - ); - if (!result) - { - return result; - } - double jBarLL = jBar.FindLowest(3, MODE_LOW); - double jBarHH = jBar.FindHighest(3, MODE_HIGH); - - // - // Bullish ... - int bullishOrderBlocksCount = orderBlockState.CountBullishOrderBlocks(); - count = bullishOrderBlocksCount; - if (IsValidSize(count)) - { - // - for (int i = count - 1; i >= 0; i--) - { - // - XCFVG *iFVG = NULL; - XStateZones iStateZones; - XCOrderBlock *iOb = orderBlockState.bullishOrderBlocks[i]; - iOb.To(cTime); - - // - // Find Exit Bar of Bullish OrderBlock Upper ... - XOHCL breakerBar; - bool hasBreakerBar = iOb.DetectBreakerBar(breakerBar); - if (!hasBreakerBar) - { - continue; - } - - // - // Detect Order Block is Hunted Or Not ... - XOHCL huntedBar; - bool isHunted = iOb.IsHunted(huntedBar); - if (isHunted) - { - continue; - } - - // - // Check Validation of Order Block ... - bool isValid = iOb.IsValidOrderBlock(); - if (!isValid) - { - continue; - } - - // - // Check Order Block Has Fair Value Gap ... - int fvgsCount = fairValueGapState.CountBullishFairValueGaps(); - bool hasFVG = IsValidSize(fvgsCount); - if (!hasFVG) - { - continue; - } - - // - // Detect an FVG for Order Block ... - for (int j = fvgsCount - 1; j >= 0; j--) - { - // - XCFVG *jFVG = fairValueGapState.bullishFairValueGaps[j]; - - // - bool isValid = - // - jFVG.IsBullish() && - jBarLL > jFVG.Upper() && - jBar.low > jFVG.Upper() && - jFVG.From() >= iOb.From() && - ((jFVG.Upper() > iOb.Upper() && - jFVG.Lower() <= iOb.Upper()) || - (jFVG.Upper() <= iOb.Upper() && - jFVG.Lower() >= iOb.Lower())) - // - ; - if (isValid) - { - // - jFVG.To(cTime); - iFVG = jFVG; - break; - } - } - - // - hasFVG = iFVG != NULL; - result = hasFVG; - if (!result) - { - continue; - } - - // // - // double upper = MathMax(iOb.Upper(), iFVG.Upper()); - // double lower = MathMin(iOb.Lower(), iFVG.Lower()); - // datetime from = iFVG.From(); - - // // - // // Detect Price Zones ... - // // Based On Decision State ... - // bool hasStateZones = CalculateStateZones( - // iStateZones, - // decisionState, - // upper, - // lower, - // from // - // ); - // result = hasStateZones; - // if (!result) - // { - // continue; - // } - - // - XFVGOrderBlock iModel; - iModel.orderBlock = iOb; - iModel.fairValueGap = iFVG; - // iModel.stateZones = iStateZones; - - // - AddRef( - iModel, - bullishOrderBlocks // - ); - } - } - - // - // Bearish ... - int bearishOrderBlocksCount = orderBlockState.CountBearishOrderBlocks(); - count = bearishOrderBlocksCount; - if (IsValidSize(count)) - { - // - for (int i = count - 1; i >= 0; i--) - { - // - XCFVG *iFVG = NULL; - XStateZones iStateZones; - XCOrderBlock *iOb = orderBlockState.bearishOrderBlocks[i]; - iOb.To(cTime); - - // - // Find Exit Bar of Bullish OrderBlock Upper ... - XOHCL breakerBar; - bool hasBreakerBar = iOb.DetectBreakerBar(breakerBar); - if (!hasBreakerBar) - { - continue; - } - - // - // Detect Order Block is Hunted Or Not ... - XOHCL huntedBar; - bool isHunted = iOb.IsHunted(huntedBar); - if (isHunted) - { - continue; - } - - // - // Check Validation of Order Block ... - bool isValid = iOb.IsValidOrderBlock(); - if (!isValid) - { - continue; - } - - // - // Check Order Block Has Fair Value Gap ... - int fvgsCount = fairValueGapState.CountBearishFairValueGaps(); - bool hasFVG = IsValidSize(fvgsCount); - if (!hasFVG) - { - continue; - } - - // - // Detect an FVG for Order Block ... - for (int j = fvgsCount - 1; j >= 0; j--) - { - // - XCFVG *jFVG = fairValueGapState.bearishFairValueGaps[j]; - - // - bool isValid = - // - jFVG.IsBearish() && - jBarHH < jFVG.Lower() && - jBar.high < jFVG.Lower() && - jFVG.From() >= iOb.From() && - ((jFVG.Upper() > iOb.Lower() && - jFVG.Lower() <= iOb.Lower()) || - (jFVG.Upper() <= iOb.Upper() && - jFVG.Lower() >= iOb.Lower())) - // - ; - if (isValid) - { - // - jFVG.To(cTime); - iFVG = jFVG; - break; - } - } - - // - hasFVG = iFVG != NULL; - result = hasFVG; - if (!result) - { - continue; - } - - // - double upper = MathMax(iOb.Upper(), iFVG.Upper()); - double lower = MathMin(iOb.Lower(), iFVG.Lower()); - datetime from = iFVG.From(); - - // // - // // Detect Price Zones ... - // // Based On Decision State ... - // bool hasStateZones = CalculateStateZones( - // iStateZones, - // decisionState, - // upper, - // lower, - // from // - // ); - // result = hasStateZones; - // if (!result) - // { - // continue; - // } - - // - XFVGOrderBlock iModel; - iModel.orderBlock = iOb; - iModel.fairValueGap = iFVG; - // iModel.stateZones = iStateZones; - - // - AddRef( - iModel, - bearishOrderBlocks // - ); - } - } - - // - // Check Order Blocks ... - bullishOrderBlocksCount = ArraySize(bullishOrderBlocks); - bool hasBullishOrderBlocks = IsValidSize(bullishOrderBlocksCount); - - // - // Check Order Blocks ... - bearishOrderBlocksCount = ArraySize(bearishOrderBlocks); - bool hasBearishOrderBlocks = IsValidSize(bearishOrderBlocksCount); - - // - result = - // - hasBullishOrderBlocks || - hasBearishOrderBlocks - // - ; - if (!result) - { - return result; - } - - // - bool isBullish = hasBullishOrderBlocks && !hasBearishOrderBlocks; - bool isBearish = hasBearishOrderBlocks && !hasBullishOrderBlocks; - - // - forDir = - isBullish - ? X_DIRECTION_BULLISH - : isBearish - ? X_DIRECTION_BEARISH - : X_DIRECTION_NONE; - - // - result = forDir != X_DIRECTION_NONE; - if (!result) - { - return result; - } - - // - return result; -} - /** * Detect a Zone Breaker Bar ... * diff --git a/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 b/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 index caa8e834..aebd7f37 100644 --- a/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 +++ b/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 @@ -1662,10 +1662,10 @@ class XCX121SMCStrategy : public XCX121SMCBaseStrategy { // useXSignal = false; - useXOBSSignal = false; + useXOBSSignal = true; useXHKPVSignal = false; - useXOBPVSignal = true; - useXIOBPVSignal = true; + useXOBPVSignal = false; + useXIOBPVSignal = false; // string symbol = GetSymbol();