diff --git a/Classes/x-saherelm.x-poi.drawer.class.mq5 b/Classes/x-saherelm.x-poi.drawer.class.mq5 index de39646d..c1b300db 100644 --- a/Classes/x-saherelm.x-poi.drawer.class.mq5 +++ b/Classes/x-saherelm.x-poi.drawer.class.mq5 @@ -563,7 +563,8 @@ class XCPOIDrawer : public XCBase bool DrawBox( XBoxZone &box, XCBoxObject *&object, - bool ignoreAt = true // + bool ignoreAt = true, + string name = NULL // ) { // @@ -589,7 +590,9 @@ class XCPOIDrawer : public XCBase } // - string name = box.GetTag(); + name = IsSpecifiedValid(name) + ? name + : box.GetTag(); result = DrawBox( object, name, diff --git a/Experts/x-saherelm.xfima.backtester.ea.mq5 b/Experts/x-saherelm.xfima.backtester.ea.mq5 index b71c8d57..ed3537dd 100644 --- a/Experts/x-saherelm.xfima.backtester.ea.mq5 +++ b/Experts/x-saherelm.xfima.backtester.ea.mq5 @@ -154,7 +154,7 @@ XFIMAMarketStructureDrawerConfig marketStructureDrawerConfig; // POI Drawer Conf // // Drawer and eaDraws ... -// CArrayObj *eaDraws; // Drawn Objects ... +CArrayObj eaDraws; // Drawn Objects ... CArrayObj *marketStructureObjects; // Market Structure Objects ... // @@ -386,7 +386,6 @@ int OnInit() // // Configure XFIMA POI Detector / Drawer ... detectorConfig.Default(); - // eaDraws = new CArrayObj(); detectorConfig.FullDetect(); marketStructureDrawerConfig.FullDraw(); @@ -901,35 +900,6 @@ void AnalyseMarket(int barIndex = 0) detectorConfig // ); - // - if (marketStructureObjects == NULL) - { - marketStructureObjects = new CArrayObj(); - } - - // - // marketStructureObjects.Clear(); - - // - // Draw Only ... - - // - // Draw Market Structure ... - // int marketStructureObjectsCount = fima2Signaller.poiDrawer.DrawMarketStructure( - // marketStructure, - // marketStructureDrawerConfig, - // marketStructureObjects // - // ); - // if (IsValidIndex(marketStructureObjectsCount)) - // { - // // - // // Add Drawn Objects if Necessary ... - // // AddObjects( - // // marketStructureObjects, - // // eaDraws // - // // ); - // } - // HandleSignalLookup(bar); @@ -951,6 +921,8 @@ void HandleSignalLookup(XOHCL &bar) // string iName = NULL; + XBoxZone supports[]; + XBoxZone resistances[]; bool isBullish = false; int barIndex = bar.Index(); double iPrice = EMPTY_VALUE; @@ -959,27 +931,584 @@ void HandleSignalLookup(XOHCL &bar) // // Check Required Pattern Exists ... + bool hasPinnedBar = HasDirection(marketStructure.pinnedDir); bool hasEngulfedBar = HasDirection(marketStructure.engulfedDir); bool hasSignalKeyBar = HasDirection(marketStructure.signalKeyBarPatternDir); + // + // PV Trend Line ... + string pvTrendName = "XPVTrend"; + CChartObjectTrend *pvTrendLine = NULL; + ENUM_X_DIRECTION pvTrend = X_DIRECTION_NONE; + + // + // ZigZag Trend Line ... + string zgTrendName = "XZGTrend"; + CChartObjectTrend *zgTrendLine = NULL; + ENUM_X_DIRECTION zgTrend = X_DIRECTION_NONE; + + // + // Check PV Analysis ... + bool hasPVAnalysis = marketStructure.pvAnalysis.IsValid(); + if (hasPVAnalysis) + { + // + // Support ... + XBoxZone supportBox; + XCBoxObject *iSupportObj; + has = marketStructure.pvAnalysis.HasSupportBox(supportBox); + if (has) + { + // + supportBox.to = bar.time; + AddIfNotExists( + supportBox, + supports // + ); + has = fima2Signaller.poiDrawer.DrawBox( + supportBox, + iSupportObj, + true, // Ignore At ... + supportBox.type // Name ... + ); + if (has) + { + // + XPOIStyle iStyle; + fima2Signaller.poiDrawer.GetBoxStyle( + iStyle, + supportBox.dir // + ); + fima2Signaller.poiDrawer.ApplyBoxStyle( + iSupportObj, + iStyle // + ); + iStyle.Clean(); + } + } + + // + // Resistance ... + XBoxZone resistanceBox; + XCBoxObject *iResistanceObj; + has = marketStructure.pvAnalysis.HasResistanceBox(resistanceBox); + if (has) + { + // + resistanceBox.to = bar.time; + AddIfNotExists( + resistanceBox, + supports // + ); + has = fima2Signaller.poiDrawer.DrawBox( + resistanceBox, + iResistanceObj, + true, // Ignore At ... + resistanceBox.type // Name ... + ); + if (has) + { + // + XPOIStyle iStyle; + fima2Signaller.poiDrawer.GetBoxStyle( + iStyle, + resistanceBox.dir // + ); + fima2Signaller.poiDrawer.ApplyBoxStyle( + iResistanceObj, + iStyle // + ); + iStyle.Clean(); + } + } + + // + // Pivots ... + XPivot pivots[]; + int pivotsCount = fima2Signaller.poiDetector.ExtractPVPivots( + pivots, + barIndex, + 50 // + ); + has = IsValidSize(pivotsCount); + + // + // Sort ... + Sort( + pivots, + X_SORT_BY_DATE, + X_DIRECTION_BEARISH // + ); + + // + // Remove Newest ... + ArrayRemove( + pivots, + 0, + 1 // + ); + + // + // Check Trend ... + if (has) + { + // + XPivot highs[]; + int highsCount = ExtractPivots( + highs, + pivots, + X_PIVOT_TYPE_PEAK // + ); + Sort( + highs, + X_SORT_BY_DATE, + X_DIRECTION_BEARISH // + ); + + // + XPivot lows[]; + int lowsCount = ExtractPivots( + lows, + pivots, + X_PIVOT_TYPE_VALE // + ); + Sort( + lows, + X_SORT_BY_DATE, + X_DIRECTION_BEARISH // + ); + + // + // Check Highs and Lows ... + has = IsValidSize(lowsCount) && + IsValidSize(highsCount) && + lowsCount >= 2 && + highsCount >= 2; + if (has) + { + // + // Try to Get Market Strucutre ... + + // + bool hasLowerHigh = highs[0].value < highs[1].value; + bool hasLowerLow = lows[0].value < lows[1].value; + + // + bool hasHigherHigh = highs[0].value > highs[1].value; + bool hasHigherLow = lows[0].value > lows[1].value; + + // + pvTrend = + (hasHigherHigh && + hasHigherLow) + ? X_DIRECTION_BULLISH + : (hasLowerHigh && + hasLowerLow) + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + has = HasDirection(pvTrend); + if (has) + { + // + // Select Swings for Trend Line ... + XOHCL tmpBar; + int llIDX = -1; + int hhIDX = -1; + datetime toTime = NULL; + datetime fromTime = NULL; + double toPrice = EMPTY_VALUE; + color trendColor = CLR_NONE; + double fromPrice = EMPTY_VALUE; + if (IsSpecifiedBullish(pvTrend)) + { + // + llIDX = GetLowest(lows); + hhIDX = GetHighest(lows); + + // + trendColor = clrAqua; + + // + toTime = lows[hhIDX].time; + toPrice = lows[hhIDX].value; + + // + fromTime = lows[llIDX].time; + fromPrice = lows[llIDX].value; + } + else + { + // + llIDX = GetLowest(highs); + hhIDX = GetHighest(highs); + + // + trendColor = clrMagenta; + + // + toTime = highs[llIDX].time; + toPrice = highs[llIDX].value; + + // + fromTime = highs[hhIDX].time; + fromPrice = highs[hhIDX].value; + } + + // + // Check Requirements for Trend ... + has = + NotEmptyZero(toPrice) && + NotEmptyZero(fromPrice) && + IsSpecifiedValid(toTime) && + IsSpecifiedValid(fromTime); + if (has) + { + // + has = fima2Signaller.poiDrawer.DrawTrendLine( + fromPrice, + fromTime, + toPrice, + toTime, + pvTrendLine, + pvTrendName, + true // Ray Right ... + ); + if (has) + { + pvTrendLine.Color(trendColor); + } + } + + // + // Cleanup Resources ... + tmpBar.Clean(); + } + + // + if (!has) + { + SpecifiedClean(pivots); + } + } + + // + // Cleanup Resources ... + SpecifiedClean(lows); + SpecifiedClean(highs); + } + + // + // Draw Pivots ... + has = HasChild(pivots); + if (has) + { + // + CArrayObj *drawnPivots = new CArrayObj(); + pivotsCount = fima2Signaller.poiDrawer.DrawPivots( + pivots, + drawnPivots // + ); + } + + // + // Cleanup Resources ... + SpecifiedClean(pivots); + } + + // + // Check ZigZag Analysis ... + bool hasZGAnalysis = marketStructure.zigzagAnalysis.IsValid(); + if (hasZGAnalysis) + { + // + // Support ... + // XBoxZone supportBox; + // XCBoxObject *iSupportObj; + // has = marketStructure.zigzagAnalysis.HasSupportBox(supportBox); + // if (has) + // { + // // + // supportBox.to = bar.time; + // AddIfNotExists( + // supportBox, + // supports // + // ); + // has = fima2Signaller.poiDrawer.DrawBox( + // supportBox, + // iSupportObj, + // true, // Ignore At ... + // supportBox.type // Name ... + // ); + // if (has) + // { + // // + // XPOIStyle iStyle; + // fima2Signaller.poiDrawer.GetBoxStyle( + // iStyle, + // supportBox.dir // + // ); + // fima2Signaller.poiDrawer.ApplyBoxStyle( + // iSupportObj, + // iStyle // + // ); + // iStyle.Clean(); + // } + // } + + // + // Resistance ... + // XBoxZone resistanceBox; + // XCBoxObject *iResistanceObj; + // has = marketStructure.zigzagAnalysis.HasResistanceBox(resistanceBox); + // if (has) + // { + // // + // resistanceBox.to = bar.time; + // AddIfNotExists( + // resistanceBox, + // supports // + // ); + // has = fima2Signaller.poiDrawer.DrawBox( + // resistanceBox, + // iResistanceObj, + // true, // Ignore At ... + // resistanceBox.type // Name ... + // ); + // if (has) + // { + // // + // XPOIStyle iStyle; + // fima2Signaller.poiDrawer.GetBoxStyle( + // iStyle, + // resistanceBox.dir // + // ); + // fima2Signaller.poiDrawer.ApplyBoxStyle( + // iResistanceObj, + // iStyle // + // ); + // iStyle.Clean(); + // } + // } + + // + // Pivots ... + XPivot pivots[]; + int pivotsCount = fima2Signaller.poiDetector.ExtractZigZagPivots( + pivots, + barIndex, + 10 // + ); + has = IsValidSize(pivotsCount); + + // + // Sort ... + Sort( + pivots, + X_SORT_BY_DATE, + X_DIRECTION_BEARISH // + ); + + // + // Remove Newest ... + ArrayRemove( + pivots, + 0, + 1 // + ); + + // + // Check Trend ... + if (has) + { + // + XPivot highs[]; + int highsCount = ExtractPivots( + highs, + pivots, + X_PIVOT_TYPE_PEAK // + ); + Sort( + highs, + X_SORT_BY_DATE, + X_DIRECTION_BEARISH // + ); + + // + XPivot lows[]; + int lowsCount = ExtractPivots( + lows, + pivots, + X_PIVOT_TYPE_VALE // + ); + Sort( + lows, + X_SORT_BY_DATE, + X_DIRECTION_BEARISH // + ); + + // + // Check Highs and Lows ... + has = IsValidSize(lowsCount) && + IsValidSize(highsCount) && + lowsCount >= 2 && + highsCount >= 2; + if (has) + { + // + // Try to Get Market Strucutre ... + + // + bool hasLowerHigh = highs[0].value < highs[1].value; + bool hasLowerLow = lows[0].value < lows[1].value; + + // + bool hasHigherHigh = highs[0].value > highs[1].value; + bool hasHigherLow = lows[0].value > lows[1].value; + + // + zgTrend = + (hasHigherHigh && + hasHigherLow) + ? X_DIRECTION_BULLISH + : (hasLowerHigh && + hasLowerLow) + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + has = HasDirection(zgTrend); + if (has) + { + // + // Select Swings for Trend Line ... + XOHCL tmpBar; + int llIDX = -1; + int hhIDX = -1; + datetime toTime = NULL; + datetime fromTime = NULL; + double toPrice = EMPTY_VALUE; + color trendColor = CLR_NONE; + double fromPrice = EMPTY_VALUE; + if (IsSpecifiedBullish(zgTrend)) + { + // + llIDX = GetLowest(lows); + hhIDX = GetHighest(lows); + + // + trendColor = clrAqua; + + // + toTime = lows[hhIDX].time; + toPrice = lows[hhIDX].value; + + // + fromTime = lows[llIDX].time; + fromPrice = lows[llIDX].value; + } + else + { + // + llIDX = GetLowest(highs); + hhIDX = GetHighest(highs); + + // + trendColor = clrMagenta; + + // + toTime = highs[llIDX].time; + toPrice = highs[llIDX].value; + + // + fromTime = highs[hhIDX].time; + fromPrice = highs[hhIDX].value; + } + + // + // Check Requirements for Trend ... + has = + NotEmptyZero(toPrice) && + NotEmptyZero(fromPrice) && + IsSpecifiedValid(toTime) && + IsSpecifiedValid(fromTime); + if (has) + { + // + has = fima2Signaller.poiDrawer.DrawTrendLine( + fromPrice, + fromTime, + toPrice, + toTime, + zgTrendLine, + zgTrendName, + true // Ray Right ... + ); + if (has) + { + zgTrendLine.Color(trendColor); + } + } + + // + // Cleanup Resources ... + tmpBar.Clean(); + } + + // + if (!has) + { + SpecifiedClean(pivots); + } + } + + // + // Cleanup Resources ... + SpecifiedClean(lows); + SpecifiedClean(highs); + } + + // + // Draw Pivots ... + has = HasChild(pivots); + if (has) + { + // + CArrayObj *drawnPivots = new CArrayObj(); + pivotsCount = fima2Signaller.poiDrawer.DrawPivots( + pivots, + drawnPivots // + ); + } + + // + // Cleanup Resources ... + SpecifiedClean(pivots); + } + // // Selecting Price Type of Bar based on Dir ... - has = hasEngulfedBar || + has = hasPinnedBar || + hasEngulfedBar || hasSignalKeyBar; if (has) { // // Retrieve Direction ... - if (hasEngulfedBar) + if (hasPinnedBar) + { + // + iDir = marketStructure.pinnedDir; + iName = "XPin_" + ToXString(iDir) + ToXString(TimeToSeconds(bar.time)); + } + else if (hasEngulfedBar) { // iDir = marketStructure.engulfedDir; iName = "XEngulf_" + ToXString(iDir) + ToXString(TimeToSeconds(bar.time)); } - else + else if (hasSignalKeyBar) { + // iDir = marketStructure.signalKeyBarPatternDir; - iName = "XEngulf_" + ToXString(iDir) + ToXString(TimeToSeconds(bar.time)); + iName = "SignalKey_" + ToXString(iDir) + ToXString(TimeToSeconds(bar.time)); } // @@ -1002,6 +1531,70 @@ void HandleSignalLookup(XOHCL &bar) has = isBullish ? iPrice < iMABandLower : iPrice > iMABandUpper; + + // + // Check Support and Resistance ... + + // + // Support ... + bool hasSupport = marketStructure.support.IsValid(); + if (hasSupport) + { + // + AddIfNotExists( + marketStructure.support, + supports // + ); + + // + XCBoxObject *iObj; + has = fima2Signaller.poiDrawer.DrawBox( + marketStructure.support, + iObj); + if (has) + { + } + } + + // + // Resistance ... + bool hasResistance = marketStructure.resistance.IsValid(); + if (hasResistance) + { + // + AddIfNotExists( + marketStructure.resistance, + resistances // + ); + + // + XCBoxObject *iObj; + has = fima2Signaller.poiDrawer.DrawBox( + marketStructure.resistance, + iObj); + if (has) + { + } + } + + // + // Validate Happens in Zone ... + int insideZoneIDX = -1; + has = has && + (isBullish + ? HasInside( + insideZoneIDX, + bar, + supports // + ) + : HasInside( + insideZoneIDX, + bar, + resistances // + )) && + IsValidIndex(insideZoneIDX); + + // if (has) { // @@ -1026,11 +1619,25 @@ void HandleSignalLookup(XOHCL &bar) true, // Ignore Bar Tag ... 10 // Threshold ... ); - - // - Print("Detect a Potential Place for Price Movement: ", ToXString(iDir), ", Time: ", bar.time); + if (has) + { + } } } + + // + // Checking Liquidities ... + + // + if (has) + { + Print("Detect a Potential Place for Price Movement: ", ToXString(iDir), ", Time: ", bar.time); + } + + // + // Cleanup Resources ... + SpecifiedClean(supports); + SpecifiedClean(resistances); } // \ No newline at end of file diff --git a/Libraries/x-saherelm.x-poi.extensions.lib.mq5 b/Libraries/x-saherelm.x-poi.extensions.lib.mq5 index 0f3a446f..05aac1b2 100644 --- a/Libraries/x-saherelm.x-poi.extensions.lib.mq5 +++ b/Libraries/x-saherelm.x-poi.extensions.lib.mq5 @@ -4253,6 +4253,115 @@ bool IsInside( return result; } +/** + * Check a Bar is Inside a Zone or not ... + * + * @param index: int, reference to holds detected index ... + * @param bar: reference to Specified Bar ... + * @param source: reference collection to provide source ... + * + * @return ( bool ) + */ +bool HasInside( + int &index, + XOHCL &bar, + XBoxZone &source[] // +) +{ + // + bool result = false; + + // + // Prepare ... + index = -1; + + // + // Validate ... + result = bar.IsValid() && + HasChild(source); + if (!result) + { + return result; + } + + // + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + result = IsInside( + bar, + source[i] // + ); + if (result) + { + // + index = i; + break; + } + } + + // + return result; +} + +/** + * Extract all Items which Specified Bar is inside them ... + * + * @param bar: reference to Specified Bar ... + * @param dest: reference to result ... + * @param source: reference collection to provide source ... + * + * @return ( int ) + */ +int ExtractInsides( + XOHCL &bar, + XBoxZone &dest[], + XBoxZone &source[] // +) +{ + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Validate ... + bool has = bar.IsValid() && + HasChild(source); + if (!result) + { + return result; + } + + // + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = IsInside( + bar, + source[i] // + ); + if (has) + { + // + AddIfNotExists( + source[i], + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + /** * Collect all Bars which Breakes Specified Zone ... *