/////////////////////////////////////////////////////// // // 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 ... // // 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 Calculations ... * * @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 = lowers[i] + (uppers[i] - lowers[i]); // Add( iValue, ranges // ); } // result = ArraySize(ranges); ArrayReverse(ranges); // // Cleanup Resources ... // Clean(uppers); Clean(lowers); // return result; } /** * Retrieve Price Velocities ... * * @param velocities: double Collection, Price Velocities ... * @param bar: XOHCL instance Reference, Start Bar ... * @param type: ENUM_X_PRICE member ... * @param loopback: int, loopback period for Calculations ... * * @return ( int ) */ int GetPriceVelocity( double &velocities[], XOHCL &bar, ENUM_X_PRICE type = X_PRICE_CLOSE, int loopback = 14 // ) { // int result = 0; // Clean(velocities); loopback = NormalizeInt(loopback, 1); // result = IsValid(type) && bar.IsValid(); // int to = bar.Index(); int from = to + loopback; for (int i = to; i < from; i++) { // double iPrice = GetAppliedPrice( bar.symbol, bar.period, i, type // ); // double pPrice = GetAppliedPrice( bar.symbol, bar.period, i + 1, type // ); // double iVelocity = MathAbs(iPrice - pPrice); Add( iVelocity, velocities // ); } // result = ArraySize(velocities); // 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_MEDIAN, int loopback = 14 // ) { // double result = 0; // bool has = false; // loopback = NormalizeInt(loopback, 1); // has = bar.IsValid() && IsValid(type); 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; } /** * Detect Big Price Change Happens or not ... * * @param bar: XOHCL instance reference, Start Bar ... * @param dir: ENUM_X_DIRECTION member, Event Direction ... * @param rootIDX: int, Root of Momentum Index ... * @param type: ENUM_X_PRICE member, Price Type ... * @param forcBodyInRange: bool, Use Body in Range Detection ... * @param rangeExtendMultiplier: double, a Multiplier for Checking Price Range ... * * @return ( bool ) */ bool IsSharp( XOHCL &bar, ENUM_X_DIRECTION &dir, int &rootIDX, ENUM_X_PRICE type = X_PRICE_CLOSE, bool forcBodyInRange = true, double rangeExtendMultiplier = 2.0 // ) { // bool result = false; // dir = X_DIRECTION_NONE; rangeExtendMultiplier = NormalizeDouble(rangeExtendMultiplier, 1); // result = bar.IsValid() && IsValid(type); if (!result) { return result; } // double minPriceChangePercent = 0; int loopback = GetPeriodSharpData( minPriceChangePercent, bar.period // ); // // Retrieve Price Change Percent ... double priceChangePercent = GetPriceChangeRate( bar, type, loopback // ); // // Velocities ... double velocities[]; int velocitiesCount = GetPriceVelocity( velocities, bar, type, loopback // ); double velocitiesAvg = GetAverage(velocities); double oldPrice = GetAppliedPrice( bar.symbol, bar.period, bar.Index() + loopback, type // ); double newPrice = bar.GetPrice(type); double currVelocity = MathAbs(oldPrice - newPrice); // // Calculate HH and LL ... // double hh = 0; double ll = 0; int hhIDX = -1; int llIDX = -1; result = CalculateLoopbackHLData( hhIDX, hh, llIDX, ll, bar, loopback // ); result = result && ll > 0 && hh > ll && IsValidIndex(llIDX) && IsValidIndex(hhIDX); if (!result) { return result; } // int hhDiff = (hhIDX - bar.Index()); int llDiff = (llIDX - bar.Index()); // // Bool Get Boundary Direction ... // // Check Price Change Rate ... // bool isBullish = // hhDiff <= 1 && llIDX > hhIDX && priceChangePercent > 0 && priceChangePercent >= minPriceChangePercent && currVelocity > (velocitiesAvg * rangeExtendMultiplier) // ; // bool isBearish = // llDiff <= 1 && hhIDX > llIDX && priceChangePercent < 0 && MathAbs(priceChangePercent) >= minPriceChangePercent && currVelocity > (velocitiesAvg * rangeExtendMultiplier) // ; // result = isBullish || isBearish; if (result) { // rootIDX = isBullish ? llIDX : hhIDX; // dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; } // return result; } // // Actions ... /** * Detect Spike ... * * @param bar: XOHCL instance reference, Start Bar ... * @param dir: ENUM_X_DIRECTION member, Event Direction ... * @param type: ENUM_X_PRICE member, Price Type ... * @param forcBodyInRange: bool, Use Body in Range Detection ... * @param rangeExtendMultiplier: double, a Multiplier for Checking Price Range ... * @param sameBars: int, Specified How Many Same Bars Required for an Spike ... * * @return ( bool ) */ bool IsSpike( XOHCL &bar, ENUM_X_DIRECTION &dir, int &rootIDX, ENUM_X_PRICE type = X_PRICE_CLOSE, bool forcBodyInRange = true, double rangeExtendMultiplier = 2.0, int sameBars = 3 // ) { // bool result = false; // dir = X_DIRECTION_NONE; sameBars = NormalizeInt(sameBars, 2); // result = IsValid(type) && bar.IsValid(); if (!result) { return result; } // // First We Have to Has a Big Change ... int sharpRootIDX = -1; result = IsSharp( bar, dir, sharpRootIDX, type, forcBodyInRange, rangeExtendMultiplier // ); if (!result) { return result; } // // Check Has Same Bars ... int sameBarsIndex = -1; ENUM_X_DIRECTION sameBarsDir; result = HasSameBars( bar, sameBarsDir, sameBarsIndex, sameBars // ); if (!result) { return result; } // // Check Same Bars Direction sames To Price Change ... result = sameBarsDir == dir; if (!result) { return result; } // rootIDX = sharpRootIDX; // return result; } /** * Check a Bar is Support Bar or not ... * * @param bar: XOHCL instance ... * @param supportBar: XOHCL instance, Provides Fouded Support Bar ... * @param range: Integer, Specified Verifiation Range ... * * @return ( bool ) */ bool HasSupport( XOHCL &bar, XOHCL &supportBar, int range = 21 // ) { // bool result = false; // result = bar.IsValid(); if (!result) { return result; } // int barIndex = bar.Index() + range; result = IsValidIndex(barIndex); if (!result) { // supportBar.Clean(); return result; } result = supportBar.Init( bar.symbol, bar.period, barIndex // ); // result = supportBar.low < supportBar.GetDown(); if (!result) { // supportBar.Clean(); return result; } // double selectedValue = supportBar.GetDown(); // int llIDX = bar.FindLowestIndex(range - 1, MODE_LOW); result = IsValidIndex(llIDX); if (!result) { // supportBar.Clean(); return result; } // double llValue = iLow( bar.symbol, bar.period, llIDX // ); // result = llValue >= selectedValue; if (!result) { // supportBar.Clean(); return result; } // result = supportBar.IsValid(); // return result; } /** * Check a Bar is Resistance Bar or not ... * * @param bar: XOHCL instance ... * @param resistanceBar: XOHCL instance, Provides Fouded Support Bar ... * @param range: Integer, Specified Verifiation Range ... * * @return ( bool ) */ bool HasResistance( XOHCL &bar, XOHCL &resistanceBar, int range = 21 // ) { // bool result = false; // resistanceBar.Clean(); // result = bar.IsValid(); if (!result) { return result; } // int barIndex = bar.Index() + range; result = IsValidIndex(barIndex); if (!result) { // resistanceBar.Clean(); return result; } result = resistanceBar.Init( bar.symbol, bar.period, barIndex // ); // result = resistanceBar.low < resistanceBar.GetDown(); if (!result) { // resistanceBar.Clean(); return result; } // double selectedValue = resistanceBar.GetUp(); // int hhIDX = bar.FindHighestIndex(range - 1, MODE_HIGH); result = IsValidIndex(hhIDX); if (!result) { // resistanceBar.Clean(); return result; } // double hhValue = iHigh( bar.symbol, bar.period, hhIDX // ); // result = hhValue >= selectedValue; if (!result) { // resistanceBar.Clean(); return result; } // result = resistanceBar.IsValid(); // return result; } /** * Detect a Fair Value Gap Based on Given Bar ... * * @param bar: XOHCL instance, Specified Start Bar ... * @param fromBar: XOHCL instance, Provides Start Bar of FVG ... * @param toBar: XOHCL instance, Provides End Bar of FVG ... * @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 HasFairValueGap( XOHCL &bar, XOHCL &fromBar, XOHCL &toBar, ENUM_X_DIRECTION &dir, int sameBars = 3 // ) { // bool result = false; // toBar.Clean(); fromBar.Clean(); dir = X_DIRECTION_NONE; sameBars = NormalizeInt(sameBars, 1); // result = bar.IsValid(); if (!result) { // toBar.Clean(); fromBar.Clean(); return result; } // int index = 0; result = HasSameBars( bar, dir, index, sameBars // ); if (!result) { return result; } // bool isBullish = IsBullish(dir); // int to = bar.Index(); int from = index > (to + sameBars) ? to + sameBars : index; for (int i = from; i > to; i--) { // result = fromBar.Init( bar.symbol, bar.period, i // ); if (!result) { break; } // result = toBar.Init( bar.symbol, bar.period, i - 2 // ); if (!result) { break; } // result = isBullish ? fromBar.high < toBar.low : fromBar.low > toBar.high; if (result) { break; } } // if (!result) { // toBar.Clean(); fromBar.Clean(); dir = X_DIRECTION_NONE; } // return result; } /** * 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 forceSpike = true, bool forceFairValueGap = true, bool forceSupportResistance = true // ) { // bool result = false; // ob.Clean(); dir = X_DIRECTION_NONE; sameBars = NormalizeInt(sameBars, 1); // result = bar.IsValid(); if (!result) { return result; } // // First Step We Have to Check Same Bars ... int spikeRootIDX = -1; int sameBarsIndex = -1; result = HasSameBars( bar, dir, sameBarsIndex, sameBars // ); if (!result) { // ob.Clean(); return result; } // // Must an Spike Happens ... if (forceSpike) { // ENUM_X_DIRECTION spikeDir; result = IsSpike( bar, spikeDir, spikeRootIDX, // Spike Root Index ... X_PRICE_CLOSE, // Price Type ... true, // Force Body ... 1.0, // Range Extend Multiplier ... sameBars // ); result = result && dir == spikeDir; if (!result) { // ob.Clean(); return result; } } // // Select Order Block Bar ... result = ob.Init( bar.symbol, bar.period, sameBarsIndex + 1 // ); ENUM_X_DIRECTION obDir = ob.GetDirection(); result = result && dir == Opposit(obDir); if (!result) { // ob.Clean(); return result; } // // if Bullish OB => Supports ... // if Bearish OB => Resistance ... if (forceSupportResistance) { // XOHCL supResBar; // // Check Support ... bool isSupport = HasSupport( ob, supResBar // ); // // Check Resistance ... bool isResistance = HasResistance( ob, supResBar // ); // supResBar.Clean(); // result = result && (IsBullish(dir) ? isSupport : isResistance); // if (!result) { ob.Clean(); } } // // Force Check Fair ValueGaps ... if (forceFairValueGap) { // XOHCL toBar; XOHCL fromBar; ENUM_X_DIRECTION fvgDir; bool isFVG = HasFairValueGap( bar, fromBar, toBar, fvgDir, sameBars // ); // result = isFVG && result && dir == fvgDir; // toBar.Clean(); fromBar.Clean(); } // return result; } /** * Check a Bar has Consolidation Zone or not ... * * @param bar: XOHCL instance, Specified Start Bar ... * @param zone: XConsolidationZone instance, consolidation Zone Object ... * @param minLoopback: int, min Allowed Lopback for Consolidating ... * @param range: double, Consolidation Range ... * @param upperAppliedTo: ENUM_X_PRICE member, Upper Selection Price ... * @param lowerAppliedTo: ENUM_X_PRICE member, Lower Selection Price ... * * @return ( bool ) */ bool HasConsolidationZone( XOHCL &bar, XConsolidationZone &zone, int minLoopback = 7, double range = 50, ENUM_X_PRICE upperAppliedTo = X_PRICE_HIGH, ENUM_X_PRICE lowerAppliedTo = X_PRICE_LOW // ) { // bool result = false; // zone.Clean(); range = NormalizeDouble(range, 50); minLoopback = NormalizeInt(minLoopback, 7); // result = bar.IsValid(); if (!result) { return result; } // double points = GetPoints(bar.symbol); int index = bar.Index() + 1; int length = minLoopback; // double upperPrice[]; int upperPriceCount = FillPrice( upperPrice, bar, length, upperAppliedTo // ); // double lowerPrice[]; int lowerPriceCount = FillPrice( lowerPrice, bar, length, lowerAppliedTo // ); // result = upperPriceCount == lowerPriceCount && lowerPriceCount == length; if (!result) { // Clean(upperPrice); Clean(lowerPrice); // return result; } // double upper = upperPrice[ArrayMaximum(upperPrice)]; double lower = lowerPrice[ArrayMinimum(lowerPrice)]; // bool isBullishBreake = bar.low > lower && bar.high > upper && bar.GetUp() > upper; bool isBearishBreake = bar.high < upper && bar.low < lower && bar.GetDown() < lower; result = isBullishBreake || isBearishBreake; if (!result) { // Clean(upperPrice); Clean(lowerPrice); // return result; } // double delta = upper - lower; result = delta <= range * points; if (!result) { // Clean(upperPrice); Clean(lowerPrice); // return result; } // while (delta <= range * points) { // length++; // upperPriceCount = FillPrice( upperPrice, bar, length, upperAppliedTo // ); // lowerPriceCount = FillPrice( lowerPrice, bar, length, lowerAppliedTo // ); // bool isValid = upperPriceCount == lowerPriceCount && lowerPriceCount == length; if (!isValid) { break; } // double iUpper = upperPrice[ArrayMaximum(upperPrice)]; double iLower = lowerPrice[ArrayMinimum(lowerPrice)]; // delta = iUpper - iLower; if (delta <= range * points) { // upper = iUpper; lower = iLower; } } // Clean(upperPrice); Clean(lowerPrice); // // Filling Zone ... zone.upper = upper; zone.lower = lower; zone.symbol = bar.symbol; zone.period = bar.period; zone.to = iTime( bar.symbol, bar.period, bar.Index() + 1 // ); zone.from = iTime( bar.symbol, bar.period, bar.Index() + length // ); zone.dir = isBullishBreake ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // result = zone.IsValid(); if (!result) { zone.Clean(); } // return result; } // // Candlestick ... /** * Check Specified Bar is Doji Pattern or not ... * * @param bar: XOHCL instance reference, Specified Bar to Check ... * @param dir: ENUM_X_DIRECTION member, Specified Doji Direction ... * @param shadowMultiplier: double, Specified Shadow Multiplier ... * * @return ( bool ) */ bool IsDoji( XOHCL &bar, ENUM_X_DIRECTION &dir, double shadowMultiplier = 1.5 // ) { // bool result = false; // dir = X_DIRECTION_NONE; shadowMultiplier = NormalizeDouble(shadowMultiplier, 1.5, 3); // result = bar.IsValid(); if (!result) { return result; } // double body = bar.GetBody(); double range = bar.GetRange(); // result = body > 0 && range > 0 ? (body / range < 0.1) : false; if (result) { // dir = bar.GetLowShadow() >= (bar.GetHighShadow() * shadowMultiplier) ? X_DIRECTION_BULLISH : bar.GetHighShadow() >= (bar.GetLowShadow() * shadowMultiplier) ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; // result = HasDirection(dir); } // return result; } /** * Check Specified Bar is Pullback or not ... * * @param bar: XOHCL instance reference, Specified Bar to Check ... * @param dir: ENUM_X_DIRECTION member, Specified Doji Direction ... * @param loopback: int, Specified Loopback ... * * @return ( bool ) */ bool IsSwing( XOHCL &bar, ENUM_X_DIRECTION &dir, int loopback = 7 // ) { // bool result = false; // dir = X_DIRECTION_NONE; loopback = NormalizeInt(loopback, 1); // result = bar.IsValid(); if (!result) { return result; } // XOHCL pBar; result = bar.GetPreviousBar(pBar); if (!result) { // pBar.Clean(); return result; } // XOHCL ppBar; result = pBar.GetPreviousBar(ppBar); if (!result) { // pBar.Clean(); ppBar.Clean(); return result; } // bool isBullish = // pBar.low < bar.low && pBar.low < ppBar.low && bar.GetDown() > pBar.low // ; // bool isBearish = // pBar.high > bar.high && pBar.high > ppBar.high && bar.GetUp() < pBar.high // ; // result = isBullish || isBearish; if (result) { // dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // ppBar.Clean(); int pBarIDX = pBar.Index(); for (int i = pBarIDX + 1; i < pBarIDX + loopback; i++) { // bool has = ppBar.Init( pBar.symbol, pBar.period, i // ); // isBullish = has && isBullish && pBar.low < ppBar.low; // isBearish = has && isBearish && pBar.high > ppBar.high; } // result = isBullish || isBearish; if (!result) { dir = X_DIRECTION_NONE; } } // // Cleanup Resources ... // pBar.Clean(); ppBar.Clean(); // return result; } /** * Check Specified Bar is Hammer Pattern or not ... * * @param bar: XOHCL instance reference, Specified Bar to Check ... * @param dir: ENUM_X_DIRECTION member, Specified Doji Direction ... * @param bodyMultiplier: double, Specified Body Multiplier ... * * @return ( bool ) */ bool IsHammer( XOHCL &bar, ENUM_X_DIRECTION &dir, double bodyMultiplier = 2.0 // ) { // bool result = false; // dir = X_DIRECTION_NONE; bodyMultiplier = NormalizeDouble(bodyMultiplier, 1.5, 3); // result = bar.IsValid(); if (!result) { return result; } // double body = bar.GetBody(); double lShadow = bar.GetLowShadow(); double hShadow = bar.GetHighShadow(); // bool isBullish = hShadow < body && lShadow > (bodyMultiplier * body); // bool isBearish = lShadow < body && hShadow > (bodyMultiplier * body); // result = isBullish || isBearish; if (result) { // dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; } // return result; } /** * Check Specified Bar is Engulfed Prev Bar or not ... * * @param bar: XOHCL instance reference, Specified Bar to Check ... * @param dir: ENUM_X_DIRECTION member, Specified Doji Direction ... * * @return ( bool ) */ bool IsEngulfed( XOHCL &bar, ENUM_X_DIRECTION &dir // ) { // bool result = false; // dir = X_DIRECTION_NONE; // result = bar.IsValid(); if (!result) { return result; } // XOHCL pBar; result = bar.GetPreviousBar(pBar); if (!result) { // pBar.Clean(); return result; } // result = bar.GetBody() > pBar.GetBody(); if (!result) { // pBar.Clean(); return result; } // bool isBullish = bar.IsBullish() && pBar.IsBearish() && bar.GetDown() <= pBar.GetDown() && bar.GetUp() > pBar.GetUp(); // bool isBearish = bar.IsBearish() && pBar.IsBullish() && bar.GetUp() >= pBar.GetUp() && bar.GetDown() < pBar.GetDown(); // result = isBullish || isBearish; if (result) { // dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; } // // Cleanup Resources ... // pBar.Clean(); // return result; } /** * Check Specified Bar is Momentum Bar or not ... * * @param bar: XOHCL instance reference, Specified Bar to Check ... * @param dir: ENUM_X_DIRECTION member, Specified Doji Direction ... * @param forceBarType: bool, Force Apply Bar Type ... * @param forceFiboPressure: bool, Force Apply Bar Type ... * * @return ( bool ) */ bool IsRejected( XOHCL &bar, ENUM_X_DIRECTION &dir, bool forceBarType = true, bool forceFiboPressure = true // ) { // bool result = false; // dir = X_DIRECTION_NONE; // result = bar.IsValid(); if (!result) { return result; } // // Check Bar Must Be Swing ... result = IsSwing( bar, dir // ); if (!result) { return result; } // bool isBullish = IsBullish(dir); bool isBearish = IsBearish(dir); // // Check Force Type ... if (forceBarType) { // isBullish = isBullish && bar.IsBullish(); // isBearish = isBearish && bar.IsBearish(); } // // Check Force Fibo Pressure ... if (forceFiboPressure) { // bool hasBullishFiboPressure = HasFiboPressure( bar, X_DIRECTION_BULLISH, X_FIBO_LEVEL_270 // ); // bool hasBearishFiboPressure = HasFiboPressure( bar, X_DIRECTION_BEARISH, X_FIBO_LEVEL_270 // ); // isBullish = isBullish && hasBullishFiboPressure; // isBearish = isBearish && hasBearishFiboPressure; } // result = isBullish || isBearish; if (!result) { dir = X_DIRECTION_NONE; } // return result; } /** * Check Specified Bar is Momentum Bar or not ... * * @param bar: XOHCL instance reference, Specified Bar to Check ... * @param dir: ENUM_X_DIRECTION member, Specified Doji Direction ... * @param loopback: int, Specified Loopback ... * @param rangeExtendMultiplier: double, a Multiplier for Checking Price Range ... * * @return ( bool ) */ bool IsMomentum( XOHCL &bar, ENUM_X_DIRECTION &dir, int loopback = 2, double rangeExtendMultiplier = 1.5 // ) { // bool result = false; // dir = X_DIRECTION_NONE; loopback = NormalizeInt(loopback, 1); rangeExtendMultiplier = NormalizeDouble(rangeExtendMultiplier, 1); // result = bar.IsValid(); if (!result) { return result; } // XOHCL pBar; result = bar.GetPreviousBar(pBar); if (!result) { // pBar.Clean(); return result; } // // Calculate HH and LL ... double hh = 0; double ll = 0; int hhIDX = -1; int llIDX = -1; result = CalculateLoopbackHLData( hhIDX, hh, llIDX, ll, bar, loopback // s ); result = result && ll > 0 && hh > ll && IsValidIndex(llIDX) && IsValidIndex(hhIDX); if (!result) { // pBar.Clean(); return result; } // bool isBullish = bar.low > ll && bar.close >= hh && bar.IsBullish() && bar.low > pBar.low && bar.high > pBar.high && bar.GetBody() > pBar.GetBody() && bar.GetRange() > pBar.GetRange() && bar.GetShadows() < pBar.GetShadows(); // bool isBearish = bar.high < hh && bar.close <= ll && bar.IsBearish() && bar.low < pBar.low && bar.high < pBar.high && bar.GetBody() > pBar.GetBody() && bar.GetRange() > pBar.GetRange() && bar.GetShadows() < pBar.GetShadows(); // result = isBullish || isBearish; if (result) { // dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; } // pBar.Clean(); // return result; } /** * Check Specified Bar is Pullback or not ... * * @param bar: XOHCL instance reference, Specified Bar to Check ... * @param dir: ENUM_X_DIRECTION member, Specified Doji Direction ... * @param loopback: int, Specified Loopback ... * @param forceBody: bool, Force Using Body ... * * @return ( bool ) */ bool IsPullback( XOHCL &bar, ENUM_X_DIRECTION &dir, int loopback = 3, bool forceBody = false // ) { // bool result = false; // dir = X_DIRECTION_NONE; loopback = NormalizeInt(loopback, 3); // result = bar.IsValid(); if (!result) { return result; } // // Check Bar Must Engulfed ... result = IsEngulfed( bar, dir // ); if (!result) { return result; } // // Calculate HH and LL ... double hh = 0; double ll = 0; int hhIDX = -1; int llIDX = -1; result = CalculateLoopbackHLData( hhIDX, hh, llIDX, ll, bar, loopback // ); result = result && ll > 0 && hh > ll && IsValidIndex(llIDX) && IsValidIndex(hhIDX); if (!result) { return result; } // bool isBullish = bar.high > hh && bar.low > ll; // bool isBearish = bar.high < hh && bar.low < ll; // result = isBullish || isBearish; if (result) { // if (forceBody) { // isBullish = isBullish && bar.GetUp() > hh && bar.GetDown() > ll && llIDX == bar.Index() + 1; // isBearish = isBearish && bar.GetUp() < hh && bar.GetDown() < ll && hhIDX == bar.Index() + 1; // result = isBullish || isBearish; } // if (result) { // dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; } } // return result; } // protected: // // private: // // // Props ... // // Actions ... // }; //