From 849fc73ee26d68c5dd04e3628dde98dd15112131 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Thu, 14 Nov 2024 00:31:40 +0330 Subject: [PATCH] Finish Order Blocks Detection ... --- Classes/x-saherelm.x-bar.analyser.class.mq5 | 242 +++++++++++ Classes/x-saherelm.x-cobject.class.mq5 | 140 +++++- Classes/x-saherelm.x-poi.class.mq5 | 444 ++++++++++++++++++++ Classes/x-saherelm.x-poi.drawer.class.mq5 | 317 ++++++++++---- 4 files changed, 1048 insertions(+), 95 deletions(-) diff --git a/Classes/x-saherelm.x-bar.analyser.class.mq5 b/Classes/x-saherelm.x-bar.analyser.class.mq5 index 06856b74..83f1926c 100644 --- a/Classes/x-saherelm.x-bar.analyser.class.mq5 +++ b/Classes/x-saherelm.x-bar.analyser.class.mq5 @@ -223,6 +223,97 @@ class XCBarAnalyser : public XCBase return result; } + /** + * Detect Consolidation Range ... + * + * @param index: Integer, Start Bar Index ... + * @param range: Integer, Range of Bars ... + * @param maxRange: Consolidation Price Range in Points ... + * @param symbol: String, Symbol ... + * @param period: ENUM_TIMEFRAMES member, Period ... + * + * @return ( bool ) + */ + bool IsConsolidating( + int index, + int range, + double maxRange, + string symbol = NULL, + ENUM_TIMEFRAMES period = NULL // + ) + { + // + bool result = false; + + // + if (index < 0) + { + index = 0; + } + + // + if (range < 1) + { + range = 1; + } + + // + if (maxRange < 1) + { + maxRange = 1; + } + + // + // Normalize ... + symbol = NormalizeSymbol(symbol); + period = NormalizePeriod(period); + + // + // Point Value ... + double point = GetPoints(symbol); + + // + double high = iHigh( + symbol, + period, + index // + ); + double low = iLow( + symbol, + period, + index // + ); + + // + // Detect Range High and Low ... + for (int i = 1; i < range; i++) + { + // + double iH = iHigh( + symbol, + period, + index + i // + ); + + // + double iL = iLow( + symbol, + period, + index + i // + ); + + // + high = MathMax(high, iH); + low = MathMin(low, iL); + } + + // + result = (high - low) <= (maxRange * point); + + // + return result; + } + // // Commons ... @@ -909,6 +1000,157 @@ class XCBarAnalyser : public XCBase return result; } + // + // Order Blocks ... + + /** + * Detect an Order Block Based on Given Bar ... + * + * @param bar: XOHCL instance, Specified Start Bar ... + * @param ob: XOHCL instance, Fill it if Order Block Found ... + * @param dir: ENUM_X_DIRECTION member, Specified Founded Order Block Direction ... + * @param sameBars: Integer, Specified Min Same Bars for Detecting Order Block ... + * + * @return ( bool ) + */ + bool HasOrderBlock( + XOHCL &bar, + XOHCL &ob, + ENUM_X_DIRECTION &dir, + int sameBars = 3 // + ) + { + // + bool result = false; + + // + ob.Clean(); + dir = X_DIRECTION_NONE; + + // + if (sameBars < 1) + { + sameBars = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + bool canContinue = true; + int sameBullishBarsFounded = 0; + int sameBearishBarsFounded = 0; + bool canContinueForBullish = true; + bool canContinueForBearish = true; + while (canContinue) + { + // + XOHCL iBar; + result = iBar.Init( + bar.symbol, + bar.period, + index // + ); + if (!result) + { + break; + } + + // + bool isBullish = iBar.IsBullish(); + bool isBearish = iBar.IsBearish(); + result = isBullish || + isBearish; + if (!result) + { + break; + } + + // + if (isBullish) + { + // + sameBullishBarsFounded++; + canContinueForBearish = false; + } + else + { + // + sameBearishBarsFounded++; + canContinueForBullish = false; + } + + // + result = canContinueForBullish || + canContinueForBearish; + if (!result) + { + break; + } + + // + canContinueForBullish = + canContinueForBullish && + sameBullishBarsFounded > 0; + + // + canContinueForBearish = + canContinueForBearish && + sameBearishBarsFounded > 0; + + // + canContinue = + canContinueForBullish || + canContinueForBearish; + if (canContinue) + { + index++; + } + } + + // + bool hasBullishOB = + sameBullishBarsFounded >= sameBars; + + // + bool hasBearishOB = + sameBearishBarsFounded >= sameBars; + + // + result = hasBullishOB || + hasBearishOB; + if (!result) + { + return result; + } + + // + int obIndex = index; + result = ob.Init( + bar.symbol, + bar.period, + obIndex // + ); + if (!result) + { + return result; + } + + // + dir = + hasBullishOB + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + // protected: // diff --git a/Classes/x-saherelm.x-cobject.class.mq5 b/Classes/x-saherelm.x-cobject.class.mq5 index 06cccc5c..bd6b1305 100644 --- a/Classes/x-saherelm.x-cobject.class.mq5 +++ b/Classes/x-saherelm.x-cobject.class.mq5 @@ -1136,7 +1136,8 @@ class XCResistanceZoneObject : public XCZoneObject // // Supply Zone ... -class XCSupplyZoneObject : public XCZoneObject { +class XCSupplyZoneObject : public XCZoneObject +{ // public: // @@ -1200,7 +1201,8 @@ class XCSupplyZoneObject : public XCZoneObject { // // Demand Zone ... -class XCDemandZoneObject : public XCZoneObject { +class XCDemandZoneObject : public XCZoneObject +{ // public: // @@ -1258,7 +1260,139 @@ class XCDemandZoneObject : public XCZoneObject { */ virtual ENUM_XCHARTOBJECTS Type() { - return X_SUPPLY_ZONE_OBJ; + return X_DEMAND_ZONE_OBJ; + } +}; + +// +// Bullish Order Block ... +class XCBullishOrderBlockObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCOrderBlock instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCOrderBlock &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBullish(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BULLISH_ORDERBLOCK_OBJ; + } +}; + +// +// Bearish Order Block ... +class XCBearishOrderBlockObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCOrderBlock instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCOrderBlock &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBearish(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BULLISH_ORDERBLOCK_OBJ; } }; diff --git a/Classes/x-saherelm.x-poi.class.mq5 b/Classes/x-saherelm.x-poi.class.mq5 index 29d6019e..4e5e7711 100644 --- a/Classes/x-saherelm.x-poi.class.mq5 +++ b/Classes/x-saherelm.x-poi.class.mq5 @@ -377,6 +377,36 @@ class XCPOIDetector : public XCBaseAlert mSupplyAndDemandRange = value; } + // + // Order Blocks ... + + /** + * Get Order Blocks Detection Bars ... + * + * @return ( int ) + */ + int OrderBlocksSameBars() + { + return mOrderBlocksSameBars; + } + + /** + * Set Order Blocks Detection Bars ... + * + * @param value: Argument 1 + */ + void OrderBlocksSameBars(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mOrderBlocksSameBars = value; + } + // // Actions ... @@ -768,6 +798,68 @@ class XCPOIDetector : public XCBaseAlert } } + // + // Order Blocks ... + int obSameBars = OrderBlocksSameBars(); + if (obSameBars > 0) + { + // + // Bullish Order Block ... + isDetected = DetectBullishOrderBlock(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BULLISH_ORDERBLOCK_DETECTED; + XCOrderBlock *param; + bool hasItem = GetLastItem( + param, + mBullishOrderBlocks // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Bearish Order Block ... + isDetected = DetectBearishOrderBlock(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BEARISH_ORDERBLOCK_DETECTED; + XCOrderBlock *param; + bool hasItem = GetLastItem( + param, + mBearishOrderBlocks // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + } + // ValidatePOIs(cBar); @@ -863,6 +955,10 @@ class XCPOIDetector : public XCBaseAlert // Clean(mSupplyZones); Clean(mDemandZones); + + // + Clean(mBullishOrderBlocks); + Clean(mBearishOrderBlocks); } /** @@ -911,6 +1007,9 @@ class XCPOIDetector : public XCBaseAlert // SupplyAndDemandRange(144); + + // + OrderBlocksSameBars(3); } // @@ -983,6 +1082,10 @@ class XCPOIDetector : public XCBaseAlert int supplyZonesCount = 0; int demandZonesCount = 0; + // + int bullishOrderBlocksCount = 0; + int bearishOrderBlocksCount = 0; + // bool canContinue = true; @@ -1067,6 +1170,28 @@ class XCPOIDetector : public XCBaseAlert ArrayReverse(mDemandZones); } + // + // Oder Blocks ... + int obSameBars = OrderBlocksSameBars(); + if (obSameBars > 0) + { + // + // Bullish Order Blocks ... + bullishOrderBlocksCount = DetectRequiredBullishOrderBlocks(barIndex); + if (bullishOrderBlocksCount == requiredPOIs) + { + ArrayReverse(mBullishOrderBlocks); + } + + // + // Bearish Order Blocks ... + bearishOrderBlocksCount = DetectRequiredBearishOrderBlocks(barIndex); + if (bearishOrderBlocksCount == requiredPOIs) + { + ArrayReverse(mBearishOrderBlocks); + } + } + // canContinue = // @@ -1118,6 +1243,16 @@ class XCPOIDetector : public XCBaseAlert // Demand Zones ... demandZonesCount < requiredPOIs // + || + // + // Bullish Order Blocks ... + bullishOrderBlocksCount < requiredPOIs + // + || + // + // Bearish Order Blocks ... + bearishOrderBlocksCount < requiredPOIs + // ; if (canContinue) { @@ -2986,12 +3121,321 @@ class XCPOIDetector : public XCBaseAlert // // Order Blocks ... + int mOrderBlocksSameBars; // Order Blocks Detection Bars ... // // Bullish OB ... + XCOrderBlock *mBullishOrderBlocks[]; + + /** + * Detect Bullish Order Block ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBullishOrderBlock(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + if (sameBars < 0) + { + return result; + } + + // + XOHCL obBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasOrderBlock( + bar, + obBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BULLISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + XCOrderBlock *ob; + ob = new XCOrderBlock(); + result = ob.Init( + obBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + ob.To(cTime); + + // + Add( + ob, + mBullishOrderBlocks // + ); + + // // + // XCBullishOrderBlockObject *iObj; + // bool isCreated = mDrawer.CreateBullishOrderBlock( + // ob, + // iObj // + // ); + // if (isCreated) + // { + // AddObjectIfNotExists(iObj); + // } + } + } + + // + return result; + } + + /** + * Detect Required Bullish Order Blocks ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBullishOrderBlocks(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBullishOrderBlocks); + if (count >= required) + { + // + result = count; + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + if (sameBars < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBullishOrderBlock(bar); + + // + result = ArraySize(mBullishOrderBlocks); + + // + return result; + } // // Bearish OB ... + XCOrderBlock *mBearishOrderBlocks[]; + + /** + * Detect Bearish Order Block ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBearishOrderBlock(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + if (sameBars < 0) + { + return result; + } + + // + XOHCL obBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasOrderBlock( + bar, + obBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BEARISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + XCOrderBlock *ob; + ob = new XCOrderBlock(); + result = ob.Init( + obBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + ob.To(cTime); + + // + Add( + ob, + mBearishOrderBlocks // + ); + + // // + // XCBearishOrderBlockObject *iObj; + // bool isCreated = mDrawer.CreateBearishOrderBlock( + // ob, + // iObj // + // ); + // if (isCreated) + // { + // AddObjectIfNotExists(iObj); + // } + } + } + + // + return result; + } + + /** + * Detect Required Bearish Order Blocks ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBearishOrderBlocks(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBearishOrderBlocks); + if (count >= required) + { + // + result = count; + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + if (sameBars < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBearishOrderBlock(bar); + + // + result = ArraySize(mBearishOrderBlocks); + + // + return result; + } // // Fair Value Gaps ... diff --git a/Classes/x-saherelm.x-poi.drawer.class.mq5 b/Classes/x-saherelm.x-poi.drawer.class.mq5 index c7df6f35..70708655 100644 --- a/Classes/x-saherelm.x-poi.drawer.class.mq5 +++ b/Classes/x-saherelm.x-poi.drawer.class.mq5 @@ -1269,6 +1269,103 @@ class XCPOIDrawer : public XCBase mBearishFVGStyle = value; } + // + // Virtuals ... + + /** + * Apply Default Configurations ... + */ + virtual void Default() + { + // + // Apply Default Props ... + + // + Prefix(NULL); + ChartIdentification(0); + SubWindowIdentification(0); + + // + SwingLowWidth(3); + SwingLowArrow(108); + SwingLowColor(clrAqua); + + // + SwingHighWidth(3); + SwingHighArrow(108); + SwingHighColor(clrMagenta); + + // + BullishMomentumBarWidth(3); + BullishMomentumBarArrow(225); + BullishMomentumBarColor(clrAqua); + + // + BearishMomentumBarWidth(3); + BearishMomentumBarArrow(226); + BearishMomentumBarColor(clrMagenta); + + // + BullishRejectionBarWidth(3); + BullishRejectionBarArrow(217); + BullishRejectionBarColor(clrAqua); + + // + BearishRejectionBarWidth(3); + BearishRejectionBarArrow(218); + BearishRejectionBarColor(clrMagenta); + + // + SupportZoneFill(false); + SupportZoneWidth(1); + SupportZoneStyle(STYLE_DOT); + SupportZoneColor(clrLime); + + // + ResistanceZoneFill(false); + ResistanceZoneWidth(1); + ResistanceZoneStyle(STYLE_DOT); + ResistanceZoneColor(clrRed); + + // + SupplyZoneFill(false); + SupplyZoneWidth(1); + SupplyZoneStyle(STYLE_DOT); + SupplyZoneColor(clrRed); + + // + DemandZoneFill(false); + DemandZoneWidth(1); + DemandZoneStyle(STYLE_DOT); + DemandZoneColor(clrGreen); + + // + BullishOrderBlockFill(false); + BullishOrderBlockWidth(1); + BullishOrderBlockStyle(STYLE_DASHDOT); + BullishOrderBlockColor(clrLime); + + // + BearishOrderBlockFill(false); + BearishOrderBlockWidth(1); + BearishOrderBlockStyle(STYLE_DASHDOT); + BearishOrderBlockColor(clrRed); + + // + BullishFVGFill(true); + BullishFVGWidth(1); + BullishFVGStyle(STYLE_DOT); + BullishFVGColor(clrLime); + + // + BearishFVGFill(true); + BearishFVGWidth(1); + BearishFVGStyle(STYLE_DOT); + BearishFVGColor(clrRed); + + // + } + // // Object Creators ... @@ -1917,102 +2014,138 @@ class XCPOIDrawer : public XCBase return result; } + /** + * Create Bullish Order Block Object ... + * + * @param zone: XCOrderBlock instance ... + * @param object: XCBullishOrderBlockObject pointer ... + * + * @return ( bool ) + */ + bool CreateBullishOrderBlock( + XCOrderBlock &zone, + XCBullishOrderBlockObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid() && + zone.IsBullish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = BullishOrderBlockFill(); + int width = BullishOrderBlockWidth(); + color crl = BullishOrderBlockColor(); + ENUM_LINE_STYLE style = BullishOrderBlockStyle(); + + // + object = new XCBullishOrderBlockObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + /** + * Create Bearish Order Block Object ... + * + * @param zone: XCOrderBlock instance ... + * @param object: XCBearishOrderBlockObject pointer ... + * + * @return ( bool ) + */ + bool CreateBearishOrderBlock( + XCOrderBlock &zone, + XCBearishOrderBlockObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid() && + zone.IsBearish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = BearishOrderBlockFill(); + int width = BearishOrderBlockWidth(); + color crl = BearishOrderBlockColor(); + ENUM_LINE_STYLE style = BearishOrderBlockStyle(); + + // + object = new XCBearishOrderBlockObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + // protected: // - // - void Default() - { - // - // Apply Default Props ... - - // - Prefix(NULL); - ChartIdentification(0); - SubWindowIdentification(0); - - // - SwingLowWidth(3); - SwingLowArrow(108); - SwingLowColor(clrAqua); - - // - SwingHighWidth(3); - SwingHighArrow(108); - SwingHighColor(clrMagenta); - - // - BullishMomentumBarWidth(3); - BullishMomentumBarArrow(225); - BullishMomentumBarColor(clrAqua); - - // - BearishMomentumBarWidth(3); - BearishMomentumBarArrow(226); - BearishMomentumBarColor(clrMagenta); - - // - BullishRejectionBarWidth(3); - BullishRejectionBarArrow(217); - BullishRejectionBarColor(clrAqua); - - // - BearishRejectionBarWidth(3); - BearishRejectionBarArrow(218); - BearishRejectionBarColor(clrMagenta); - - // - SupportZoneFill(false); - SupportZoneWidth(1); - SupportZoneStyle(STYLE_DOT); - SupportZoneColor(clrLime); - - // - ResistanceZoneFill(false); - ResistanceZoneWidth(1); - ResistanceZoneStyle(STYLE_DOT); - ResistanceZoneColor(clrRed); - - // - SupplyZoneFill(false); - SupplyZoneWidth(1); - SupplyZoneStyle(STYLE_DOT); - SupplyZoneColor(clrRed); - - // - DemandZoneFill(false); - DemandZoneWidth(1); - DemandZoneStyle(STYLE_DOT); - DemandZoneColor(clrGreen); - - // - BullishOrderBlockFill(true); - BullishOrderBlockWidth(1); - BullishOrderBlockStyle(STYLE_DOT); - BullishOrderBlockColor(clrLime); - - // - BearishOrderBlockFill(true); - BearishOrderBlockWidth(1); - BearishOrderBlockStyle(STYLE_DOT); - BearishOrderBlockColor(clrRed); - - // - BullishFVGFill(true); - BullishFVGWidth(1); - BullishFVGStyle(STYLE_DOT); - BullishFVGColor(clrLime); - - // - BearishFVGFill(true); - BearishFVGWidth(1); - BearishFVGStyle(STYLE_DOT); - BearishFVGColor(clrRed); - - // - } - // private: //