3454 lines
78 KiB
Plaintext
3454 lines
78 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 ...
|
|
|
|
//
|
|
// Extensions ...
|
|
void FillLiquidity(
|
|
XOHCL &lBar,
|
|
ENUM_X_DIRECTION lDir,
|
|
XBoxZone &lq,
|
|
datetime to //
|
|
)
|
|
{
|
|
//
|
|
// Normalize Args ...
|
|
lq.Clean();
|
|
to = NormalizeTime(to);
|
|
|
|
//
|
|
// Validate Args ...
|
|
bool has = lBar.IsValid() &&
|
|
HasDirection(lDir);
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
lq.to = to;
|
|
lq.dir = lDir;
|
|
lq.type = "XLQ";
|
|
lq.from = lBar.time;
|
|
lq.symbol = lBar.symbol;
|
|
lq.period = lBar.period;
|
|
lq.upper = IsBullish(lDir)
|
|
? lBar.GetDown()
|
|
: lBar.high;
|
|
lq.lower = IsBullish(lDir)
|
|
? lBar.low
|
|
: lBar.GetUp();
|
|
}
|
|
|
|
//
|
|
// 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 forceDiff: bool, Force to Calculate Range using Onl Price Diff ...
|
|
* @param loopback: int, loopback period for Range Calculations ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int GetPriceRange(
|
|
double &ranges[],
|
|
XOHCL &bar,
|
|
bool forceBody = false,
|
|
bool forceDiff = 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 iDiff = uppers[i] - lowers[i];
|
|
double iValue =
|
|
forceDiff
|
|
? iDiff
|
|
: lowers[i] + iDiff;
|
|
|
|
//
|
|
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 Range Block ...
|
|
*/
|
|
bool DetectRangeBlocks(
|
|
XOHCL &bar,
|
|
XBoxZone &upper,
|
|
XBoxZone &lower,
|
|
int loopback = 288,
|
|
ENUM_SERIESMODE upperRangeUpperMode = MODE_HIGH,
|
|
ENUM_SERIESMODE upperRangeLowerMode = MODE_LOW,
|
|
ENUM_SERIESMODE lowerRangeUpperMode = MODE_HIGH,
|
|
ENUM_SERIESMODE lowerRangeLowerMode = MODE_LOW //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Args ...
|
|
upper.Clean();
|
|
lower.Clean();
|
|
loopback = NormalizeInt(loopback, 10);
|
|
|
|
//
|
|
// Validate Args ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL iBar;
|
|
result = iBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
bar.Index() + loopback //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double hhUpper = iBar.FindHighest(loopback, upperRangeUpperMode);
|
|
double hhLower = iBar.FindHighest(loopback, upperRangeLowerMode);
|
|
|
|
//
|
|
double llUpper = iBar.FindLowest(loopback, lowerRangeUpperMode);
|
|
double llLower = iBar.FindLowest(loopback, lowerRangeLowerMode);
|
|
|
|
//
|
|
double bhhUpper = bar.FindHighest(iBar.Index() - bar.Index(), upperRangeUpperMode);
|
|
double bhhLower = bar.FindHighest(iBar.Index() - bar.Index(), upperRangeLowerMode);
|
|
|
|
//
|
|
double bllUpper = bar.FindLowest(iBar.Index() - bar.Index(), lowerRangeUpperMode);
|
|
double bllLower = bar.FindLowest(iBar.Index() - bar.Index(), lowerRangeLowerMode);
|
|
|
|
//
|
|
hhUpper = MathMax(hhUpper, bhhUpper);
|
|
hhLower = MathMax(hhLower, bhhLower);
|
|
|
|
//
|
|
llUpper = MathMin(llUpper, bllUpper);
|
|
llLower = MathMin(llLower, bllLower);
|
|
|
|
//
|
|
datetime from = GetBarTime(
|
|
iBar.symbol,
|
|
iBar.period,
|
|
iBar.Index() + loopback //
|
|
);
|
|
|
|
//
|
|
upper.from = from;
|
|
upper.type = "XRNG";
|
|
upper.to = bar.time;
|
|
upper.upper = hhUpper;
|
|
upper.lower = hhLower;
|
|
upper.symbol = iBar.symbol;
|
|
upper.period = iBar.period;
|
|
upper.dir = X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
lower.from = from;
|
|
lower.type = "XRNG";
|
|
lower.to = bar.time;
|
|
lower.upper = llUpper;
|
|
lower.lower = llLower;
|
|
lower.symbol = iBar.symbol;
|
|
lower.period = iBar.period;
|
|
lower.dir = X_DIRECTION_BULLISH;
|
|
|
|
//
|
|
result = upper.IsValid() &&
|
|
lower.IsValid();
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
upper.Clean();
|
|
lower.Clean();
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Specified Bars Range Volume ...
|
|
*
|
|
* @param bar: XOHCL instance reference ...
|
|
* @param bullishVolume: double
|
|
* @param bearishVolume: double
|
|
* @param loopback: int
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool CalculateRangeVolume(
|
|
XOHCL &bar,
|
|
double &bullishVolume,
|
|
double &bearishVolume,
|
|
int loopback = 5 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Args ...
|
|
bullishVolume = 0;
|
|
bearishVolume = 0;
|
|
loopback = NormalizeInt(loopback, 3);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL iBar;
|
|
bool has = false;
|
|
int start = bar.Index();
|
|
int end = start + loopback;
|
|
for (int i = start; i <= end; i++)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
has = iBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i //
|
|
);
|
|
if (!has)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
bool isBullish = iBar.IsBullish();
|
|
bool isBearish = iBar.IsBearish();
|
|
|
|
//
|
|
if (isBullish)
|
|
{
|
|
bullishVolume += (double)iBar.volume;
|
|
}
|
|
else if (isBearish)
|
|
{
|
|
bearishVolume += (double)iBar.volume;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
bullishVolume += (double)iBar.volume;
|
|
bearishVolume += (double)iBar.volume;
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
}
|
|
|
|
//
|
|
result = iBar.IsValid();
|
|
|
|
//
|
|
iBar.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 ...
|
|
|
|
/**
|
|
* Check a Bar is End of an OrderBlock Bar or Not ...
|
|
*
|
|
* @param bar: XOHCL ...
|
|
* @param box: XBoxZone ...
|
|
* @param forceFVGBarType: bool, Force all Bars must be Same as Direction ...
|
|
* @param forceOBTwoBar: bool, Force Two Bars of OB Start must be InDirection ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsOB(
|
|
XOHCL &bar,
|
|
XBoxZone &box,
|
|
bool forceFVGBarType = false,
|
|
bool forceOBTwoBar = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
box.Clean();
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Bar Must be FVG ...
|
|
result = IsFVG(
|
|
bar,
|
|
box,
|
|
forceFVGBarType //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
box.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
box.type = "XOB";
|
|
|
|
//
|
|
bool isBullish = box.IsBullish();
|
|
bool isBearish = box.IsBearish();
|
|
|
|
//
|
|
// Order Block Includes an FVG which Starts by atleast One
|
|
// or More Indirectional Bars ...
|
|
XOHCL fvgLastBar;
|
|
XOHCL fvgLastBarPrev;
|
|
XOHCL fvgLastBarPrev2;
|
|
|
|
//
|
|
int barIndex = bar.Index();
|
|
int fvgLastBarIndex = barIndex + 3;
|
|
result = fvgLastBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
fvgLastBarIndex //
|
|
);
|
|
result =
|
|
result &&
|
|
fvgLastBar.GetPreviousBar(fvgLastBarPrev);
|
|
result =
|
|
result &&
|
|
fvgLastBarPrev.GetPreviousBar(fvgLastBarPrev2);
|
|
if (!result)
|
|
{
|
|
//
|
|
box.Clean();
|
|
fvgLastBar.Clean();
|
|
fvgLastBarPrev.Clean();
|
|
fvgLastBarPrev2.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check FVG Last Bar ...
|
|
|
|
//
|
|
bool isBullishBlock =
|
|
isBullish &&
|
|
(fvgLastBar.IsBearish() ||
|
|
(fvgLastBar.IsBullish() &&
|
|
fvgLastBarPrev.IsBearish()));
|
|
|
|
//
|
|
bool isBearishBlock =
|
|
isBearish &&
|
|
(fvgLastBar.IsBullish() ||
|
|
(fvgLastBar.IsBearish() &&
|
|
fvgLastBarPrev.IsBullish()));
|
|
|
|
//
|
|
// Update Box ...
|
|
|
|
//
|
|
if (isBullishBlock ||
|
|
isBearishBlock)
|
|
{
|
|
//
|
|
box.from = fvgLastBar.time;
|
|
|
|
//
|
|
box.lower = MathMin(box.lower, fvgLastBar.low);
|
|
box.upper = MathMax(box.upper, fvgLastBar.high);
|
|
}
|
|
|
|
//
|
|
// Apply Force Two Bar ...
|
|
if (forceOBTwoBar)
|
|
{
|
|
//
|
|
isBullishBlock =
|
|
isBullishBlock &&
|
|
fvgLastBarPrev.IsBearish();
|
|
|
|
//
|
|
isBearishBlock =
|
|
isBearishBlock &&
|
|
fvgLastBarPrev.IsBullish();
|
|
|
|
//
|
|
// Update Box ...
|
|
if (isBullishBlock ||
|
|
isBearishBlock)
|
|
{
|
|
//
|
|
box.from = fvgLastBarPrev.time;
|
|
box.lower = MathMin(box.lower, fvgLastBarPrev.low);
|
|
box.upper = MathMax(box.upper, fvgLastBarPrev.high);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = isBullishBlock ||
|
|
isBearishBlock;
|
|
if (!result)
|
|
{
|
|
//
|
|
box.Clean();
|
|
fvgLastBar.Clean();
|
|
fvgLastBarPrev.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = box.IsValid();
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
fvgLastBar.Clean();
|
|
fvgLastBarPrev.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a Bar is End of an FVG Bar or Not ...
|
|
*
|
|
* @param bar: XOHCL ...
|
|
* @param box: XBoxZone ...
|
|
* @param forceType: bool, Force all Bars must be Same as Direction ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsFVG(
|
|
XOHCL &bar,
|
|
XBoxZone &box,
|
|
bool forceType = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
box.Clean();
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL pBar;
|
|
XOHCL p2Bar;
|
|
result = bar.GetPreviousBar(pBar);
|
|
result = result &&
|
|
pBar.GetPreviousBar(p2Bar);
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = p2Bar.high < bar.low;
|
|
bool isBearish = p2Bar.low > bar.high;
|
|
|
|
//
|
|
result = isBullish ||
|
|
isBearish;
|
|
|
|
//
|
|
// Apply Force Type ...
|
|
if (result)
|
|
{
|
|
//
|
|
if (isBullish)
|
|
{
|
|
//
|
|
result =
|
|
bar.IsBullish() &&
|
|
pBar.IsBullish() &&
|
|
p2Bar.IsBullish();
|
|
}
|
|
else if (isBearish)
|
|
{
|
|
//
|
|
result =
|
|
bar.IsBearish() &&
|
|
pBar.IsBearish() &&
|
|
p2Bar.IsBearish();
|
|
}
|
|
}
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
box.to = bar.time;
|
|
box.from = p2Bar.time;
|
|
box.symbol = bar.symbol;
|
|
box.period = bar.period;
|
|
box.dir = isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
box.upper = isBullish
|
|
? bar.low
|
|
: p2Bar.low;
|
|
box.lower = isBullish
|
|
? p2Bar.high
|
|
: bar.high;
|
|
box.type = "XFVG";
|
|
}
|
|
|
|
//
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
result = box.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a Bar is a Trigger Box or Not ...
|
|
*
|
|
* @param bar: XOHCL instance Referernce, Specified Start Bar to Check ...
|
|
* @param trigger: XBoxZone instance Reference, Holds Detected Trigger Bar ...
|
|
* @param ob: XBoxZone instance Reference, Holds Detected Trigger Bar's OB ...
|
|
* @param fvg: XBoxZone instance Reference, Holds Detected Trigger Bar's FVG ...
|
|
* @param rLiquidity: XBoxZone instance Reference, Holds Detected Trigger Bar's Reversal Side Liquidity ...
|
|
* @param fLiquidity: XBoxZone instance Reference, Holds Detected Trigger Bar's Following Side Liquidity ...
|
|
* @param swingBar: XOHCL instance Referernce, Holds Detected Trigger Bar's Swing ...
|
|
* @param loopback: int, Loopback Bars Count ...
|
|
* @param maxAllowedRange: double, Max Allowed Trigger's OB Range ...
|
|
* @param minAllowedBlockEdgeLength: int, Min Allowed Block Edge Validation Length ...
|
|
* @param forceOBOppositBar: bool, Force OB to Start by Opposite Bar ...
|
|
* @param forceFVGBarType: bool, Force FVG to Has Same Bar Type ...
|
|
* @param forceGapBarBreakout: bool, Force Gap Bar Breakout OB Edge ...
|
|
* @param forceHasSwingBar: bool, Force Has Swing Bar ...
|
|
* @param forceHasLiquidity: bool, Force Has Following Liquidity ...
|
|
* @param forceHasReversalLiquidity: bool, Force Has Reversal Liquidity ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsTrigger(
|
|
XOHCL &bar,
|
|
XBoxZone &trigger,
|
|
XBoxZone &ob,
|
|
XBoxZone &fvg,
|
|
XBoxZone &rLiquidity,
|
|
XBoxZone &fLiquidity,
|
|
XOHCL &swingBar,
|
|
int loopback = 10,
|
|
double maxAllowedRange = 0.0,
|
|
int minAllowedBlockEdgeLength = 0,
|
|
bool forceOBOppositBar = true,
|
|
bool forceFVGBarType = true,
|
|
bool forceGapBarBreakout = true,
|
|
bool forceHasSwingBar = true,
|
|
bool forceHasLiquidity = true,
|
|
bool forceHasReversalLiquidity = true //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Args ...
|
|
ob.Clean();
|
|
fvg.Clean();
|
|
trigger.Clean();
|
|
swingBar.Clean();
|
|
rLiquidity.Clean();
|
|
fLiquidity.Clean();
|
|
loopback = NormalizeInt(loopback, 5);
|
|
|
|
//
|
|
// Validate Args ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL pBar;
|
|
XOHCL tmpBar;
|
|
XOHCL tmpPBar;
|
|
ENUM_X_DIRECTION iDir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = bar.GetPreviousBar(pBar);
|
|
|
|
//
|
|
// Detect Base Order Block ...
|
|
result =
|
|
result &&
|
|
//
|
|
// Order Block Detection ...
|
|
IsOB(
|
|
pBar,
|
|
ob,
|
|
forceFVGBarType,
|
|
forceOBOppositBar //
|
|
) &&
|
|
//
|
|
// Gap Detection ...
|
|
IsFVG(
|
|
pBar,
|
|
fvg,
|
|
forceFVGBarType //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
trigger = ob;
|
|
trigger.type = "XTRG";
|
|
}
|
|
|
|
//
|
|
// Reading Requirements ...
|
|
|
|
//
|
|
double points = GetPoints(bar.symbol);
|
|
|
|
//
|
|
bool isBullish = ob.IsBullish();
|
|
bool isBearish = ob.IsBearish();
|
|
|
|
//
|
|
int toIDX = trigger.ToIndex();
|
|
int fromIDX = trigger.FromIndex();
|
|
|
|
//
|
|
// Validate Gaps Bar Breakeout ...
|
|
if (result &&
|
|
forceGapBarBreakout)
|
|
{
|
|
//
|
|
// Extract Gap Bar ...
|
|
tmpBar.Clean();
|
|
tmpPBar.Clean();
|
|
result =
|
|
//
|
|
// Retrieve Bars ...
|
|
fvg.ToBar(tmpBar) &&
|
|
tmpBar.GetPreviousBar(tmpPBar) &&
|
|
//
|
|
// Validate Gap Bar is Momentum Bar ...
|
|
IsMomentum(
|
|
tmpPBar,
|
|
iDir,
|
|
1 //
|
|
) &&
|
|
iDir == fvg.dir &&
|
|
//
|
|
// Validate ...
|
|
(isBullish
|
|
? tmpPBar.close > ob.upper
|
|
: tmpPBar.close < ob.lower);
|
|
|
|
//
|
|
tmpBar.Clean();
|
|
tmpPBar.Clean();
|
|
}
|
|
|
|
//
|
|
// Validate Range ...
|
|
if (result &&
|
|
maxAllowedRange > 0)
|
|
{
|
|
//
|
|
double range = ob.GetRange();
|
|
result = range <= (maxAllowedRange * points);
|
|
}
|
|
|
|
//
|
|
// Validating Swing Bar ...
|
|
if (result &&
|
|
forceHasSwingBar)
|
|
{
|
|
//
|
|
int swingIDX = -1;
|
|
result = ob.FromBar(tmpBar);
|
|
if (result)
|
|
{
|
|
//
|
|
// Detect Swing Bar Index ...
|
|
if (isBullish)
|
|
{
|
|
swingIDX = tmpBar.FindLowestIndex(loopback, MODE_LOW);
|
|
}
|
|
else if (isBearish)
|
|
{
|
|
swingIDX = tmpBar.FindHighestIndex(loopback, MODE_HIGH);
|
|
}
|
|
result = IsValidIndex(swingIDX);
|
|
if (result)
|
|
{
|
|
//
|
|
// Initialize Swing Bar ...
|
|
result = swingBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
swingIDX //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Update Trigger Block based on Swing Bar ...
|
|
result = swingBar.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
// Update From ...
|
|
trigger.from = ((datetime)MathMin((int)trigger.from, (int)swingBar.time));
|
|
|
|
//
|
|
// Update Edge ...
|
|
if (isBullish)
|
|
{
|
|
trigger.lower = MathMin(trigger.lower, swingBar.GetDown());
|
|
}
|
|
else if (isBearish)
|
|
{
|
|
trigger.upper = MathMax(trigger.upper, swingBar.GetUp());
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
tmpBar.Clean();
|
|
}
|
|
|
|
//
|
|
// Validate Min Block Edge ...
|
|
if (result &&
|
|
minAllowedBlockEdgeLength > 0)
|
|
{
|
|
//
|
|
fromIDX = trigger.FromIndex();
|
|
if (result)
|
|
{
|
|
//
|
|
// Looping Back ...
|
|
for (int i = fromIDX; i < fromIDX + minAllowedBlockEdgeLength; i++)
|
|
{
|
|
//
|
|
// Initialize i Bar ...
|
|
result = tmpBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i //
|
|
);
|
|
result =
|
|
result &&
|
|
(isBullish
|
|
? tmpBar.low > trigger.lower
|
|
: tmpBar.high > trigger.upper);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
tmpBar.Clean();
|
|
}
|
|
result = tmpBar.IsValid();
|
|
|
|
//
|
|
// Update Trigger Block ...
|
|
if (result)
|
|
{
|
|
trigger.from = ((datetime)(MathMin((int)trigger.from, (int)tmpBar.time)));
|
|
}
|
|
}
|
|
|
|
//
|
|
tmpBar.Clean();
|
|
}
|
|
|
|
//
|
|
// Validating Liquidity ...
|
|
if (result &&
|
|
(forceHasLiquidity ||
|
|
forceHasReversalLiquidity))
|
|
{
|
|
//
|
|
// Try to Detect Liquidity ...
|
|
toIDX = ob.ToIndex();
|
|
for (int i = toIDX; i < toIDX + (loopback * 10); i++)
|
|
{
|
|
//
|
|
// Initialize i Bar ...
|
|
result = tmpBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Detect Liquidity ...
|
|
bool isRejected =
|
|
result &&
|
|
IsRejected(
|
|
tmpBar,
|
|
iDir,
|
|
false, // Force Bar Type ...
|
|
true // Force Fibo Pressure ...
|
|
);
|
|
bool isBullishRejected =
|
|
isRejected &&
|
|
IsBullish(iDir);
|
|
bool isBearishRejected =
|
|
isRejected &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// Validate Liquidities ...
|
|
if (isBullish)
|
|
{
|
|
//
|
|
if (isBullishRejected &&
|
|
forceHasLiquidity &&
|
|
!fLiquidity.IsValid() &&
|
|
tmpBar.low < trigger.lower)
|
|
{
|
|
//
|
|
// Filling Following Liquidity ...
|
|
FillLiquidity(
|
|
tmpBar,
|
|
trigger.dir,
|
|
fLiquidity,
|
|
trigger.to //
|
|
);
|
|
}
|
|
|
|
//
|
|
if (isBearishRejected &&
|
|
!rLiquidity.IsValid() &&
|
|
forceHasReversalLiquidity &&
|
|
tmpBar.high > trigger.upper)
|
|
{
|
|
//
|
|
// Filling Revrsal Liquidity ...
|
|
FillLiquidity(
|
|
tmpBar,
|
|
Opposit(trigger.dir),
|
|
rLiquidity,
|
|
trigger.to //
|
|
);
|
|
}
|
|
}
|
|
else if (isBearish)
|
|
{
|
|
//
|
|
if (isBearishRejected &&
|
|
forceHasLiquidity &&
|
|
!fLiquidity.IsValid() &&
|
|
tmpBar.high > trigger.upper)
|
|
{
|
|
//
|
|
// Filling Following Liquidity ...
|
|
FillLiquidity(
|
|
tmpBar,
|
|
trigger.dir,
|
|
fLiquidity,
|
|
trigger.to //
|
|
);
|
|
}
|
|
|
|
//
|
|
if (isBullishRejected &&
|
|
!rLiquidity.IsValid() &&
|
|
forceHasReversalLiquidity &&
|
|
tmpBar.low < trigger.lower)
|
|
{
|
|
//
|
|
// Filling Reversal Liquidity ...
|
|
FillLiquidity(
|
|
tmpBar,
|
|
Opposit(trigger.dir),
|
|
rLiquidity,
|
|
trigger.to //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
if ((!forceHasLiquidity
|
|
? true
|
|
: fLiquidity.IsValid()) &&
|
|
(!forceHasReversalLiquidity
|
|
? true
|
|
: rLiquidity.IsValid()))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
tmpBar.Clean();
|
|
}
|
|
tmpBar.Clean();
|
|
|
|
//
|
|
result = (!forceHasLiquidity
|
|
? true
|
|
: fLiquidity.IsValid()) &&
|
|
(!forceHasReversalLiquidity
|
|
? true
|
|
: rLiquidity.IsValid());
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
pBar.Clean();
|
|
tmpBar.Clean();
|
|
tmpPBar.Clean();
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
//
|
|
ob.Clean();
|
|
fvg.Clean();
|
|
trigger.Clean();
|
|
swingBar.Clean();
|
|
rLiquidity.Clean();
|
|
fLiquidity.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
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 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 Swing or not ...
|
|
*
|
|
* @param bar: XOHCL instance reference, Specified Bar to Check ...
|
|
* @param dir: ENUM_X_DIRECTION member, Specified 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's Prev Bar is Simple Swing or not ...
|
|
*
|
|
* @param bar: XOHCL instance reference, Specified Bar to it's Prev Check ...
|
|
* @param dir: ENUM_X_DIRECTION member, Specified Direction ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSimpleSwing(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
// Valdate Args ...
|
|
result = bar.IsValid();
|
|
|
|
//
|
|
// Reading Requirements ...
|
|
XOHCL cBar;
|
|
XOHCL pBar;
|
|
XOHCL p2Bar;
|
|
result =
|
|
bar.GetPreviousBar(cBar);
|
|
result =
|
|
result &&
|
|
cBar.GetPreviousBar(pBar);
|
|
result =
|
|
result &&
|
|
pBar.GetPreviousBar(p2Bar);
|
|
if (!result)
|
|
{
|
|
//
|
|
cBar.Clean();
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Now we Have to Check pBar is Swing Low or High ...
|
|
|
|
//
|
|
bool isPBarSwingLow =
|
|
pBar.low < cBar.low &&
|
|
pBar.low < p2Bar.low;
|
|
|
|
//
|
|
bool isPBarSwingHigh =
|
|
pBar.high > cBar.high &&
|
|
pBar.high > p2Bar.high;
|
|
|
|
//
|
|
result = isPBarSwingLow ||
|
|
isPBarSwingHigh;
|
|
if (result)
|
|
{
|
|
//
|
|
dir = isPBarSwingLow
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
}
|
|
|
|
//
|
|
// Cleanup Resourses ...
|
|
|
|
//
|
|
cBar.Clean();
|
|
pBar.Clean();
|
|
p2Bar.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 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 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 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 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 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 Specified Bar is Sequence Edge Breaker Bar or not ...
|
|
*
|
|
* @param bar: XOHCL instance reference, Specified Bar to Check ...
|
|
* @param dir: ENUM_X_DIRECTION member, Holds Founded Direction ...
|
|
* @param loopback: int, Specified Loopback ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSeqBreakEdge(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int loopback = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Args ...
|
|
dir = X_DIRECTION_NONE;
|
|
loopback = NormalizeInt(loopback, 3);
|
|
|
|
//
|
|
// Validate Args ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
|
|
//
|
|
// Check Has Sequence or not ...
|
|
XOHCL pBar;
|
|
XOHCL iBar;
|
|
XOHCL iPBar;
|
|
bool has = false;
|
|
int index = bar.Index();
|
|
int start = index + 1;
|
|
int end = start + loopback - 1;
|
|
bool hasBullishSeq = true;
|
|
bool hasBearishSeq = true;
|
|
for (int i = start; i < end; i++)
|
|
{
|
|
//
|
|
// Initialize Indexed Bar(s) ...
|
|
has = iBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i //
|
|
);
|
|
has =
|
|
has &&
|
|
iBar.GetPreviousBar(iPBar);
|
|
|
|
//
|
|
// Bullish Sequence ...
|
|
if (hasBullishSeq)
|
|
{
|
|
//
|
|
hasBullishSeq =
|
|
has &&
|
|
iBar.low > iPBar.low;
|
|
}
|
|
|
|
//
|
|
// Bearish Sequence ...
|
|
if (hasBearishSeq)
|
|
{
|
|
//
|
|
hasBearishSeq =
|
|
has &&
|
|
iBar.high < iPBar.high;
|
|
}
|
|
|
|
//
|
|
if (!hasBullishSeq &&
|
|
!hasBearishSeq)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
iPBar.Clean();
|
|
}
|
|
iBar.Clean();
|
|
iPBar.Clean();
|
|
|
|
//
|
|
// Check a Sequence Detect ...
|
|
result = hasBullishSeq ||
|
|
hasBearishSeq;
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
iBar.Clean();
|
|
iPBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Previous Bar ...
|
|
result = bar.GetPreviousBar(pBar);
|
|
|
|
//
|
|
// Now we Have Ensure has a Sequence ...
|
|
|
|
//
|
|
isBullish =
|
|
result &&
|
|
hasBearishSeq &&
|
|
bar.high > pBar.high;
|
|
|
|
//
|
|
isBearish =
|
|
result &&
|
|
hasBullishSeq &&
|
|
bar.low < pBar.low;
|
|
|
|
//
|
|
// Summarizing Result ...
|
|
result = isBullish ||
|
|
isBearish;
|
|
if (result)
|
|
{
|
|
//
|
|
dir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
pBar.Clean();
|
|
iBar.Clean();
|
|
iPBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar is Sequence Type Breaker Bar or not ...
|
|
*
|
|
* @param bar: XOHCL instance reference, Specified Bar to Check ...
|
|
* @param dir: ENUM_X_DIRECTION member, Holds Founded Direction ...
|
|
* @param loopback: int, Specified Loopback ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSeqBreakType(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int loopback = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Args ...
|
|
dir = X_DIRECTION_NONE;
|
|
loopback = NormalizeInt(loopback, 3);
|
|
|
|
//
|
|
// Validate Args ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
|
|
//
|
|
// Check Has Sequence or not ...
|
|
XOHCL iBar;
|
|
bool has = false;
|
|
int index = bar.Index();
|
|
int start = index + 1;
|
|
int end = start + loopback;
|
|
bool hasBullishSeq = true;
|
|
bool hasBearishSeq = true;
|
|
for (int i = start; i < end; i++)
|
|
{
|
|
//
|
|
// Initialize Indexed Bar(s) ...
|
|
has = iBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i //
|
|
);
|
|
|
|
//
|
|
// Bullish Sequence ...
|
|
if (hasBullishSeq)
|
|
{
|
|
//
|
|
hasBullishSeq =
|
|
has &&
|
|
iBar.IsBullish();
|
|
}
|
|
|
|
//
|
|
// Bearish Sequence ...
|
|
if (hasBearishSeq)
|
|
{
|
|
//
|
|
hasBearishSeq =
|
|
has &&
|
|
iBar.IsBearish();
|
|
}
|
|
|
|
//
|
|
if (!hasBullishSeq &&
|
|
!hasBearishSeq)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
}
|
|
iBar.Clean();
|
|
|
|
//
|
|
// Check a Sequence Detect ...
|
|
result = hasBullishSeq ||
|
|
hasBearishSeq;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Now we Have Ensure has a Sequence ...
|
|
|
|
//
|
|
isBullish =
|
|
result &&
|
|
hasBearishSeq &&
|
|
bar.IsBullish();
|
|
|
|
//
|
|
isBearish =
|
|
result &&
|
|
hasBullishSeq &&
|
|
bar.IsBearish();
|
|
|
|
//
|
|
// Summarizing Result ...
|
|
result = isBullish ||
|
|
isBearish;
|
|
if (result)
|
|
{
|
|
//
|
|
dir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
iBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar is Fully Sequence Breker Bar or not ...
|
|
*
|
|
* @param bar: XOHCL instance reference, Specified Bar to Check ...
|
|
* @param dir: ENUM_X_DIRECTION member, Holds Founded Direction ...
|
|
* @param loopback: int, Specified Loopback ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSeqBreak(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int loopback = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Args ...
|
|
dir = X_DIRECTION_NONE;
|
|
loopback = NormalizeInt(loopback, 3);
|
|
|
|
//
|
|
// Validate Args ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Seq Edge ...
|
|
ENUM_X_DIRECTION seqEdgeDir;
|
|
bool isSeqEdgeBreaked = IsSeqBreakEdge(
|
|
bar,
|
|
seqEdgeDir //
|
|
);
|
|
|
|
//
|
|
// Check Seq Type ...
|
|
ENUM_X_DIRECTION seqTypeDir;
|
|
bool isSeqTypeBreaked = IsSeqBreakType(
|
|
bar,
|
|
seqTypeDir //
|
|
);
|
|
|
|
//
|
|
// Check Result ...
|
|
result = isSeqEdgeBreaked &&
|
|
isSeqTypeBreaked &&
|
|
seqEdgeDir == seqTypeDir;
|
|
if (result)
|
|
{
|
|
dir = seqEdgeDir;
|
|
}
|
|
|
|
//
|
|
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 IsValidForTrigger(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
bool allowCond1 = true,
|
|
bool allowCond2 = true,
|
|
bool allowCond3 = true,
|
|
bool allowCond4 = true,
|
|
bool allowCond5 = true,
|
|
bool allowCond6 = true,
|
|
bool allowCond7 = true //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Args ...
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
// Validate Args ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Prepare Requirements ...
|
|
XOHCL pBar;
|
|
XOHCL p2Bar;
|
|
int loopback = 3;
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
ENUM_X_DIRECTION iDir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
// Retrieve Bar's Prev ...
|
|
result = bar.GetPreviousBar(pBar);
|
|
result = result &&
|
|
pBar.GetPreviousBar(p2Bar);
|
|
|
|
//
|
|
// Handle Detect Trigger Bar ...
|
|
if (result)
|
|
{
|
|
//
|
|
// Check States ...
|
|
|
|
//
|
|
// Rejected ...
|
|
bool isRejected = IsRejected(
|
|
pBar,
|
|
iDir,
|
|
false, // Force Type ...
|
|
true // Force Fibo Pressure ...
|
|
);
|
|
bool isBullishRejected =
|
|
isRejected &&
|
|
IsBullish(iDir);
|
|
bool isBearishRejected =
|
|
isRejected &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// Simple Rejected ...
|
|
bool isSimpleRejected = IsRejected(
|
|
pBar,
|
|
iDir,
|
|
false, // Force Type ...
|
|
false // Force Fibo Pressure ...
|
|
);
|
|
bool isSimpleBullishRejected =
|
|
isSimpleRejected &&
|
|
IsBullish(iDir);
|
|
bool isSimpleBearishRejected =
|
|
isSimpleRejected &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// Full Directional Rejection ...
|
|
bool isFullRejected = IsRejected(
|
|
pBar,
|
|
iDir,
|
|
true, // Force Type ...
|
|
true // Force Fibo Pressure ...
|
|
);
|
|
bool isFullBullishRejected =
|
|
isFullRejected &&
|
|
IsBullish(iDir);
|
|
bool isFullBearishRejected =
|
|
isRejected &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// Engulfed ...
|
|
bool isEngulfed = IsEngulfed(
|
|
pBar,
|
|
iDir //
|
|
);
|
|
bool isBullishEngulfed =
|
|
isEngulfed &&
|
|
IsBullish(iDir);
|
|
bool isBearishEngulfed =
|
|
isEngulfed &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// Momentum ...
|
|
bool isMomentum = IsMomentum(
|
|
pBar,
|
|
iDir //
|
|
);
|
|
bool isBullishMomentum =
|
|
isMomentum &&
|
|
IsBullish(iDir);
|
|
bool isBearishMomentum =
|
|
isMomentum &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// Simple Swing ...
|
|
bool isSwing = IsSimpleSwing(
|
|
pBar,
|
|
iDir //
|
|
);
|
|
bool isBullishSwing =
|
|
isSwing &&
|
|
IsBullish(iDir);
|
|
bool isBearishSwing =
|
|
isSwing &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// Full Swing ...
|
|
bool isFullSwing = IsSwing(
|
|
pBar,
|
|
iDir,
|
|
5 //
|
|
);
|
|
bool isFullBullishSwing =
|
|
isFullSwing &&
|
|
IsBullish(iDir);
|
|
bool isFullBearishSwing =
|
|
isFullSwing &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// Sequence Breaker ...
|
|
bool isSeqBreak = IsSeqBreak(
|
|
pBar,
|
|
iDir,
|
|
3 //
|
|
);
|
|
bool isBullishSeqBreak =
|
|
isSeqBreak &&
|
|
IsBullish(iDir);
|
|
bool isBearishSeqBreak =
|
|
isSeqBreak &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// Now we have to Combine Conditions ...
|
|
|
|
//
|
|
// Cond 1 ...
|
|
bool isBullishCond1 = false;
|
|
bool isBearishCond1 = false;
|
|
if (allowCond1)
|
|
{
|
|
//
|
|
// Bullish ...
|
|
isBullishCond1 =
|
|
//
|
|
isFullBullishRejected
|
|
//
|
|
;
|
|
|
|
//
|
|
// Bearish ...
|
|
isBearishCond1 =
|
|
//
|
|
isFullBearishRejected
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
// Cond 2 ...
|
|
bool isBullishCond2 = false;
|
|
bool isBearishCond2 = false;
|
|
if (allowCond2)
|
|
{
|
|
//
|
|
// Bullish ...
|
|
isBullishCond2 =
|
|
//
|
|
isBullishSwing &&
|
|
isBullishRejected
|
|
//
|
|
;
|
|
|
|
//
|
|
// Bearish ...
|
|
isBearishCond2 =
|
|
//
|
|
isBearishSwing &&
|
|
isBearishRejected
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
// Cond 3 ...
|
|
bool isBullishCond3 = false;
|
|
bool isBearishCond3 = false;
|
|
if (allowCond3)
|
|
{
|
|
//
|
|
// Bullish ...
|
|
isBullishCond3 =
|
|
//
|
|
isBullishSwing &&
|
|
(isBullishRejected ||
|
|
isBullishEngulfed ||
|
|
isBullishMomentum)
|
|
//
|
|
;
|
|
|
|
//
|
|
// Bearish ...
|
|
isBearishCond3 =
|
|
//
|
|
isBearishSwing &&
|
|
(isBearishRejected ||
|
|
isBearishEngulfed ||
|
|
isBearishMomentum)
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
// Cond 4 ...
|
|
bool isBullishCond4 = false;
|
|
bool isBearishCond4 = false;
|
|
if (allowCond4)
|
|
{
|
|
//
|
|
// Bullish ...
|
|
isBullishCond4 =
|
|
//
|
|
isBullishSwing &&
|
|
isBullishSeqBreak &&
|
|
(isBullishRejected ||
|
|
isBullishEngulfed ||
|
|
isBullishMomentum)
|
|
//
|
|
;
|
|
|
|
//
|
|
// Bearish ...
|
|
isBearishCond4 =
|
|
//
|
|
isBearishSwing &&
|
|
isBearishSeqBreak &&
|
|
(isBearishRejected ||
|
|
isBearishEngulfed ||
|
|
isBearishMomentum)
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
// Cond 5 ...
|
|
bool isBullishCond5 = false;
|
|
bool isBearishCond5 = false;
|
|
if (allowCond5)
|
|
{
|
|
//
|
|
// Bullish ...
|
|
isBullishCond5 =
|
|
//
|
|
isFullBullishSwing &&
|
|
(isBullishRejected ||
|
|
isBullishEngulfed ||
|
|
isBullishMomentum)
|
|
//
|
|
;
|
|
|
|
//
|
|
// Bearish ...
|
|
isBearishCond5 =
|
|
//
|
|
isFullBearishSwing &&
|
|
(isBearishRejected ||
|
|
isBearishEngulfed ||
|
|
isBearishMomentum)
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
// Cond 6 ...
|
|
bool isBullishCond6 = false;
|
|
bool isBearishCond6 = false;
|
|
if (allowCond6)
|
|
{
|
|
//
|
|
// Bullish ...
|
|
isBullishCond6 =
|
|
//
|
|
p2Bar.IsBearish() &&
|
|
pBar.IsBullish() &&
|
|
pBar.low < p2Bar.low &&
|
|
pBar.high > p2Bar.high &&
|
|
pBar.GetDown() <= p2Bar.GetDown() &&
|
|
(isBullishEngulfed ||
|
|
isBullishMomentum ||
|
|
isSimpleBullishRejected)
|
|
//
|
|
;
|
|
|
|
//
|
|
// Bearish ...
|
|
isBearishCond6 =
|
|
//
|
|
p2Bar.IsBullish() &&
|
|
pBar.IsBearish() &&
|
|
pBar.high > p2Bar.high &&
|
|
pBar.low < p2Bar.low &&
|
|
pBar.GetUp() >= p2Bar.GetUp() &&
|
|
(isBearishEngulfed ||
|
|
isBearishMomentum ||
|
|
isSimpleBearishRejected)
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
// Cond 7 ...
|
|
bool isBullishCond7 = false;
|
|
bool isBearishCond7 = false;
|
|
if (allowCond7)
|
|
{
|
|
//
|
|
// Bullish ...
|
|
isBullishCond7 =
|
|
//
|
|
p2Bar.IsBearish() &&
|
|
pBar.IsBullish() &&
|
|
pBar.low < p2Bar.low &&
|
|
pBar.high > p2Bar.high &&
|
|
pBar.GetUp() >= p2Bar.GetUp()
|
|
//
|
|
;
|
|
|
|
//
|
|
// Bearish ...
|
|
isBearishCond7 =
|
|
//
|
|
p2Bar.IsBullish() &&
|
|
pBar.IsBearish() &&
|
|
pBar.high > p2Bar.high &&
|
|
pBar.low < p2Bar.low &&
|
|
pBar.GetDown() <= p2Bar.GetDown()
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
// Summarizie Result ...
|
|
|
|
//
|
|
isBullish =
|
|
//
|
|
isBullishCond1 ||
|
|
isBullishCond2 ||
|
|
isBullishCond3 ||
|
|
isBullishCond4 ||
|
|
isBullishCond5 ||
|
|
isBullishCond6 ||
|
|
isBullishCond7
|
|
//
|
|
;
|
|
|
|
//
|
|
isBearish =
|
|
//
|
|
isBearishCond1 ||
|
|
isBearishCond2 ||
|
|
isBearishCond3 ||
|
|
isBearishCond4 ||
|
|
isBearishCond5 ||
|
|
isBearishCond6 ||
|
|
isBearishCond7
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = (isBullish &&
|
|
!isBearish) ||
|
|
(isBearish &&
|
|
!isBullish);
|
|
if (result)
|
|
{
|
|
//
|
|
dir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Actions ...
|
|
|
|
//
|
|
};
|
|
|
|
// |