/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // -------------------------------------- // Name: XPOI // Description: Bar Analysing ... // // 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.base.class.mq5" #include "../Libraries/x-saherelm.x-poi.lib.mq5" // // Definitions ... // #define X_PERCENTAGE_GOLDEN_MULTIPLIER 100000 // // Implementations ... class XCBarAnalyser : public XCBase { // public: // // // Constructor(s) ... void XCBarAnalyser() { } // // Deconstructor ... void ~XCBarAnalyser() { } // // Getter(s) / Setter(s) ... // // Providers ... /** * Calculate Loopback Data for Specific Bar ... * * @param index: Integer, Bar Current Index ... * @param start: Integer, Start of Loopback ... * @param end: Integer, End of Loopback ... * @param count: Integer, Number of Calculating Bars ... * @param bar: XOHCL instance, Specified Bar ... * @param loopback: Integer, Loopback Length ... * @return ( bool ) */ bool CalculateLoopbackData( int &index, int &start, int &end, int &count, XOHCL &bar, int loopback = 1 // ) { // bool result = false; // if (loopback < 1) { loopback = 1; } // index = -1; start = -1; end = -1; count = -1; // result = bar.IsValid(); if (!result) { return result; } // index = bar.Index(); start = index + 1; end = start + loopback; count = end - start; result = count >= 1; if (!result) { return result; } // return result; } /** * Retrieve Loopback HH & LL Data ... * * @param hhIDX: Integer, HH Index ... * @param hh: Double, HH Value ... * @param llIDX: Integer, LL Index ... * @param ll: Double, LL Value ... * @param bar: XOHCL instance ... * @param loopback: Integer, Loopback Length ... * * @return ( bool ) */ bool CalculateLoopbackHLData( int &hhIDX, double &hh, int &llIDX, double &ll, XOHCL &bar, int loopback // ) { // bool result = false; // if (loopback < 1) { loopback = 1; } // int index = -1; int start = -1; int end = -1; int count = -1; result = CalculateLoopbackData( index, start, end, count, bar, loopback // ); if (!result) { return result; } // hhIDX = iHighest( bar.symbol, bar.period, MODE_HIGH, count, start // ); result = IsValidIndex(hhIDX); if (!result) { return result; } // llIDX = iLowest( bar.symbol, bar.period, MODE_LOW, count, start // ); result = IsValidIndex(llIDX); if (!result) { return result; } // hh = iHigh( bar.symbol, bar.period, hhIDX // ); ll = iLow( bar.symbol, bar.period, llIDX // ); // return result; } /** * Fill Prices ... * * @param prices: double collection * @param bar: XOHCL instance reference, Provides Start ... * @param loopback: int, Specified How Many Bars Process ... * @param type: ENUM_X_PRICE member, Specified Price Type ... * * @return ( bool ) */ bool FillPrice( double &prices[], XOHCL &bar, int loopback = 14, ENUM_X_PRICE type = X_PRICE_CLOSE // ) { // bool result = false; // Clean(prices); // loopback = NormalizeInt(loopback, 1); // result = IsValid(type) && bar.IsValid(); if (!result) { return result; } // string symbol = bar.symbol; ENUM_TIMEFRAMES period = bar.period; // // Calculate Loopback Data ... int index = -1; int start = -1; int end = -1; int count = -1; result = CalculateLoopbackData( index, start, end, count, bar, loopback // ); if (!result) { return result; } // for (int i = index; i < count; i++) { // XOHCL iBar; bool isInited = iBar.Init( symbol, period, i // ); if (!isInited) { // iBar.Clean(); continue; } // double iPrice = iBar.GetPrice(type); // isInited = NotEmptyZero(iPrice); if (isInited) { // Add( iPrice, prices // ); } // iBar.Clean(); } // result = ArraySize(prices) == count; if (!result) { Clean(prices); } // ArrayReverse(prices); // return result; } /** * Calculate Price Range ... * * @param ranges: double Collection, Calculated Ranges ... * @param bar: XOHCL instance Reference, Start Bar ... * @param forceBody: bool, Force to Calculate Range using Body ... * @param loopback: int, loopback period for Range Calculated ... * * @return ( int ) */ int GetPriceRange( double &ranges[], XOHCL &bar, bool forceBody = false, int loopback = 14 // ) { // int result = 0; // Clean(ranges); // loopback = NormalizeInt(loopback, 1); // if (!bar.IsValid()) { return result; } // bool has = false; // // Select Uppers Prices ... double uppers[]; int uppersCount = 0; if (forceBody) { // has = FillPrice( uppers, bar, loopback, X_PRICE_UP // ); } else { // has = FillPrice( uppers, bar, loopback, X_PRICE_HIGH // ); } if (has) { uppersCount = ArraySize(uppers); } // // Select Lower Prices ... double lowers[]; int lowersCount = 0; if (forceBody) { // has = FillPrice( lowers, bar, loopback, X_PRICE_DOWN // ); } else { // has = FillPrice( lowers, bar, loopback, X_PRICE_LOW // ); } if (has) { lowersCount = ArraySize(lowers); } // // Validate Filled Prices ... has = IsValidSize(uppersCount) && IsValidSize(lowersCount) && uppersCount == lowersCount; if (!has) { // Clean(uppers); Clean(lowers); // return result; } // for (int i = 0; i < uppersCount; i++) { // double iValue = uppers[i] - lowers[i]; // Add( iValue, ranges // ); } // result = ArraySize(ranges); ArrayReverse(ranges); // // Cleanup Resources ... // Clean(uppers); Clean(lowers); // return result; } /** * Calculate Price Change Percent ... * * @param bar: XOHCL instance Reference, Start Bar ... * @param type: ENUM_X_PRICE member, Specified Price Type ... * @param loopback: int, loopback period for Range Calculated ... * * @return ( double ) */ double GetPriceChangeRate( XOHCL &bar, ENUM_X_PRICE type = X_PRICE_CLOSE, int loopback = 14 // ) { // double result = 0; // bool has = false; // loopback = NormalizeInt(loopback, 1); // has = IsValid(type) && bar.IsValid(); if (!has) { return result; } // XOHCL oldBar; has = oldBar.Init( bar.symbol, bar.period, bar.Index() + loopback // ); if (!has) { // oldBar.Clean(); // return result; } double newPrice = bar.GetPrice(type); double oldPrice = oldBar.GetPrice(type); // result = ((newPrice - oldPrice) / oldPrice) / 100; // oldBar.Clean(); // return result; } /** * Detect Same Bars ... * * @param bar: XOHCL instance, Start Bar ... * @param dir: ENUM_X_DIRECTION member, Holds Result Direction ... * @param index: Integer, Holds Result Index ... * @param sameBars: Iteger, Required Same Bar ... * * @return ( bool ) */ bool HasSameBars( XOHCL &bar, ENUM_X_DIRECTION &dir, int &index, int sameBars = 3 // ) { // bool result = false; // dir = X_DIRECTION_NONE; // if (sameBars < 1) { sameBars = 1; } // result = bar.IsValid(); if (!result) { return result; } // index = bar.Index() + 1; 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 if (isBearish) { // sameBearishBarsFounded++; canContinueForBullish = false; } else { // sameBullishBarsFounded = 0; sameBearishBarsFounded = 0; canContinueForBullish = false; canContinueForBearish = false; } // result = canContinueForBullish || canContinueForBearish; if (!result) { break; } // canContinueForBullish = canContinueForBullish && sameBullishBarsFounded > 0; // canContinueForBearish = canContinueForBearish && sameBearishBarsFounded > 0; // canContinue = canContinueForBullish || canContinueForBearish; if (canContinue) { index++; } } // bool hasBullishSameBars = sameBullishBarsFounded >= sameBars; // bool hasBearishSameBars = sameBearishBarsFounded >= sameBars; // result = hasBullishSameBars || hasBearishSameBars; if (!result) { return result; } // index--; // dir = hasBullishSameBars ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // return result; } /** * Check Fibonacci Level 382 Pressure ... * * @param bar: XOHCL instance ... * @param dir: ENUM_X_DIRECTION member ... * * @return ( bool ) */ bool HasFiboPressure( XOHCL &bar, ENUM_X_DIRECTION forDir, ENUM_X_FIBO_LEVELS level // ) { // bool result = false; // result = bar.IsValid() && HasDirection(forDir); if (!result) { return result; } // bool isBullish = IsBullish(forDir); bool isBearish = IsBearish(forDir); // double fiboLevelValue = GetFibonacciLevel( bar.high, bar.low, level, forDir // ); // bool isBullishPressured = isBullish && bar.GetDown() > fiboLevelValue; bool isBearishPressured = isBearish && bar.GetUp() < fiboLevelValue; // result = isBullishPressured || isBearishPressured; // return result; } // // Actions ... bool IsSpike( XOHCL &bar, XOHCL &fromBar, XOHCL &toBar, ENUM_X_DIRECTION &dir, double minPriceChangePercent = 1.5, ENUM_X_PRICE type = X_PRICE_CLOSE, bool forcBodyInRange = true, double rangeExtendMultiplier = 2, int loopback = 14 // ) { // bool result = false; // toBar.Clean(); fromBar.Clean(); dir = X_DIRECTION_NONE; loopback = NormalizeInt(loopback, 1); rangeExtendMultiplier = NormalizeDouble(rangeExtendMultiplier, 1); minPriceChangePercent = NormalizeDouble(minPriceChangePercent, 1.5); // int periodSeconds = PeriodSeconds(bar.period); double divider = X_PERCENTAGE_GOLDEN_MULTIPLIER; double periodMult = (periodSeconds / PeriodSeconds(PERIOD_M5)) * 0.2; minPriceChangePercent /= (divider / periodMult); // result = bar.IsValid(); if (!result) { return result; } // double ranges[]; int rangesCount = GetPriceRange( ranges, bar, forcBodyInRange, loopback // ); result = IsValidSize(rangesCount); if (!result) { // Clean(ranges); // return result; } // double rangeMax = GetMax(ranges); double rangeMin = GetMin(ranges); double rangeAverage = GetAverage(ranges); double priceChangePercent = GetPriceChangeRate( bar, type, loopback // ); // static double maxPriceChange = 0; static double minPriceChange = 0; if (maxPriceChange == 0 || maxPriceChange < priceChangePercent) { maxPriceChange = priceChangePercent; } if (minPriceChange == 0 || minPriceChange > priceChangePercent) { minPriceChange = priceChangePercent; } // bool isBullish = // priceChangePercent > 0 && priceChangePercent >= minPriceChangePercent // ; // bool isBearish = // priceChangePercent < 0 && MathAbs(priceChangePercent) >= minPriceChangePercent // ; // result = isBullish || isBearish; if (result) { // dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; } // // Cleanup Resources ... // Clean(ranges); // return result; } // protected: // // private: // // // Props ... // // Actions ... // }; //