From 8212d542f27b27fe1e07053361d0f340121adc08 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Wed, 23 Oct 2024 11:42:34 +0330 Subject: [PATCH] Complete Supply and Demand Zone ... --- Classes/x-saherelm.x-chart-objects.class.mq5 | 82 +- Classes/x-saherelm.x-poi.class.mq5 | 1408 +++++++++++++++++- Experts/x-saherelm.x-121.smc.ea.mq5 | 6 +- Libraries/x-saherelm.x-poi.lib.mq5 | 24 +- 4 files changed, 1452 insertions(+), 68 deletions(-) diff --git a/Classes/x-saherelm.x-chart-objects.class.mq5 b/Classes/x-saherelm.x-chart-objects.class.mq5 index 044fe057..a5c3989e 100644 --- a/Classes/x-saherelm.x-chart-objects.class.mq5 +++ b/Classes/x-saherelm.x-chart-objects.class.mq5 @@ -42,6 +42,8 @@ enum ENUM_XCHARTOBJECTS X_MARKET_SESSION, X_SUPPORT_ZONE, X_RESISTANCE_ZONE, + X_SUPPLY_ZONE, + X_DEMAND_ZONE, }; enum ENUM_X_CHART_IDS @@ -411,8 +413,6 @@ class XCZoneObject : public CChartObject long chart_id, const string name, const int window, - const datetime time1, - const datetime time2, const XZone &zone, const string objprefix = NULL, const bool forceRect = false // @@ -421,14 +421,9 @@ class XCZoneObject : public CChartObject // bool result = false; - // - NormalizeTime(time2); - // XZone tmpZone = zone; result = - time1 < time2 && - IsValid(time1) && IsValid(name) && tmpZone.IsValid(); if (!result) @@ -441,13 +436,14 @@ class XCZoneObject : public CChartObject chart_id, name, window, - time1, - time2, + zone.from, + zone.to, zone.upper, zone.upper, zone.lower, zone.lower, - objprefix // + objprefix, + forceRect // ); // @@ -850,3 +846,69 @@ class XCResistanceZoneObject : public XCZoneObject }; // +// Supply Zone ... +class XCSupplyZoneObject : public XCZoneObject +{ + // + public: + // + + // + // Constructors ... + void XCSupplyZoneObject() + { + } + + // + // Deconstructors ... + void ~XCSupplyZoneObject() + { + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_SUPPLY_ZONE; + } + + // +}; + +// +// Demand Zone ... +class XCDemandZoneObject : public XCZoneObject +{ + // + public: + // + + // + // Constructors ... + void XCDemandZoneObject() + { + } + + // + // Deconstructors ... + void ~XCDemandZoneObject() + { + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_DEMAND_ZONE; + } + + // +}; + +// diff --git a/Classes/x-saherelm.x-poi.class.mq5 b/Classes/x-saherelm.x-poi.class.mq5 index d3bd0dd3..d6c8285b 100644 --- a/Classes/x-saherelm.x-poi.class.mq5 +++ b/Classes/x-saherelm.x-poi.class.mq5 @@ -1258,6 +1258,226 @@ class XCPOI : public XSCBaseAlert mResistanceZonePriceType = value; } + // + // Supply Zone ... + + /** + * Get Draw Supply Zone State ... + * + * @return ( bool ) + */ + bool AllowDrawSupplyZones() + { + return mAllowDrawSupplyZones; + } + + /** + * Set Draw Supply Zone State ... + * + * @param value: Boolean ... + */ + void AllowDrawSupplyZones(bool value) + { + mAllowDrawSupplyZones = value; + } + + /** + * Get Supply Zone Width ... + * + * @return ( int ) + */ + int SupplyZoneWidth() + { + return mSupplyZoneWidth; + } + + /** + * Set Supply Zone Width ... + * + * @param value: Integer ... + */ + void SupplyZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSupplyZoneWidth = value; + } + + /** + * Get Supply Zone Color ... + * + * @return ( color ) + */ + color SupplyZoneColor() + { + return mSupplyZoneColor; + } + + /** + * Set Supply Zone Color ... + * + * @param value: Color ... + */ + void SupplyZoneColor(color value) + { + mSupplyZoneColor = value; + } + + /** + * Get Supply Zone Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE SupplyZoneStyle() + { + return mSupplyZoneStyle; + } + + /** + * Set Supply Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void SupplyZoneStyle(ENUM_LINE_STYLE value) + { + mSupplyZoneStyle = value; + } + + /** + * Get Supply Zone Detecting Period ... + * + * @return ( ENUM_TIMEFRAMES ) ... + */ + ENUM_TIMEFRAMES SupplyZonePeriod() + { + return mSupplyZonePeriod; + } + + /** + * Set Supply Zone Detecting Period ... + * + * @param value: ENUM_TIMEFRAMES member ... + */ + void SupplyZonePeriod(ENUM_TIMEFRAMES value) + { + mSupplyZonePeriod = value; + } + + // + // Demand Zone ... + + /** + * Get Draw Demand Zone State ... + * + * @return ( bool ) + */ + bool AllowDrawDemandZones() + { + return mAllowDrawDemandZones; + } + + /** + * Set Draw Demand Zone State ... + * + * @param value: Boolean ... + */ + void AllowDrawDemandZones(bool value) + { + mAllowDrawDemandZones = value; + } + + /** + * Get Demand Zone Width ... + * + * @return ( int ) + */ + int DemandZoneWidth() + { + return mDemandZoneWidth; + } + + /** + * Set Demand Zone Width ... + * + * @param value: Integer ... + */ + void DemandZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mDemandZoneWidth = value; + } + + /** + * Get Demand Zone Color ... + * + * @return ( color ) + */ + color DemandZoneColor() + { + return mDemandZoneColor; + } + + /** + * Set Demand Zone Color ... + * + * @param value: Color ... + */ + void DemandZoneColor(color value) + { + mDemandZoneColor = value; + } + + /** + * Get Demand Zone Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE DemandZoneStyle() + { + return mDemandZoneStyle; + } + + /** + * Set Demand Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void DemandZoneStyle(ENUM_LINE_STYLE value) + { + mDemandZoneStyle = value; + } + + /** + * Get Demand Zone Detecting Period ... + * + * @return ( ENUM_TIMEFRAMES ) ... + */ + ENUM_TIMEFRAMES DemandZonePeriod() + { + return mDemandZonePeriod; + } + + /** + * Set Demand Zone Detecting Period ... + * + * @param value: ENUM_TIMEFRAMES member ... + */ + void DemandZonePeriod(ENUM_TIMEFRAMES value) + { + mDemandZonePeriod = value; + } + // // Actions ... @@ -1351,6 +1571,8 @@ class XCPOI : public XSCBaseAlert // // Trading Days ... + + // int tradingDaysCount = ArraySize(mTradingDays); int tradingDayIDX = HasTradeDay(zDayBar.time); if (IsValidIndex(tradingDayIDX)) @@ -1403,6 +1625,8 @@ class XCPOI : public XSCBaseAlert // // Market Session ... + + // int marketSessionsCount = ArraySize(mMarketSessions); int sessionsCount = ArraySize(mSessions); bool isSessionFound = false; @@ -1501,7 +1725,12 @@ class XCPOI : public XSCBaseAlert } // - // Detect Swing High ... + // Swing Highs and Lows ... + + // + // Swing Highs ... + + // int swingHighsCount = ArraySize(mSwingHighs); bool isSingHigh = pBar.IsSimpleSwingHigh(SwingHighThreshold()); if (isSingHigh) @@ -1521,12 +1750,14 @@ class XCPOI : public XSCBaseAlert X_SWING_HIGH_DETECTED, state // ); - OnSwingHighDetected(pBar); - NotifySwingHighEventListeners(pBar); + OnSwingHighEvent(X_SWING_HIGH_DETECTED, pBar); + NotifySwingHighEventListeners(X_SWING_HIGH_DETECTED, pBar); } // - // Detect Swing Low ... + // Swing Lows ... + + // int swingLowsCount = ArraySize(mSwingLows); bool isSingLow = pBar.IsSimpleSwingLow(SwingLowThreshold()); if (isSingLow) @@ -1546,12 +1777,14 @@ class XCPOI : public XSCBaseAlert X_SWING_LOW_DETECTED, state // ); - OnSwingLowDetected(pBar); - NotifySwingLowEventListeners(pBar); + OnSwingLowEvent(X_SWING_LOW_DETECTED, pBar); + NotifySwingLowEventListeners(X_SWING_LOW_DETECTED, pBar); } // - // Detect Momentum Bar ... + // Momentum Bars ... + + // int momentumBarsCount = ArraySize(mMomentumBars); bool isStrongBar = cBar.IsStrong(MomentumBarPercent()); bool isSharpBullish = cBar.IsSharpBullish( @@ -1583,12 +1816,14 @@ class XCPOI : public XSCBaseAlert X_MOMENTUM_BAR_DETECTED, state // ); - OnMomentumBarDetected(cBar); - NotifyMomentumBarEventListeners(cBar); + OnMomentumBarEvent(X_MOMENTUM_BAR_DETECTED, cBar); + NotifyMomentumBarEventListeners(X_MOMENTUM_BAR_DETECTED, cBar); } // // Rejection Bars ... + + // int rejectionBarsCount = ArraySize(mRejectionBars); int rejectionBarLoopBackBarIndex = RejectionBarLoopBack() + 1; XOHCL iRBar; @@ -1628,13 +1863,18 @@ class XCPOI : public XSCBaseAlert X_REJECTION_BAR_DETECTED, state // ); - OnRejectionBarDetected(iRBar); - NotifyRejectionBarEventListeners(iRBar); + OnRejectionBarEvent(X_REJECTION_BAR_DETECTED, iRBar); + NotifyRejectionBarEventListeners(X_REJECTION_BAR_DETECTED, iRBar); } } // - // Support Zone ... + // Support and Resistance Zones ... + + // + // Support Zones ... + + // int supportZonesCount = ArraySize(mSupportZones); XOHCL support; bool hasSupport = cBar.HasSupport( @@ -1659,13 +1899,15 @@ class XCPOI : public XSCBaseAlert X_SUPPORT_ZONE_DETECTED, state // ); - OnSupportZoneDetected(support); - NotifySupportZoneEventListeners(support); + OnSupportZoneEvent(X_SUPPORT_ZONE_DETECTED, support); + NotifySupportZoneEventListeners(X_SUPPORT_ZONE_DETECTED, support); } } // // Resistance Zone ... + + // int resistanceZonesCount = ArraySize(mResistanceZones); XOHCL resistance; bool hasResistance = cBar.HasResistance( @@ -1690,8 +1932,265 @@ class XCPOI : public XSCBaseAlert X_RESISTANCE_ZONE_DETECTED, state // ); - OnResistanceZoneDetected(resistance); - NotifyResistanceZoneEventListeners(resistance); + OnResistanceZoneEvent(X_RESISTANCE_ZONE_DETECTED, resistance); + NotifyResistanceZoneEventListeners(X_RESISTANCE_ZONE_DETECTED, resistance); + } + } + + // + // Supply and Demand Zones ... + + // + // Supply Zones ... + + // + int supplyZonesCount = ArraySize(mSupplyZones); + datetime endTime = cBar.time; + XOHCL cSupplyBar; + bool isSupplyBarInited = cSupplyBar.Init( + Symbol(), + SupplyZonePeriod(), + 0 // + ); + if (isSupplyBarInited) + { + // + datetime lastSupplyBarTime = cSupplyBar + .GetLastBarTimeOfPeriod(Period()); + if (zBar.time == lastSupplyBarTime) + { + // + datetime startTime = cSupplyBar.time; + int cSupplyZonePeriodIndex = iBarShift( + Symbol(), + Period(), + cSupplyBar.time // + ); + + // + // Find Swings ... + XOHCL swings[]; + for (int i = 0; i < cSupplyZonePeriodIndex; i++) + { + // + XOHCL iBar; + bool isIBarInited = iBar.Init( + Symbol(), + Period(), + i // + ); + if (!isIBarInited) + { + continue; + } + + // + // Check is Bar Swing or not ... + bool isSwing = iBar.IsSimpleSwingHigh(); + if (!isSwing) + { + continue; + } + + // + AddRef( + iBar, + swings // + ); + } + + // + // Select Max Swing for Supply Zone ... + XOHCL selectedSwing; + int swingsCount = ArraySize(swings); + if (IsValidSize(swingsCount)) + { + // + for (int i = 0; i < swingsCount; i++) + { + // + XOHCL iSwing = swings[i]; + if (!selectedSwing.IsValid() || + selectedSwing.high < iSwing.high) + { + selectedSwing = iSwing; + } + } + } + + // + // Check Swing ... + if (selectedSwing.IsValid()) + { + // + XZone zone; + bool isInited = zone.Init( + selectedSwing.high, + selectedSwing.low, + ToString(X_POI_SUPPLY_ZONE) + "_" + ToString(SupplyZonePeriod()), + startTime, + endTime // + ); + if (isInited) + { + // + int zoneIDX = FindZoneIndex( + zone, + mSupplyZones // + ); + + // + if (!IsValidIndex(zoneIDX)) + { + // + AddRef( + zone, + mSupplyZones // + ); + + // + supplyZonesCount = ArraySize(mSupplyZones); + + // + DrawSupplyZones(); + + // + Add( + X_SUPPLY_ZONE_DETECTED, + state // + ); + OnSupplyZoneEvent(X_SUPPLY_ZONE_DETECTED, zone); + NotifySupplyZoneEventListeners(X_SUPPLY_ZONE_DETECTED, zone); + } + } + } + } + } + + // + // Demand Zones ... + + // + int demandZonesCount = ArraySize(mDemandZones); + endTime = cBar.time; + XOHCL cDemandBar; + bool isDemandBarInited = cDemandBar.Init( + Symbol(), + DemandZonePeriod(), + 0 // + ); + if (isDemandBarInited) + { + // + datetime lastDemandBarTime = cDemandBar + .GetLastBarTimeOfPeriod(Period()); + if (zBar.time == lastDemandBarTime) + { + // + datetime startTime = cDemandBar.time; + int cDemandZonePeriodIndex = iBarShift( + Symbol(), + Period(), + cDemandBar.time // + ); + + // + // Find Swings ... + XOHCL swings[]; + for (int i = 0; i < cDemandZonePeriodIndex; i++) + { + // + XOHCL iBar; + bool isIBarInited = iBar.Init( + Symbol(), + Period(), + i // + ); + if (!isIBarInited) + { + continue; + } + + // + // Check is Bar Swing or not ... + bool isSwing = iBar.IsSimpleSwingLow(); + if (!isSwing) + { + continue; + } + + // + AddRef( + iBar, + swings // + ); + } + + // + // Select Max Swing for Supply Zone ... + XOHCL selectedSwing; + int swingsCount = ArraySize(swings); + if (IsValidSize(swingsCount)) + { + // + for (int i = 0; i < swingsCount; i++) + { + // + XOHCL iSwing = swings[i]; + if (!selectedSwing.IsValid() || + selectedSwing.low > iSwing.low) + { + selectedSwing = iSwing; + } + } + } + + // + // Check Swing ... + if (selectedSwing.IsValid()) + { + // + XZone zone; + bool isInited = zone.Init( + selectedSwing.high, + selectedSwing.low, + ToString(X_POI_DEMAND_ZONE) + "_" + ToString(SupplyZonePeriod()), + startTime, + endTime // + ); + if (isInited) + { + // + int zoneIDX = FindZoneIndex( + zone, + mDemandZones // + ); + + // + if (!IsValidIndex(zoneIDX)) + { + // + AddRef( + zone, + mDemandZones // + ); + + // + demandZonesCount = ArraySize(mDemandZones); + + // + DrawDemandZones(); + + // + Add( + X_DEMAND_ZONE_DETECTED, + state // + ); + OnDemandZoneEvent(X_DEMAND_ZONE_DETECTED, zone); + NotifyDemandZoneEventListeners(X_DEMAND_ZONE_DETECTED, zone); + } + } + } } } @@ -1720,6 +2219,8 @@ class XCPOI : public XSCBaseAlert AllowDrawSwingLows(state); AllowDrawSwingHighs(state); AllowDrawTradingDays(state); + AllowDrawSupplyZones(state); + AllowDrawDemandZones(state); AllowDrawSupportZones(state); AllowDrawMomentumBars(state); AllowDrawRejectionBars(state); @@ -1752,6 +2253,8 @@ class XCPOI : public XSCBaseAlert AllowDrawSwingLows(state); AllowDrawSwingHighs(state); AllowDrawTradingDays(state); + AllowDrawSupplyZones(state); + AllowDrawDemandZones(state); AllowDrawSupportZones(state); AllowDrawMomentumBars(state); AllowDrawRejectionBars(state); @@ -1780,10 +2283,17 @@ class XCPOI : public XSCBaseAlert */ virtual void ApplyDefaultConfig() { + // + // Common ... + // ChartID(0); Window(0); + // + MaxNumberOfPOIs(10); + MaxNumberOfRequiredPOIs(2); + // // Trading Days ... TradingDaysStartColor(clrYellow); @@ -1858,22 +2368,24 @@ class XCPOI : public XSCBaseAlert SessionOpenHours(9); // - MaxNumberOfPOIs(10); - MaxNumberOfRequiredPOIs(2); + // Swing High and Low (s) ... // + // Swing Highs ... SwingHighWidth(5); SwingHighThreshold(3); SwingHighArrowCode(108); SwingHighColor(clrMagenta); // + // Swing Lows ... SwingLowWidth(5); SwingLowThreshold(3); SwingLowArrowCode(108); SwingLowColor(clrAqua); // + // Momentum Bars ... MomentumBarPercent(55); MomentumBarLoopBack(3); MomentumBarSharpRatio(1.2); @@ -1884,6 +2396,7 @@ class XCPOI : public XSCBaseAlert MomentumBarBearishColor(clrMagenta); // + // Rejection Bars ... RejectionBarPercent(55); RejectionBarLoopBack(5); RejectionBarSharpRatio(1.5); @@ -1894,6 +2407,10 @@ class XCPOI : public XSCBaseAlert RejectionBarBearishColor(clrMagenta); // + // Support and Resistance Zones ... + + // + // Support Zones ... SupportZoneLoopBack(52); SupportZoneWidth(1); SupportZoneColor(clrLime); @@ -1901,12 +2418,30 @@ class XCPOI : public XSCBaseAlert SupportZonePriceType(X_PRICE_CLOSE); // + // Resistance Zones ... ResistanceZoneLoopBack(52); ResistanceZoneWidth(1); ResistanceZoneColor(clrRed); ResistanceZoneStyle(STYLE_DOT); ResistanceZonePriceType(X_PRICE_CLOSE); + // + // Supply and Deman Zones ... + + // + // Supply Zones ... + SupplyZoneWidth(1); + SupplyZoneColor(clrDarkRed); + SupplyZoneStyle(STYLE_DASH); + SupplyZonePeriod(GetHindMostPeriod(Period())); + + // + // Demand Zones ... + DemandZoneWidth(1); + DemandZoneColor(clrDarkGreen); + DemandZoneStyle(STYLE_DASH); + DemandZonePeriod(GetHindMostPeriod(Period())); + // } @@ -1936,6 +2471,9 @@ class XCPOI : public XSCBaseAlert // // Event Listeners ... + // + // Trading Days ... + /** * Calls When new Trading Day Event Happens ... * @@ -1961,6 +2499,9 @@ class XCPOI : public XSCBaseAlert ); } + // + // Market Sessions ... + /** * Calls When new Market Session Event Happens ... * @@ -1988,17 +2529,27 @@ class XCPOI : public XSCBaseAlert ); } + // + // Swings ... + + // + // Swing Highs ... + /** - * Calls When new Swing High Detected ... + * Calls When new Swing High Event ... * + * @param event: ENUM_XPOI_EVENTS member ... * @param bar: XOHCL instance ... */ - virtual void OnSwingHighDetected(XOHCL &bar) + virtual void OnSwingHighEvent( + ENUM_XPOI_EVENTS event, + XOHCL &bar // + ) { } /** - * Register an Event Listener for New Swing High Detected ... + * Register an Event Listener for New Swing High Event ... * * @param listener: TXOHCLEventHandler instance ... */ @@ -2011,17 +2562,24 @@ class XCPOI : public XSCBaseAlert ); } + // + // Swing Lows ... + /** * Calls When new Swing Low Detected ... * + * @param event: ENUM_XPOI_EVENTS member ... * @param bar: XOHCL instance ... */ - virtual void OnSwingLowDetected(XOHCL &bar) + virtual void OnSwingLowEvent( + ENUM_XPOI_EVENTS event, + XOHCL &bar // + ) { } /** - * Register an Event Listener for New Swing Low Detected ... + * Register an Event Listener for New Swing Low Event ... * * @param listener: TXOHCLEventHandler instance ... */ @@ -2034,17 +2592,24 @@ class XCPOI : public XSCBaseAlert ); } + // + // Momentum Bar ... + /** - * Calls When new Momentum Bar Detected ... + * Calls When new Momentum Bar Event ... * + * @param event: ENUM_XPOI_EVENTS member ... * @param bar: XOHCL instance ... */ - virtual void OnMomentumBarDetected(XOHCL &bar) + virtual void OnMomentumBarEvent( + ENUM_XPOI_EVENTS event, + XOHCL &bar // + ) { } /** - * Register an Event Listener for New Momentum Bar Detected ... + * Register an Event Listener for New Momentum Bar Event ... * * @param listener: TXOHCLEventHandler instance ... */ @@ -2057,17 +2622,24 @@ class XCPOI : public XSCBaseAlert ); } + // + // Rejection Bar ... + /** - * Calls When new Rejection Bar Detected ... + * Calls When new Rejection Bar Event ... * + * @param event: ENUM_XPOI_EVENTS member ... * @param bar: XOHCL instance ... */ - virtual void OnRejectionBarDetected(XOHCL &bar) + virtual void OnRejectionBarEvent( + ENUM_XPOI_EVENTS event, + XOHCL &bar // + ) { } /** - * Register an Event Listener for New Rejection Bar Detected ... + * Register an Event Listener for New Rejection Bar Event ... * * @param listener: TXOHCLEventHandler instance ... */ @@ -2080,17 +2652,27 @@ class XCPOI : public XSCBaseAlert ); } + // + // Support and Resistance Zones ... + + // + // Support Zones ... + /** - * Calls When new Support Zone Detected ... + * Calls When new Support Zone Event ... * + * @param event: ENUM_XPOI_EVENTS member ... * @param bar: XOHCL instance ... */ - virtual void OnSupportZoneDetected(XOHCL &bar) + virtual void OnSupportZoneEvent( + ENUM_XPOI_EVENTS event, + XOHCL &bar // + ) { } /** - * Register an Event Listener for New Support Zone Detected ... + * Register an Event Listener for New Support Zone Event ... * * @param listener: TXOHCLEventHandler instance ... */ @@ -2103,17 +2685,24 @@ class XCPOI : public XSCBaseAlert ); } + // + // Resistance Zones ... + /** - * Calls When new Resistance Zone Detected ... + * Calls When new Resistance Zone Event ... * + * @param event: ENUM_XPOI_EVENTS member ... * @param bar: XOHCL instance ... */ - virtual void OnResistanceZoneDetected(XOHCL &bar) + virtual void OnResistanceZoneEvent( + ENUM_XPOI_EVENTS event, + XOHCL &bar // + ) { } /** - * Register an Event Listener for New Resistance Zone Detected ... + * Register an Event Listener for New Resistance Zone Event ... * * @param listener: TXOHCLEventHandler instance ... */ @@ -2126,6 +2715,69 @@ class XCPOI : public XSCBaseAlert ); } + // + // Supply and Demand Zones ... + + // + // Supply Zones ... + + /** + * Calls When new Supply Zone Event ... + * + * @param event: ENUM_XPOI_EVENTS member ... + * @param zone: XZone instance ... + */ + virtual void OnSupplyZoneEvent( + ENUM_XPOI_EVENTS event, + XZone &zone // + ) + { + } + + /** + * Register an Event Listener for New Supply Zone Event ... + * + * @param listener: TXZoneEventHandler instance ... + */ + void AddSupplyZoneEventListener(TXZoneEventHandler listener) + { + // + Add( + listener, + mSupplyZoneEventListeners // + ); + } + + // + // Demand Zones ... + + /** + * Calls When new Demand Zone Event ... + * + * @param event: ENUM_XPOI_EVENTS member ... + * @param zone: XZone instance ... + */ + virtual void OnDemandZoneEvent( + ENUM_XPOI_EVENTS event, + XZone &zone // + ) + { + } + + /** + * Register an Event Listener for New Demand Zone Event ... + * + * @param listener: TXZoneEventHandler instance ... + */ + // void AddDemandZoneEventListener(TXZoneEventHandler listener) + // { + // // + // Add( + // listener, + // mDemandZoneEventListeners // + // ); + // } + // protected: // @@ -2207,7 +2859,7 @@ class XCPOI : public XSCBaseAlert // Detect POI(s) based On Current Bar ... // - // XTradeDays ... + // Trade Days ... int daysCount = ArraySize(mTradingDays); if (daysCount < requiredPOIs) { @@ -2259,7 +2911,7 @@ class XCPOI : public XSCBaseAlert } // - // Session ... + // Market Sessions ... int sessionsCount = ArraySize(mSessions); int marketSessionsCount = ArraySize(mMarketSessions); if (IsValidSize(sessionsCount) && @@ -2323,6 +2975,9 @@ class XCPOI : public XSCBaseAlert } } + // + // Swning Highs and Lows ... + // // Swing Highs ... int swingHighsCount = ArraySize(mSwingHighs); @@ -2344,7 +2999,7 @@ class XCPOI : public XSCBaseAlert } // - // Swing Low ... + // Swing Lows ... int swingLowsCount = ArraySize(mSwingLows); if (swingLowsCount < requiredPOIs) { @@ -2436,7 +3091,10 @@ class XCPOI : public XSCBaseAlert } // - // Support Zone ... + // Support nad Resistance Zones ... + + // + // Support Zones ... int supportZonesCount = ArraySize(mSupportZones); if (supportZonesCount < requiredPOIs) { @@ -2461,7 +3119,7 @@ class XCPOI : public XSCBaseAlert } // - // Resistance Zone ... + // Resistance Zones ... int resistanceZonesCount = ArraySize(mResistanceZones); if (resistanceZonesCount < requiredPOIs) { @@ -2485,29 +3143,239 @@ class XCPOI : public XSCBaseAlert } } + // + // Supply and Demand Zones ... + + // + // Supply Zones ... + int supplyZonesCount = ArraySize(mSupplyZones); + if (supplyZonesCount < requiredPOIs) + { + // + datetime endTime = cBar.time; + + // + datetime cSupplyZoneStartTime = iTime( + Symbol(), + SupplyZonePeriod(), + supplyZonesCount + 1 // + ); + datetime startTime = cSupplyZoneStartTime; + + // + int cSupplyZoneStartIndex = iBarShift( + Symbol(), + Period(), + cSupplyZoneStartTime // + ); + + // + XOHCL swings[]; + for (int i = 0; i < cSupplyZoneStartIndex; i++) + { + // + XOHCL iBar; + bool isIBarInited = iBar.Init( + Symbol(), + Period(), + i // + ); + if (!isIBarInited) + { + continue; + } + + // + // Check is Bar Swing or not ... + bool isSwing = iBar.IsSimpleSwingHigh(); + if (!isSwing) + { + continue; + } + + // + AddRef( + iBar, + swings // + ); + } + + // + XOHCL selectedSwing; + int swingsCount = ArraySize(swings); + if (IsValidSize(swingsCount)) + { + // + for (int i = 0; i < swingsCount; i++) + { + // + XOHCL iSwing = swings[i]; + if (!selectedSwing.IsValid() || + selectedSwing.high < iSwing.high) + { + selectedSwing = iSwing; + } + } + } + + // + if (selectedSwing.IsValid()) + { + // + XZone zone; + bool isInited = zone.Init( + selectedSwing.high, + selectedSwing.low, + ToString(X_POI_SUPPLY_ZONE) + "_" + ToString(SupplyZonePeriod()), + startTime, + endTime // + ); + if (isInited) + { + // + AddRef( + zone, + mSupplyZones // + ); + + // + supplyZonesCount = ArraySize(mSupplyZones); + } + } + } + + // + // Demand Zones ... + int demandZonesCount = ArraySize(mDemandZones); + if (demandZonesCount < requiredPOIs) + { + // + datetime endTime = cBar.time; + + // + datetime cDemandZoneStartTime = iTime( + Symbol(), + DemandZonePeriod(), + demandZonesCount + 1 // + ); + datetime startTime = cDemandZoneStartTime; + + // + int cDemandZoneStartIndex = iBarShift( + Symbol(), + Period(), + cDemandZoneStartTime // + ); + + // + XOHCL swings[]; + for (int i = 0; i < cDemandZoneStartIndex; i++) + { + // + XOHCL iBar; + bool isIBarInited = iBar.Init( + Symbol(), + Period(), + i // + ); + if (!isIBarInited) + { + continue; + } + + // + // Check is Bar Swing or not ... + bool isSwing = iBar.IsSimpleSwingLow(); + if (!isSwing) + { + continue; + } + + // + AddRef( + iBar, + swings // + ); + } + + // + XOHCL selectedSwing; + int swingsCount = ArraySize(swings); + if (IsValidSize(swingsCount)) + { + // + for (int i = 0; i < swingsCount; i++) + { + // + XOHCL iSwing = swings[i]; + if (!selectedSwing.IsValid() || + selectedSwing.low > iSwing.low) + { + selectedSwing = iSwing; + } + } + } + + // + if (selectedSwing.IsValid()) + { + // + XZone zone; + bool isInited = zone.Init( + selectedSwing.high, + selectedSwing.low, + ToString(X_POI_DEMAND_ZONE) + "_" + ToString(SupplyZonePeriod()), + startTime, + endTime // + ); + if (isInited) + { + // + AddRef( + zone, + mDemandZones // + ); + + // + demandZonesCount = ArraySize(mDemandZones); + } + } + } + // // Detect Required Conditions for Loop ... // // + // Market Sessions Requirements ... bool isNeedMoreMarketSessions = (!IsValidSize(sessionsCount) ? true : marketSessionsCount < (sessionsCount * requiredPOIs)); canContinue = // + // Trade Days ... daysCount < requiredPOIs || // + // Market Sessions ... isNeedMoreMarketSessions || // + // Swing High and Low (s) ... swingHighsCount < requiredPOIs || swingLowsCount < requiredPOIs || // + // Momentum Bars ... momentumBarsCount < requiredPOIs || // + // Rejection Bars ... rejectionBarsCount < requiredPOIs || // + // Support and Resistance Zones ... supportZonesCount < requiredPOIs || - resistanceZonesCount < requiredPOIs + resistanceZonesCount < requiredPOIs || + // + // Supply and Demand Zones ... + supplyZonesCount < requiredPOIs || + demandZonesCount < requiredPOIs // ; if (canContinue) @@ -2643,6 +3511,38 @@ class XCPOI : public XSCBaseAlert ); Clean(tmpBars); + // + XZone tmpZones[]; + + // + // Supply and Demand Zones ... + + // + Copy( + mSupplyZones, + tmpZones // + ); + Clean(mSupplyZones); + ArrayReverse(tmpZones); + Copy( + tmpZones, + mSupplyZones // + ); + Clean(tmpZones); + + // + Copy( + mDemandZones, + tmpZones // + ); + Clean(mDemandZones); + ArrayReverse(tmpZones); + Copy( + tmpZones, + mDemandZones // + ); + Clean(tmpZones); + // // ... @@ -2678,6 +3578,10 @@ class XCPOI : public XSCBaseAlert // DestroySupportZones(); DestroyResistanceZones(); + + // + DestroySupplyZones(); + DestroyDemandZones(); } /** @@ -2744,6 +3648,22 @@ class XCPOI : public XSCBaseAlert Clean(mResistanceZones); } + /** + * Destroy Supply Zones ... + */ + void DestroySupplyZones() + { + Clean(mSupplyZones); + } + + /** + * Destroy Demand Zones ... + */ + void DestroyDemandZones() + { + Clean(mDemandZones); + } + // // Draw Actions ... @@ -2771,6 +3691,10 @@ class XCPOI : public XSCBaseAlert // DrawSupportZones(); DrawResistanceZones(); + + // + DrawSupplyZones(); + DrawDemandZones(); } /** @@ -3101,6 +4025,88 @@ class XCPOI : public XSCBaseAlert } } + /** + * Draw Supply Zones ... + */ + void DrawSupplyZones() + { + // + bool allow = AllowDrawSupplyZones(); + if (!allow) + { + return; + } + + // + int count = ArraySize(mSupplyZones); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + XZone iSupplyZone = mSupplyZones[i]; + + // + string iName = iSupplyZone.GetTag(); + int iIDX = HasObject( + iName, + mSupplyZoneObjects // + ); + if (IsValidIndex(iIDX)) + { + continue; + } + + // + CreateSupplyZoneObject(iSupplyZone, iName); + } + } + + /** + * Draw Demand Zones ... + */ + void DrawDemandZones() + { + // + bool allow = AllowDrawDemandZones(); + if (!allow) + { + return; + } + + // + int count = ArraySize(mDemandZones); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + XZone iDemandZone = mDemandZones[i]; + + // + string iName = iDemandZone.GetTag(); + int iIDX = HasObject( + iName, + mDemandZoneObjects // + ); + if (IsValidIndex(iIDX)) + { + continue; + } + + // + CreateDemandZoneObject(iDemandZone, iName); + } + } + // /** @@ -3111,6 +4117,8 @@ class XCPOI : public XSCBaseAlert // DestroySwingLowObjects(); DestroySwingHighObjects(); + DestroySupplyZoneObjects(); + DestroyDemandZoneObjects(); DestroyMomentumBarObjects(); DestroySupportZoneObjects(); DestroyRejectionBarObjects(); @@ -3183,6 +4191,22 @@ class XCPOI : public XSCBaseAlert mResistanceZoneObjects.Clear(); } + /** + * Destroy Supply Zone Drawn Objects ... + */ + void DestroySupplyZoneObjects() + { + mSupplyZoneObjects.Clear(); + } + + /** + * Destroy Demand Zone Drawn Objects ... + */ + void DestroyDemandZoneObjects() + { + mDemandZoneObjects.Clear(); + } + // // ... @@ -3237,6 +4261,9 @@ class XCPOI : public XSCBaseAlert // // Event Handler Notifiers ... + // + // Trading Days ... + /** * Notify New Trading Day Event Handlers ... * @@ -3262,6 +4289,9 @@ class XCPOI : public XSCBaseAlert } } + // + // Market Sessions ... + /** * Notify New Market Session Event Handlers ... * @@ -3289,12 +4319,22 @@ class XCPOI : public XSCBaseAlert } } + // + // Swings ... + + // + // Swing Highs ... + /** * Notify New Swing High Point Event Handlers ... * + * @param event: ENUM_XPOI_EVENTS member ... * @param bar: XOHCL instance ... */ - void NotifySwingHighEventListeners(XOHCL &bar) + void NotifySwingHighEventListeners( + ENUM_XPOI_EVENTS event, + XOHCL &bar // + ) { // if (!bar.IsValid()) @@ -3314,16 +4354,23 @@ class XCPOI : public XSCBaseAlert { // TXOHCLEventHandler iListener = mSwingHighEventListeners[i]; - iListener(bar); + iListener(event, bar); } } + // + // Swing Lows ... + /** * Notify New Swing Low Point Event Handlers ... * + * @param event: ENUM_XPOI_EVENTS member ... * @param bar: XOHCL instance ... */ - void NotifySwingLowEventListeners(XOHCL &bar) + void NotifySwingLowEventListeners( + ENUM_XPOI_EVENTS event, + XOHCL &bar // + ) { // if (!bar.IsValid()) @@ -3343,16 +4390,23 @@ class XCPOI : public XSCBaseAlert { // TXOHCLEventHandler iListener = mSwingLowEventListeners[i]; - iListener(bar); + iListener(event, bar); } } + // + // Momentum Bars ... + /** * Notify New Momentum Bar Event Handlers ... * + * @param event: ENUM_XPOI_EVENTS member ... * @param bar: XOHCL instance ... */ - void NotifyMomentumBarEventListeners(XOHCL &bar) + void NotifyMomentumBarEventListeners( + ENUM_XPOI_EVENTS event, + XOHCL &bar // + ) { // if (!bar.IsValid()) @@ -3372,16 +4426,23 @@ class XCPOI : public XSCBaseAlert { // TXOHCLEventHandler iListener = mMomentumBarEventListeners[i]; - iListener(bar); + iListener(event, bar); } } + // + // Rejection Bars ... + /** * Notify New Rejection Bar Event Handlers ... * + * @param event: ENUM_XPOI_EVENTS member ... * @param bar: XOHCL instance ... */ - void NotifyRejectionBarEventListeners(XOHCL &bar) + void NotifyRejectionBarEventListeners( + ENUM_XPOI_EVENTS event, + XOHCL &bar // + ) { // if (!bar.IsValid()) @@ -3401,16 +4462,26 @@ class XCPOI : public XSCBaseAlert { // TXOHCLEventHandler iListener = mRejectionBarEventListeners[i]; - iListener(bar); + iListener(event, bar); } } + // + // Support and Resistance Zones ... + + // + // Support Zones ... + /** * Notify New Support Zone Event Handlers ... * + * @param event: ENUM_XPOI_EVENTS member ... * @param bar: XOHCL instance ... */ - void NotifySupportZoneEventListeners(XOHCL &bar) + void NotifySupportZoneEventListeners( + ENUM_XPOI_EVENTS event, + XOHCL &bar // + ) { // if (!bar.IsValid()) @@ -3430,16 +4501,23 @@ class XCPOI : public XSCBaseAlert { // TXOHCLEventHandler iListener = mSupportZoneEventListeners[i]; - iListener(bar); + iListener(event, bar); } } + // + // Resistance Zones ... + /** * Notify New Resistance Zone Event Handlers ... * + * @param event: ENUM_XPOI_EVENTS member ... * @param bar: XOHCL instance ... */ - void NotifyResistanceZoneEventListeners(XOHCL &bar) + void NotifyResistanceZoneEventListeners( + ENUM_XPOI_EVENTS event, + XOHCL &bar // + ) { // if (!bar.IsValid()) @@ -3459,7 +4537,82 @@ class XCPOI : public XSCBaseAlert { // TXOHCLEventHandler iListener = mResistanceZoneEventListeners[i]; - iListener(bar); + iListener(event, bar); + } + } + + // + // Supply and Demand Zones ... + + // + // Supply Zones ... + + /** + * Notify New Supply Zone Event Handlers ... + * + * @param event: ENUM_XPOI_EVENTS member ... + * @param bar: XZone instance ... + */ + void NotifySupplyZoneEventListeners( + ENUM_XPOI_EVENTS event, + XZone &zone // + ) + { + // + if (!zone.IsValid()) + { + return; + } + + // + int count = ArraySize(mSupplyZoneEventListeners); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TXZoneEventHandler iListener = mSupplyZoneEventListeners[i]; + iListener(event, zone); + } + } + + // + // Demand Zones ... + + /** + * Notify New Demand Zone Event Handlers ... + * + * @param event: ENUM_XPOI_EVENTS member ... + * @param bar: XZone instance ... + */ + void NotifyDemandZoneEventListeners( + ENUM_XPOI_EVENTS event, + XZone &zone // + ) + { + // + if (!zone.IsValid()) + { + return; + } + + // + int count = ArraySize(mDemandZoneEventListeners); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TXZoneEventHandler iListener = mDemandZoneEventListeners[i]; + iListener(event, zone); } } @@ -3472,6 +4625,8 @@ class XCPOI : public XSCBaseAlert Clean(mSwingLowEventListeners); Clean(mSwingHighEventListeners); Clean(mTradingDayEventListeners); + Clean(mSupplyZoneEventListeners); + Clean(mDemandZoneEventListeners); Clean(mMomentumBarEventListeners); Clean(mSupportZoneEventListeners); Clean(mRejectionBarEventListeners); @@ -3927,6 +5082,51 @@ class XCPOI : public XSCBaseAlert } // + + /** + * Find Specified Zone Index ... + * + * @param zone: XZone instance + * @param list: XZone Collection ... + * + * @return ( int ) + */ + int FindZoneIndex( + XZone &zone, + XZone &list[] // + ) + { + // + int result = -1; + + // + int count = ArraySize(list); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XZone iZone = list[i]; + + // + if (iZone.upper == zone.upper && + iZone.lower == zone.lower) + { + // + result = i; + break; + } + } + + // + return result; + } + + // private: // @@ -4474,11 +5674,111 @@ class XCPOI : public XSCBaseAlert bool mAllowDrawSupplyZones; // Draw Supply Zone ... int mSupplyZoneWidth; // Supply Zone Width ... color mSupplyZoneColor; // Supply Zone Color ... - ENUM_LINE_STYLE mResistanceZoneStyle; // Supply Zone Style ... + ENUM_LINE_STYLE mSupplyZoneStyle; // Supply Zone Style ... + ENUM_TIMEFRAMES mSupplyZonePeriod; // Supply Zone Detection Period ... XZone mSupplyZones[]; // Supply Zones ... CArrayObj mSupplyZoneObjects; // Supply Zone Chart Objects ... TXZoneEventHandler mSupplyZoneEventListeners[]; // Supply Zone Event Listeners ... + /** + * Create an Object to Represent Supply Zones on Chart ... + + * @param bar: XZone instance ... + * @param name: String ... + */ + void CreateSupplyZoneObject( + XZone &zone, + string name // + ) + { + // + if (!zone.IsValid() || + !IsValid(name)) + { + return; + } + + // + XCSupplyZoneObject *iObj; + iObj = new XCSupplyZoneObject(); + bool isCreated = iObj.CreateByZone( + ChartID(), + name, + Window(), + zone, + NULL, // Object Prefix ... + true // Force Draw Rect ... + ); + if (!isCreated) + { + return; + } + + // + // Configure Object ... + iObj.ZoneColor(SupplyZoneColor()); + iObj.ZoneStyle(SupplyZoneStyle()); + iObj.ZoneWidth(SupplyZoneWidth()); + + // + mSupplyZoneObjects.Add(iObj); + } + + // + // Demand Zone ... + bool mAllowDrawDemandZones; // Draw Demand Zone ... + int mDemandZoneWidth; // Demand Zone Width ... + color mDemandZoneColor; // Demand Zone Color ... + ENUM_LINE_STYLE mDemandZoneStyle; // Demand Zone Style ... + ENUM_TIMEFRAMES mDemandZonePeriod; // Demand Zone Detection Period ... + XZone mDemandZones[]; // Demand Zones ... + CArrayObj mDemandZoneObjects; // Demand Zone Chart Objects ... + TXZoneEventHandler mDemandZoneEventListeners[]; // Demand Zone Event Listeners ... + + /** + * Create an Object to Represent Demand Zones on Chart ... + + * @param bar: XZone instance ... + * @param name: String ... + */ + void CreateDemandZoneObject( + XZone &zone, + string name // + ) + { + // + if (!zone.IsValid() || + !IsValid(name)) + { + return; + } + + // + XCDemandZoneObject *iObj; + iObj = new XCDemandZoneObject(); + bool isCreated = iObj.CreateByZone( + ChartID(), + name, + Window(), + zone, + NULL, // Object Prefix ... + true // Force Draw Rect ... + ); + if (!isCreated) + { + return; + } + + // + // Configure Object ... + iObj.ZoneColor(DemandZoneColor()); + iObj.ZoneStyle(DemandZoneStyle()); + iObj.ZoneWidth(DemandZoneWidth()); + + // + mDemandZoneObjects.Add(iObj); + } + // }; diff --git a/Experts/x-saherelm.x-121.smc.ea.mq5 b/Experts/x-saherelm.x-121.smc.ea.mq5 index 7ab56f78..157e5710 100644 --- a/Experts/x-saherelm.x-121.smc.ea.mq5 +++ b/Experts/x-saherelm.x-121.smc.ea.mq5 @@ -431,9 +431,13 @@ bool InitEA() _Period // ); eaPOI.EnableDrawPOIs(); - eaPOI.AllowDrawSwingHighs(false); eaPOI.AllowDrawSwingLows(false); + eaPOI.AllowDrawSwingHighs(false); eaPOI.AllowDrawMomentumBars(false); + eaPOI.AllowDrawSupportZones(false); + eaPOI.AllowDrawRejectionBars(false); + eaPOI.AllowDrawMarketSessions(false); + eaPOI.AllowDrawResistanceZones(false); eaPOI.Init(); // // diff --git a/Libraries/x-saherelm.x-poi.lib.mq5 b/Libraries/x-saherelm.x-poi.lib.mq5 index 83f627b2..409a1c62 100644 --- a/Libraries/x-saherelm.x-poi.lib.mq5 +++ b/Libraries/x-saherelm.x-poi.lib.mq5 @@ -338,6 +338,10 @@ struct XZone double lower; string prefix; + // + datetime from; + datetime to; + // // Constructor ... void XZone() @@ -349,7 +353,9 @@ struct XZone bool Init( double _upper, double _lower, - string _prefix // + string _prefix, + datetime _from, + datetime _to // ) { // @@ -360,16 +366,22 @@ struct XZone _upper > 0 && _lower > 0 && _upper > _lower && - IsValid(_prefix); + IsValid(_prefix) && + IsValid(_from); if (!result) { return result; } + // + NormalizeTime(_to); + // upper = _upper; lower = _lower; prefix = _prefix; + from = _from; + to = _to; // result = IsValid(); @@ -386,6 +398,8 @@ struct XZone lower = 0; // + to = NULL; + from = NULL; prefix = NULL; } @@ -399,6 +413,8 @@ struct XZone result = upper > 0 && lower > 0 && upper > lower && + IsValid(to) && + IsValid(from) && IsValid(prefix); // @@ -425,6 +441,7 @@ struct XZone // // XOHCL Event Handler ... typedef void (*TXOHCLEventHandler)( + ENUM_XPOI_EVENTS event, XOHCL &bar // ); @@ -444,7 +461,8 @@ typedef void (*TXSessionEventHandler)( // // Zone Handler ... typedef void (*TXZoneEventHandler)( - ENUM_XPOI_EVENTS event // + ENUM_XPOI_EVENTS event, + XZone &zone // ); //