3402 lines
75 KiB
Plaintext
3402 lines
75 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Indicator
|
|
// -------------------------------------------------
|
|
// Name: XCXCAEAPOIDetector ...
|
|
// Description: Class for XCAEA POI Detector ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://saherelm.ir"
|
|
#property version "1.00"
|
|
#property description "SaherElm Class for XCAEA POI Detector"
|
|
#property strict
|
|
|
|
//
|
|
// Imports ...
|
|
#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5"
|
|
#include "../../Classes/x-saherelm.x-poi.drawer.class.mq5"
|
|
#include "../Helpers/xcaea.helper.mq5"
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
enum ENUM_XCA_PIVOTS
|
|
{
|
|
XCA_NONE, // None
|
|
XCA_PEAK, // Peak
|
|
XCA_VALE, // Vale
|
|
XCA_FVG_BULL, // FVGBull
|
|
XCA_FVG_BEAR, // FVGBear
|
|
XCA_RSI_COOS, // RSICOOS
|
|
XCA_RSI_CUOB, // RSICUOB
|
|
XCA_TREND_BULL, // TrendBull
|
|
XCA_TREND_BEAR, // TrendBear
|
|
};
|
|
|
|
//
|
|
bool IsValid(ENUM_XCA_PIVOTS value)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = value != XCA_NONE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string ToString(ENUM_XCA_PIVOTS value)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
result = EnumToString(value);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION GetDirection(ENUM_XCA_PIVOTS value)
|
|
{
|
|
//
|
|
ENUM_X_DIRECTION result = X_DIRECTION_NONE;
|
|
|
|
//
|
|
switch (value)
|
|
{
|
|
//
|
|
case XCA_VALE:
|
|
case XCA_FVG_BULL:
|
|
case XCA_RSI_COOS:
|
|
case XCA_TREND_BULL:
|
|
result = X_DIRECTION_BULLISH;
|
|
break;
|
|
|
|
//
|
|
case XCA_PEAK:
|
|
case XCA_FVG_BEAR:
|
|
case XCA_RSI_CUOB:
|
|
case XCA_TREND_BEAR:
|
|
result = X_DIRECTION_BEARISH;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string GetBoxType(ENUM_XCA_PIVOTS value)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
switch (value)
|
|
{
|
|
//
|
|
case XCA_VALE:
|
|
case XCA_PEAK:
|
|
case XCA_RSI_COOS:
|
|
case XCA_RSI_CUOB:
|
|
result = ToString(value);
|
|
break;
|
|
//
|
|
case XCA_FVG_BULL:
|
|
case XCA_FVG_BEAR:
|
|
result = "XCA_FVG";
|
|
break;
|
|
|
|
//
|
|
case XCA_TREND_BULL:
|
|
case XCA_TREND_BEAR:
|
|
result = "XCA_TREND";
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_XCA_PIVOTS GetPivotType(XBoxZone &value)
|
|
{
|
|
//
|
|
ENUM_XCA_PIVOTS result = XCA_NONE;
|
|
|
|
//
|
|
bool has = value.IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isPeak = value.type == GetBoxType(XCA_PEAK) &&
|
|
value.dir == GetDirection(XCA_PEAK);
|
|
bool isVale = value.type == GetBoxType(XCA_VALE) &&
|
|
value.dir == GetDirection(XCA_VALE);
|
|
bool isFVGBull = value.type == GetBoxType(XCA_FVG_BULL) &&
|
|
value.dir == GetDirection(XCA_FVG_BULL);
|
|
bool isFVGBear = value.type == GetBoxType(XCA_FVG_BEAR) &&
|
|
value.dir == GetDirection(XCA_FVG_BEAR);
|
|
bool isRSICrossedOverOS = value.type == GetBoxType(XCA_RSI_COOS) &&
|
|
value.dir == GetDirection(XCA_RSI_COOS);
|
|
bool isRSICrossedUnderOB = value.type == GetBoxType(XCA_RSI_CUOB) &&
|
|
value.dir == GetDirection(XCA_RSI_CUOB);
|
|
bool isTrendBullish = value.type == GetBoxType(XCA_TREND_BULL) &&
|
|
value.dir == GetDirection(XCA_TREND_BULL);
|
|
bool isTrendBearish = value.type == GetBoxType(XCA_TREND_BEAR) &&
|
|
value.dir == GetDirection(XCA_TREND_BEAR);
|
|
|
|
//
|
|
if (isPeak)
|
|
{
|
|
result = XCA_PEAK;
|
|
}
|
|
else if (isVale)
|
|
{
|
|
result = XCA_VALE;
|
|
}
|
|
else if (isFVGBull)
|
|
{
|
|
result = XCA_FVG_BULL;
|
|
}
|
|
else if (isFVGBear)
|
|
{
|
|
result = XCA_FVG_BEAR;
|
|
}
|
|
else if (isRSICrossedOverOS)
|
|
{
|
|
result = XCA_RSI_COOS;
|
|
}
|
|
else if (isRSICrossedUnderOB)
|
|
{
|
|
result = XCA_RSI_CUOB;
|
|
}
|
|
else if (isTrendBullish)
|
|
{
|
|
result = XCA_TREND_BULL;
|
|
}
|
|
else if (isTrendBearish)
|
|
{
|
|
result = XCA_TREND_BEAR;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int ExtractPivots(
|
|
XBoxZone &extracted[],
|
|
ENUM_XCA_PIVOTS type,
|
|
XBoxZone &source[] //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(extracted);
|
|
|
|
//
|
|
bool has =
|
|
IsValid(type) &&
|
|
HasChild(source);
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = ArraySize(source);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XBoxZone iBox = source[i];
|
|
|
|
//
|
|
ENUM_XCA_PIVOTS iType = GetPivotType(iBox);
|
|
|
|
//
|
|
has = iType == type;
|
|
if (has)
|
|
{
|
|
//
|
|
AddRef(
|
|
iBox,
|
|
extracted //
|
|
);
|
|
}
|
|
|
|
//
|
|
iBox.Clean();
|
|
}
|
|
|
|
//
|
|
result = ArraySize(extracted);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool IsFakeBreakeout(
|
|
XBoxZone &pivot,
|
|
XCXCAEAHelper *helper,
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = NormalizeInt(barIndex, 0);
|
|
|
|
//
|
|
result = pivot.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int fromIDX = pivot.FromIndex();
|
|
result = barIndex < fromIDX;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = pivot.IsBullish();
|
|
|
|
//
|
|
// Retrieve Required Bars ...
|
|
XOHCL cBar;
|
|
XOHCL pBar;
|
|
XOHCL p2Bar;
|
|
XOHCL p3Bar;
|
|
result = cBar.Init(
|
|
pivot.symbol,
|
|
pivot.period,
|
|
barIndex //
|
|
);
|
|
result = result &&
|
|
cBar.GetPreviousBar(pBar);
|
|
result = result &&
|
|
pBar.GetPreviousBar(p2Bar);
|
|
result = result &&
|
|
p2Bar.GetPreviousBar(p3Bar);
|
|
if (!result)
|
|
{
|
|
//
|
|
cBar.Clean();
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
p3Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//
|
|
// Bars Conditions ...
|
|
|
|
//
|
|
ENUM_X_DIRECTION cBarDir;
|
|
|
|
//
|
|
// Hammer ...
|
|
bool isCBarHammer = helper
|
|
.barAnalyser
|
|
.IsHammer(
|
|
cBar,
|
|
cBarDir //
|
|
);
|
|
bool isCBarBullishHammer =
|
|
isCBarHammer &&
|
|
IsBullish(cBarDir);
|
|
bool isCBarBearishHammer =
|
|
isCBarHammer &&
|
|
IsBearish(cBarDir);
|
|
|
|
//
|
|
// Rejected ...
|
|
bool isCBarRejected = helper
|
|
.barAnalyser
|
|
.IsRejected(
|
|
cBar,
|
|
cBarDir,
|
|
false, // Force Type ...
|
|
true // Force Fibo Pressure ...
|
|
);
|
|
bool isCBarBullishRejected =
|
|
isCBarRejected &&
|
|
IsBullish(cBarDir);
|
|
bool isCBarBearishRejected =
|
|
isCBarRejected &&
|
|
IsBearish(cBarDir);
|
|
|
|
//
|
|
// Engulfed ...
|
|
bool isCBarEngulfed = helper
|
|
.barAnalyser
|
|
.IsEngulfed(
|
|
cBar,
|
|
cBarDir //
|
|
);
|
|
bool isCBarBullishEngulfed =
|
|
isCBarEngulfed &&
|
|
IsBullish(cBarDir);
|
|
bool isCBarBearishEngulfed =
|
|
isCBarEngulfed &&
|
|
IsBearish(cBarDir);
|
|
|
|
//
|
|
// Momentum ...
|
|
bool isCBarMomentum = helper
|
|
.barAnalyser
|
|
.IsMomentum(
|
|
cBar,
|
|
cBarDir,
|
|
1 //
|
|
);
|
|
bool isCBarBullishMomentum =
|
|
isCBarMomentum &&
|
|
IsBullish(cBarDir);
|
|
bool isCBarBearishMomentum =
|
|
isCBarMomentum &&
|
|
IsBearish(cBarDir);
|
|
|
|
//
|
|
bool isCBarHasBullishPower = isCBarBullishRejected ||
|
|
isCBarBullishEngulfed ||
|
|
isCBarBullishMomentum;
|
|
|
|
//
|
|
bool isCBarHasBearishPower = isCBarBearishRejected ||
|
|
isCBarBearishEngulfed ||
|
|
isCBarBearishMomentum;
|
|
|
|
//
|
|
bool isBarPowerfull =
|
|
isBullish
|
|
? isCBarHasBullishPower
|
|
: isCBarHasBearishPower;
|
|
|
|
//
|
|
double breakPrice =
|
|
isBullish
|
|
? pivot.lower
|
|
: pivot.upper;
|
|
|
|
//
|
|
// CBar Must Go back InSide Box ...
|
|
bool isBarInside =
|
|
cBar.GetUp() > breakPrice &&
|
|
cBar.GetDown() < breakPrice &&
|
|
cBar.GetDirection() == pivot.dir;
|
|
|
|
//
|
|
result =
|
|
//
|
|
// Bar Must Inside Pivot ...
|
|
isBarInside &&
|
|
//
|
|
// Bar Must Has Required Direction Power ...
|
|
isBarPowerfull
|
|
//
|
|
;
|
|
|
|
//
|
|
cBar.Clean();
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
p3Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
struct XCAPivot
|
|
{
|
|
//
|
|
// Props ...
|
|
datetime to;
|
|
double value;
|
|
string symbol;
|
|
datetime from;
|
|
double reserve;
|
|
ENUM_XCA_PIVOTS type;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
double values[];
|
|
|
|
//
|
|
// Constructor ...
|
|
XCAPivot()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Cleanup ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
value = 0;
|
|
to = NULL;
|
|
reserve = 0;
|
|
from = NULL;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
type = XCA_NONE;
|
|
|
|
//
|
|
Clean(values);
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
/**
|
|
* Validate ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
from < to &&
|
|
value != 0 &&
|
|
IsValid(to) &&
|
|
IsValid(from) &&
|
|
IsValid(type) &&
|
|
IsValid(symbol) &&
|
|
IsValid(period);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a Model is Same as this or not ...
|
|
*
|
|
* @param pivot: XCAPivot ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSameAs(XCAPivot &pivot)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
IsValid() &&
|
|
pivot.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
to == pivot.to &&
|
|
from == pivot.from &&
|
|
type == pivot.type &&
|
|
value == pivot.value &&
|
|
symbol == pivot.symbol &&
|
|
period == pivot.period;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve To Index ...
|
|
*
|
|
* @param forPeriod: ENUM_TIMEFRAMES, Specified Period ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int ToIndex(
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
result = GetBarIndex(
|
|
symbol,
|
|
forPeriod,
|
|
to //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve From Index ...
|
|
*
|
|
* @param forPeriod: ENUM_TIMEFRAMES, Specified Period ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int FromIndex(
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
result = GetBarIndex(
|
|
symbol,
|
|
forPeriod,
|
|
from //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Age of Pivot ...
|
|
*
|
|
* @param forPeriod: ENUM_TIMEFRAMES, Specified Period ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int GetAge(
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
int toIDX = ToIndex(forPeriod);
|
|
int fromIDX = FromIndex(forPeriod);
|
|
|
|
//
|
|
result = fromIDX - toIDX;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Converts Pivot to Box ...
|
|
*
|
|
* @param box: XBoxZone instance reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool AsBox(
|
|
XBoxZone &box //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
box.Clean();
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION iDir = GetDirection(type);
|
|
|
|
//
|
|
result = HasDirection(iDir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish =
|
|
IsBullish(iDir) &&
|
|
value < reserve;
|
|
|
|
//
|
|
bool isBearish =
|
|
IsBearish(iDir) &&
|
|
value > reserve;
|
|
|
|
//
|
|
result = isBullish ||
|
|
isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
box.to = to;
|
|
box.dir = iDir;
|
|
box.from = from;
|
|
box.symbol = symbol;
|
|
box.period = period;
|
|
|
|
//
|
|
string typeStr = GetBoxType(type);
|
|
box.type = typeStr;
|
|
|
|
//
|
|
box.upper =
|
|
isBullish
|
|
? reserve
|
|
: value;
|
|
box.lower =
|
|
isBullish
|
|
? value
|
|
: reserve;
|
|
|
|
//
|
|
result = box.IsValid();
|
|
if (!result)
|
|
{
|
|
box.Clean();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Implementations ...
|
|
class XCXCAEAPOIDetector : public XCBase
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Pivot Verifications and Max Allowed Holding Items ...
|
|
int maxAllowedPivots; // Max Allowed Holding Pibots ...
|
|
int pivotVerifications; // Pivots Verifications ...
|
|
int pivotDetectionLoopbac; // Pivots Detection Loopback ...
|
|
double ticksDividerInPoints; // Ticks and Volume Detection Divider in Point ...
|
|
|
|
//
|
|
// TREND ...
|
|
XBoxZone trendPivotP; // Prev Pivot of Market Trend ...
|
|
XBoxZone trendPivotC; // Current Pivot of Market Trend ...
|
|
ENUM_X_DIRECTION trendDir; // Trend Direction ...
|
|
|
|
//
|
|
// Breaked Pivots ...
|
|
XBoxZone invalidPivots[];
|
|
|
|
//
|
|
// Constructors ...
|
|
XCXCAEAPOIDetector(
|
|
XCXCAEAHelper *_helper //
|
|
)
|
|
{
|
|
//
|
|
helper = _helper;
|
|
drawer = new XCPOIDrawer();
|
|
barAnalyser = new XCBarAnalyser();
|
|
|
|
//
|
|
Default();
|
|
}
|
|
|
|
//
|
|
// De Constructors ...
|
|
~XCXCAEAPOIDetector()
|
|
{
|
|
//
|
|
CleanPivots();
|
|
|
|
//
|
|
ZeroMemory(helper);
|
|
ZeroMemory(drawer);
|
|
ZeroMemory(barAnalyser);
|
|
}
|
|
|
|
//
|
|
// Properties ...
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
virtual void Default()
|
|
{
|
|
//
|
|
// COMMON ...
|
|
|
|
//
|
|
maxAllowedPivots = 50;
|
|
pivotVerifications = 5;
|
|
ticksDividerInPoints = 15;
|
|
pivotDetectionLoopbac = 100;
|
|
|
|
//
|
|
// PV ...
|
|
|
|
//
|
|
detectPeakPivots = false;
|
|
detectValePivots = false;
|
|
|
|
//
|
|
maxAllowedPVLifetime = 0;
|
|
applySwingsOnPVPivots = false;
|
|
selectRejectedPVPivots = false;
|
|
selectEngulfedPVPivots = false;
|
|
selectPVWhichStartByFVG = false;
|
|
applySupportAndResistanceOnPVPivots = false;
|
|
|
|
//
|
|
// FVG ...
|
|
|
|
//
|
|
detectFVGBullishPivots = false;
|
|
detectFVGBearishPivots = false;
|
|
|
|
//
|
|
selectSameBarFVGs = false;
|
|
maxAllowedFVGLifetime = 0;
|
|
validateFVGUsingPV = false;
|
|
applyPVToFVGBoundary = false;
|
|
selectRejectedFVGPivots = false;
|
|
selectEngulfedFVGPivots = false;
|
|
validateFVGUsingManalyser = false;
|
|
applyLastBarToFVGBoundary = false;
|
|
selectOnlyFVGWhichHasIndirectionalLastBar = false;
|
|
|
|
//
|
|
// TREND ...
|
|
|
|
//
|
|
detectTrendBullishPivots = false;
|
|
detectTrendBearishPivots = false;
|
|
|
|
//
|
|
}
|
|
|
|
//
|
|
void Detect(
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
int loopback = pivotDetectionLoopbac;
|
|
loopback = NormalizeInt(loopback, 50);
|
|
|
|
//
|
|
int idx = -1;
|
|
int count = 0;
|
|
bool has = false;
|
|
|
|
//
|
|
int zIDX = 0;
|
|
int cIDX = zIDX + 1;
|
|
int pIDX = cIDX + 1;
|
|
int p2IDX = pIDX + 1;
|
|
int p3IDX = p2IDX + 1;
|
|
|
|
//
|
|
newPeakPivotDetected = false;
|
|
newValePivotDetected = false;
|
|
newFVGBullishPivotDetected = false;
|
|
newFVGBearishPivotDetected = false;
|
|
newTrendBullishPivotDetected = false;
|
|
newTrendBearishPivotDetected = false;
|
|
|
|
//
|
|
int index = barIndex;
|
|
int start = index;
|
|
int end = index + loopback;
|
|
while (start < end)
|
|
{
|
|
//
|
|
// Retrieve Conditions ...
|
|
XCAEAConditions conditions;
|
|
has = helper.GetConditions(
|
|
conditions,
|
|
start,
|
|
10 //
|
|
);
|
|
if (!has)
|
|
{
|
|
conditions.Clean();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Retrieve Bars ...
|
|
XOHCL zBar;
|
|
XOHCL cBar;
|
|
XOHCL pBar;
|
|
XOHCL p2Bar;
|
|
has = zBar.Init(
|
|
conditions.symbol,
|
|
conditions.period,
|
|
start //
|
|
);
|
|
has =
|
|
has &&
|
|
zBar.GetPreviousBar(cBar);
|
|
has =
|
|
has &&
|
|
cBar.GetPreviousBar(pBar);
|
|
has =
|
|
has &&
|
|
pBar.GetPreviousBar(p2Bar);
|
|
if (!has)
|
|
{
|
|
//
|
|
zBar.Clean();
|
|
cBar.Clean();
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
conditions.Clean();
|
|
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Checking Pivots ...
|
|
|
|
//
|
|
// PV ...
|
|
|
|
//
|
|
// PEAK ...
|
|
if (detectPeakPivots)
|
|
{
|
|
//
|
|
newPeakPivotDetected = DetectPeakAndValePivot(
|
|
barIndex,
|
|
X_DIRECTION_BEARISH,
|
|
zBar,
|
|
cBar,
|
|
pBar,
|
|
p2Bar,
|
|
conditions //
|
|
);
|
|
}
|
|
|
|
//
|
|
// VALE ...
|
|
if (detectValePivots)
|
|
{
|
|
//
|
|
newValePivotDetected = DetectPeakAndValePivot(
|
|
barIndex,
|
|
X_DIRECTION_BULLISH,
|
|
zBar,
|
|
cBar,
|
|
pBar,
|
|
p2Bar,
|
|
conditions //
|
|
);
|
|
}
|
|
|
|
//
|
|
// FVG ...
|
|
|
|
//
|
|
// Bullish ...
|
|
if (detectFVGBullishPivots)
|
|
{
|
|
//
|
|
newFVGBullishPivotDetected = DetectFVGPivot(
|
|
barIndex,
|
|
X_DIRECTION_BULLISH,
|
|
zBar,
|
|
cBar,
|
|
pBar,
|
|
p2Bar,
|
|
conditions //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Bearish ...
|
|
if (detectFVGBearishPivots)
|
|
{
|
|
//
|
|
newFVGBearishPivotDetected = DetectFVGPivot(
|
|
barIndex,
|
|
X_DIRECTION_BEARISH,
|
|
zBar,
|
|
cBar,
|
|
pBar,
|
|
p2Bar,
|
|
conditions //
|
|
);
|
|
}
|
|
|
|
//
|
|
// TREND ...
|
|
|
|
//
|
|
// Bullish ...
|
|
if (detectTrendBullishPivots)
|
|
{
|
|
//
|
|
newTrendBullishPivotDetected = DetectTrendPivot(
|
|
barIndex,
|
|
X_DIRECTION_BULLISH,
|
|
zBar,
|
|
cBar,
|
|
pBar,
|
|
p2Bar,
|
|
conditions //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Bearish ...
|
|
if (detectTrendBearishPivots)
|
|
{
|
|
//
|
|
newTrendBearishPivotDetected = DetectTrendPivot(
|
|
barIndex,
|
|
X_DIRECTION_BEARISH,
|
|
zBar,
|
|
cBar,
|
|
pBar,
|
|
p2Bar,
|
|
conditions //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Others ...
|
|
|
|
//
|
|
start++;
|
|
|
|
//
|
|
zBar.Clean();
|
|
cBar.Clean();
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
conditions.Clean();
|
|
}
|
|
|
|
//
|
|
SortPivots();
|
|
}
|
|
|
|
//
|
|
void Validate(
|
|
XBoxZone &unavailables[],
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
// Implement Validation Senarios ...
|
|
|
|
//
|
|
// PV ...
|
|
ValidatePeakValePivots(
|
|
unavailables,
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
// FVG ...
|
|
ValidateFVGPivots(
|
|
unavailables,
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
// TREND ...
|
|
ValidateTrendPivots(
|
|
unavailables,
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
SortPivots();
|
|
}
|
|
|
|
//
|
|
int FillPivots(
|
|
XBoxZone &pivots[],
|
|
ENUM_X_DIRECTION forDir = X_DIRECTION_ALL //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(pivots);
|
|
|
|
//
|
|
if (forDir == X_DIRECTION_NONE)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = 0;
|
|
bool has = false;
|
|
|
|
//
|
|
bool canFillBullish =
|
|
forDir == X_DIRECTION_ALL ||
|
|
forDir == X_DIRECTION_BULLISH;
|
|
|
|
//
|
|
bool canFillBearish =
|
|
forDir == X_DIRECTION_ALL ||
|
|
forDir == X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
// Bullish ...
|
|
if (canFillBullish)
|
|
{
|
|
//
|
|
Copy(
|
|
valePivots,
|
|
pivots,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
fvgBullishPivots,
|
|
pivots,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
trendBullishPivots,
|
|
pivots,
|
|
false //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Bearish ...
|
|
if (canFillBearish)
|
|
{
|
|
//
|
|
Copy(
|
|
peakPivots,
|
|
pivots,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
fvgBearishPivots,
|
|
pivots,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
trendBearishPivots,
|
|
pivots,
|
|
false //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = ArraySize(pivots);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Pivots ...
|
|
|
|
//
|
|
// INVALID Pivots ...
|
|
|
|
//
|
|
bool HasInvalidPivots()
|
|
{
|
|
return HasChild(invalidPivots);
|
|
}
|
|
|
|
//
|
|
int CountInvalidPivots()
|
|
{
|
|
return ArraySize(invalidPivots);
|
|
}
|
|
|
|
//
|
|
// PV ...
|
|
|
|
//
|
|
int maxAllowedPVLifetime; // Max Allowed PV Life ...
|
|
bool applySwingsOnPVPivots; // Apply Swings on PV Pivots ...
|
|
bool selectRejectedPVPivots; // Select Rejected PV Pivots ...
|
|
bool selectEngulfedPVPivots; // Select Engulfed PV Pivots ...
|
|
bool selectPVWhichStartByFVG; // Select PV Pivots Which Starts by FVG ...
|
|
bool applySupportAndResistanceOnPVPivots; // Apply Support and Resistance on PV Pivots ...
|
|
|
|
//
|
|
bool DetectPeakAndValePivot(
|
|
int barIndex,
|
|
ENUM_X_DIRECTION forDir,
|
|
XOHCL &zBar,
|
|
XOHCL &cBar,
|
|
XOHCL &pBar,
|
|
XOHCL &p2Bar,
|
|
XCAEAConditions &conditions //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Checking Direction ...
|
|
result = HasDirection(forDir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool forBullish = IsBullish(forDir);
|
|
bool forBearish = IsBearish(forDir);
|
|
|
|
//
|
|
// Check Allowed ...
|
|
result =
|
|
forBullish
|
|
? detectValePivots
|
|
: detectPeakPivots;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Args ...
|
|
result =
|
|
//
|
|
barIndex >= 0 &&
|
|
zBar.IsValid() &&
|
|
cBar.IsValid() &&
|
|
pBar.IsValid() &&
|
|
p2Bar.IsValid()
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Define Requirements ...
|
|
|
|
//
|
|
int zIDX = 0;
|
|
int cIDX = zIDX + 1;
|
|
int pIDX = cIDX + 1;
|
|
int p2IDX = pIDX + 1;
|
|
|
|
//
|
|
datetime cTime = zBar.time;
|
|
string symbol = zBar.symbol;
|
|
ENUM_TIMEFRAMES period = zBar.period;
|
|
double points = GetPoints(symbol);
|
|
|
|
//
|
|
// Reading Conditional Values ...
|
|
|
|
//
|
|
// PEAK ...
|
|
double zPeak = conditions.peakBuffer[zIDX];
|
|
double cPeak = conditions.peakBuffer[cIDX];
|
|
double pPeak = conditions.peakBuffer[pIDX];
|
|
double p2Peak = conditions.peakBuffer[p2IDX];
|
|
|
|
//
|
|
// PEAK Golden ...
|
|
double zPeakGolden = conditions.peakGoldenBuffer[zIDX];
|
|
double cPeakGolden = conditions.peakGoldenBuffer[cIDX];
|
|
double pPeakGolden = conditions.peakGoldenBuffer[pIDX];
|
|
double p2PeakGolden = conditions.peakGoldenBuffer[p2IDX];
|
|
|
|
//
|
|
// VALE ...
|
|
double zVale = conditions.valeBuffer[zIDX];
|
|
double cVale = conditions.valeBuffer[cIDX];
|
|
double pVale = conditions.valeBuffer[pIDX];
|
|
double p2Vale = conditions.valeBuffer[p2IDX];
|
|
|
|
//
|
|
// VALE Golden ...
|
|
double zValeGolden = conditions.valeGoldenBuffer[zIDX];
|
|
double cValeGolden = conditions.valeGoldenBuffer[cIDX];
|
|
double pValeGolden = conditions.valeGoldenBuffer[pIDX];
|
|
double p2ValeGolden = conditions.valeGoldenBuffer[p2IDX];
|
|
|
|
//
|
|
// SWING High ..
|
|
double zSwingHigh = conditions.swingHighBuffer[zIDX];
|
|
double cSwingHigh = conditions.swingHighBuffer[cIDX];
|
|
double pSwingHigh = conditions.swingHighBuffer[pIDX];
|
|
double p2SwingHigh = conditions.swingHighBuffer[p2IDX];
|
|
|
|
//
|
|
// SWING Low ...
|
|
double zSwingLow = conditions.swingLowBuffer[zIDX];
|
|
double cSwingLow = conditions.swingLowBuffer[cIDX];
|
|
double pSwingLow = conditions.swingLowBuffer[pIDX];
|
|
double p2SwingLow = conditions.swingLowBuffer[p2IDX];
|
|
|
|
//
|
|
// SUPPORT ...
|
|
double zSupport = conditions.supportBuffer[zIDX];
|
|
double cSupport = conditions.supportBuffer[cIDX];
|
|
double pSupport = conditions.supportBuffer[pIDX];
|
|
double p2Support = conditions.supportBuffer[p2IDX];
|
|
|
|
//
|
|
// RESISTANCE ...
|
|
double zResistance = conditions.resistanceBuffer[zIDX];
|
|
double cResistance = conditions.resistanceBuffer[cIDX];
|
|
double pResistance = conditions.resistanceBuffer[pIDX];
|
|
double p2Resistance = conditions.resistanceBuffer[p2IDX];
|
|
|
|
//
|
|
// Detecting Bar Conditions ...
|
|
|
|
//
|
|
ENUM_X_DIRECTION cBarDir;
|
|
|
|
//
|
|
// Rejected ...
|
|
bool isCBarRejected = helper
|
|
.barAnalyser
|
|
.IsRejected(
|
|
cBar,
|
|
cBarDir,
|
|
false, // Force Type ...
|
|
false // Force Fibo Pressure ...
|
|
);
|
|
|
|
//
|
|
bool isCBarBullishRejected =
|
|
forBullish &&
|
|
isCBarRejected &&
|
|
IsBullish(cBarDir);
|
|
bool isCBarBearishRejected =
|
|
forBearish &&
|
|
isCBarRejected &&
|
|
IsBearish(cBarDir);
|
|
|
|
//
|
|
bool isPBarRejected = helper
|
|
.barAnalyser
|
|
.IsRejected(
|
|
pBar,
|
|
cBarDir,
|
|
false, // Force Type ...
|
|
false // Force Fibo Pressure ...
|
|
);
|
|
bool isPBarBullishRejected =
|
|
forBullish &&
|
|
isPBarRejected &&
|
|
IsBullish(cBarDir);
|
|
bool isPBarBearishRejected =
|
|
forBearish &&
|
|
isPBarRejected &&
|
|
IsBearish(cBarDir);
|
|
|
|
//
|
|
bool isBarBullishRejected =
|
|
forBullish &&
|
|
(isCBarBullishRejected ||
|
|
isPBarBullishRejected);
|
|
|
|
//
|
|
bool isBarBearishRejected =
|
|
forBearish &&
|
|
(isCBarBearishRejected ||
|
|
isPBarBearishRejected);
|
|
|
|
//
|
|
// Engulfed ...
|
|
bool isCBarEngulfed = helper
|
|
.barAnalyser
|
|
.IsEngulfed(
|
|
cBar,
|
|
cBarDir //
|
|
);
|
|
bool isCBarBullishEngulfed =
|
|
forBullish &&
|
|
isCBarEngulfed &&
|
|
IsBullish(cBarDir);
|
|
bool isCBarBearishEngulfed =
|
|
forBearish &&
|
|
isCBarEngulfed &&
|
|
IsBearish(cBarDir);
|
|
|
|
//
|
|
bool isPBarEngulfed = helper
|
|
.barAnalyser
|
|
.IsEngulfed(
|
|
pBar,
|
|
cBarDir //
|
|
);
|
|
bool isPBarBullishEngulfed =
|
|
forBullish &&
|
|
isPBarEngulfed &&
|
|
IsBullish(cBarDir);
|
|
bool isPBarBearishEngulfed =
|
|
forBearish &&
|
|
isPBarEngulfed &&
|
|
IsBearish(cBarDir);
|
|
|
|
//
|
|
bool isBarBullishEngulfed =
|
|
forBullish &&
|
|
(isCBarBullishEngulfed ||
|
|
isPBarBullishEngulfed);
|
|
|
|
//
|
|
bool isBarBearishEngulfed =
|
|
forBearish &&
|
|
(isCBarBearishEngulfed ||
|
|
isPBarBearishEngulfed);
|
|
|
|
//
|
|
// Prepare Conditinal Conditions ...
|
|
|
|
//
|
|
// PEAK ...
|
|
|
|
//
|
|
bool isPeakSameLast = cPeak == pPeak;
|
|
bool isPeakSameLastPrev = pPeak == p2Peak;
|
|
|
|
//
|
|
if (applySwingsOnPVPivots)
|
|
{
|
|
//
|
|
isPeakSameLast =
|
|
isPeakSameLast &&
|
|
cSwingHigh == cPeak &&
|
|
cSwingHigh == pSwingHigh;
|
|
|
|
//
|
|
isPeakSameLastPrev =
|
|
isPeakSameLastPrev &&
|
|
pSwingHigh == pPeak &&
|
|
pSwingHigh == p2SwingHigh;
|
|
}
|
|
|
|
//
|
|
if (applySupportAndResistanceOnPVPivots)
|
|
{
|
|
//
|
|
isPeakSameLast =
|
|
isPeakSameLast &&
|
|
cResistance == cPeak &&
|
|
cResistance == pResistance;
|
|
|
|
//
|
|
isPeakSameLastPrev =
|
|
isPeakSameLastPrev &&
|
|
pResistance == pPeak &&
|
|
pResistance == p2Resistance;
|
|
}
|
|
|
|
//
|
|
bool isPeakSwitchedToSameLast = isPeakSameLast &&
|
|
!isPeakSameLastPrev;
|
|
bool isPeakFinishedFromSameLast = !isPeakSameLast &&
|
|
isPeakSameLastPrev;
|
|
|
|
//
|
|
// VALE ...
|
|
|
|
//
|
|
bool isValeSameLast = cVale == pVale;
|
|
bool isValeSameLastPrev = pVale == p2Vale;
|
|
|
|
//
|
|
if (applySwingsOnPVPivots)
|
|
{
|
|
//
|
|
isValeSameLast =
|
|
isValeSameLast &&
|
|
cSwingLow == cVale &&
|
|
cSwingLow == pSwingLow;
|
|
|
|
//
|
|
isValeSameLastPrev =
|
|
isValeSameLastPrev &&
|
|
pSwingLow == pVale &&
|
|
pSwingLow == p2SwingLow;
|
|
}
|
|
|
|
//
|
|
if (applySupportAndResistanceOnPVPivots)
|
|
{
|
|
//
|
|
isValeSameLast =
|
|
isValeSameLast &&
|
|
cSupport == cVale &&
|
|
cSupport == pSupport;
|
|
|
|
//
|
|
isValeSameLastPrev =
|
|
isValeSameLastPrev &&
|
|
pSupport == pVale &&
|
|
pSupport == p2Support;
|
|
}
|
|
|
|
//
|
|
bool isValeSwitchedToSameLast = isValeSameLast &&
|
|
!isValeSameLastPrev;
|
|
bool isValeFinishedFromSameLast = !isValeSameLast &&
|
|
isValeSameLastPrev;
|
|
|
|
//
|
|
// Summarizing Conditions ...
|
|
|
|
//
|
|
result = false;
|
|
|
|
//
|
|
bool hasStartCondition =
|
|
//
|
|
forBullish
|
|
? isValeFinishedFromSameLast
|
|
: isPeakFinishedFromSameLast
|
|
//
|
|
;
|
|
|
|
//
|
|
bool hasContinuationCondition =
|
|
//
|
|
forBullish
|
|
? isValeSameLast
|
|
: isPeakSameLast
|
|
//
|
|
;
|
|
|
|
//
|
|
bool hasEndCondition =
|
|
//
|
|
forBullish
|
|
? isValeSwitchedToSameLast
|
|
: isPeakSwitchedToSameLast
|
|
//
|
|
;
|
|
|
|
//
|
|
// Apply Validations ...
|
|
if (hasEndCondition)
|
|
{
|
|
//
|
|
bool hasSelectionType = selectRejectedPVPivots ||
|
|
selectEngulfedPVPivots;
|
|
|
|
//
|
|
bool isPVRejected =
|
|
forBullish
|
|
? (isBarBullishRejected &&
|
|
selectRejectedPVPivots)
|
|
: (isBarBearishRejected &&
|
|
selectRejectedPVPivots);
|
|
|
|
//
|
|
bool isPVEngulfed =
|
|
forBullish
|
|
? (isBarBullishEngulfed &&
|
|
selectEngulfedPVPivots)
|
|
: (isBarBearishEngulfed &&
|
|
selectEngulfedPVPivots);
|
|
|
|
//
|
|
bool isBarPassed =
|
|
!hasSelectionType
|
|
? true
|
|
: isPVRejected ||
|
|
isPVEngulfed;
|
|
|
|
//
|
|
hasEndCondition =
|
|
isBarPassed &&
|
|
hasEndCondition;
|
|
if (!hasEndCondition)
|
|
{
|
|
//
|
|
// VALE ...
|
|
if (forBullish)
|
|
{
|
|
valePivot.Clean();
|
|
}
|
|
|
|
//
|
|
// PEAK ...
|
|
if (forBearish)
|
|
{
|
|
peakPivot.Clean();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
// ReInstance Pivot ...
|
|
if (hasStartCondition)
|
|
{
|
|
//
|
|
// VALE ...
|
|
if (forBullish)
|
|
{
|
|
//
|
|
valePivot.Clean();
|
|
|
|
//
|
|
valePivot.type = XCA_VALE;
|
|
valePivot.symbol = symbol;
|
|
valePivot.period = period;
|
|
|
|
//
|
|
valePivot.to = pBar.time;
|
|
valePivot.from = pBar.time;
|
|
valePivot.value = pVale;
|
|
valePivot.reserve = pValeGolden;
|
|
}
|
|
|
|
//
|
|
// PEAK ...
|
|
if (forBearish)
|
|
{
|
|
//
|
|
peakPivot.Clean();
|
|
|
|
//
|
|
peakPivot.type = XCA_PEAK;
|
|
peakPivot.symbol = symbol;
|
|
peakPivot.period = period;
|
|
|
|
//
|
|
peakPivot.to = pBar.time;
|
|
peakPivot.from = pBar.time;
|
|
peakPivot.value = pPeak;
|
|
peakPivot.reserve = pPeakGolden;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Calculate and Fill Pivot Requirements ...
|
|
if (hasContinuationCondition)
|
|
{
|
|
//
|
|
// VALE ...
|
|
if (forBullish)
|
|
{
|
|
//
|
|
valePivot.from = pBar.time;
|
|
|
|
//
|
|
valePivot.reserve =
|
|
valePivot.reserve == 0
|
|
? pValeGolden
|
|
: MathMin(valePivot.reserve, pValeGolden);
|
|
}
|
|
|
|
//
|
|
// PEAK ...
|
|
if (forBearish)
|
|
{
|
|
//
|
|
peakPivot.from = pBar.time;
|
|
|
|
//
|
|
peakPivot.reserve =
|
|
peakPivot.reserve == 0
|
|
? pPeakGolden
|
|
: MathMax(peakPivot.reserve, pPeakGolden);
|
|
}
|
|
}
|
|
|
|
//
|
|
// End up Pivot and Store it ...
|
|
if (hasEndCondition)
|
|
{
|
|
//
|
|
// VALE ...
|
|
if (forBullish)
|
|
{
|
|
//
|
|
result =
|
|
valePivot.IsValid() &&
|
|
valePivot.GetAge() >= pivotVerifications;
|
|
if (result)
|
|
{
|
|
//
|
|
XBoxZone iBox;
|
|
result = valePivot.AsBox(iBox);
|
|
if (result)
|
|
{
|
|
//
|
|
newPeakPivotDetected = AddBox(
|
|
iBox,
|
|
valePivots //
|
|
);
|
|
}
|
|
|
|
//
|
|
iBox.Clean();
|
|
}
|
|
|
|
//
|
|
valePivot.Clean();
|
|
}
|
|
|
|
//
|
|
// PEAK ...
|
|
if (forBearish)
|
|
{
|
|
//
|
|
result =
|
|
peakPivot.IsValid() &&
|
|
peakPivot.GetAge() >= pivotVerifications;
|
|
if (result)
|
|
{
|
|
//
|
|
XBoxZone iBox;
|
|
result = peakPivot.AsBox(iBox);
|
|
if (result)
|
|
{
|
|
//
|
|
newPeakPivotDetected = AddBox(
|
|
iBox,
|
|
peakPivots //
|
|
);
|
|
}
|
|
|
|
//
|
|
iBox.Clean();
|
|
}
|
|
|
|
//
|
|
peakPivot.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void ValidatePeakValePivots(
|
|
XBoxZone &unavailables[],
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
bool applyLifetimeValidating = maxAllowedPVLifetime > 0;
|
|
|
|
//
|
|
// PEAK ...
|
|
has = HasPeakPivots();
|
|
if (has)
|
|
{
|
|
//
|
|
ApplyValidationOnBoxes(
|
|
peakPivots,
|
|
unavailables,
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
if (applyLifetimeValidating)
|
|
{
|
|
//
|
|
ApplyLifeTimeValidationOnBoxes(
|
|
peakPivots,
|
|
maxAllowedPVLifetime,
|
|
barIndex //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// VALE ...
|
|
has = HasValePivots();
|
|
if (has)
|
|
{
|
|
//
|
|
ApplyValidationOnBoxes(
|
|
valePivots,
|
|
unavailables,
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
if (applyLifetimeValidating)
|
|
{
|
|
//
|
|
ApplyLifeTimeValidationOnBoxes(
|
|
valePivots,
|
|
maxAllowedPVLifetime,
|
|
barIndex //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// PEAK ...
|
|
|
|
//
|
|
XCAPivot peakPivot;
|
|
bool detectPeakPivots;
|
|
XBoxZone peakPivots[];
|
|
bool newPeakPivotDetected;
|
|
|
|
//
|
|
bool HasPeakPivots()
|
|
{
|
|
return HasChild(peakPivots);
|
|
}
|
|
|
|
//
|
|
int CountPeakPivots()
|
|
{
|
|
return ArraySize(peakPivots);
|
|
}
|
|
|
|
//
|
|
// VALE ...
|
|
|
|
//
|
|
XCAPivot valePivot;
|
|
bool detectValePivots;
|
|
XBoxZone valePivots[];
|
|
bool newValePivotDetected;
|
|
|
|
//
|
|
bool HasValePivots()
|
|
{
|
|
return HasChild(valePivots);
|
|
}
|
|
|
|
//
|
|
int CountValePivots()
|
|
{
|
|
return ArraySize(valePivots);
|
|
}
|
|
|
|
//
|
|
// FVG ...
|
|
|
|
//
|
|
bool selectSameBarFVGs; // Select FVGs which has Same Type Bars ...
|
|
bool validateFVGUsingPV; // Detect FVG Type Two ( Validating Using PV ) ...
|
|
int maxAllowedFVGLifetime; // Max Allowed FVG Life ...
|
|
bool applyPVToFVGBoundary; // Apply PV to FVG Boundary ...
|
|
bool selectRejectedFVGPivots; // Select Rejected FVG Pivots ...
|
|
bool selectEngulfedFVGPivots; // Select Engulfed FVG Pivots ...
|
|
bool validateFVGUsingManalyser; // Detect FVG Type One ( Validating Using MAnalyser ) ...
|
|
bool applyLastBarToFVGBoundary; // Apply Last Bar to FVG Boundary ...
|
|
bool selectOnlyFVGWhichHasIndirectionalLastBar; // Select Only FVGs which has Indirectionsl Last Bar, uses to Order Block ...
|
|
|
|
//
|
|
bool DetectFVGPivot(
|
|
int barIndex,
|
|
ENUM_X_DIRECTION forDir,
|
|
XOHCL &zBar,
|
|
XOHCL &cBar,
|
|
XOHCL &pBar,
|
|
XOHCL &p2Bar,
|
|
XCAEAConditions &conditions //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Checking Direction ...
|
|
result = HasDirection(forDir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool forBullish = IsBullish(forDir);
|
|
bool forBearish = IsBearish(forDir);
|
|
|
|
//
|
|
// Check Allowed ...
|
|
result =
|
|
forBullish
|
|
? detectFVGBullishPivots
|
|
: detectFVGBearishPivots;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Args ...
|
|
result =
|
|
//
|
|
barIndex >= 0 &&
|
|
zBar.IsValid() &&
|
|
cBar.IsValid() &&
|
|
pBar.IsValid() &&
|
|
p2Bar.IsValid()
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Define Requirements ...
|
|
|
|
//
|
|
int zIDX = 0;
|
|
int cIDX = zIDX + 1;
|
|
int pIDX = cIDX + 1;
|
|
int p2IDX = pIDX + 1;
|
|
|
|
//
|
|
datetime cTime = zBar.time;
|
|
string symbol = zBar.symbol;
|
|
ENUM_TIMEFRAMES period = zBar.period;
|
|
double points = GetPoints(symbol);
|
|
|
|
//
|
|
// Reading Conditional Values ...
|
|
|
|
//
|
|
// PEAK ...
|
|
double zPeak = conditions.peakBuffer[zIDX];
|
|
double cPeak = conditions.peakBuffer[cIDX];
|
|
double pPeak = conditions.peakBuffer[pIDX];
|
|
double p2Peak = conditions.peakBuffer[p2IDX];
|
|
|
|
//
|
|
// VALE ...
|
|
double zVale = conditions.valeBuffer[zIDX];
|
|
double cVale = conditions.valeBuffer[cIDX];
|
|
double pVale = conditions.valeBuffer[pIDX];
|
|
double p2Vale = conditions.valeBuffer[p2IDX];
|
|
|
|
//
|
|
// MANALYSER ...
|
|
|
|
//
|
|
// MAH ...
|
|
double zMAH = conditions.mahBuffer[zIDX];
|
|
double cMAH = conditions.mahBuffer[cIDX];
|
|
double pMAH = conditions.mahBuffer[pIDX];
|
|
double p2MAH = conditions.mahBuffer[p2IDX];
|
|
|
|
//
|
|
// MAL ...
|
|
double zMAL = conditions.malBuffer[zIDX];
|
|
double cMAL = conditions.malBuffer[cIDX];
|
|
double pMAL = conditions.malBuffer[pIDX];
|
|
double p2MAL = conditions.malBuffer[p2IDX];
|
|
|
|
//
|
|
// MAC ...
|
|
double zMAC = conditions.macBuffer[zIDX];
|
|
double cMAC = conditions.macBuffer[cIDX];
|
|
double pMAC = conditions.macBuffer[pIDX];
|
|
double p2MAC = conditions.macBuffer[p2IDX];
|
|
|
|
//
|
|
// Detecting Bar Conditions ...
|
|
|
|
//
|
|
ENUM_X_DIRECTION p2BarDir;
|
|
|
|
//
|
|
// Rejected ...
|
|
bool isP2BarRejected = helper
|
|
.barAnalyser
|
|
.IsRejected(
|
|
p2Bar,
|
|
p2BarDir,
|
|
false, // Force Type ...
|
|
true // Force Fibo Pressure ...
|
|
);
|
|
bool isP2BarBullishRejected =
|
|
isP2BarRejected &&
|
|
IsBullish(p2BarDir);
|
|
bool isP2BarBearishRejected =
|
|
isP2BarRejected &&
|
|
IsBearish(p2BarDir);
|
|
|
|
//
|
|
// Engulfed ...
|
|
bool isP2BarEngulfed = helper
|
|
.barAnalyser
|
|
.IsEngulfed(
|
|
p2Bar,
|
|
p2BarDir //
|
|
);
|
|
bool isP2BarBullishEngulfed =
|
|
isP2BarEngulfed &&
|
|
IsBullish(p2BarDir);
|
|
bool isP2BarBearishEngulfed =
|
|
isP2BarEngulfed &&
|
|
IsBearish(p2BarDir);
|
|
|
|
//
|
|
// Prepare Conditinal Conditions ...
|
|
|
|
//
|
|
// Default FVG Detection ...
|
|
XBoxZone fvgBox;
|
|
bool isFVG = barAnalyser.IsFVG(
|
|
cBar,
|
|
fvgBox //
|
|
);
|
|
bool isBullishFVG =
|
|
isFVG &&
|
|
forBullish &&
|
|
fvgBox.IsBullish();
|
|
bool isBearishFVG =
|
|
isFVG &&
|
|
forBearish &&
|
|
fvgBox.IsBearish();
|
|
|
|
//
|
|
// Summarizing Conditions ...
|
|
|
|
//
|
|
result = false;
|
|
|
|
//
|
|
bool hasStartCondition = false;
|
|
bool hasContinuationCondition = false;
|
|
bool hasEndCondition = isBullishFVG ||
|
|
isBearishFVG;
|
|
|
|
//
|
|
// Apply all Filtering ...
|
|
if (hasEndCondition)
|
|
{
|
|
//
|
|
XOHCL p3Bar;
|
|
p2Bar.GetPreviousBar(p3Bar);
|
|
|
|
//
|
|
bool isFVGValid = true;
|
|
|
|
//
|
|
// Validate FVG Using Manalyser ...
|
|
bool isManalyserValid = false;
|
|
if (validateFVGUsingManalyser)
|
|
{
|
|
//
|
|
isManalyserValid =
|
|
hasEndCondition &&
|
|
(forBullish
|
|
? fvgBox.upper <= cMAL
|
|
: fvgBox.lower >= cMAH);
|
|
}
|
|
|
|
//
|
|
// Validate FVG Using PV ...
|
|
bool isPVValid = false;
|
|
if (validateFVGUsingPV)
|
|
{
|
|
//
|
|
isPVValid =
|
|
hasEndCondition &&
|
|
(forBullish
|
|
? (p2Peak < pPeak ||
|
|
pPeak < cPeak)
|
|
: (p2Vale > pVale ||
|
|
pVale > cVale));
|
|
}
|
|
|
|
//
|
|
// Select Pure FVG ...
|
|
bool isPureFVGValid =
|
|
!validateFVGUsingPV &&
|
|
!validateFVGUsingManalyser;
|
|
|
|
//
|
|
// Summarise Validation ...
|
|
isFVGValid =
|
|
isPVValid ||
|
|
isPureFVGValid ||
|
|
isManalyserValid;
|
|
|
|
//
|
|
bool isFVGBarPassed = false;
|
|
|
|
//
|
|
// Select Same Bars FVGs ...
|
|
bool isFVGHasSameBar = true;
|
|
if (selectSameBarFVGs)
|
|
{
|
|
//
|
|
isFVGHasSameBar =
|
|
forBullish
|
|
? (cBar.IsBullish() &&
|
|
pBar.IsBullish() &&
|
|
p2Bar.IsBullish())
|
|
: (cBar.IsBearish() &&
|
|
pBar.IsBearish() &&
|
|
p2Bar.IsBearish());
|
|
isFVGBarPassed =
|
|
isFVGBarPassed ||
|
|
isFVGHasSameBar;
|
|
}
|
|
|
|
//
|
|
// Select Rejected FVG ...
|
|
bool isFVGRejected = true;
|
|
if (selectRejectedFVGPivots)
|
|
{
|
|
//
|
|
isFVGRejected =
|
|
(forBullish
|
|
? isP2BarBullishRejected
|
|
: isP2BarBearishRejected);
|
|
isFVGBarPassed =
|
|
isFVGBarPassed ||
|
|
isFVGRejected;
|
|
}
|
|
|
|
//
|
|
// Select Engulfed FVG ...
|
|
bool isFVGEngulfed = true;
|
|
if (selectEngulfedFVGPivots)
|
|
{
|
|
//
|
|
isFVGEngulfed =
|
|
(forBullish
|
|
? isP2BarBullishEngulfed
|
|
: isP2BarBearishEngulfed);
|
|
isFVGBarPassed =
|
|
isFVGBarPassed ||
|
|
isFVGEngulfed;
|
|
}
|
|
|
|
//
|
|
// Select Only FVGs Which Has Indirectional Last Bar ...
|
|
bool isFVGHasIndirectionalStart = true;
|
|
if (selectOnlyFVGWhichHasIndirectionalLastBar)
|
|
{
|
|
//
|
|
isFVGHasIndirectionalStart =
|
|
p3Bar.IsValid() &&
|
|
(forBullish
|
|
? p3Bar.IsBearish()
|
|
: p3Bar.IsBullish());
|
|
isFVGBarPassed =
|
|
isFVGBarPassed ||
|
|
isFVGHasIndirectionalStart;
|
|
}
|
|
|
|
//
|
|
// Summarise Bar Pass ...
|
|
isFVGBarPassed =
|
|
(selectSameBarFVGs ||
|
|
selectRejectedFVGPivots ||
|
|
selectEngulfedFVGPivots ||
|
|
selectOnlyFVGWhichHasIndirectionalLastBar)
|
|
? isFVGBarPassed
|
|
: true;
|
|
|
|
//
|
|
hasEndCondition = isFVGValid &&
|
|
isFVGBarPassed;
|
|
|
|
//
|
|
// Apply Boundary ...
|
|
if (hasEndCondition)
|
|
{
|
|
//
|
|
double iValue =
|
|
forBullish
|
|
? fvgBox.upper
|
|
: fvgBox.lower;
|
|
|
|
//
|
|
if (applyPVToFVGBoundary)
|
|
{
|
|
//
|
|
fvgBox.upper =
|
|
forBullish
|
|
? fvgBox.upper
|
|
: cPeak;
|
|
|
|
//
|
|
fvgBox.lower =
|
|
forBullish
|
|
? cVale
|
|
: fvgBox.lower;
|
|
}
|
|
|
|
//
|
|
if (applyLastBarToFVGBoundary)
|
|
{
|
|
//
|
|
fvgBox.lower = MathMin(p3Bar.low, fvgBox.lower);
|
|
fvgBox.upper = MathMax(p3Bar.high, fvgBox.upper);
|
|
}
|
|
}
|
|
|
|
//
|
|
p3Bar.Clean();
|
|
}
|
|
|
|
//
|
|
// ReInstance Pivot ...
|
|
if (hasStartCondition)
|
|
{
|
|
//
|
|
}
|
|
|
|
//
|
|
// Calculate and Fill Pivot Requirements ...
|
|
if (hasContinuationCondition)
|
|
{
|
|
//
|
|
}
|
|
|
|
//
|
|
// End up Pivot and Store it ...
|
|
if (hasEndCondition)
|
|
{
|
|
//
|
|
XBoxZone iBox;
|
|
XCAPivot iPivot;
|
|
|
|
//
|
|
iPivot.to = fvgBox.to;
|
|
iPivot.from = fvgBox.from;
|
|
iPivot.symbol = fvgBox.symbol;
|
|
iPivot.period = fvgBox.period;
|
|
iPivot.type = forBullish
|
|
? XCA_FVG_BULL
|
|
: XCA_FVG_BEAR;
|
|
iPivot.value = forBullish
|
|
? fvgBox.lower
|
|
: fvgBox.upper;
|
|
iPivot.reserve = forBullish
|
|
? fvgBox.upper
|
|
: fvgBox.lower;
|
|
|
|
//
|
|
result = iPivot.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
result = iPivot.AsBox(iBox);
|
|
if (result)
|
|
{
|
|
//
|
|
if (forBullish)
|
|
{
|
|
//
|
|
result = AddBox(
|
|
iBox,
|
|
fvgBullishPivots //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
result = AddBox(
|
|
iBox,
|
|
fvgBearishPivots //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
iBox.Clean();
|
|
iPivot.Clean();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void ValidateFVGPivots(
|
|
XBoxZone &unavailables[],
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
bool applyLifetimeValidating = maxAllowedFVGLifetime > 0;
|
|
|
|
//
|
|
// Bullish ...
|
|
has = HasFVGBullishPivots();
|
|
if (has)
|
|
{
|
|
//
|
|
ApplyValidationOnBoxes(
|
|
fvgBullishPivots,
|
|
unavailables,
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
if (applyLifetimeValidating)
|
|
{
|
|
//
|
|
ApplyLifeTimeValidationOnBoxes(
|
|
fvgBullishPivots,
|
|
maxAllowedFVGLifetime,
|
|
barIndex //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bearish ...
|
|
has = HasFVGBearishPivots();
|
|
if (has)
|
|
{
|
|
//
|
|
ApplyValidationOnBoxes(
|
|
fvgBearishPivots,
|
|
unavailables,
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
if (applyLifetimeValidating)
|
|
{
|
|
//
|
|
ApplyLifeTimeValidationOnBoxes(
|
|
fvgBearishPivots,
|
|
maxAllowedFVGLifetime,
|
|
barIndex //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// FVG Bullish Pivots ...
|
|
|
|
//
|
|
bool detectFVGBullishPivots;
|
|
XBoxZone fvgBullishPivots[];
|
|
bool newFVGBullishPivotDetected;
|
|
|
|
//
|
|
bool HasFVGBullishPivots()
|
|
{
|
|
return HasChild(fvgBullishPivots);
|
|
}
|
|
|
|
//
|
|
int CountFVGBullishPivots()
|
|
{
|
|
return ArraySize(fvgBullishPivots);
|
|
}
|
|
|
|
//
|
|
// FVG Bearish Pivots ...
|
|
|
|
//
|
|
bool detectFVGBearishPivots;
|
|
XBoxZone fvgBearishPivots[];
|
|
bool newFVGBearishPivotDetected;
|
|
|
|
//
|
|
bool HasFVGBearishPivots()
|
|
{
|
|
return HasChild(fvgBearishPivots);
|
|
}
|
|
|
|
//
|
|
int CountFVGBearishPivots()
|
|
{
|
|
return ArraySize(fvgBearishPivots);
|
|
}
|
|
|
|
//
|
|
// TREND ...
|
|
|
|
//
|
|
int maxAllowedTrendLifetime; // Max Allowed Trend Life ...
|
|
|
|
//
|
|
bool DetectTrendPivot(
|
|
int barIndex,
|
|
ENUM_X_DIRECTION forDir,
|
|
XOHCL &zBar,
|
|
XOHCL &cBar,
|
|
XOHCL &pBar,
|
|
XOHCL &p2Bar,
|
|
XCAEAConditions &conditions //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Checking Direction ...
|
|
result = HasDirection(forDir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool forBullish = IsBullish(forDir);
|
|
bool forBearish = IsBearish(forDir);
|
|
|
|
//
|
|
// Check Allowed ...
|
|
result =
|
|
forBullish
|
|
? detectTrendBullishPivots
|
|
: detectTrendBearishPivots;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Args ...
|
|
result =
|
|
//
|
|
barIndex >= 0 &&
|
|
zBar.IsValid() &&
|
|
cBar.IsValid() &&
|
|
pBar.IsValid() &&
|
|
p2Bar.IsValid()
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Define Requirements ...
|
|
|
|
//
|
|
int zIDX = 0;
|
|
int cIDX = zIDX + 1;
|
|
int pIDX = cIDX + 1;
|
|
int p2IDX = pIDX + 1;
|
|
|
|
//
|
|
datetime cTime = zBar.time;
|
|
string symbol = zBar.symbol;
|
|
ENUM_TIMEFRAMES period = zBar.period;
|
|
double points = GetPoints(symbol);
|
|
|
|
//
|
|
// Reading Conditional Values ...
|
|
|
|
//
|
|
// TREND ...
|
|
double zTrend = conditions.trendBuffer[zIDX];
|
|
double cTrend = conditions.trendBuffer[cIDX];
|
|
double pTrend = conditions.trendBuffer[pIDX];
|
|
double p2Trend = conditions.trendBuffer[p2IDX];
|
|
|
|
//
|
|
// TREND State ...
|
|
double zTrendState = conditions.trendStateBuffer[zIDX];
|
|
double cTrendState = conditions.trendStateBuffer[cIDX];
|
|
double pTrendState = conditions.trendStateBuffer[pIDX];
|
|
double p2TrendState = conditions.trendStateBuffer[p2IDX];
|
|
|
|
//
|
|
// Prepare Conditinal Conditions ...
|
|
|
|
//
|
|
// Bullish ...
|
|
|
|
//
|
|
bool isTrendBullish =
|
|
cTrendState > 0;
|
|
bool isTrendBullishPrev =
|
|
pTrendState > 0;
|
|
|
|
//
|
|
bool isTrendSwitchedToBullish = isTrendBullish &&
|
|
!isTrendBullishPrev;
|
|
bool isTrendFinishedFromBullish = !isTrendBullish &&
|
|
isTrendBullishPrev;
|
|
|
|
//
|
|
// Bearish ...
|
|
|
|
//
|
|
bool isTrendBearish =
|
|
cTrendState < 0;
|
|
bool isTrendBearishPrev =
|
|
pTrendState < 0;
|
|
|
|
//
|
|
bool isTrendSwitchedToBearish = isTrendBearish &&
|
|
!isTrendBearishPrev;
|
|
bool isTrendFinishedFromBearish = !isTrendBearish &&
|
|
isTrendBearishPrev;
|
|
|
|
//
|
|
// Summarizing Conditions ...
|
|
|
|
//
|
|
result = false;
|
|
|
|
//
|
|
bool hasStartCondition =
|
|
forBullish
|
|
? isTrendFinishedFromBullish
|
|
: isTrendFinishedFromBearish;
|
|
bool hasContinuationCondition =
|
|
forBullish
|
|
? isTrendBullish
|
|
: isTrendBearish;
|
|
bool hasEndCondition =
|
|
forBullish
|
|
? isTrendSwitchedToBullish
|
|
: isTrendSwitchedToBearish;
|
|
|
|
//
|
|
// ReInstance Pivot ...
|
|
if (hasStartCondition)
|
|
{
|
|
//
|
|
// Bullish ...
|
|
if (forBullish)
|
|
{
|
|
//
|
|
trendBullishPivot.Clean();
|
|
|
|
//
|
|
trendBullishPivot.symbol = symbol;
|
|
trendBullishPivot.period = period;
|
|
trendBullishPivot.type = XCA_TREND_BULL;
|
|
|
|
//
|
|
trendBullishPivot.to = pBar.time;
|
|
trendBullishPivot.from = pBar.time;
|
|
trendBullishPivot.value = pTrend;
|
|
trendBullishPivot.reserve = pTrend;
|
|
}
|
|
|
|
//
|
|
// Bearish ...
|
|
if (forBearish)
|
|
{
|
|
//
|
|
trendBearishPivot.Clean();
|
|
|
|
//
|
|
trendBearishPivot.symbol = symbol;
|
|
trendBearishPivot.period = period;
|
|
trendBearishPivot.type = XCA_TREND_BEAR;
|
|
|
|
//
|
|
trendBearishPivot.to = pBar.time;
|
|
trendBearishPivot.from = pBar.time;
|
|
trendBearishPivot.value = pTrend;
|
|
trendBearishPivot.reserve = pTrend;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Calculate and Fill Pivot Requirements ...
|
|
if (hasContinuationCondition)
|
|
{
|
|
//
|
|
// Bullish ...
|
|
if (forBullish)
|
|
{
|
|
//
|
|
trendBullishPivot.from = pBar.time;
|
|
|
|
//
|
|
Add(
|
|
pTrend,
|
|
trendBullishPivot.values //
|
|
);
|
|
Add(
|
|
pTrend,
|
|
trendBullishPivot.values //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Bearish ...
|
|
if (forBearish)
|
|
{
|
|
//
|
|
trendBearishPivot.from = pBar.time;
|
|
|
|
//
|
|
Add(
|
|
pTrend,
|
|
trendBearishPivot.values //
|
|
);
|
|
Add(
|
|
pTrend,
|
|
trendBearishPivot.values //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// End up Pivot and Store it ...
|
|
if (hasEndCondition)
|
|
{
|
|
//
|
|
// Bullish ...
|
|
if (forBullish)
|
|
{
|
|
//
|
|
// Update Values ...
|
|
trendBullishPivot.value = GetMin(trendBullishPivot.values);
|
|
trendBullishPivot.reserve = GetMax(trendBullishPivot.values);
|
|
|
|
//
|
|
result =
|
|
trendBullishPivot.IsValid() &&
|
|
trendBullishPivot.GetAge() >= pivotVerifications;
|
|
if (result)
|
|
{
|
|
//
|
|
XBoxZone iBox;
|
|
result = trendBullishPivot.AsBox(iBox);
|
|
if (result)
|
|
{
|
|
//
|
|
newTrendBullishPivotDetected = AddBox(
|
|
iBox,
|
|
trendBullishPivots //
|
|
);
|
|
}
|
|
|
|
//
|
|
iBox.Clean();
|
|
}
|
|
|
|
//
|
|
trendBullishPivot.Clean();
|
|
}
|
|
|
|
//
|
|
// Bearish ...
|
|
if (forBearish)
|
|
{
|
|
//
|
|
// Update Values ...
|
|
trendBearishPivot.value = GetMax(trendBearishPivot.values);
|
|
trendBearishPivot.reserve = GetMin(trendBearishPivot.values);
|
|
|
|
//
|
|
result =
|
|
trendBearishPivot.IsValid() &&
|
|
trendBearishPivot.GetAge() >= pivotVerifications;
|
|
if (result)
|
|
{
|
|
//
|
|
XBoxZone iBox;
|
|
result = trendBearishPivot.AsBox(iBox);
|
|
if (result)
|
|
{
|
|
//
|
|
newTrendBearishPivotDetected = AddBox(
|
|
iBox,
|
|
trendBearishPivots //
|
|
);
|
|
}
|
|
|
|
//
|
|
iBox.Clean();
|
|
}
|
|
|
|
//
|
|
trendBearishPivot.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void ValidateTrendPivots(
|
|
XBoxZone &unavailables[],
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
bool applyLifetimeValidating = maxAllowedTrendLifetime > 0;
|
|
|
|
//
|
|
// Bullish ...
|
|
has = HasTrendBullishPivots();
|
|
if (has)
|
|
{
|
|
//
|
|
ApplyValidationOnBoxes(
|
|
trendBullishPivots,
|
|
unavailables,
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
if (applyLifetimeValidating)
|
|
{
|
|
//
|
|
ApplyLifeTimeValidationOnBoxes(
|
|
trendBullishPivots,
|
|
maxAllowedTrendLifetime,
|
|
barIndex //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bearish ...
|
|
has = HasTrendBearishPivots();
|
|
if (has)
|
|
{
|
|
//
|
|
ApplyValidationOnBoxes(
|
|
trendBearishPivots,
|
|
unavailables,
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
if (applyLifetimeValidating)
|
|
{
|
|
//
|
|
ApplyLifeTimeValidationOnBoxes(
|
|
trendBearishPivots,
|
|
maxAllowedTrendLifetime,
|
|
barIndex //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bullish ...
|
|
|
|
//
|
|
XCAPivot trendBullishPivot;
|
|
XBoxZone trendBullishPivots[];
|
|
bool detectTrendBullishPivots;
|
|
bool newTrendBullishPivotDetected;
|
|
|
|
//
|
|
bool HasTrendBullishPivots()
|
|
{
|
|
return HasChild(trendBullishPivots);
|
|
}
|
|
|
|
//
|
|
int CountTrendBullishPivots()
|
|
{
|
|
return ArraySize(trendBullishPivots);
|
|
}
|
|
|
|
//
|
|
// Bearish ...
|
|
|
|
//
|
|
XCAPivot trendBearishPivot;
|
|
XBoxZone trendBearishPivots[];
|
|
bool detectTrendBearishPivots;
|
|
bool newTrendBearishPivotDetected;
|
|
|
|
//
|
|
bool HasTrendBearishPivots()
|
|
{
|
|
return HasChild(trendBearishPivots);
|
|
}
|
|
|
|
//
|
|
int CountTrendBearishPivots()
|
|
{
|
|
return ArraySize(trendBearishPivots);
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Prrivate ...
|
|
private:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
XCPOIDrawer *drawer;
|
|
XCXCAEAHelper *helper;
|
|
XCBarAnalyser *barAnalyser;
|
|
|
|
//
|
|
bool AddBox(
|
|
XBoxZone &box,
|
|
XBoxZone &boxes[] //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = box.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int idx = -1;
|
|
bool isExists = FindBoxIndex(
|
|
idx,
|
|
box,
|
|
boxes //
|
|
);
|
|
result = !isExists;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int before = ArraySize(boxes);
|
|
|
|
//
|
|
AddRef(
|
|
box,
|
|
boxes //
|
|
);
|
|
|
|
//
|
|
int after = ArraySize(boxes);
|
|
|
|
//
|
|
result = after > before;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool ValidateBox(
|
|
XBoxZone &box,
|
|
XBoxZone &unavailables[],
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Bar Index ...
|
|
barIndex = NormalizeInt(barIndex, 0);
|
|
|
|
//
|
|
// Ceck Input Box is Valid ...
|
|
result = box.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Input Box is Available ...
|
|
bool canCheckUnAvailableBoxes = HasChild(unavailables);
|
|
if (canCheckUnAvailableBoxes)
|
|
{
|
|
//
|
|
int idx = -1;
|
|
bool isUnAvailable = FindBoxIndex(
|
|
idx,
|
|
box,
|
|
unavailables //
|
|
);
|
|
result = !isUnAvailable;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Input Box is Breaked or not ...
|
|
|
|
//
|
|
// Check Bar Index must after Box To Index ...
|
|
int toIDX = box.ToIndex();
|
|
int fromIDX = box.FromIndex();
|
|
result = toIDX > barIndex &&
|
|
fromIDX > barIndex &&
|
|
fromIDX > toIDX;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detect Box Applied Boundary Price ...
|
|
// For Checking Break of Box ...
|
|
bool isBullish = box.IsBullish();
|
|
double boundary =
|
|
isBullish
|
|
? box.lower
|
|
: box.upper;
|
|
|
|
//
|
|
// for validating Box Break we have to wait At Least 3 Bars Close
|
|
// out of Box Boundary ...
|
|
int barsLength = 3;
|
|
|
|
//
|
|
// Calculate Start Checking Bar Index ...
|
|
int startCheckBreaktionBarIndex = toIDX - barsLength;
|
|
bool isBarIndexValid = startCheckBreaktionBarIndex > 0 &&
|
|
barIndex < startCheckBreaktionBarIndex;
|
|
result = isBarIndexValid;
|
|
if (!result)
|
|
{
|
|
//
|
|
// Assume Box is Valid if Bar Index not Valid for Checking ...
|
|
result = true;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Try to Check Box Validation if Everything is OK ...
|
|
XOHCL cBar;
|
|
XOHCL pBar;
|
|
XOHCL p2Bar;
|
|
bool isValid = false;
|
|
bool isBreaked = false;
|
|
for (int i = barIndex; i < startCheckBreaktionBarIndex; i++)
|
|
{
|
|
//
|
|
// Initialize Bars ...
|
|
isValid = cBar.Init(
|
|
box.symbol,
|
|
box.period,
|
|
i + 1 //
|
|
);
|
|
isValid =
|
|
result &&
|
|
cBar.GetPreviousBar(pBar);
|
|
isValid =
|
|
result &&
|
|
pBar.GetPreviousBar(p2Bar);
|
|
if (!isValid)
|
|
{
|
|
//
|
|
cBar.Clean();
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
result = false;
|
|
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Preparing Conditions ...
|
|
|
|
//
|
|
bool isBullishBreaked =
|
|
isBullish &&
|
|
cBar.close < boundary &&
|
|
pBar.close < boundary &&
|
|
p2Bar.close < boundary;
|
|
|
|
//
|
|
bool isBearishBreaked =
|
|
!isBullish &&
|
|
cBar.close > boundary &&
|
|
pBar.close > boundary &&
|
|
p2Bar.close > boundary;
|
|
|
|
//
|
|
// Calculate Result ...
|
|
isBreaked = isBullishBreaked ||
|
|
isBearishBreaked;
|
|
if (isBreaked)
|
|
{
|
|
//
|
|
cBar.Clean();
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
result = false;
|
|
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
cBar.Clean();
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
}
|
|
|
|
//
|
|
result = isValid &&
|
|
!isBreaked;
|
|
if (!result)
|
|
{
|
|
//
|
|
int idx = -1;
|
|
bool isExists = FindBoxIndex(
|
|
idx,
|
|
box,
|
|
invalidPivots //
|
|
);
|
|
if (!isExists)
|
|
{
|
|
//
|
|
AddRef(
|
|
box,
|
|
invalidPivots //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Cleanup Resource ...
|
|
|
|
//
|
|
cBar.Clean();
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void CleanPivots()
|
|
{
|
|
//
|
|
Clean(invalidPivots);
|
|
|
|
//
|
|
peakPivot.Clean();
|
|
valePivot.Clean();
|
|
trendBullishPivot.Clean();
|
|
trendBearishPivot.Clean();
|
|
|
|
//
|
|
Clean(peakPivots);
|
|
Clean(valePivots);
|
|
|
|
//
|
|
Clean(fvgBullishPivots);
|
|
Clean(fvgBearishPivots);
|
|
|
|
//
|
|
Clean(trendBullishPivots);
|
|
Clean(trendBearishPivots);
|
|
}
|
|
|
|
//
|
|
void SortPivots()
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
// Invalid Pivots ...
|
|
has = HasInvalidPivots();
|
|
if (has)
|
|
{
|
|
ApplySortOnBoxes(invalidPivots);
|
|
}
|
|
|
|
//
|
|
// PV ...
|
|
|
|
//
|
|
// PEAK ...
|
|
has = HasPeakPivots();
|
|
if (has)
|
|
{
|
|
ApplySortOnBoxes(peakPivots);
|
|
}
|
|
|
|
//
|
|
// VALE ...
|
|
has = HasValePivots();
|
|
if (has)
|
|
{
|
|
ApplySortOnBoxes(valePivots);
|
|
}
|
|
|
|
//
|
|
// FVG ...
|
|
|
|
//
|
|
// Bullish ...
|
|
has = HasFVGBullishPivots();
|
|
if (has)
|
|
{
|
|
ApplySortOnBoxes(fvgBullishPivots);
|
|
}
|
|
|
|
//
|
|
// Bearish ...
|
|
has = HasFVGBearishPivots();
|
|
if (has)
|
|
{
|
|
ApplySortOnBoxes(fvgBearishPivots);
|
|
}
|
|
|
|
//
|
|
// TREND ...
|
|
|
|
//
|
|
// Bullish ...
|
|
has = HasTrendBullishPivots();
|
|
if (has)
|
|
{
|
|
ApplySortOnBoxes(trendBullishPivots);
|
|
}
|
|
|
|
//
|
|
// Bearish ...
|
|
has = HasTrendBearishPivots();
|
|
if (has)
|
|
{
|
|
ApplySortOnBoxes(trendBearishPivots);
|
|
}
|
|
}
|
|
|
|
//
|
|
void ApplySortOnBoxes(
|
|
XBoxZone &items[] //
|
|
)
|
|
{
|
|
//
|
|
int idx = -1;
|
|
bool has = false;
|
|
|
|
//
|
|
has = HasChild(items);
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XBoxZone tmp[];
|
|
Copy(
|
|
items,
|
|
tmp //
|
|
);
|
|
Clean(items);
|
|
|
|
//
|
|
while (HasChild(tmp))
|
|
{
|
|
//
|
|
idx = GetOldest(tmp);
|
|
has = IsValidIndex(idx);
|
|
if (!has)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
XBoxZone iBox = tmp[idx];
|
|
ArrayRemove(
|
|
tmp,
|
|
idx,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
AddRef(
|
|
iBox,
|
|
items //
|
|
);
|
|
}
|
|
|
|
//
|
|
CleanupArray(
|
|
items,
|
|
maxAllowedPivots //
|
|
);
|
|
|
|
//
|
|
Clean(tmp);
|
|
}
|
|
|
|
//
|
|
void ApplyValidationOnBoxes(
|
|
XBoxZone &items[],
|
|
XBoxZone &unavailables[],
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = HasChild(items);
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XBoxZone tmp[];
|
|
Copy(
|
|
items,
|
|
tmp //
|
|
);
|
|
Clean(items);
|
|
while (HasChild(tmp))
|
|
{
|
|
//
|
|
XBoxZone iBox = tmp[0];
|
|
ArrayRemove(
|
|
tmp,
|
|
0,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
has = ValidateBox(
|
|
iBox,
|
|
unavailables,
|
|
barIndex //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
AddRef(
|
|
iBox,
|
|
items //
|
|
);
|
|
}
|
|
|
|
//
|
|
iBox.Clean();
|
|
//
|
|
}
|
|
|
|
//
|
|
Clean(tmp);
|
|
}
|
|
|
|
//
|
|
void ApplyLifeTimeValidationOnBoxes(
|
|
XBoxZone &items[],
|
|
int maxAllowedAge = 0,
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
barIndex = NormalizeInt(barIndex, 0);
|
|
|
|
//
|
|
has =
|
|
maxAllowedAge > 0 &&
|
|
HasChild(items);
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
datetime cTime = GetBarTime(
|
|
helper.GetSymbol(),
|
|
helper.GetPeriod(),
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
XBoxZone tmp[];
|
|
Copy(
|
|
items,
|
|
tmp //
|
|
);
|
|
Clean(items);
|
|
|
|
//
|
|
while (HasChild(tmp))
|
|
{
|
|
//
|
|
XBoxZone iBox = tmp[0];
|
|
ArrayRemove(
|
|
tmp,
|
|
0,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
datetime defTo = iBox.to;
|
|
iBox.to = cTime;
|
|
|
|
//
|
|
int iAge = iBox.GetAge();
|
|
has = iAge <= maxAllowedAge;
|
|
iBox.to = defTo;
|
|
if (has)
|
|
{
|
|
//
|
|
AddRef(
|
|
iBox,
|
|
items //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
int idx = -1;
|
|
bool isExists = FindBoxIndex(
|
|
idx,
|
|
iBox,
|
|
invalidPivots //
|
|
);
|
|
if (!isExists)
|
|
{
|
|
//
|
|
AddRef(
|
|
iBox,
|
|
invalidPivots //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
iBox.Clean();
|
|
}
|
|
|
|
//
|
|
Clean(tmp);
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
// |