This commit is contained in:
2025-10-23 13:05:34 +03:30
parent 8b85de5de4
commit 2edb26cfc2
7 changed files with 1267 additions and 85 deletions
@@ -1650,6 +1650,254 @@ class XCMarketPatternDetector : public XCBase
return result;
}
bool IsConsolidationPattern(
XOHCL &bar,
XBoxZone &zone,
ENUM_X_DIRECTION &dir,
int validationLength = 5,
ENUM_X_PRICE breakPriceType = X_PRICE_CLOSE,
ENUM_X_PRICE upperPriceType = X_PRICE_HIGH,
ENUM_X_PRICE lowerPriceType = X_PRICE_LOW //
)
{
//
// Descriptions:
// ===============
// Consolidation Zones Happens by Highest High and Lowest Low
// of Specified Range which Breakes From one Side ...
//
//
bool result = false;
//
// Prepare ...
zone.Clean();
CleanDirection(dir);
//
// Normalize ...
validationLength = NormalizeInt(validationLength, 3);
//
// Validate ...
result = bar.IsValid() &&
IsXValid(lowerPriceType) &&
IsXValid(upperPriceType) &&
IsXValid(breakPriceType);
if (!result)
{
return result;
}
//
// Define Requirements ...
XOHCL iBar;
bool has = false;
datetime to = NULL;
datetime from = NULL;
double iLow = EMPTY_VALUE;
bool hasLowShadow = false;
double lower = EMPTY_VALUE;
double upper = EMPTY_VALUE;
double iHigh = EMPTY_VALUE;
bool hasHighShadow = false;
double iPrice = EMPTY_VALUE;
bool isLowerBreaked = false;
bool isUpperBreaked = false;
//
// Loop Through Bars ...
int barIndex = bar.Index();
int idx = barIndex;
bool canLookup = IsValidIndex(idx);
while (canLookup)
{
//
// Initialize Indexed Bar ...
idx++;
iBar.Clean();
result = bar.BarAt(idx, iBar);
if (!result)
{
break;
}
//
// Update Time ...
if (idx == barIndex + 1)
{
to = iBar.time;
}
//
// Extract Low and High Price ...
iLow = iBar.GetPrice(lowerPriceType);
iHigh = iBar.GetPrice(upperPriceType);
result = NotEmptyZero(iLow) &&
NotEmptyZero(iHigh);
if (!result)
{
break;
}
//
// Check Bar Has Low/High Shadow ...
hasLowShadow = iBar.GetLowShadow() > iBar.GetHighShadow();
hasHighShadow = iBar.GetHighShadow() > iBar.GetLowShadow();
//
// Update Range Lower and Upper based on Shadows ...
//
// Lower ...
if (hasLowShadow)
{
//
// Check Can Update ...
has =
!NotEmptyZero(lower)
? true
: iLow < lower;
if (has)
{
lower = iLow;
}
}
//
// Upper ...
if (hasHighShadow)
{
//
// Check Can Update ...
has =
!NotEmptyZero(upper)
? true
: iHigh > upper;
if (has)
{
upper = iHigh;
}
}
//
// Check Price Breakes ...
iPrice = iBar.GetPrice(breakPriceType);
result = NotEmptyZero(iPrice);
if (!result)
{
break;
}
//
// Check Upper/Lower breakes ...
isLowerBreaked = iPrice < lower;
isUpperBreaked = iPrice > upper;
//
canLookup = (!isLowerBreaked && !isUpperBreaked);
if (!canLookup)
{
break;
}
//
from = iBar.time;
}
//
// Validate Calculations ...
result =
//
IsXValid(to) &&
IsXValid(from) &&
from < to &&
//
NotEmptyZero(lower) &&
NotEmptyZero(upper) &&
upper > lower
//
;
//
// Validate To Edge Breakes ...
if (result)
{
//
iPrice = bar.GetPrice(breakPriceType);
result = NotEmptyZero(iPrice);
//
// Validate To Edge Breakes ...
if (result)
{
//
isUpperBreaked = iPrice > upper;
isLowerBreaked = iPrice < lower;
//
// Validate To Break ...
result = isUpperBreaked || isLowerBreaked;
}
//
// Prepare Direction ...
if (result)
{
//
dir =
isUpperBreaked
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
}
//
// Validate Direction ...
result = HasDirection(dir);
}
//
// Prepare Zone ...
if (result)
{
//
zone.to = to;
zone.dir = dir;
zone.from = from;
zone.at = bar.time;
zone.upper = upper;
zone.lower = lower;
zone.symbol = bar.symbol;
zone.period = bar.period;
zone.type = ToXString(X_BAR_PATTERN_CONSOLIDATION);
//
// Validate Zone ...
result = zone.IsValid();
//
// Validate Zone Length ...
if (result)
{
result = zone.FromIndex() - zone.ToIndex() >= validationLength;
}
}
//
// Cleanup ...
if (!result)
{
//
zone.Clean();
CleanDirection(dir);
}
iBar.Clean();
//
return result;
}
//
// FVG ...