Files
MQL5Data/Classes/x-saherelm.x-market.pattern.class.mq5
T

3694 lines
92 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// ----------------------------------------------
// Name: XCMarketPatternDetector
// Description: provides all Alerts requirements ...
//
//
// 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 "../Classes/x-saherelm.x-bar.analyser.class.mq5"
#include "../Libraries/x-saherelm.x-pivot.analysis.lib.mq5"
#include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5"
#include "../Libraries/x-saherelm.x-poi.lib.mq5"
//
// Definitions ...
//
// Implementation ...
class XCMarketPatternDetector : public XCBase
{
//
// Public ...
public:
//
// Props ...
//
XBoxZone zones[];
XBoxZone majorSupport;
XBoxZone minorSupport;
XBoxZone majorResistance;
XBoxZone minorResistance;
//
// Constructor ...
XCMarketPatternDetector()
{
barAnalyser = new XCBarAnalyser();
}
//
// Deconstructor ...
~XCMarketPatternDetector()
{
//
delete barAnalyser;
ZeroMemory(barAnalyser);
}
//
// Actions / Helpers ...
//
double CalculateQuarter()
{
//
double result = -1;
//
// Validate ...
bool has = majorSupport.IsValid() &&
majorResistance.IsValid();
if (!has)
{
return result;
}
//
result = majorSupport.upper + ((majorResistance.lower - majorSupport.upper) / 2);
//
return result;
}
//
// Analysers ...
/**
* Check for Price Touch Support Level ...
*
* @param bar: XOHCL, Specified Bar ...
* @param supportBar: XOHCL, reference to holds Zone Bar ...
* @param supportBox: XBoxZone, reference to holds Zone Box ...
* @param validationLength: int, Validation Length ...
* @param maxAllowedLoopback: int, Max Allowed Loopback to Detection ...
*
* @return ( bool )
*/
bool IsSupportTouched(
XOHCL &bar,
XOHCL &supportBar,
XBoxZone &supportBox,
int validationLength = 21,
int maxAllowedLoopback = 1500 //
)
{
//
bool result = false;
//
// Prepare ...
supportBar.Clean();
supportBox.Clean();
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Check Support Exists ...
result = HasSupport(
bar,
supportBar,
validationLength,
maxAllowedLoopback //
);
if (!result)
{
//
supportBar.Clean();
return result;
}
//
// Extract Support Box ...
result = ToSupportBox(
supportBar,
supportBox //
);
//
// Retrieve Previous Bar ...
XOHCL pBar;
result =
result &&
bar.GetPreviousBar(pBar);
//
// Chekc Price of Bar ...
result =
result &&
pBar.low < supportBox.upper;
//
// Cleanup Resources ...
if (!result)
{
//
supportBar.Clean();
supportBox.Clean();
}
pBar.Clean();
//
return result;
}
/**
* Check for Price Touch Resistance Level ...
*
* @param bar: XOHCL, Specified Bar ...
* @param supportBar: XOHCL, reference to holds Zone Bar ...
* @param supportBox: XBoxZone, reference to holds Zone Box ...
* @param validationLength: int, Validation Length ...
* @param maxAllowedLoopback: int, Max Allowed Loopback to Detection ...
*
* @return ( bool )
*/
bool IsResistanceTouched(
XOHCL &bar,
XOHCL &resistanceBar,
XBoxZone &resistanceBox,
int validationLength = 21,
int maxAllowedLoopback = 1500 //
)
{
//
bool result = false;
//
// Prepare ...
resistanceBar.Clean();
resistanceBox.Clean();
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Check Resistance Exists ...
result = HasResistance(
bar,
resistanceBar,
validationLength,
maxAllowedLoopback //
);
if (!result)
{
//
resistanceBar.Clean();
return result;
}
//
// Extract Resistance Box ...
result = ToResistanceBox(
resistanceBar,
resistanceBox //
);
//
// Retrieve Previous Bar ...
XOHCL pBar;
result =
result &&
bar.GetPreviousBar(pBar);
//
// Chekc Price of Bar ...
result =
result &&
pBar.high > resistanceBox.lower;
//
// Cleanup Resources ...
if (!result)
{
//
resistanceBar.Clean();
resistanceBox.Clean();
}
pBar.Clean();
//
return result;
}
//
// Detectors ...
/**
* Check Specified Bar is Peak or Vale ...
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
* @param validationLength: int, Validation Length ...
*
* @return ( bool )
*/
bool IsPV(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
int validationLength = 7,
ENUM_X_PRICE peakPriceType = X_PRICE_HIGH, //
ENUM_X_PRICE valePriceType = X_PRICE_LOW //
)
{
//
bool result = false;
//
// Prepare ...
CleanDirection(dir);
//
// Normalize ...
validationLength = NormalizeInt(validationLength, 2);
//
// Validate ...
result = bar.IsValid() &&
IsXValid(peakPriceType) &&
IsXValid(valePriceType);
if (!result)
{
return result;
}
//
int valeIndex = -1;
double vale = bar.FindLowest(
valeIndex,
validationLength,
valePriceType //
);
double barVale = bar.GetPrice(valePriceType);
bool isVale =
NotEmptyZero(vale) &&
NotEmptyZero(barVale) &&
IsValidIndex(valeIndex) &&
vale >= barVale;
//
int peakIndex = -1;
double peak = bar.FindHighest(
peakIndex,
validationLength,
peakPriceType //
);
double barPeak = bar.GetPrice(peakPriceType);
bool isPeak =
NotEmptyZero(peak) &&
NotEmptyZero(barPeak) &&
IsValidIndex(peakIndex) &&
peak <= barPeak;
//
result = (isVale && !isPeak) ||
(isPeak && !isVale);
if (result)
{
//
dir =
isVale
? X_DIRECTION_BULLISH
: isPeak
? X_DIRECTION_BEARISH
: X_DIRECTION_NONE;
}
//
// Get Result ...
result = HasDirection(dir);
//
// Cleanup Resources ...
//
return result;
}
/**
* Check Specified Bar is Momentum Bar or not ...
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
* @param requiredBars: int, bar range for approve Momentum ...
* @param approvedMultiplier: double, a Multipler for approve Momentum ...
*
* @return ( bool )
*/
bool IsMomentumBar(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
int requiredBars = 3,
double approvedMultiplier = 2 //
)
{
//
bool result = false;
//
// Prepare ...
CleanDirection(dir);
//
// Normalizing ...
requiredBars = NormalizeInt(requiredBars, 3, 10);
approvedMultiplier = NormalizeDouble(approvedMultiplier, 2, 5);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Calculate Requirements ...
//
XOHCL iBar;
bool has = false;
double rangeBody = 0;
int start = bar.Index() + 1;
int end = start + requiredBars;
for (int i = start; i < end; i++)
{
//
// Initialized Bar ...
has = iBar.Init(
bar.symbol,
bar.period,
i //
);
//
// Summarize Body Sizes ...
if (has)
{
rangeBody += iBar.GetBody();
}
//
iBar.Clean();
}
//
// Calculate Body Approvement ...
result = bar.GetBody() >= (approvedMultiplier * rangeBody);
if (!result)
{
return result;
}
//
// Check Direction ...
dir = bar.GetDirection();
//
// Get Result ...
result = HasDirection(dir);
//
// Cleanup Resources ...
iBar.Clean();
//
return result;
}
/**
* Check Specified Bar is Engulfed Bar or not ...
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
*
* @return ( bool )
*/
bool IsEngulfedBar(
XOHCL &bar,
ENUM_X_DIRECTION &dir //
)
{
//
bool result = false;
//
// Prepare ...
CleanDirection(dir);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Calculate Requirements ...
//
XOHCL iBar;
result = bar.GetPreviousBar(iBar);
if (!result)
{
//
iBar.Clean();
return result;
}
//
// Check Prev Bar Must Inside Bar ...
result = bar.GetUp() > iBar.GetUp() &&
bar.GetDown() < iBar.GetDown();
if (!result)
{
//
iBar.Clean();
return result;
}
//
// Check Directions ...
bool isBullish =
iBar.IsBearish() &&
bar.IsBullish();
bool isBearish =
iBar.IsBullish() &&
bar.IsBearish();
result = isBullish || isBearish;
if (!result)
{
//
iBar.Clean();
return result;
}
//
dir = bar.GetDirection();
//
// Get Result ...
result = HasDirection(dir);
//
// Cleanup Resources ...
iBar.Clean();
//
return result;
}
/**
* Check Specified Bar is True Gapped Bar or not ...
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
* @param approvedPointMultiplier: double, Gap Validation Multiplier in Point ...
*
* @return ( bool )
*/
bool IsTrueGapedBar(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
double approvedPointMultiplier = 1 //
)
{
//
bool result = false;
//
// Prepare ...
CleanDirection(dir);
//
// Normalizing ...
approvedPointMultiplier = NormalizeDouble(approvedPointMultiplier, 1, 100);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Calculate Requirements ...
//
XOHCL iBar;
result = bar.GetPreviousBar(iBar);
if (!result)
{
//
iBar.Clean();
return result;
}
//
// Check Directions ...
bool isBullish =
iBar.IsBullish() &&
bar.IsBullish();
bool isBearish =
iBar.IsBearish() &&
bar.IsBearish();
result = isBullish || isBearish;
if (!result)
{
//
iBar.Clean();
return result;
}
//
double point = GetPoints(bar.symbol);
double approvedGapSize = approvedPointMultiplier * point;
//
// Check Gap Exists ...
result =
isBullish
? bar.low > iBar.high
: iBar.low > bar.high;
if (!result)
{
//
iBar.Clean();
return result;
}
//
// Validate Gap Size ...
double gapSize = isBullish
? bar.low - iBar.high
: iBar.low - bar.high;
result = gapSize >= approvedGapSize;
if (!result)
{
//
iBar.Clean();
return result;
}
//
dir = bar.GetDirection();
//
// Get Result ...
result = HasDirection(dir);
//
// Cleanup Resources ...
iBar.Clean();
//
return result;
}
/**
* Check Specified Bar is Pinned Bar or not ...
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
* @param shadowApprovedMultiplier: double, Shadow Size Approve Multiplier ...
* @param minimumPinBarRangeMultiplier: doubble, Range Size Approve Multiplier in Point ...
* @param forceDirection: bool, Apply Force Bar Type ...
*
* @return ( bool )
*/
bool IsPinnedBar(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
double shadowApprovedMultiplier = 3,
double minimumPinBarRangeMultiplier = 4,
bool forceDirection = false //
)
{
//
bool result = false;
//
// Prepare ...
CleanDirection(dir);
//
// Normalizing ...
shadowApprovedMultiplier = NormalizeDouble(shadowApprovedMultiplier, 2, 5);
minimumPinBarRangeMultiplier = NormalizeDouble(minimumPinBarRangeMultiplier, 2, 100);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Calculate Requirements ...
double body = bar.GetBody();
double lowShadow = bar.GetLowShadow();
double highShadow = bar.GetHighShadow();
//
// Check Directions ...
bool isBullish =
lowShadow > body &&
lowShadow > highShadow &&
lowShadow >= (body * shadowApprovedMultiplier);
bool isBearish =
highShadow > body &&
highShadow > lowShadow &&
highShadow > (body * shadowApprovedMultiplier);
result = isBullish || isBearish;
if (!result)
{
return result;
}
//
// Checking Force Bar Type ...
if (forceDirection)
{
//
result =
isBullish
? bar.IsBullish()
: bar.IsBearish();
}
if (!result)
{
return result;
}
//
// Check Range Validation ...
double point = GetPoints(bar.symbol);
double approvedRange = minimumPinBarRangeMultiplier * point;
result = bar.GetRange() >= approvedRange;
if (!result)
{
return result;
}
//
// Setting Direction ...
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
result = HasDirection(dir);
//
return result;
}
/**
* Check Specified Bar has Star Pattern or not ...
* Morning Star => Bullish
* Evening Star => Bearish
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
*
* @return ( bool )
*/
bool IsStarPattern(
XOHCL &bar,
ENUM_X_DIRECTION &dir //
)
{
//
bool result = false;
//
// Prepare ...
CleanDirection(dir);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Get Requirements ...
XOHCL pBar, p2Bar;
result = bar.GetPreviousBar(pBar);
result = result &&
pBar.GetPreviousBar(p2Bar);
if (!result)
{
//
pBar.Clean();
p2Bar.Clean();
//
return result;
}
//
// Check Directions ...
bool isBullish =
bar.IsBullish() &&
p2Bar.IsBearish();
bool isBearish =
bar.IsBearish() &&
p2Bar.IsBullish();
result = isBullish || isBearish;
if (!result)
{
//
pBar.Clean();
p2Bar.Clean();
//
return result;
}
//
// Checking Gap Exists Between Bars ...
result =
isBullish
? p2Bar.GetDown() > pBar.GetUp() &&
pBar.GetUp() < bar.GetDown()
: p2Bar.GetUp() < pBar.GetDown() &&
pBar.GetDown() > bar.GetUp();
if (!result)
{
//
pBar.Clean();
p2Bar.Clean();
//
return result;
}
//
// Check Bar Close Validation ...
double barClosedApprovedPrice = p2Bar.GetDown() + ((p2Bar.GetUp() - p2Bar.GetDown()) / 2);
result =
isBullish
? bar.close > barClosedApprovedPrice
: bar.close < barClosedApprovedPrice;
if (!result)
{
//
pBar.Clean();
p2Bar.Clean();
//
return result;
}
//
// Validating PBar Body and Shadow ...
double body = pBar.GetBody();
double lowShadow = pBar.GetLowShadow();
double highShadow = pBar.GetHighShadow();
result =
body < bar.GetBody() &&
body < p2Bar.GetBody() &&
(isBullish
? lowShadow > body &&
lowShadow > highShadow
: highShadow > body &&
highShadow > lowShadow);
if (!result)
{
//
pBar.Clean();
p2Bar.Clean();
//
return result;
}
//
dir = bar.GetDirection();
//
// Get Result ...
result = HasDirection(dir);
//
// Cleanup Resources ...
pBar.Clean();
p2Bar.Clean();
//
return result;
}
/**
* Check Specified Bar has Pirecing Pattern or not ...
* Piercing => Bullish
* Dark Cloud Cover => Bearish
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
*
* @return ( bool )
*/
bool IsPiercingPattern(
XOHCL &bar,
ENUM_X_DIRECTION &dir //
)
{
//
bool result = false;
//
// Prepare ...
CleanDirection(dir);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
XOHCL pBar;
result = bar.GetPreviousBar(pBar);
if (!result)
{
//
pBar.Clean();
return result;
}
//
// Check Directions ...
bool isBullish =
bar.IsBullish() &&
pBar.IsBearish();
bool isBearish =
bar.IsBearish() &&
pBar.IsBullish();
result = isBullish || isBearish;
if (!result)
{
//
pBar.Clean();
return result;
}
//
// Check Bar Close ...
double barCloseApprovedPrice = pBar.GetDown() + ((pBar.GetUp() - pBar.GetDown()) / 2);
result =
isBullish
? bar.close > barCloseApprovedPrice
: bar.close < barCloseApprovedPrice;
if (!result)
{
//
pBar.Clean();
return result;
}
//
dir = bar.GetDirection();
//
// Get Result ...
result = HasDirection(dir);
//
// Cleanup Resources ...
pBar.Clean();
//
return result;
}
/**
* Check Specified Bar has Rising Pattern or not ...
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
*
* @return ( bool )
*/
bool IsRisingPattern(
XOHCL &bar,
ENUM_X_DIRECTION &dir //
)
{
//
bool result = false;
//
// Prepare ...
CleanDirection(dir);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Reading Required Bars ...
XOHCL iBar;
XOHCL bars[];
bool has = false;
int start = bar.Index();
int end = start + 5;
for (int i = start; i < end; i++)
{
//
// Initialized Bar ...
has = iBar.Init(
bar.symbol,
bar.period,
i //
);
if (has)
{
//
AddRef(
iBar,
bars //
);
}
//
iBar.Clean();
}
result = ArraySize(bars) == 5;
if (!result)
{
//
iBar.Clean();
SpecifiedClean(bars);
//
return result;
}
//
// Check Directions ...
bool isBullish =
bars[0].IsBullish() &&
bars[4].IsBullish() &&
bars[1].IsBearish() &&
bars[2].IsBearish() &&
bars[3].IsBearish();
bool isBearish =
bars[0].IsBearish() &&
bars[4].IsBearish() &&
bars[1].IsBullish() &&
bars[2].IsBullish() &&
bars[3].IsBullish();
result = isBullish || isBearish;
if (!result)
{
//
iBar.Clean();
SpecifiedClean(bars);
//
return result;
}
//
// Check Range Validation ...
double upper = bars[4].GetUp();
double lower = bars[4].GetDown();
//
double max = MathMax(bars[1].GetUp(), bars[2].GetUp());
max = MathMax(max, bars[3].GetUp());
//
double min = MathMin(bars[1].GetDown(), bars[2].GetDown());
min = MathMin(min, bars[3].GetDown());
//
result =
max < upper &&
min > lower &&
(isBullish
? bars[0].close > bars[4].GetUp()
: bars[0].close < bars[4].GetDown());
if (!result)
{
//
iBar.Clean();
SpecifiedClean(bars);
//
return result;
}
//
dir = bar.GetDirection();
//
// Get Result ...
result = HasDirection(dir);
//
// Cleanup Resources ...
iBar.Clean();
SpecifiedClean(bars);
//
return result;
}
/**
* Check Specified Bar has Flag Pattern or not ...
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
* @param swingBar: XOHCL, Detected Swing Bar ...
* @param minimumPullbackBars: int, Minimum Shoulders of Swing Bar ...
*
* @return ( bool )
*/
bool IsFlagPattern(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
XOHCL &swingBar,
int minimumPullbackBars = 3 //
)
{
//
bool result = false;
//
// Prepare ...
swingBar.Clean();
CleanDirection(dir);
//
// Normalizing ...
minimumPullbackBars = NormalizeInt(minimumPullbackBars, 3, 10);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Reading Previous Bar ...
XOHCL pBar;
result = bar.GetPreviousBar(pBar);
if (!result)
{
//
pBar.Clean();
return result;
}
//
// Check Directions ...
bool isBullish =
bar.IsBullish() &&
bar.close > pBar.GetUp();
bool isBearish =
bar.IsBearish() &&
bar.close < pBar.GetDown();
result = isBullish || isBearish;
if (!result)
{
//
pBar.Clean();
return result;
}
//
// Detect Swing Bar ...
ENUM_X_SWING_TYPE swingType =
isBullish
? X_SWING_HIGH
: X_SWING_LOW;
result =
result &&
IsXValid(swingType) &&
bar.FindNextSwingBar(
swingType,
swingBar,
minimumPullbackBars //
) &&
(isBullish
? swingBar.IsBullish() &&
swingBar.high > pBar.high
: swingBar.IsBearish() &&
swingBar.low < pBar.low);
if (!result)
{
//
pBar.Clean();
swingBar.Clean();
//
return result;
}
//
dir = bar.GetDirection();
//
// Get Result ...
result = HasDirection(dir);
//
// Cleanup Resources ...
pBar.Clean();
if (!result)
{
swingBar.Clean();
}
//
return result;
}
/**
* Check Specified Bar has SignalKey Bar Pattern or not ...
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
* @param shadowApprovedMultiplier: double, Shadow Size Approve Multiplier ...
* @param minimumPinBarRangeMultiplier: doubble, Range Size Approve Multiplier in Point ...
* @param forceDirection: bool, Apply Force Bar Type ...
*
* @return ( bool )
*/
bool IsSignalKeyBarPattern(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
double shadowApprovedMultiplier = 3,
double minimumPinBarRangeMultiplier = 4,
bool forceDirection = false //
)
{
//
bool result = false;
//
// Prepare ...
CleanDirection(dir);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Get Requirements ...
XOHCL pBar;
result = bar.GetPreviousBar(pBar);
if (!result)
{
return result;
}
//
// Chck Previous Bar must Pinned ...
result = IsPinnedBar(
pBar,
dir,
shadowApprovedMultiplier,
minimumPinBarRangeMultiplier,
forceDirection //
);
if (!result)
{
//
pBar.Clean();
return result;
}
//
// Check Direction ...
bool isBullish =
bar.IsBullish() &&
IsSpecifiedBullish(dir) &&
bar.close > pBar.high;
bool isBearish =
bar.IsBearish() &&
IsSpecifiedBearish(dir) &&
bar.close < pBar.low;
result = isBullish || isBearish;
if (!result)
{
//
pBar.Clean();
return result;
}
//
dir = bar.GetDirection();
//
result = HasDirection(dir);
//
// Cleanup Resources ...
pBar.Clean();
//
return result;
}
//
// FVG ...
/**
* Check For FVG Exists in Specified Loopback Period ...
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
* @param fvg: XBoxZone, reference for Holding FVG ...
* @param maxLoopback: int, Max Allowed Loopback to Lookup FVG ...
*
* @return ( bool )
*/
bool HasFVG(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
XBoxZone &fvg,
int maxLoopback = 5 //
)
{
//
bool result = false;
//
// Prepare ...
fvg.Clean();
CleanDirection(dir);
//
// Normalize ...
maxLoopback = NormalizeInt(maxLoopback, 3);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
XOHCL iBar;
bool has = false;
int start = bar.Index();
int end = start + maxLoopback;
for (int i = start; i < end; i++)
{
//
// Initialize iBar ...
has = iBar.Init(
bar.symbol,
bar.period,
i //
);
if (!has)
{
continue;
}
//
// Check iBar is FVG or not ...
has = barAnalyser.IsFVG(
iBar,
fvg,
true // Force Bar Type ...
);
if (!has)
{
//
fvg.Clean();
iBar.Clean();
CleanDirection(dir);
//
continue;
}
//
iBar.Clean();
dir = fvg.dir;
//
break;
}
//
// Check FVG Exists ...
result = fvg.IsValid();
//
// Check Direction Exists ...
result =
result &&
HasDirection(dir);
//
// Cleanup Resources ...
if (!result)
{
//
fvg.Clean();
CleanDirection(dir);
}
iBar.Clean();
//
return result;
}
//
// OB ...
/**
* Check For OB Exists in Specified Loopback Period ...
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
* @param ob: XBoxZone, reference for Holding OB ...
* @param maxLoopback: int, Max Allowed Loopback to Lookup OB ...
*
* @return ( bool )
*/
bool HasOB(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
XBoxZone &ob,
int maxLoopback = 5 //
)
{
//
bool result = false;
//
// Prepare ...
ob.Clean();
CleanDirection(dir);
//
// Normalize ...
maxLoopback = NormalizeInt(maxLoopback, 3);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
XOHCL iBar;
bool has = false;
int start = bar.Index();
int end = start + maxLoopback;
for (int i = start; i < end; i++)
{
//
// Initialize iBar ...
has = iBar.Init(
bar.symbol,
bar.period,
i //
);
if (!has)
{
continue;
}
//
// Check iBar is OB or not ...
has = barAnalyser.IsOB(
iBar,
ob,
true, // Force FVG Bar Type ...
true // Force OB First Two Bar InDirection ...
);
if (!has)
{
//
ob.Clean();
iBar.Clean();
CleanDirection(dir);
//
continue;
}
//
iBar.Clean();
dir = ob.dir;
//
break;
}
//
// Check OB Exists ...
result = ob.IsValid();
//
// Check Direction Exists ...
result =
result &&
HasDirection(dir);
//
// Cleanup Resources ...
if (!result)
{
//
ob.Clean();
CleanDirection(dir);
}
iBar.Clean();
//
return result;
}
//
// Trending ...
/**
* Check Trend Exists Based on Swings ...
*
* @param bar: XOHCL, Specified Bar ...
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
* @param swings: XOHCL Array, Holds Swings ...
* @param numberOfSwings: int, Number of Swing Points for Detect Trend ...
* @param swingShoulders: int, Swing Shoulders Approvement Length ...
*
* @return ( bool )
*/
bool HasSwingTrend(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
XOHCL &swings[],
int numberOfSwings = 3,
int swingShoulders = 7 //
)
{
//
bool result = false;
//
// Prepare ...
CleanDirection(dir);
SpecifiedClean(swings);
//
// Normalizing ...
numberOfSwings = NormalizeInt(numberOfSwings, 3, 10);
swingShoulders = NormalizeInt(swingShoulders, 3);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Check Trend Direction ...
XOHCL iSwing;
int idx = -1;
bool has = false;
XOHCL swingLows[];
XOHCL swingHighs[];
int lastSwingLowIndex = bar.Index();
int lastSwingHighIndex = bar.Index();
while (ArraySize(swingLows) < numberOfSwings || ArraySize(swingHighs) < numberOfSwings)
{
//
bool canLookupSwingLow = ArraySize(swingLows) < numberOfSwings;
bool canLookupSwingHigh = ArraySize(swingHighs) < numberOfSwings;
if (!canLookupSwingLow && !canLookupSwingHigh)
{
break;
}
//
// Handle Swing Lows ...
if (canLookupSwingLow)
{
//
iSwing.Clean();
idx = FindXSwing(
X_SWING_LOW,
bar.symbol,
bar.period,
lastSwingLowIndex + 1,
swingShoulders //
);
has = IsValidIndex(idx);
if (has)
{
//
has = iSwing.Init(
bar.symbol,
bar.period,
idx //
);
if (has)
{
//
AddRef(
iSwing,
swingLows //
);
//
lastSwingLowIndex = idx;
}
}
}
//
// Handle Swing Highs ...
if (canLookupSwingHigh)
{
//
iSwing.Clean();
idx = FindXSwing(
X_SWING_HIGH,
bar.symbol,
bar.period,
lastSwingHighIndex + 1,
swingShoulders //
);
has = IsValidIndex(idx);
if (has)
{
//
has = iSwing.Init(
bar.symbol,
bar.period,
idx //
);
if (has)
{
//
AddRef(
iSwing,
swingHighs //
);
//
lastSwingHighIndex = idx;
}
}
}
}
//
// Check Trend Based On Swings ...
//
// Check Directions ...
//
bool isBullish = false;
bool isBearish = false;
//
datetime oldestSwingLow = NULL;
datetime oldestSwingHigh = NULL;
//
// Checking Bullish Trend based on Swing Lows ...
int count = ArraySize(swingLows);
for (int i = 0; i < count - 1; i++)
{
//
has = swingLows[i].low > swingLows[i + 1].low;
isBullish =
!isBullish
? has
: isBullish && has;
if (!isBullish)
{
break;
}
//
datetime oldeTime = MathMin(swingLows[i].time, swingLows[i + 1].time);
oldestSwingLow =
!IsSpecifiedValid(oldestSwingLow)
? oldeTime
: MathMin(oldestSwingLow, oldeTime);
}
//
// Checking Bearish Trend based on Swing Highs ...
count = ArraySize(swingHighs);
for (int i = 0; i < count - 1; i++)
{
//
has = swingHighs[i].high < swingHighs[i + 1].high;
isBearish =
!isBearish
? has
: isBearish && has;
if (!isBearish)
{
break;
}
//
datetime oldeTime = MathMin(swingHighs[i].time, swingHighs[i + 1].time);
oldestSwingHigh =
!IsSpecifiedValid(oldestSwingHigh)
? oldeTime
: MathMin(oldestSwingHigh, oldeTime);
}
//
result = isBullish || isBearish;
if (!result)
{
//
iSwing.Clean();
SpecifiedClean(swingLows);
SpecifiedClean(swingHighs);
//
return result;
}
//
if (isBullish &&
isBearish &&
IsSpecifiedValid(oldestSwingLow) &&
IsSpecifiedValid(oldestSwingHigh))
{
//
// Here we Have to Detect Newest Trend or Oldest Trend ...
isBullish = oldestSwingLow < oldestSwingHigh;
isBearish = oldestSwingHigh < oldestSwingLow;
}
//
result = (isBullish && !isBearish) ||
(isBearish && !isBullish);
if (!result)
{
//
iSwing.Clean();
SpecifiedClean(swingLows);
SpecifiedClean(swingHighs);
//
return result;
}
//
if (isBullish)
{
//
Copy(
swingLows,
swings //
);
//
dir = X_DIRECTION_BULLISH;
}
else
{
//
Copy(
swingHighs,
swings //
);
//
dir = X_DIRECTION_BEARISH;
}
//
iSwing.Clean();
SpecifiedClean(swingLows);
SpecifiedClean(swingHighs);
//
return result;
}
/**
* Check Specified Bar Has Support or not ...
*
* @param bar: XOHCL, Specified Bar ...
* @param support: XOHCL, Supported Bar ...
* @param validationLength: int, Validation Length ...
* @param maxAllowedLoopback: int, Max Allowed Loopback to Detection ...
*
* @return ( bool )
*/
bool HasSupport(
XOHCL &bar,
XOHCL &support,
int validationLength = 21,
int maxAllowedLoopback = 1500 //
)
{
//
bool result = false;
//
// Prepare ...
support.Clean();
//
// Normalizing ...
validationLength = NormalizeInt(validationLength, 7);
maxAllowedLoopback = NormalizeInt(maxAllowedLoopback, 21, 1500);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Find Support Swing ...
int idx = -1;
bool has = false;
int lookupIDX = bar.Index();
while (!IsValidIndex(idx) &&
lookupIDX < maxAllowedLoopback)
{
//
// Detect Swing ...
idx = FindXSwing(
X_SWING_LOW,
bar.symbol,
bar.period,
lookupIDX,
validationLength //
);
has = IsValidIndex(idx);
if (!has)
{
//
lookupIDX++;
continue;
}
//
// Retrieve Swing Bar ...
has = support.Init(
bar.symbol,
bar.period,
idx //
);
if (!has)
{
//
idx = -1;
lookupIDX++;
support.Clean();
continue;
}
//
// Check Suppor Low Shadow ...
has = support.GetDown() < bar.low;
if (!has)
{
//
idx = -1;
lookupIDX++;
support.Clean();
continue;
}
//
if (IsValidIndex(idx))
{
break;
}
}
//
result = support.IsValid();
//
return result;
}
/**
* Check Specified Bar Has Resistance or not ...
*
* @param bar: XOHCL, Specified Bar ...
* @param resistence: XOHCL, Resistanced Bar ...
* @param validationLength: int, Validation Length ...
* @param maxAllowedLoopback: int, Max Allowed Loopback to Detection ...
*
* @return ( bool )
*/
bool HasResistance(
XOHCL &bar,
XOHCL &resistence,
int validationLength = 21,
int maxAllowedLoopback = 1500 //
)
{
//
bool result = false;
//
// Prepare ...
resistence.Clean();
//
// Normalizing ...
validationLength = NormalizeInt(validationLength, 7);
maxAllowedLoopback = NormalizeInt(maxAllowedLoopback, 21, 1500);
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Find Support Swing ...
int idx = -1;
bool has = false;
int lookupIDX = bar.Index();
while (!IsValidIndex(idx) &&
lookupIDX < maxAllowedLoopback)
{
//
// Detect Swing ...
idx = FindXSwing(
X_SWING_HIGH,
bar.symbol,
bar.period,
lookupIDX,
validationLength //
);
has = IsValidIndex(idx);
if (!has)
{
//
lookupIDX++;
continue;
}
//
// Retrieve Swing Bar ...
has = resistence.Init(
bar.symbol,
bar.period,
idx //
);
if (!has)
{
//
idx = -1;
lookupIDX++;
resistence.Clean();
continue;
}
//
// Check Resistance High Shadow ...
has = resistence.GetUp() > bar.high;
if (!has)
{
//
idx = -1;
lookupIDX++;
resistence.Clean();
continue;
}
//
if (IsValidIndex(idx))
{
break;
}
}
//
result = resistence.IsValid();
//
return result;
}
//
// Analysers ...
/**
* Analyse Specified Bar ...
*
* @param bar: XOHCL, reference to Specified Bar ...
* @param analysis: XPatternAnalysis, reference to holds Analysis result ...
* @param config: XPatternAnalysisConfig, reference to Provides Detector Configs ...
*
* @return ( bool )
*/
bool AnalyseBarPatterns(
XOHCL &bar,
XPatternAnalysis &analysis,
XPatternAnalysisConfig &config //
)
{
//
bool result = false;
//
// Prepare ...
analysis.Clean();
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
analysis.bar = bar;
analysis.time = TimeCurrent();
//
XOHCL iSwing;
XBoxZone iZone;
ENUM_X_DIRECTION iDir;
ENUM_X_BAR_PATTERN iPattern;
//
bool has;
bool isBullish;
bool isBearish;
//
bool canDetect;
bool canDetectBullish;
bool canDetectBearish;
//
// Bars Detectors ...
//
// XPV High Low Detection ...
canDetect = config.CanDetect(X_BAR_PATTERN_HIGH) ||
config.CanDetect(X_BAR_PATTERN_LOW);
if (canDetect)
{
//
has = IsPV(
bar,
iDir,
config.pvValidationLength,
config.peakPriceType,
config.valePriceType //
);
//
canDetectBullish = config.CanDetect(X_BAR_PATTERN_LOW);
canDetectBearish = config.CanDetect(X_BAR_PATTERN_HIGH);
//
isBullish =
has &&
IsXBullish(iDir) &&
canDetectBullish;
//
isBearish =
has &&
IsXBearish(iDir) &&
canDetectBearish;
//
canDetect = isBullish ||
isBearish;
if (canDetect)
{
//
iPattern =
isBearish
? X_BAR_PATTERN_HIGH
: X_BAR_PATTERN_LOW;
//
analysis.AddPattern(
iPattern,
iDir //
);
}
}
//
// Momentum ...
iPattern = X_BAR_PATTERN_MOMENTUM;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = IsMomentumBar(
bar,
iDir,
config.momentumBarValidationLength,
config.momentumBarApprovedMultiplier //
);
//
canDetectBullish = config.CanDetect(
iPattern,
X_DIRECTION_BULLISH //
);
canDetectBearish = config.CanDetect(
iPattern,
X_DIRECTION_BEARISH //
);
//
isBullish = has &&
IsXBullish(iDir) &&
canDetectBullish;
isBearish = has &&
IsXBearish(iDir) &&
canDetectBearish;
//
canDetect = isBullish ||
isBearish;
if (canDetect)
{
//
analysis.AddPattern(
iPattern,
iDir //
);
}
}
//
// Engulfed ...
iPattern = X_BAR_PATTERN_ENGULFED;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = IsEngulfedBar(
bar,
iDir //
);
//
canDetectBullish = config.CanDetect(
iPattern,
X_DIRECTION_BULLISH //
);
canDetectBearish = config.CanDetect(
iPattern,
X_DIRECTION_BEARISH //
);
//
isBullish = has &&
IsXBullish(iDir) &&
canDetectBullish;
isBearish = has &&
IsXBearish(iDir) &&
canDetectBearish;
//
canDetect = isBullish ||
isBearish;
if (canDetect)
{
//
analysis.AddPattern(
iPattern,
iDir //
);
}
}
//
// TrueGap ...
iPattern = X_BAR_PATTERN_TRUE_GAPED;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = IsTrueGapedBar(
bar,
iDir,
config.trueGapApprovedStrength //
);
//
canDetectBullish = config.CanDetect(
iPattern,
X_DIRECTION_BULLISH //
);
canDetectBearish = config.CanDetect(
iPattern,
X_DIRECTION_BEARISH //
);
//
isBullish = has &&
IsXBullish(iDir) &&
canDetectBullish;
isBearish = has &&
IsXBearish(iDir) &&
canDetectBearish;
//
canDetect = isBullish ||
isBearish;
if (canDetect)
{
//
analysis.AddPattern(
iPattern,
iDir //
);
}
}
//
// Pinned ...
iPattern = X_BAR_PATTERN_PINNED;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = IsPinnedBar(
bar,
iDir,
config.pinBarShadowApprovedMultiplier,
config.pinBarRangeMultiplier,
config.pinBarForceDirection //
);
//
canDetectBullish = config.CanDetect(
iPattern,
X_DIRECTION_BULLISH //
);
canDetectBearish = config.CanDetect(
iPattern,
X_DIRECTION_BEARISH //
);
//
isBullish = has &&
IsXBullish(iDir) &&
canDetectBullish;
isBearish = has &&
IsXBearish(iDir) &&
canDetectBearish;
//
canDetect = isBullish ||
isBearish;
if (canDetect)
{
//
analysis.AddPattern(
iPattern,
iDir //
);
}
}
//
// Pattern Detectors ...
//
// Star ...
iPattern = X_BAR_PATTERN_STAR;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = IsStarPattern(
bar,
iDir //
);
//
canDetectBullish = config.CanDetect(
iPattern,
X_DIRECTION_BULLISH //
);
canDetectBearish = config.CanDetect(
iPattern,
X_DIRECTION_BEARISH //
);
//
isBullish = has &&
IsXBullish(iDir) &&
canDetectBullish;
isBearish = has &&
IsXBearish(iDir) &&
canDetectBearish;
//
canDetect = isBullish ||
isBearish;
if (canDetect)
{
//
analysis.AddPattern(
iPattern,
iDir //
);
}
}
//
// Piercing ...
iPattern = X_BAR_PATTERN_PIERCING;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = IsPiercingPattern(
bar,
iDir //
);
//
canDetectBullish = config.CanDetect(
iPattern,
X_DIRECTION_BULLISH //
);
canDetectBearish = config.CanDetect(
iPattern,
X_DIRECTION_BEARISH //
);
//
isBullish = has &&
IsXBullish(iDir) &&
canDetectBullish;
isBearish = has &&
IsXBearish(iDir) &&
canDetectBearish;
//
canDetect = isBullish ||
isBearish;
if (canDetect)
{
//
analysis.AddPattern(
iPattern,
iDir //
);
}
}
//
// Rising ...
iPattern = X_BAR_PATTERN_RISING;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = IsRisingPattern(
bar,
iDir //
);
//
canDetectBullish = config.CanDetect(
iPattern,
X_DIRECTION_BULLISH //
);
canDetectBearish = config.CanDetect(
iPattern,
X_DIRECTION_BEARISH //
);
//
isBullish = has &&
IsXBullish(iDir) &&
canDetectBullish;
isBearish = has &&
IsXBearish(iDir) &&
canDetectBearish;
//
canDetect = isBullish ||
isBearish;
if (canDetect)
{
//
analysis.AddPattern(
iPattern,
iDir //
);
}
}
//
// Flag ...
iPattern = X_BAR_PATTERN_FLAG;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = IsFlagPattern(
bar,
iDir,
iSwing,
config.flagPatternPullbackLength //
);
//
canDetectBullish = config.CanDetect(
iPattern,
X_DIRECTION_BULLISH //
);
canDetectBearish = config.CanDetect(
iPattern,
X_DIRECTION_BEARISH //
);
//
isBullish = has &&
IsXBullish(iDir) &&
canDetectBullish;
isBearish = has &&
IsXBearish(iDir) &&
canDetectBearish;
//
canDetect = isBullish ||
isBearish;
if (canDetect)
{
//
analysis.AddPattern(
iPattern,
iDir //
);
//
analysis.flagSwing = iSwing;
}
}
//
// SignalKey ...
iPattern = X_BAR_PATTERN_SIGNALKEY;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = IsSignalKeyBarPattern(
bar,
iDir,
config.pinBarShadowApprovedMultiplier,
config.pinBarRangeMultiplier,
config.pinBarForceDirection //
);
//
canDetectBullish = config.CanDetect(
iPattern,
X_DIRECTION_BULLISH //
);
canDetectBearish = config.CanDetect(
iPattern,
X_DIRECTION_BEARISH //
);
//
isBullish = has &&
IsXBullish(iDir) &&
canDetectBullish;
isBearish = has &&
IsXBearish(iDir) &&
canDetectBearish;
//
canDetect = isBullish ||
isBearish;
if (canDetect)
{
//
analysis.AddPattern(
iPattern,
iDir //
);
}
}
//
// Zone Detectors ...
//
// OB ...
iPattern = X_BAR_PATTERN_OB;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = barAnalyser.IsOB(
bar,
iZone,
config.fvgForceType,
config.obForceTwoBar //
);
//
canDetectBullish = config.CanDetect(
iPattern,
X_DIRECTION_BULLISH //
);
canDetectBearish = config.CanDetect(
iPattern,
X_DIRECTION_BEARISH //
);
//
isBullish = has &&
iZone.IsBullish() &&
canDetectBullish;
isBearish = has &&
iZone.IsBearish() &&
canDetectBearish;
//
canDetect = isBullish ||
isBearish;
if (canDetect)
{
//
analysis.AddPattern(
iPattern,
iZone.dir //
);
//
analysis.ob = iZone;
}
}
//
// FVG ...
iPattern = X_BAR_PATTERN_FVG;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = barAnalyser.IsFVG(
bar,
iZone,
config.fvgForceType //
);
//
canDetectBullish = config.CanDetect(
iPattern,
X_DIRECTION_BULLISH //
);
canDetectBearish = config.CanDetect(
iPattern,
X_DIRECTION_BEARISH //
);
//
isBullish = has &&
iZone.IsBullish() &&
canDetectBullish;
isBearish = has &&
iZone.IsBearish() &&
canDetectBearish;
//
canDetect = isBullish ||
isBearish;
if (canDetect)
{
//
analysis.AddPattern(
iPattern,
iZone.dir //
);
//
analysis.fvg = iZone;
}
}
//
// Support ...
iPattern = X_BAR_PATTERN_SUPPORT;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = HasSupport(
bar,
iSwing,
config.supportAndResistanceValidationLength,
config.supportAndResistanceLoopbackLength //
);
if (has)
{
//
has = ToSupportBox(
iSwing,
iZone,
bar.time,
config.supportAndResistanceValidationLength //
);
if (has)
{
//
analysis.AddPattern(
iPattern,
iZone.dir //
);
//
analysis.support = iZone;
}
}
}
//
// Resistance ...
iPattern = X_BAR_PATTERN_RESISTANCE;
canDetect = config.CanDetect(iPattern);
if (canDetect)
{
//
has = HasResistance(
bar,
iSwing,
config.supportAndResistanceValidationLength,
config.supportAndResistanceLoopbackLength //
);
if (has)
{
//
has = ToResistanceBox(
iSwing,
iZone,
bar.time,
config.supportAndResistanceValidationLength //
);
if (has)
{
//
analysis.AddPattern(
iPattern,
iZone.dir //
);
//
analysis.resistance = iZone;
}
}
}
//
// Validate Analysis ...
result = analysis.IsValid();
//
// Update Quarter ...
if (result)
{
//
// Retrieve Previous Bar ...
XOHCL pBar;
has = bar.GetPreviousBar(pBar);
if (has)
{
//
// Update Quarter ...
UpdateZones(
bar,
analysis.quarterActions,
config.quarterZonesValidationLength, // Zones Validation Length ...
config.quarterZonesRequiredToStart, // Zones Count to Start Processing ...
config.quarterZoneDetectionLoopback // Zones Detection Loopback ...
);
//
// Fill Quarter Props ...
analysis.majorSupport = majorSupport;
analysis.minorSupport = minorSupport;
analysis.quarter = CalculateQuarter();
analysis.majorResistance = majorResistance;
analysis.minorResistance = minorResistance;
//
// Update To Times ...
if (analysis.majorSupport.IsValid())
{
analysis.majorSupport.to = bar.time;
}
if (analysis.minorSupport.IsValid())
{
analysis.minorSupport.to = bar.time;
}
if (analysis.majorResistance.IsValid())
{
analysis.majorResistance.to = bar.time;
}
if (analysis.minorResistance.IsValid())
{
analysis.minorResistance.to = bar.time;
}
}
}
//
// Cleanup Resources ...
iZone.Clean();
iSwing.Clean();
CleanDirection(iDir);
//
return result;
}
/**
* Update and Manage Support and Resistance Zones ...
*
* @param bar: XOHCL, reference to Specified Bar ...
* @param actions: ENUM_X_DETECTOR_ZONE_ACTION, refernce collection to Notify happens actions ...
* @param validationLength: int, Validation Length for Zones ...
* @param requiredZones: int, Number of required Zones to collecting ...
* @param loopback: int, Max Allowed Loopback Bars for Collecting ...
*
* @return ( int )
*/
int UpdateZones(
XOHCL &bar,
ENUM_X_DETECTOR_ZONE_ACTION &actions[],
int validationLength = 3,
int requiredZones = 10,
int loopback = 1500 //
)
{
//
int result = 0;
//
// Prepare ...
XClean(actions);
//
// Normalize ...
loopback = NormalizeInt(loopback, 100);
requiredZones = NormalizeInt(requiredZones, 5);
validationLength = NormalizeInt(validationLength, 2);
//
// Validate ...
bool has = bar.IsValid();
if (!has)
{
return result;
}
//
int barIndex = bar.Index();
//
// Collect or Manage Zones ...
XOHCL zoneBar;
XBoxZone iZone;
bool hasZone = HasChild(zones);
int zonesCount = ArraySize(zones);
int zoneDetectionLoopback = (validationLength * 2);
if (!hasZone)
{
//
XOHCL iBar;
int start = barIndex;
int end = barIndex + loopback;
for (int i = start; i < end; i++)
{
//
// Extract Detected Zones ...
iBar.Clean();
has = bar.BarAt(i, iBar);
if (!has)
{
continue;
}
//
// Check Support ...
iZone.Clean();
zoneBar.Clean();
has = HasSupport(
iBar,
zoneBar,
validationLength, // Zone Validation Length ...
zoneDetectionLoopback // Zone Detection Loopback ...
);
has = has &&
ToSupportBox(zoneBar, iZone, bar.time);
if (has)
{
//
AddIfNotExists(
iZone,
zones //
);
}
//
// Check Resistance ...
iZone.Clean();
zoneBar.Clean();
has = HasResistance(
iBar,
zoneBar,
validationLength, // Zone Validation Length ...
zoneDetectionLoopback // Zone Detection Loopback ...
);
has = has &&
ToResistanceBox(zoneBar, iZone, bar.time);
if (has)
{
//
AddIfNotExists(
iZone,
zones //
);
}
//
// Validate Number of Zones ...
zonesCount = ArraySize(zones);
if (zonesCount >= requiredZones)
{
break;
}
}
//
iBar.Clean();
iZone.Clean();
zoneBar.Clean();
//
// Update Has Zones ...
hasZone = HasChild(zones);
zonesCount = ArraySize(zones);
}
//
// Manage Exists Zones ...
if (hasZone)
{
//
// Update Zones To Time ...
UpdateToTime(zones, bar.time);
//
// Validate Zones ...
CheckZones(bar, zones);
//
// Remove Breaked Zones ...
RemoveBreakedZones(zones);
//
hasZone = HasChild(zones);
zonesCount = ArraySize(zones);
}
//
// Minimum Exists Zones for Detecting majors ...
int minNumberOfZonesForMajors = 5;
bool canLookupMajor = hasZone &&
zonesCount >= minNumberOfZonesForMajors;
//
// Supports ...
//
// Check Zones Existances ...
bool hasMajorSupport = majorSupport.IsValid();
bool hasMinorSupport = minorSupport.IsValid();
//
// Check Major Support State ...
if (hasMajorSupport)
{
//
XOHCL pBar;
has = bar.GetPreviousBar(pBar);
if (has)
{
//
bool isBreaked = pBar.close < majorSupport.lower;
if (isBreaked)
{
//
int idx = -1;
has = FindIndex(idx, majorSupport, zones);
if (has)
{
zones[idx].breakAt = pBar.time;
}
majorSupport.Clean();
minorSupport.Clean();
hasMajorSupport = false;
hasMinorSupport = false;
Add(
X_DETECTOR_ZONE_ACTION_MAJOR_SUPPORT_BREAKED,
actions //
);
}
}
//
pBar.Clean();
}
//
// Look For Major Support ...
if (!hasMajorSupport)
{
//
minorSupport.Clean();
hasMinorSupport = false;
//
// Lookup Major ...
if (canLookupMajor)
{
//
int idx = GetLowestByDir(zones, X_DIRECTION_BULLISH);
hasMajorSupport = IsValidIndex(idx) && !IsXValid(zones[idx].breakAt);
if (hasMajorSupport)
{
//
majorSupport = zones[idx];
Add(
X_DETECTOR_ZONE_ACTION_MAJOR_SUPPORT_DETECTED,
actions //
);
}
}
}
//
// Resistances ...
//
// Check Zones Existances ...
bool hasMajorResistance = majorResistance.IsValid();
bool hasMinorResistance = minorResistance.IsValid();
//
// Check Major Resistance State ...
if (hasMajorResistance)
{
//
XOHCL pBar;
has = bar.GetPreviousBar(pBar);
if (has)
{
//
bool isBreaked = pBar.close > majorResistance.upper;
if (isBreaked)
{
//
int idx = -1;
has = FindIndex(idx, majorResistance, zones);
if (has)
{
zones[idx].breakAt = pBar.time;
}
majorResistance.Clean();
minorResistance.Clean();
hasMajorResistance = false;
hasMinorResistance = false;
Add(
X_DETECTOR_ZONE_ACTION_MAJOR_RESISTANCE_BREAKED,
actions //
);
}
}
//
pBar.Clean();
}
//
// Look For Major Resistance ...
if (!hasMajorResistance)
{
//
minorResistance.Clean();
hasMinorResistance = false;
//
// Lookup Major ...
if (canLookupMajor)
{
//
int idx = GetHighestByDir(zones, X_DIRECTION_BEARISH);
hasMajorResistance = IsValidIndex(idx);
if (hasMajorResistance)
{
//
majorResistance = zones[idx];
Add(
X_DETECTOR_ZONE_ACTION_MAJOR_RESISTANCE_DETECTED,
actions //
);
}
}
}
//
// Check Majors Exixsts ...
has = hasMajorSupport &&
hasMajorResistance;
if (has)
{
//
double quarter = CalculateQuarter();
//
// For Looking up Minor Support, we
// have to Ensure Major Support Exists ...
if (hasMajorSupport)
{
//
majorSupport.to = bar.time;
//
// Look for Minor Support ...
if (!hasMinorSupport)
{
//
XBoxZone _supports[];
int _supportsCount = ExtractByDirection(
_supports,
zones,
X_DIRECTION_BULLISH //
);
_supportsCount = RemoveBreakedZones(_supports);
has = IsValidSize(_supportsCount);
if (has)
{
//
// Remove Major ...
Remove(
majorSupport,
_supports //
);
//
// Count Remain Zones ...
_supportsCount = ArraySize(_supports);
has = IsValidSize(_supportsCount);
if (has)
{
//
// Minors Selected by Youngest ...
int idx = quarter > 0
? GetYoungestBelow(quarter, _supports)
: GetYoungest(_supports);
hasMinorSupport = IsValidIndex(idx) && !IsXValid(_supports[idx].breakAt);
if (hasMinorSupport)
{
//
minorSupport = _supports[idx];
minorSupport.to = bar.time;
minorSupport.from = minorSupport.at;
Add(
X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_DETECTED,
actions //
);
}
}
}
//
XClean(_supports);
}
//
// Validate Minor Support Place ...
if (quarter > 0 &&
hasMinorSupport)
{
//
hasMinorSupport = minorSupport.upper < quarter;
if (!hasMinorSupport)
{
//
int idx = -1;
has = FindIndex(
idx,
minorSupport,
zones //
);
if (has)
{
zones[idx].breakAt = bar.time;
}
minorSupport.Clean();
}
}
//
// Refine exists Minor Support ...
if (hasMinorSupport)
{
//
minorSupport.to = bar.time;
//
XOHCL pBar;
has = bar.GetPreviousBar(pBar);
if (has)
{
//
// Check Break ...
bool isBreaked = pBar.close < minorSupport.lower;
if (isBreaked)
{
//
minorSupport.Clean();
Add(
X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_BREAKED,
actions //
);
}
//
// Check Test ...
bool isTested = !isBreaked &&
pBar.low < minorSupport.upper &&
pBar.low > minorSupport.lower &&
bar.close > minorSupport.lower &&
bar.open > minorSupport.lower;
if (isTested)
{
//
Add(
X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_RETESTED,
actions //
);
}
//
// Check Refine ...
bool canRefine = !isBreaked &&
pBar.low < minorSupport.lower &&
pBar.close > minorSupport.lower;
if (canRefine)
{
//
minorSupport.upper = minorSupport.lower;
minorSupport.lower = pBar.low;
Add(
pBar.time,
minorSupport.refines //
);
Add(
X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_REFINED,
actions //
);
}
//
// Check New Minor Support ...
has = !isTested &&
!canRefine;
if (has)
{
//
// Check Above Minor Support has Support ...
XBoxZone _supports[];
int _supportsCount = ExtractByDirection(
_supports,
zones,
X_DIRECTION_BULLISH //
);
Remove(majorSupport, _supports);
Remove(minorSupport, _supports);
RemoveBreakedZones(_supports);
_supportsCount = ArraySize(_supports);
has = IsValidSize(_supportsCount);
if (has)
{
//
int idx = GetLowestAfter(minorSupport.from, _supports);
hasMinorSupport = IsValidIndex(idx) &&
(quarter <= 0
? true
: _supports[idx].upper < quarter);
if (hasMinorSupport)
{
//
minorSupport = _supports[idx];
minorSupport.to = bar.time;
minorSupport.from = minorSupport.at;
Add(
X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_DETECTED,
actions //
);
}
}
}
}
//
pBar.Clean();
}
}
//
// For Looking up Minor Resistance, we
// have to Ensure Major Resistance Exists ...
if (hasMajorResistance)
{
//
majorResistance.to = bar.time;
//
// Look for Minor Resistance ...
if (!hasMinorResistance)
{
//
XBoxZone _resistances[];
int _resistancesCount = ExtractByDirection(
_resistances,
zones,
X_DIRECTION_BEARISH //
);
_resistancesCount = RemoveBreakedZones(_resistances);
has = IsValidSize(_resistancesCount);
if (has)
{
//
// Remove Major ...
Remove(
majorResistance,
_resistances //
);
//
// Count Remain Zones ...
_resistancesCount = ArraySize(_resistances);
has = IsValidSize(_resistancesCount);
if (has)
{
//
// Minors Selected Youngest ...
int idx = GetYoungestAbove(quarter, _resistances);
hasMinorResistance = IsValidIndex(idx);
if (hasMinorResistance)
{
//
minorResistance = _resistances[idx];
minorResistance.to = bar.time;
minorResistance.from = minorResistance.at;
Add(
X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_DETECTED,
actions //
);
}
}
}
//
XClean(_resistances);
}
//
// Validate Minor Support Place ...
if (quarter > 0 &&
hasMinorResistance)
{
//
hasMinorResistance = minorResistance.lower > quarter;
if (!hasMinorResistance)
{
//
int idx = -1;
has = FindIndex(
idx,
minorResistance,
zones //
);
if (has)
{
zones[idx].breakAt = bar.time;
}
minorResistance.Clean();
}
}
//
// Refine exists Minor Resistance ...
if (hasMinorResistance)
{
//
minorResistance.to = bar.time;
//
// Check Retesting ...
XOHCL pBar;
has = bar.GetPreviousBar(pBar);
if (has)
{
//
// Check Break ...
bool isBreaked = pBar.close > minorResistance.upper;
if (isBreaked)
{
//
minorResistance.Clean();
Add(
X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_BREAKED,
actions //
);
}
//
// Check Test ...
bool isTested = !isBreaked &&
pBar.high > minorResistance.lower &&
pBar.high < minorResistance.upper &&
bar.close < minorResistance.upper &&
bar.open < minorResistance.upper;
if (isTested)
{
//
Add(
X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_RETESTED,
actions //
);
}
//
// Check Refine ...
bool canRefine = !isBreaked &&
pBar.high > minorResistance.upper &&
pBar.close < minorResistance.upper;
if (canRefine)
{
//
minorResistance.lower = minorResistance.upper;
minorResistance.upper = pBar.high;
Add(
pBar.time,
minorResistance.refines //
);
Add(
X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_REFINED,
actions //
);
}
//
// Check New Minor Resistace ...
has = !isTested &&
!canRefine;
if (has)
{
//
// Check Above Minor Resistance has Resistance ...
XBoxZone _resistances[];
int _resistancesCount = ExtractByDirection(
_resistances,
zones,
X_DIRECTION_BEARISH //
);
Remove(majorResistance, _resistances);
Remove(minorResistance, _resistances);
RemoveBreakedZones(_resistances);
_resistancesCount = ArraySize(_resistances);
has = IsValidSize(_resistancesCount);
if (has)
{
//
int idx = GetHighestAfter(minorResistance.from, _resistances);
hasMinorResistance = IsValidIndex(idx) &&
(quarter <= 0
? true
: _resistances[idx].lower > quarter);
if (hasMinorResistance)
{
//
minorResistance = _resistances[idx];
minorResistance.to = bar.time;
minorResistance.from = minorResistance.at;
Add(
X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_DETECTED,
actions //
);
}
}
}
}
//
pBar.Clean();
}
}
}
else
{
//
int idx = -1;
//
has = minorSupport.IsValid() &&
FindIndex(
idx,
minorSupport,
zones //
);
if (has)
{
zones[idx].breakAt = bar.time;
}
minorSupport.Clean();
hasMinorSupport = false;
//
has = minorResistance.IsValid() &&
FindIndex(
idx,
minorResistance,
zones //
);
if (has)
{
zones[idx].breakAt = bar.time;
}
minorResistance.Clean();
hasMinorResistance = false;
}
//
// Check Bar Zones to Update Zones ...
//
// Check Support ...
iZone.Clean();
zoneBar.Clean();
has = HasSupport(
bar,
zoneBar,
validationLength, // Zone Validation Length ...
zoneDetectionLoopback // Zone Detection Loopback ...
);
has = has &&
ToSupportBox(zoneBar, iZone, bar.time);
if (has)
{
//
AddIfNotExists(
iZone,
zones //
);
}
//
// Check Resistance ...
iZone.Clean();
zoneBar.Clean();
has = HasResistance(
bar,
zoneBar,
validationLength, // Zone Validation Length ...
zoneDetectionLoopback // Zone Detection Loopback ...
);
has = has &&
ToResistanceBox(zoneBar, iZone, bar.time);
if (has)
{
//
AddIfNotExists(
iZone,
zones //
);
}
//
// Actions Counting ...
result = ArraySize(actions);
//
// Cleanup ...
iZone.Clean();
zoneBar.Clean();
//
return result;
}
//
// Protected ...
protected:
//
//
// Tools / Actions ...
/**
* Check Zones and Manage them ...
*
* @param forBar: XOHCL, reference to Specified Bar ...
* @param _zones: XBoxZone, reference to Specified Zone Collection ...
* @param sortBy: X_SORT_BY_DATE, Sort Zones by ...
* @param sortDir: ENUM_X_DIRECTION, Sort Zones in Direction ...
* @param maxAllowed: int, Specified Max Allowed Zones ...
*/
void CheckZones(
XOHCL &forBar,
XBoxZone &_zones[],
ENUM_X_SORT_BY sortBy = X_SORT_BY_DATE,
ENUM_X_DIRECTION sortDir = X_DIRECTION_BEARISH,
int maxAllowed = 50 //
)
{
//
// Normalize ...
maxAllowed = NormalizeInt(maxAllowed, 0);
//
// Validate ...
bool has = forBar.IsValid() &&
HasChild(_zones);
if (!has)
{
return;
}
//
// Looping Through Zones ...
int count = ArraySize(_zones);
for (int i = 0; i < count; i++)
{
//
// Check Break ...
has = IsXValid(_zones[i].breakAt);
if (has)
{
continue;
}
//
_zones[i].to = forBar.time;
//
// Check for Test ...
has = IsTested(
forBar,
_zones[i] //
);
if (has)
{
//
Add(
forBar.time,
_zones[i].tests //
);
}
//
// Check for Inside ...
has = IsInside(
forBar,
_zones[i] //
);
if (has)
{
//
Add(
forBar.time,
_zones[i].insides //
);
}
//
// Check for Break ...
has = IsBreaked(
forBar,
_zones[i] //
);
if (has)
{
//
Add(
forBar.time,
_zones[i].breaks //
);
}
//
// Check for Act ...
has = IsActed(
forBar,
_zones[i] //
);
if (has)
{
//
Add(
forBar.time,
_zones[i].acteds //
);
}
//
// Check for FakeBreakes ...
has = IsFakeBreaked(
forBar,
_zones[i] //
);
if (has)
{
//
Add(
forBar.time,
_zones[i].fakeBreaks //
);
}
//
// Check for Valid Breakes ...
has = IsValidBreaked(
forBar,
_zones[i] //
);
if (has)
{
_zones[i].breakAt = forBar.time;
}
}
//
// Apply Sort and Cleanup ...
Sort(
_zones,
sortBy,
sortDir,
maxAllowed //
);
}
//
// Private ...
private:
//
// Props ...
XCBarAnalyser *barAnalyser;
//
// Helpers ...
/**
* Clean Specified Referenced Direction ...
*
* @param dir: ENUM_X_DIRECTION
*/
void CleanDirection(ENUM_X_DIRECTION &dir)
{
dir = X_DIRECTION_NONE;
}
};
//