2204 lines
48 KiB
Plaintext
2204 lines
48 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-poi.extensions.lib.mq5"
|
|
#include "../Libraries/x-saherelm.x-poi.lib.mq5"
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
// Implementation ...
|
|
class XCMarketPatternDetector : public XCBase
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XCMarketPatternDetector()
|
|
{
|
|
barAnalyser = new XCBarAnalyser();
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
~XCMarketPatternDetector()
|
|
{
|
|
//
|
|
delete barAnalyser;
|
|
ZeroMemory(barAnalyser);
|
|
}
|
|
|
|
//
|
|
// Actions / Helpers ...
|
|
|
|
//
|
|
// 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 ...
|
|
|
|
bool IsPeak(
|
|
XOHCL &bar,
|
|
int validationLength = 7 //
|
|
) {
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize ...
|
|
validationLength = NormalizeInt(validationLength, 2);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Define Requirements ...
|
|
result = bar.FindHighest(validationLength, MODE_HIGH) <= bar.high;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsVale(
|
|
XOHCL &bar,
|
|
int validationLength = 7 //
|
|
) {
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize ...
|
|
validationLength = NormalizeInt(validationLength, 2);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Define Requirements ...
|
|
result = bar.FindLowest(validationLength, MODE_LOW) >= bar.low;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* 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 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
CleanDirection(dir);
|
|
|
|
//
|
|
// Normalize ...
|
|
validationLength = NormalizeInt(validationLength, 2);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Define Requirements ...
|
|
XOHCL iBar;
|
|
bool isPeak = true;
|
|
bool isVale = true;
|
|
int start = bar.Index();
|
|
int end = start + validationLength;
|
|
for (int i = start; i < end; i++)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
result = bar.BarAt(i, iBar);
|
|
if (!result)
|
|
{
|
|
//
|
|
isVale = false;
|
|
isPeak = false;
|
|
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
isPeak =
|
|
isPeak &&
|
|
iBar.high <= bar.high;
|
|
|
|
//
|
|
isVale =
|
|
isVale &&
|
|
iBar.low >= bar.low;
|
|
|
|
//
|
|
if (!isPeak && !isVale)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result =
|
|
(isPeak && !isVale) ||
|
|
(isVale && !isPeak);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = isVale
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
// Get Result ...
|
|
result = HasDirection(dir);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
iBar.Clean();
|
|
|
|
//
|
|
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 IsStartPattern(
|
|
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 ...
|
|
* @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;
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
};
|
|
|
|
// |