/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // -------------------------------------- // Name: XPOI // Description: Provides Point of Interests ... // - Swing Highs; // - Swing Lows; // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://www.saherelm.ir" #property version "1.00" #property strict // // Imports ... // #include "../Classes/x-saherelm.x-alert.class.mq5" #include "../Classes/x-saherelm.x-poi.drawer.class.mq5" #include "../Libraries/x-saherelm.x-poi.lib.mq5" // #include // // Implementation ... // // POI Detector Class ... class XCPOIDetector : public XCBaseAlert { // public: // XCPOIDrawer mDrawer; // // Constructors ... /** * Create an Instance ... * * @param symbol: String ... * @param period: ENUM_TIMEFRAMES member ... */ void XCPOIDetector( string symbol, ENUM_TIMEFRAMES period // ) { // // Attach Required Properties ... mSymbol = symbol; mPeriod = period; // // Initialize Bar Tracker ... mBarTracker.Init( mSymbol, mPeriod // ); // // Apply Default Configurations ... ApplyDefaultConfig(); } // // Deconstructor ... void ~XCPOIDetector() { Destroy(); } // // Getter(s) / Setter(s) ... /** * Retrieve Detector Symbol ... * * @return ( string ) */ string GetSymbol() { return mSymbol; } /** * Retrieve Detector Period ... * * @return ( ENUM_TIMEFRAMES ) */ ENUM_TIMEFRAMES GetPeriod() { return mPeriod; } /** * Get Max Number of POIs which holds ... * * @return ( int ) */ int MaxNumberOfPOIs() { return mMaxNumberOfPOIs; } /** * Set Max Number of POIs which holds ... * 0 => Infinity ... * * @param value: Integer ... */ void MaxNumberOfPOIs(int value) { // if (value < 0) { value = 0; } // mMaxNumberOfPOIs = value; } /** * Get Number of POI(s) which must Find at Initializations ... * * @return ( int ) */ int MaxNumberOfRequiredPOIs() { return mMaxNumberOfRequiredPOIs; } /** * Set Number of POI(s) which must Find at Initializations ... * 2 is Default ... * * @param value: Integer ... */ void MaxNumberOfRequiredPOIs(int value) { // if (value < 2) { value = 2; } // mMaxNumberOfRequiredPOIs = value; } /** * Check Is Locked or not ... * * @return ( bool ) */ bool IsLocked() { return mLock; } // // POI(s) Configs ... // // Swings ... /** * Get Swing Verification Range Length ... * * @return ( int ) */ int SwingRange() { return mSwingRange; } /** * Set Swing Verification Range Length ... * * @param value: Integer ... */ void SwingRange(int value) { // if (value < 0) { value = 0; } // mSwingRange = value; } // // Actions ... /** * Initialize POI Detector ... */ void Init() { DetectRequiredPOIs(); } /** * Update POI(s) ... * * @param state: an Array Refrence of ENUM_XPOI_EVENTS members ... */ int Update( ENUM_XPOI_EVENTS &state[] // ) { // int result = 0; // Clean(state); // // Check Bar Tracker if Waits ... if (!mBarTracker.IsNewBar()) { return result; } // int zIndex = 0; int cIndex = zIndex + 1; int pIndex = cIndex + 1; int ppIndex = pIndex + 1; // datetime cTime = TimeCurrent(); // XOHCL zBar; bool isInited = zBar.Init( mSymbol, mPeriod, zIndex // ); if (!isInited) { return result; } // XOHCL cBar; isInited = cBar.Init( mSymbol, mPeriod, cIndex // ); if (!isInited) { return result; } // XOHCL pBar; isInited = pBar.Init( mSymbol, mPeriod, pIndex // ); if (!isInited) { return result; } // XOHCL ppBar; isInited = ppBar.Init( mSymbol, mPeriod, ppIndex // ); if (!isInited) { return result; } // XOHCL zDayBar; isInited = zDayBar.Init( mSymbol, PERIOD_D1, zIndex // ); if (!isInited) { return result; } // CleanupUnusedPOIs(); // mBarTracker.Waits(); // result = ArraySize(state); // return result; } /** * Destroy Class ... */ void Destroy() { // DestroyPOIs(); DestroySessions(); DestroyEventListeners(); } // // Retrievers ... /** * Get Current State of POIs ... * * @param state: XPOIState instance ... */ void GetState( XPOIState &state // ) { // state.Clean(); // state.symbol = mSymbol; state.period = mPeriod; state.reportedAt = TimeCurrent(); // // TODO: Fill State ... } // // Event Listeners ... // // Destroy ... /** * Destroy Detected POI(s) ... */ void DestroyPOIs() { } /** * Destroy Added Sessions ... */ void DestroySessions() { } /** * Destroy Rejistered Event Handlers ... */ void DestroyEventListeners() { } // // Virtual Actions ... /** * Apply Default Configurations ... */ virtual void ApplyDefaultConfig() { // // Common ... // MaxNumberOfPOIs(10); MaxNumberOfRequiredPOIs(2); // SwingRange(2); // } // protected: // // // Actions ... /** * Lock ... */ void Lock() { mLock = true; } /** * Unlock ... */ void Unlock() { mLock = false; } /** * Detect Required POI(s) ... * * @param barIndex: Integer Start bar index ... * 0 is Default ... */ void DetectRequiredPOIs(int barIndex = 0) { // // Validate Reuired POI(s) ... int requiredPOIs = MaxNumberOfRequiredPOIs(); if (requiredPOIs <= 0) { return; } // // Locking Detector ... Lock(); // // Normalize Bar Index ... if (barIndex < 0) { barIndex = 0; } // int swingLowsCount = 0; int swingHighsCount = 0; // bool canContinue = true; // while (canContinue) { // // Swing Highs ... swingHighsCount = DetectRequiredSwingHighs(barIndex); // // Swing Lows ... swingLowsCount = DetectRequiredSwingLows(barIndex); // canContinue = // // Swing Highs ... swingHighsCount < requiredPOIs // || // // Swing Lows ... swingLowsCount < requiredPOIs // ; if (canContinue) { barIndex++; } } // swingHighsCount = ArraySize(mSwingHighs); swingLowsCount = ArraySize(mSwingLows); // // Unlocking Detector ... Unlock(); } /** * Cleanup Unused Objects ... */ void CleanupUnusedPOIs() { // int maxAllowed = MaxNumberOfPOIs(); if (!IsValidSize(maxAllowed)) { return; } // // // int tradingDaysCount = ArraySize(mTradingDays); // int marketSessionsCount = ArraySize(mMarketSessions); // int swingHighsCount = ArraySize(mSwingHighs); // int swingLowsCount = ArraySize(mSwingLows); // int momentumBarsCount = ArraySize(mMomentumBars); // int rejectionBarsCount = ArraySize(mRejectionBars); // int supportZonesCount = ArraySize(mSupportZones); // int resistanceZonesCount = ArraySize(mResistanceZones); // int supplyZonesCount = ArraySize(mSupplyZones); // int demandZonesCount = ArraySize(mDemandZones); // int bullishOBsCount = ArraySize(mBullishOrderBlocks); // int bearishOBsCount = ArraySize(mBearishOrderBlocks); // int bullishFVGsCount = ArraySize(mBullishFVGs); // int bearishFVGsCount = ArraySize(mBearishFVGs); // // // int from = 0; // int requiredPOIs = MaxNumberOfRequiredPOIs(); // int count = maxAllowed - requiredPOIs; // int to = count - 1; // // // // Trading Days ... // if (tradingDaysCount >= maxAllowed) // { // // // ArrayRemove( // mTradingDays, // from, // count // // ); // // // mTradingDayObjects.DeleteRange( // from, // to // // ); // } // // // // Market Sessions ... // if (marketSessionsCount >= maxAllowed) // { // // // ArrayRemove( // mMarketSessions, // from, // count // // ); // // // mMarketSessionObjects.DeleteRange( // from, // to // // ); // } // // // // Momentum Bars ... // if (momentumBarsCount >= maxAllowed) // { // // // ArrayRemove( // mMomentumBars, // from, // count // // ); // // // mMomentumBarObjects.DeleteRange( // from, // to // // ); // } // // // // Rejection Bars ... // if (rejectionBarsCount >= maxAllowed) // { // // // ArrayRemove( // mRejectionBars, // from, // count // // ); // // // mRejectionBarObjects.DeleteRange( // from, // to // // ); // } // // // // Swing High and Low (s) ... // // // // Swing Highs ... // if (swingHighsCount >= maxAllowed) // { // // // ArrayRemove( // mSwingHighs, // from, // count // // ); // // // mSwingHighObjects.DeleteRange( // from, // to // // ); // } // // // // Swing Lows ... // if (swingLowsCount >= maxAllowed) // { // // // ArrayRemove( // mSwingLows, // from, // count // // ); // // // mSwingLowObjects.DeleteRange( // from, // to // // ); // } // // // // Support and Resistance Zones ... // // // // Support Zones ... // if (supportZonesCount >= maxAllowed) // { // // // ArrayRemove( // mSupportZones, // from, // count // // ); // // // mSupportZoneObjects.DeleteRange( // from, // to // // ); // } // // // // Resistance Zones ... // if (resistanceZonesCount >= maxAllowed) // { // // // ArrayRemove( // mResistanceZones, // from, // count // // ); // // // mResistanceZoneObjects.DeleteRange( // from, // to // // ); // } // // // // Supply and Demand Zones ... // // // // Supply Zones ... // if (supplyZonesCount >= maxAllowed) // { // // // ArrayRemove( // mSupplyZones, // from, // count // // ); // // // mSupplyZoneObjects.DeleteRange( // from, // to // // ); // } // // // // Demand Zones ... // if (demandZonesCount >= maxAllowed) // { // // // ArrayRemove( // mDemandZones, // from, // count // // ); // // // mDemandZoneObjects.DeleteRange( // from, // to // // ); // } // // // // Order Blocks ... // // // // Bullish Order Blocks ... // if (bullishOBsCount >= maxAllowed) // { // // // ArrayRemove( // mBullishOrderBlocks, // from, // count // // ); // // // mBullishOrderBlockObjects.DeleteRange( // from, // to // // ); // } // // // // Bearish Order Blocks ... // if (bearishOBsCount >= maxAllowed) // { // // // ArrayRemove( // mBearishOrderBlocks, // from, // count // // ); // // // mBearishOrderBlockObjects.DeleteRange( // from, // to // // ); // } // // // // Fair Vakue Gaps ... // // // // Bullish FVGs ... // if (bullishFVGsCount >= maxAllowed) // { // // // ArrayRemove( // mBullishFVGs, // from, // count // // ); // // // mBullishFVGObjects.DeleteRange( // from, // to // // ); // } // // // // Bearish FVGs ... // if (bearishFVGsCount >= maxAllowed) // { // // // ArrayRemove( // mBearishFVGs, // from, // count // // ); // // // mBearishFVGObjects.DeleteRange( // from, // to // // ); // } // } void AddObjectIfNotExists(XCBaseObject *object) { // string name = object.ObjName(); // bool canAdd = true; int count = mDrawnObjects.Total(); if (IsValidSize(count)) { // for (int i = 0; i < count; i++) { // string iName = ((XCBaseObject *)mDrawnObjects.At(i)).ObjName(); // if (name == iName) { // canAdd = false; break; } } } // if (canAdd) { mDrawnObjects.Add(object); } } // private: // // // Props ... // bool mLock; // Lock State ... string mSymbol; // Market Symbol ... ENUM_TIMEFRAMES mPeriod; // Market Period ... int mMaxNumberOfPOIs; // Max Allowed Number of POI(s) which Can Holds ... int mMaxNumberOfRequiredPOIs; // Max Allowed Number of POI(s) which Must Find at Initializion Time ... // CArrayObj mDrawnObjects; // Drawn Objects ... XBarTracker mBarTracker; // Market Bar Tracker ... // // POI Props ... // // XDay ... // // XSession ... // // XSwing ... int mSwingRange; // Swing Verification Range Length ... // // Swing High ... XCSwing *mSwingHighs[]; // Holds Founded Swing Highs ... /** * Detect Required Swing Highs ... * * @param barIndex: Integer Start bar index ... * 0 is Default ... * * @return ( int ) */ int DetectRequiredSwingHighs(int barIndex = 0) { // int result = 0; // if (barIndex < 0) { barIndex = 0; } // int required = MaxNumberOfRequiredPOIs(); if (required <= 0) { return result; } // int count = ArraySize(mSwingHighs); if (count >= required) { // result = count; return result; } // int range = SwingRange(); if (range < 0 || barIndex < range) { return result; } // string symbol = GetSymbol(); ENUM_TIMEFRAMES period = GetPeriod(); // XOHCL bar; bool isInited = bar.Init( symbol, period, barIndex // ); if (!isInited) { return result; } // bool isSwing = true; for (int i = 1; i <= range; i++) { // // Prev Bar ... XOHCL iPrevBar; isInited = iPrevBar.Init( symbol, period, barIndex + i // ); if (!isInited) { // isSwing = false; break; } // // Next Bar ... XOHCL iNextBar; isInited = iNextBar.Init( symbol, period, barIndex - i // ); if (!isInited) { // isSwing = false; break; } // isSwing = bar.high >= iPrevBar.high && bar.high >= iNextBar.high; if (!isSwing) { break; } } // if (isSwing) { // XCSwing *swing; swing = new XCSwing(); isInited = swing.Init( bar, X_POI_SWING_HIGH // ); // if (isInited) { // Add( swing, mSwingHighs // ); // XCSwingHighObject *iObj; bool isCreated = mDrawer.CreateSwingHigh( swing, iObj // ); if (isCreated) { AddObjectIfNotExists(iObj); } } } // result = ArraySize(mSwingHighs); // return result; } // // Swing Low ... XCSwing *mSwingLows[]; // Holds Founded Swing Lows ... /** * Detect Required Swing Lows ... * * @param barIndex: Integer Start bar index ... * 0 is Default ... * * @return ( int ) */ int DetectRequiredSwingLows(int barIndex = 0) { // int result = 0; // if (barIndex < 0) { barIndex = 0; } // int required = MaxNumberOfRequiredPOIs(); if (required <= 0) { return result; } // int count = ArraySize(mSwingLows); if (count >= required) { // result = count; return result; } // int range = SwingRange(); if (range < 0 || barIndex < range) { return result; } // string symbol = GetSymbol(); ENUM_TIMEFRAMES period = GetPeriod(); // XOHCL bar; bool isInited = bar.Init( symbol, period, barIndex // ); if (!isInited) { return result; } // bool isSwing = true; for (int i = 1; i <= range; i++) { // // Prev Bar ... XOHCL iPrevBar; isInited = iPrevBar.Init( symbol, period, barIndex + i // ); if (!isInited) { // isSwing = false; break; } // // Next Bar ... XOHCL iNextBar; isInited = iNextBar.Init( symbol, period, barIndex - i // ); if (!isInited) { // isSwing = false; break; } // isSwing = bar.low <= iPrevBar.low && bar.low <= iNextBar.low; if (!isSwing) { break; } } // if (isSwing) { // XCSwing *swing; swing = new XCSwing(); isInited = swing.Init( bar, X_POI_SWING_LOW // ); // if (isInited) { // Add( swing, mSwingLows // ); // XCSwingLowObject *iObj; bool isCreated = mDrawer.CreateSwingLow( swing, iObj // ); if (isCreated) { AddObjectIfNotExists(iObj); } } } // result = ArraySize(mSwingHighs); // return result; } // // Momentum Bars ... // // Rejection Bars ... // // Support Zone(s) ... // // Resistance Zone(s) ... // // Supply Zone(s) ... // // Demand Zone(s) ... // // Order Blocks ... // // Bullish OB ... // // Bearish OB ... // // Fair Value Gaps ... // // Bullish FVG ... // // Bearish FVG ... // // Liquidity Zones ... // // Sell Side ... // // Buy Side ... // }; //