1220 lines
32 KiB
Plaintext
1220 lines
32 KiB
Plaintext
|
|
//
|
|
// Detectors ...
|
|
|
|
/**
|
|
* Detect Zones (Support / Resistance) based on XFIMA Validators ...
|
|
*
|
|
* @param zones: XBoxZone, reference to Collection for holding Detected Zones ...
|
|
* @param barIndex: int, Specified Start Looking Bar Index ...
|
|
* @param onlyValidZones: bool, Only Validation Zones ...
|
|
* @param requiredNumberOfZones: int, Specified how many zones looking for ...
|
|
* @param shadowMultiplier: double, a valid zone's Shadow side multiplier ...
|
|
* @param validationStrength: double, Validation Strength ...
|
|
* @param validationLength: int, Validation Length ...
|
|
* @param maxAllowedLoopbackLength: int, Specified Max Allowed Looping back trhough Bars for Detection ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int DetectXFIMAZones(
|
|
XBoxZone &zones[],
|
|
int barIndex = 0,
|
|
bool onlyValidZones = false,
|
|
int requiredNumberOfZones = 50,
|
|
double shadowMultiplier = 4,
|
|
double validationStrength = 1,
|
|
int validationLength = 7,
|
|
int maxAllowedLoopbackLength = 1500 //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
// Prepare ...
|
|
XClean(zones);
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = NormalizeBarIndex(barIndex);
|
|
validationLength = NormalizeInt(validationLength, 3);
|
|
shadowMultiplier = NormalizeDouble(shadowMultiplier, 2);
|
|
validationStrength = NormalizeDouble(validationStrength, 1);
|
|
requiredNumberOfZones = NormalizeInt(requiredNumberOfZones, 5);
|
|
maxAllowedLoopbackLength = NormalizeInt(maxAllowedLoopbackLength, 50);
|
|
|
|
//
|
|
// Validate ...
|
|
XOHCL bar;
|
|
bool has = IsValid() &&
|
|
bar.Init(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex + 1 //
|
|
);
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Define Requirements ...
|
|
XOHCL iBar;
|
|
XBoxZone iBox;
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
double iUpper = EMPTY_VALUE;
|
|
double iLower = EMPTY_VALUE;
|
|
double iHKUpper = EMPTY_VALUE;
|
|
double iHKLower = EMPTY_VALUE;
|
|
double iMAUpper = EMPTY_VALUE;
|
|
double iMALower = EMPTY_VALUE;
|
|
ENUM_X_DIRECTION iDir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
// Create a Loop to Detect Zones ...
|
|
int start = barIndex;
|
|
int idx = start - 1;
|
|
int end = start + maxAllowedLoopbackLength;
|
|
while (ArraySize(zones) < requiredNumberOfZones && idx < end)
|
|
{
|
|
//
|
|
idx++;
|
|
|
|
//
|
|
// Initialize Indexed Bar ...
|
|
has = bar.BarAt(idx, iBar);
|
|
if (!has)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Reading Bars ...
|
|
iMAUpper = GetMABondUpper(idx);
|
|
iMALower = GetMABondLower(idx);
|
|
iHKUpper = GetHKBondUpper(idx);
|
|
iHKLower = GetHKBondLower(idx);
|
|
|
|
//
|
|
iUpper = MathMax(iMAUpper, iHKUpper);
|
|
iLower = MathMin(iMALower, iHKLower);
|
|
|
|
//
|
|
// Check Bar State ...
|
|
has =
|
|
NotEmptyZero(iUpper) &&
|
|
NotEmptyZero(iLower);
|
|
if (!has)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check Direction of Zone ...
|
|
isBullish = iBar.low < iLower;
|
|
isBearish = iBar.high > iUpper;
|
|
has = (isBullish && !isBearish) ||
|
|
(isBearish && !isBullish);
|
|
if (!has)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Validate Price Based on Bar ...
|
|
// Validate Shadow Multiplier ...
|
|
has =
|
|
isBullish
|
|
? iBar.low < bar.low
|
|
: iBar.high > bar.high;
|
|
has =
|
|
has &&
|
|
(isBullish
|
|
? iBar.GetLowShadow() > iBar.GetHighShadow() * shadowMultiplier
|
|
: iBar.GetHighShadow() > iBar.GetLowShadow() * shadowMultiplier);
|
|
if (!has)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
iDir = isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
// Fill Bax ...
|
|
iBox.dir = iDir;
|
|
iBox.symbol = mSymbol;
|
|
iBox.period = mPeriod;
|
|
iBox.upper =
|
|
isBullish
|
|
? iBar.GetDown()
|
|
: iBar.high;
|
|
iBox.lower =
|
|
isBullish
|
|
? iBar.low
|
|
: iBar.GetUp();
|
|
iBox.type =
|
|
(isBullish ? "XFIMA_Support" : "XFIMA_Resistance") + "_" +
|
|
ToXString(NormalizePrice(iBox.upper, iBox.symbol)) + "_" +
|
|
ToXString(NormalizePrice(iBox.lower, iBox.symbol));
|
|
|
|
//
|
|
iBox.at = iBar.time;
|
|
iBox.to = bar.time;
|
|
|
|
//
|
|
// Loopback to Detect From Time ...
|
|
XOHCL pBar;
|
|
datetime fromTime = NULL;
|
|
has = iBar.GetPreviousBar(pBar);
|
|
if (has)
|
|
{
|
|
//
|
|
while (!IsXValid(fromTime))
|
|
{
|
|
//
|
|
// Check Price Inside ...
|
|
has =
|
|
isBullish
|
|
? pBar.GetDown() < iBox.lower
|
|
: pBar.GetUp() > iBox.upper;
|
|
if (has)
|
|
{
|
|
fromTime = pBar.time;
|
|
}
|
|
|
|
//
|
|
// Retrieve PrevBar ...
|
|
has = pBar.GetPreviousBar(pBar);
|
|
if (!has)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
has = IsXValid(fromTime);
|
|
if (has)
|
|
{
|
|
iBox.from = fromTime;
|
|
}
|
|
|
|
//
|
|
// Validate Zone Length ...
|
|
has = iBox.IsValid() &&
|
|
(validationStrength >= 1
|
|
? iBox.GetRange() >= validationStrength * GetPoints(iBox.symbol)
|
|
: true) &&
|
|
(iBox.FromIndex() - iBox.AtIndex() >= validationLength);
|
|
|
|
//
|
|
// Validate Zone State ...
|
|
if (has)
|
|
{
|
|
//
|
|
// Cleanup Bar ...
|
|
iBar.Clean();
|
|
|
|
//
|
|
// Loopingh through At Index ...
|
|
for (int i = iBox.ToIndex(); i < iBox.AtIndex(); i++)
|
|
{
|
|
//
|
|
// Initialized Indexed Bar ...
|
|
has = bar.BarAt(i, iBar);
|
|
if (!has)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Validate Bar ...
|
|
has =
|
|
iBox.IsBullish()
|
|
? iBar.low > iBox.lower
|
|
: iBar.high < iBox.upper;
|
|
if (!has)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
if (has)
|
|
{
|
|
//
|
|
AddIfNotExists(
|
|
iBox,
|
|
zones //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
iBar.Clean();
|
|
pBar.Clean();
|
|
iBox.Clean();
|
|
}
|
|
|
|
//
|
|
result = ArraySize(zones);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
if (!result)
|
|
{
|
|
XClean(zones);
|
|
}
|
|
bar.Clean();
|
|
iBar.Clean();
|
|
iBox.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
int DetecteXFIMAPivots(
|
|
XPivot &pivots[],
|
|
int barIndex = 0,
|
|
int requiredNumberOfPivots = 50,
|
|
int validationLength = 7,
|
|
int maxAllowedLoopbackLength = 1500, //
|
|
//
|
|
// PV ...
|
|
int pvValidationLength = 7,
|
|
//
|
|
// Momentum ...
|
|
int momentumBarValidationLength = 3,
|
|
double momentumBarApprovedMultiplier = 3,
|
|
//
|
|
// TrueGap ...
|
|
double trueGapApprovedStrength = 2,
|
|
//
|
|
// Pin ...
|
|
double pinBarShadowApprovedMultiplier = 3,
|
|
double pinBarRangeMultiplier = 4,
|
|
bool pinBarForceDirection = false,
|
|
//
|
|
// Flag ...
|
|
int flagPatternPullbackLength = 3 //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
// Prepare ...
|
|
XClean(pivots);
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = NormalizeBarIndex(barIndex);
|
|
validationLength = NormalizeInt(validationLength, 1);
|
|
requiredNumberOfPivots = NormalizeInt(requiredNumberOfPivots, 5);
|
|
maxAllowedLoopbackLength = NormalizeInt(maxAllowedLoopbackLength, 50);
|
|
|
|
//
|
|
pvValidationLength = NormalizeInt(pvValidationLength, 0);
|
|
|
|
//
|
|
momentumBarValidationLength = NormalizeInt(momentumBarValidationLength, 2);
|
|
momentumBarApprovedMultiplier = NormalizeDouble(momentumBarApprovedMultiplier, 1);
|
|
|
|
//
|
|
trueGapApprovedStrength = NormalizeDouble(trueGapApprovedStrength, 1);
|
|
|
|
//
|
|
pinBarRangeMultiplier = NormalizeDouble(pinBarRangeMultiplier, 4);
|
|
pinBarShadowApprovedMultiplier = NormalizeDouble(pinBarShadowApprovedMultiplier, 3);
|
|
|
|
//
|
|
flagPatternPullbackLength = NormalizeInt(flagPatternPullbackLength, 3);
|
|
|
|
//
|
|
// Validate ...
|
|
bool has = IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL iBar;
|
|
XOHCL tmpBar;
|
|
XPivot iPivot;
|
|
int count = 0;
|
|
string iPrefix = NULL;
|
|
int idx = barIndex - 1;
|
|
double iMin = EMPTY_VALUE;
|
|
double iMax = EMPTY_VALUE;
|
|
double iValue = EMPTY_VALUE;
|
|
ENUM_X_DIRECTION iDir = X_DIRECTION_NONE;
|
|
ENUM_X_DIRECTION tmpDir = X_DIRECTION_NONE;
|
|
ENUM_X_PIVOT_TYPE iType = X_PIVOT_TYPE_NONE;
|
|
int end = barIndex + maxAllowedLoopbackLength;
|
|
while (
|
|
idx < end &&
|
|
ArraySize(pivots) < requiredNumberOfPivots)
|
|
{
|
|
//
|
|
idx++;
|
|
|
|
//
|
|
iBar.Clean();
|
|
iPivot.Clean();
|
|
tmpBar.Clean();
|
|
iPrefix = NULL;
|
|
iDir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
has = iBar.Init(
|
|
mSymbol,
|
|
mPeriod,
|
|
idx //
|
|
);
|
|
if (!has)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Pivots List ...
|
|
|
|
//
|
|
// PV ...
|
|
bool isPV = false;
|
|
bool isPeak = false;
|
|
bool isVale = false;
|
|
tmpDir = X_DIRECTION_NONE;
|
|
if (pvValidationLength > 0)
|
|
{
|
|
//
|
|
isPV = patternDetector.IsPV(
|
|
iBar,
|
|
tmpDir,
|
|
pvValidationLength //
|
|
);
|
|
isPeak = isPV &&
|
|
IsXBearish(tmpDir);
|
|
isVale = isPV &&
|
|
IsXBullish(tmpDir);
|
|
if (isPV)
|
|
{
|
|
iPrefix += isPeak ? "XPK" : "XVL";
|
|
}
|
|
|
|
//
|
|
// Continue Loopback if PV Validation Provided and not isPV ...
|
|
if (!isPV)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Momentum Bar ...
|
|
bool isMomentum = patternDetector.IsMomentumBar(
|
|
iBar,
|
|
iDir,
|
|
momentumBarValidationLength,
|
|
momentumBarApprovedMultiplier //
|
|
);
|
|
if (isMomentum)
|
|
{
|
|
//
|
|
if (!IsXValid(tmpDir))
|
|
{
|
|
tmpDir = iDir;
|
|
}
|
|
|
|
//
|
|
if (iDir != tmpDir)
|
|
{
|
|
isMomentum = false;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
count++;
|
|
iPrefix += (IsXValid(iPrefix) ? "_" : "") + "MNTM";
|
|
}
|
|
}
|
|
|
|
//
|
|
// Engulf Bar ...
|
|
bool isEngulfed = patternDetector.IsEngulfedBar(
|
|
iBar,
|
|
iDir //
|
|
);
|
|
if (isEngulfed)
|
|
{
|
|
//
|
|
if (!IsXValid(tmpDir))
|
|
{
|
|
tmpDir = iDir;
|
|
}
|
|
|
|
//
|
|
if (iDir != tmpDir)
|
|
{
|
|
isEngulfed = false;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
count++;
|
|
iPrefix += (IsXValid(iPrefix) ? "_" : "") + "ENGLF";
|
|
}
|
|
}
|
|
|
|
//
|
|
// True Gap ...
|
|
bool isTrueGaped = patternDetector.IsTrueGapedBar(
|
|
iBar,
|
|
iDir,
|
|
trueGapApprovedStrength //
|
|
);
|
|
if (isTrueGaped)
|
|
{
|
|
//
|
|
if (!IsXValid(tmpDir))
|
|
{
|
|
tmpDir = iDir;
|
|
}
|
|
|
|
//
|
|
if (iDir != tmpDir)
|
|
{
|
|
isTrueGaped = false;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
count++;
|
|
iPrefix += (IsXValid(iPrefix) ? "_" : "") + "TG";
|
|
}
|
|
}
|
|
|
|
//
|
|
// Pin Bar ...
|
|
bool isPinned = patternDetector.IsPinnedBar(
|
|
iBar,
|
|
iDir,
|
|
pinBarShadowApprovedMultiplier,
|
|
pinBarRangeMultiplier,
|
|
pinBarForceDirection //
|
|
);
|
|
if (isPinned)
|
|
{
|
|
//
|
|
if (!IsXValid(tmpDir))
|
|
{
|
|
tmpDir = iDir;
|
|
}
|
|
|
|
//
|
|
if (iDir != tmpDir)
|
|
{
|
|
isPinned = false;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
count++;
|
|
iPrefix += (IsXValid(iPrefix) ? "_" : "") + "PND";
|
|
}
|
|
}
|
|
|
|
//
|
|
// Patterns ...
|
|
|
|
//
|
|
// Star Pattern ...
|
|
bool isStarPattern = patternDetector.IsStarPattern(
|
|
iBar,
|
|
iDir //
|
|
);
|
|
if (isStarPattern)
|
|
{
|
|
//
|
|
if (!IsXValid(tmpDir))
|
|
{
|
|
tmpDir = iDir;
|
|
}
|
|
|
|
//
|
|
if (iDir != tmpDir)
|
|
{
|
|
isStarPattern = false;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
count++;
|
|
iPrefix += (IsXValid(iPrefix) ? "_" : "") + "STR";
|
|
}
|
|
}
|
|
|
|
//
|
|
// Piercing Pattern ...
|
|
bool isPiercingPattern = patternDetector.IsPiercingPattern(
|
|
iBar,
|
|
iDir //
|
|
);
|
|
if (isPiercingPattern)
|
|
{
|
|
//
|
|
if (!IsXValid(tmpDir))
|
|
{
|
|
tmpDir = iDir;
|
|
}
|
|
|
|
//
|
|
if (iDir != tmpDir)
|
|
{
|
|
isPiercingPattern = false;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
count++;
|
|
iPrefix += (IsXValid(iPrefix) ? "_" : "") + "PRCG";
|
|
}
|
|
}
|
|
|
|
//
|
|
// Rising Pattern ...
|
|
bool isRisingPattern = patternDetector.IsRisingPattern(
|
|
iBar,
|
|
iDir //
|
|
);
|
|
if (isRisingPattern)
|
|
{
|
|
//
|
|
if (!IsXValid(tmpDir))
|
|
{
|
|
tmpDir = iDir;
|
|
}
|
|
|
|
//
|
|
if (iDir != tmpDir)
|
|
{
|
|
isRisingPattern = false;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
count++;
|
|
iPrefix += (IsXValid(iPrefix) ? "_" : "") + "RSG";
|
|
}
|
|
}
|
|
|
|
//
|
|
// Flag Pattern ...
|
|
bool isFlagPattern = patternDetector.IsFlagPattern(
|
|
iBar,
|
|
iDir,
|
|
tmpBar,
|
|
flagPatternPullbackLength //
|
|
);
|
|
if (isFlagPattern)
|
|
{
|
|
//
|
|
if (!IsXValid(tmpDir))
|
|
{
|
|
tmpDir = iDir;
|
|
}
|
|
|
|
//
|
|
if (iDir != tmpDir)
|
|
{
|
|
isFlagPattern = false;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
count++;
|
|
iPrefix += (IsXValid(iPrefix) ? "_" : "") + "FLG";
|
|
}
|
|
}
|
|
|
|
//
|
|
// Signal Key Pattern ...
|
|
bool isSignalKeyPattern = patternDetector.IsSignalKeyBarPattern(
|
|
iBar,
|
|
iDir,
|
|
pinBarShadowApprovedMultiplier,
|
|
pinBarRangeMultiplier,
|
|
pinBarForceDirection //
|
|
);
|
|
if (isSignalKeyPattern)
|
|
{
|
|
//
|
|
if (!IsXValid(tmpDir))
|
|
{
|
|
tmpDir = iDir;
|
|
}
|
|
|
|
//
|
|
if (iDir != tmpDir)
|
|
{
|
|
isSignalKeyPattern = false;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
count++;
|
|
iPrefix += (IsXValid(iPrefix) ? "_" : "") + "SKB";
|
|
}
|
|
}
|
|
|
|
//
|
|
has =
|
|
isPinned ||
|
|
isMomentum ||
|
|
isEngulfed ||
|
|
isTrueGaped ||
|
|
isStarPattern ||
|
|
isFlagPattern ||
|
|
isRisingPattern ||
|
|
isPiercingPattern ||
|
|
isSignalKeyPattern;
|
|
if (!has)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// //
|
|
// // Validate Pivot Length ...
|
|
// // Validate Pivot vs XFIMA Values ...
|
|
// for (int i = iBar.Index(); i < iBar.Index() + validationLength; i++)
|
|
// {
|
|
// //
|
|
// tmpBar.Clean();
|
|
// has = iBar.BarAt(i, tmpBar);
|
|
// if (!has)
|
|
// {
|
|
// break;
|
|
// }
|
|
|
|
// //
|
|
// iMin = EMPTY_VALUE;
|
|
// iMax = EMPTY_VALUE;
|
|
// has = GetBoundaryValues(
|
|
// iMin,
|
|
// iMax,
|
|
// i //
|
|
// );
|
|
|
|
// //
|
|
// // Validate Bar vs TmpBar and Also Boundary Values ...
|
|
// has =
|
|
// has &&
|
|
// (IsXBullish(iDir)
|
|
// ?
|
|
// // tmpBar.low < iMin &&
|
|
// (tmpBar.low > iBar.low ||
|
|
// tmpBar.GetDown() || iBar.GetDown())
|
|
// :
|
|
// // tmpBar.high > iMax &&
|
|
// (tmpBar.high < iBar.high ||
|
|
// tmpBar.GetUp() < iBar.GetUp()));
|
|
// if (!has)
|
|
// {
|
|
// break;
|
|
// }
|
|
|
|
// //
|
|
// iValue = IsXBullish(iDir)
|
|
// ? iBar.low
|
|
// : iBar.high;
|
|
|
|
// //
|
|
// iType = IsXBullish(iDir)
|
|
// ? X_PIVOT_TYPE_VALE
|
|
// : X_PIVOT_TYPE_PEAK;
|
|
|
|
// //
|
|
// tmpBar.Clean();
|
|
// }
|
|
|
|
//
|
|
has = IsXValid(iPrefix);
|
|
if (has)
|
|
{
|
|
//
|
|
iValue = IsXBullish(iDir)
|
|
? iBar.low
|
|
: iBar.high;
|
|
|
|
//
|
|
iType = IsXBullish(iDir)
|
|
? X_PIVOT_TYPE_VALE
|
|
: X_PIVOT_TYPE_PEAK;
|
|
|
|
//
|
|
// Preparing Pivot ...
|
|
has = iPivot.Init(
|
|
iValue,
|
|
iBar.time,
|
|
iBar.symbol,
|
|
iDir,
|
|
iBar.period,
|
|
iType //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
iPivot.prefix = iPrefix;
|
|
|
|
//
|
|
AddIfNotExists(
|
|
iPivot,
|
|
pivots //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
iBar.Clean();
|
|
iPivot.Clean();
|
|
tmpBar.Clean();
|
|
|
|
//
|
|
result = ArraySize(pivots);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect XFIMA Based POI Bars ...
|
|
*
|
|
* @param bars: XOHCL, reference collection to holds detected bars ...
|
|
* @param dirs: ENUM_X_DIRECTION, reference collection to holds detected bars Direction ...
|
|
* @param barIndex: int, Specified Bar Index ...
|
|
* @param forDir: ENUM_X_DIRECTION, specified which Direction of potential bars looking for ...
|
|
* @param requiredNumberOfBars: int, Specified how many bars looking for ...
|
|
* @param maxAllowedLoopbackLength: int, Specified Max Allowed Looping back trhough Bars for Detection ...
|
|
* @return ( int )
|
|
*/
|
|
int DetectXFIMAPOIBars(
|
|
XOHCL &bars[],
|
|
ENUM_X_DIRECTION &dirs[],
|
|
int barIndex = 0,
|
|
ENUM_X_DIRECTION forDir = X_DIRECTION_NONE,
|
|
int requiredNumberOfBars = 300,
|
|
int maxAllowedLoopbackLength = 1500 //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
// Prepare ...
|
|
XClean(bars);
|
|
XClean(dirs);
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = NormalizeBarIndex(barIndex);
|
|
requiredNumberOfBars = NormalizeInt(requiredNumberOfBars, 5);
|
|
maxAllowedLoopbackLength = NormalizeInt(maxAllowedLoopbackLength, 50);
|
|
|
|
//
|
|
// Validate ...
|
|
bool has = IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL iBar;
|
|
int idx = barIndex - 1;
|
|
int start = barIndex;
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
double iMin = EMPTY_VALUE;
|
|
double iMax = EMPTY_VALUE;
|
|
ENUM_X_DIRECTION iDir = X_DIRECTION_NONE;
|
|
int end = start + maxAllowedLoopbackLength;
|
|
while (ArraySize(bars) < requiredNumberOfBars ||
|
|
idx < maxAllowedLoopbackLength)
|
|
{
|
|
//
|
|
idx++;
|
|
has = iBar.Init(
|
|
mSymbol,
|
|
mPeriod,
|
|
idx //
|
|
);
|
|
if (!has)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
has = GetBoundaryValues(
|
|
iMin,
|
|
iMax,
|
|
idx //
|
|
);
|
|
if (!has)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
isBullish = iBar.low < iMin;
|
|
isBearish = iBar.high > iMax;
|
|
has =
|
|
!HasDirection(forDir)
|
|
? ((isBullish && !isBearish) ||
|
|
(isBearish && !isBullish))
|
|
: IsXBullish(forDir)
|
|
? (isBullish && !isBearish)
|
|
: (isBearish && !isBullish);
|
|
if (has)
|
|
{
|
|
//
|
|
iDir = isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
AddRef(
|
|
iBar,
|
|
bars //
|
|
);
|
|
|
|
//
|
|
Add(
|
|
iDir,
|
|
dirs //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bars);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
iBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
int DetectXFIMAReversalPOIBars(
|
|
XOHCL &bars[],
|
|
ENUM_X_DIRECTION &dirs[],
|
|
int barIndex = 0,
|
|
bool forceTouchBoundary = false,
|
|
ENUM_X_DIRECTION forDir = X_DIRECTION_NONE,
|
|
int requiredNumberOfBars = 300,
|
|
int maxAllowedLoopbackLength = 1500 //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
// Prepare ...
|
|
XClean(bars);
|
|
XClean(dirs);
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = NormalizeBarIndex(barIndex);
|
|
requiredNumberOfBars = NormalizeInt(requiredNumberOfBars, 5);
|
|
maxAllowedLoopbackLength = NormalizeInt(maxAllowedLoopbackLength, 50);
|
|
|
|
//
|
|
// Validate ...
|
|
bool has = IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detect POI Bars ...
|
|
XOHCL decisionBars[];
|
|
ENUM_X_DIRECTION decisionBarDirs[];
|
|
int decisionBarsCount = DetectXFIMAPOIBars(
|
|
decisionBars,
|
|
decisionBarDirs,
|
|
barIndex,
|
|
forDir,
|
|
requiredNumberOfBars,
|
|
maxAllowedLoopbackLength //
|
|
);
|
|
has = IsValidSize(decisionBarsCount);
|
|
if (!has)
|
|
{
|
|
//
|
|
XClean(decisionBars);
|
|
XClean(decisionBarDirs);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
double iMin = EMPTY_VALUE;
|
|
double iMax = EMPTY_VALUE;
|
|
bool isCond1Bullish = false;
|
|
bool isCond1Bearish = false;
|
|
for (int i = 0; i < decisionBarsCount; i++)
|
|
{
|
|
//
|
|
// Read Boundary Values ...
|
|
has = GetBoundaryValues(iMin, iMax, i);
|
|
if (!has)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check Bar Decision Direction ...
|
|
isBullish = IsXBullish(decisionBarDirs[i]);
|
|
isBearish = IsXBearish(decisionBarDirs[i]);
|
|
|
|
//
|
|
// Validate ...
|
|
|
|
//
|
|
isCond1Bullish = decisionBars[i].IsBullish();
|
|
|
|
//
|
|
isCond1Bearish = decisionBars[i].IsBearish();
|
|
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
(isCond1Bullish);
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
(isCond1Bearish);
|
|
|
|
//
|
|
if (forceTouchBoundary)
|
|
{
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
(decisionBars[i].high > iMin ||
|
|
decisionBars[i].GetUp() > iMin);
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
(decisionBars[i].low < iMax ||
|
|
decisionBars[i].GetDown() < iMax);
|
|
}
|
|
|
|
//
|
|
has =
|
|
isBullish ||
|
|
isBearish;
|
|
if (has)
|
|
{
|
|
//
|
|
AddRef(
|
|
decisionBars[i],
|
|
bars //
|
|
);
|
|
|
|
//
|
|
Add(
|
|
decisionBarDirs[i],
|
|
dirs //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bars);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
XClean(decisionBars);
|
|
XClean(decisionBarDirs);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
int DetectXFIMAContinuationalPOIBars(
|
|
XOHCL &bars[],
|
|
ENUM_X_DIRECTION &dirs[],
|
|
int barIndex = 0,
|
|
bool forceTouchBoundary = false,
|
|
ENUM_X_DIRECTION forDir = X_DIRECTION_NONE,
|
|
int requiredNumberOfBars = 300,
|
|
int maxAllowedLoopbackLength = 1500 //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
// Prepare ...
|
|
XClean(bars);
|
|
XClean(dirs);
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = NormalizeBarIndex(barIndex);
|
|
requiredNumberOfBars = NormalizeInt(requiredNumberOfBars, 5);
|
|
maxAllowedLoopbackLength = NormalizeInt(maxAllowedLoopbackLength, 50);
|
|
|
|
//
|
|
// Validate ...
|
|
bool has = IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detect POI Bars ...
|
|
XOHCL decisionBars[];
|
|
ENUM_X_DIRECTION decisionBarDirs[];
|
|
int decisionBarsCount = DetectXFIMAPOIBars(
|
|
decisionBars,
|
|
decisionBarDirs,
|
|
barIndex,
|
|
forDir,
|
|
requiredNumberOfBars,
|
|
maxAllowedLoopbackLength //
|
|
);
|
|
has = IsValidSize(decisionBarsCount);
|
|
if (!has)
|
|
{
|
|
//
|
|
XClean(decisionBars);
|
|
XClean(decisionBarDirs);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
double iMin = EMPTY_VALUE;
|
|
double iMax = EMPTY_VALUE;
|
|
bool isCond1Bullish = false;
|
|
bool isCond1Bearish = false;
|
|
for (int i = 0; i < decisionBarsCount; i++)
|
|
{
|
|
//
|
|
// Read Indexed Bars Boundaries ...
|
|
has = GetBoundaryValues(iMin, iMax, decisionBars[i].Index());
|
|
if (!has)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Make Direction Opposit ...
|
|
decisionBarDirs[i] = Opposit(decisionBarDirs[i]);
|
|
|
|
//
|
|
isBullish = IsXBullish(decisionBarDirs[i]);
|
|
isBearish = IsXBearish(decisionBarDirs[i]);
|
|
|
|
//
|
|
// Check Bar Validations ...
|
|
|
|
//
|
|
// Cond 1 ...
|
|
|
|
//
|
|
isCond1Bullish =
|
|
decisionBars[i].IsBearish() &&
|
|
(decisionBars[i].low >= iMax ||
|
|
(decisionBars[i].low <= iMax &&
|
|
decisionBars[i].GetUp() >= iMax));
|
|
|
|
//
|
|
isCond1Bearish =
|
|
decisionBars[i].IsBullish() &&
|
|
(decisionBars[i].high <= iMin ||
|
|
(decisionBars[i].high >= iMin &&
|
|
decisionBars[i].GetDown() <= iMin));
|
|
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
(isCond1Bullish);
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
(isCond1Bearish);
|
|
|
|
//
|
|
if (forceTouchBoundary)
|
|
{
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
(decisionBars[i].low >= iMax ||
|
|
(decisionBars[i].low <= iMax &&
|
|
decisionBars[i].GetUp() >= iMax));
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
(decisionBars[i].high <= iMin ||
|
|
(decisionBars[i].high >= iMin &&
|
|
decisionBars[i].GetDown() <= iMin));
|
|
}
|
|
|
|
//
|
|
has =
|
|
isBullish ||
|
|
isBearish;
|
|
if (has)
|
|
{
|
|
//
|
|
AddRef(
|
|
decisionBars[i],
|
|
bars //
|
|
);
|
|
|
|
//
|
|
Add(
|
|
decisionBarDirs[i],
|
|
dirs //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = MathMin(ArraySize(bars), ArraySize(dirs));
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
XClean(decisionBars);
|
|
XClean(decisionBarDirs);
|
|
|
|
//
|
|
return result;
|
|
}
|