Files
MQL5Data/Classes/x-saherelm.x-bar.analyser.class.mq5
T
2025-03-18 23:41:12 +03:30

2646 lines
56 KiB
Plaintext

///////////////////////////////////////////////////////
//
// 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 )
*/
int FillPrice(
double &prices[],
XOHCL &bar,
int loopback = 14,
ENUM_X_PRICE type = X_PRICE_CLOSE //
)
{
//
int result = 0;
//
Clean(prices);
//
loopback = NormalizeInt(loopback, 1);
//
bool has = IsValid(type) &&
bar.IsValid();
if (!has)
{
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;
has = CalculateLoopbackData(
index,
start,
end,
count,
bar,
loopback //
);
if (!has)
{
return result;
}
//
for (int i = start; i < end; 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);
has = result == count;
if (!has)
{
//
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 supportIDX = bar.Index() + range;
result = supportBar.Init(
bar.symbol,
bar.period,
supportIDX //
);
if (!result)
{
//
supportBar.Clean();
return result;
}
//
result = bar.low > supportBar.low;
if (!result)
{
//
supportBar.Clean();
return result;
}
//
// Validate Point ...
for (int i = 1; i < range; i++)
{
//
XOHCL iPBar;
XOHCL iNBar;
bool iHas = false;
//
iHas = iPBar.Init(
bar.symbol,
bar.period,
supportIDX + i //
);
result = iHas;
if (!result)
{
break;
}
//
iHas = iNBar.Init(
bar.symbol,
bar.period,
supportIDX - i //
);
result = iHas;
if (!result)
{
break;
}
//
result = supportBar.low < iPBar.low &&
supportBar.low < iNBar.low;
if (!result)
{
break;
}
}
//
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;
//
result = bar.IsValid();
if (!result)
{
return result;
}
//
int resistanceIDX = bar.Index() + range;
result = resistanceBar.Init(
bar.symbol,
bar.period,
resistanceIDX //
);
if (!result)
{
//
resistanceBar.Clean();
return result;
}
//
result = bar.high < resistanceBar.high;
if (!result)
{
//
resistanceBar.Clean();
return result;
}
//
// Validate Point ...
for (int i = 1; i < range; i++)
{
//
XOHCL iPBar;
XOHCL iNBar;
bool iHas = false;
//
iHas = iPBar.Init(
bar.symbol,
bar.period,
resistanceIDX + i //
);
result = iHas;
if (!result)
{
break;
}
//
iHas = iNBar.Init(
bar.symbol,
bar.period,
resistanceIDX - i //
);
result = iHas;
if (!result)
{
break;
}
//
result = resistanceBar.high > iPBar.high &&
resistanceBar.high > iNBar.high;
if (!result)
{
break;
}
}
//
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;
}
//
XOHCL sBar;
if (bar.Index() == 0)
{
//
result = bar.GetPreviousBar(sBar);
if (!result)
{
//
sBar.Clean();
return result;
}
}
else
{
sBar = bar;
}
//
// 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.5, // Range Extend Multiplier ...
sameBars //
);
result =
result &&
dir == spikeDir;
if (!result)
{
//
ob.Clean();
return result;
}
}
//
// Select OB Candidate Bars ...
XOHCL sameBar;
XOHCL rootBar;
XOHCL rootPBar;
result = sameBar.Init(
bar.symbol,
bar.period,
sameBarsIndex + 1 //
);
if (!result)
{
//
sBar.Clean();
sameBar.Clean();
return result;
}
result = rootBar.Init(
bar.symbol,
bar.period,
spikeRootIDX //
);
if (!result)
{
//
sBar.Clean();
rootBar.Clean();
sameBar.Clean();
return result;
}
result = rootBar.GetPreviousBar(rootPBar);
if (!result)
{
//
sBar.Clean();
rootBar.Clean();
sameBar.Clean();
rootPBar.Clean();
return result;
}
//
// Select ob Bar ...
if (rootBar.GetDirection() == Opposit(dir))
{
ob = rootBar;
}
else if (rootPBar.GetDirection() == Opposit(dir))
{
ob = rootPBar;
}
else if (sameBar.GetDirection() == Opposit(dir))
{
ob = sameBar;
}
else
{
ob.Clean();
}
//
// Select Order Block Bar ...
result = ob.IsValid();
ENUM_X_DIRECTION obDir = ob.GetDirection();
result =
result &&
dir == Opposit(obDir);
if (!result)
{
//
sBar.Clean();
rootBar.Clean();
sameBar.Clean();
rootPBar.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();
sBar.Clean();
rootBar.Clean();
sameBar.Clean();
rootPBar.Clean();
//
return result;
}
}
//
// 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();
}
//
// Cleanup Resource ...
//
sBar.Clean();
rootBar.Clean();
sameBar.Clean();
rootPBar.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;
}
//
XOHCL pBar;
result = bar.GetPreviousBar(pBar);
if (!result)
{
//
pBar.Clean();
return result;
}
//
bool isBullish =
//
bar.low < pBar.low &&
bar.GetShadows() > bar.GetBody() &&
bar.GetLowShadow() > bar.GetBody() &&
bar.GetLowShadow() > bar.GetHighShadow()
//
;
//
bool isBearish =
//
bar.high > pBar.high &&
bar.GetShadows() > bar.GetBody() &&
bar.GetHighShadow() > bar.GetBody() &&
bar.GetHighShadow() > bar.GetLowShadow()
//
;
//
result = isBullish ||
isBearish;
if (!result)
{
//
pBar.Clean();
return result;
}
//
// Check Force Type ...
if (forceBarType)
{
//
isBullish =
isBullish &&
bar.IsBullish();
//
isBearish =
isBearish &&
bar.IsBearish();
//
result = isBullish ||
isBearish;
if (!result)
{
//
pBar.Clean();
return result;
}
}
//
// Check Force Fibo Pressure ...
if (forceFiboPressure)
{
//
bool hasBullishFiboPressure =
HasFiboPressure(
bar,
X_DIRECTION_BULLISH,
X_FIBO_LEVEL_236 //
);
//
bool hasBearishFiboPressure =
HasFiboPressure(
bar,
X_DIRECTION_BEARISH,
X_FIBO_LEVEL_236 //
);
//
isBullish =
isBullish &&
hasBullishFiboPressure;
//
isBearish =
isBearish &&
hasBearishFiboPressure;
}
//
result = isBullish ||
isBearish;
if (result)
{
//
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
}
//
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 loopback: int, Specified Loopback ...
*
* @return ( bool )
*/
bool IsMomentum(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
int loopback = 2 //
)
{
//
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;
}
//
// 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;
}
//
//
//
/**
* Check a Bar is Valid for Specified Direction of Positions ...
*
* @param bar: XOHCL instance, Start Bar ...
* @param dir: ENUM_X_DIRECTION member, Provide Direction ...
*
* @return ( bool )
*/
bool IsValidForPosition(
XOHCL &bar,
ENUM_X_DIRECTION &dir //
)
{
//
bool result = false;
//
int loopback = 3;
dir = X_DIRECTION_NONE;
//
result = bar.IsValid();
if (!result)
{
return result;
}
//
// DOJI ...
ENUM_X_DIRECTION dojiDir;
bool isDoji = IsDoji(
bar,
dojiDir //
);
bool isBullishDoji =
isDoji &&
IsBullish(dojiDir);
bool isBearishDoji =
isDoji &&
IsBearish(dojiDir);
//
// SWING ...
ENUM_X_DIRECTION swingDir;
bool isSwing = IsSwing(
bar,
swingDir //
);
bool isBullishSwing =
isSwing &&
IsBullish(swingDir);
bool isBearishSwing =
isSwing &&
IsBearish(swingDir);
//
// HAMMER ...
ENUM_X_DIRECTION hammerDir;
bool isHammer = IsHammer(
bar,
hammerDir //
);
bool isBullishHammer =
isHammer &&
IsBullish(hammerDir);
bool isBearishHammer =
isHammer &&
IsBearish(hammerDir);
//
// ENGULF ...
ENUM_X_DIRECTION engulfDir;
bool isEngulfed = IsEngulfed(
bar,
engulfDir //
);
bool isBullishEngulfed =
isEngulfed &&
IsBullish(engulfDir);
bool isBearishEngulfed =
isEngulfed &&
IsBearish(engulfDir);
//
// REJECTED ...
ENUM_X_DIRECTION rejectedDir;
bool isRejected = IsRejected(
bar,
rejectedDir //
);
bool isBullishRejected =
isRejected &&
IsBullish(rejectedDir);
bool isBearishRejected =
isRejected &&
IsBearish(rejectedDir);
//
// MOMENTUM ...
ENUM_X_DIRECTION momentumDir;
bool isMomentum = IsMomentum(
bar,
momentumDir //
);
bool isBullishMomentum =
isMomentum &&
IsBullish(momentumDir);
bool isBearishMomentum =
isMomentum &&
IsBearish(momentumDir);
//
// PULLBACK ...
ENUM_X_DIRECTION pullbackDir;
bool isPullback = IsPullback(
bar,
pullbackDir //
);
bool isBullishPullback =
isPullback &&
IsBullish(pullbackDir);
bool isBearishPullback =
isPullback &&
IsBearish(pullbackDir);
//
// Summarize Conditions ...
//
bool isBullishOr =
isBullishDoji ||
isBullishSwing ||
isBullishHammer ||
isBullishEngulfed ||
isBullishRejected ||
isBullishMomentum ||
isBullishPullback;
//
bool isBearishOr =
isBearishDoji ||
isBearishSwing ||
isBearishHammer ||
isBearishEngulfed ||
isBearishRejected ||
isBearishMomentum ||
isBearishPullback;
//
bool isBullish =
isBullishOr &&
!isBearishOr;
//
bool isBearish =
!isBullishOr &&
isBearishOr;
//
result = isBullish ||
isBearish;
if (result)
{
//
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
}
//
return result;
}
//
protected:
//
//
private:
//
//
// Props ...
//
// Actions ...
//
};
//