1434 lines
34 KiB
Plaintext
1434 lines
34 KiB
Plaintext
XBoxZone iPeak;
|
|
XBoxZone iVale;
|
|
XBoxZone iOBBull;
|
|
XBoxZone iOBBear;
|
|
XBoxZone iMTBull;
|
|
XBoxZone iMTBear;
|
|
|
|
//
|
|
iPeak.Clean();
|
|
iVale.Clean();
|
|
iOBBull.Clean();
|
|
iOBBear.Clean();
|
|
iMTBull.Clean();
|
|
iMTBear.Clean();
|
|
|
|
//
|
|
// Select MT Block ...
|
|
// if (result)
|
|
// {
|
|
// //
|
|
// // New MT Pivot Detected ...
|
|
// if (detector.newMTBullishPivotDetected)
|
|
// {
|
|
// //
|
|
// idx = GetYoungest(detector.mtBullishPivots);
|
|
// if (IsValidIndex(idx))
|
|
// {
|
|
// iMTBull = detector.mtBullishPivots[idx];
|
|
// }
|
|
// }
|
|
// else if (detector.newMTBearishPivotDetected)
|
|
// {
|
|
// //
|
|
// idx = GetYoungest(detector.mtBearishPivots);
|
|
// if (IsValidIndex(idx))
|
|
// {
|
|
// iMTBear = detector.mtBearishPivots[idx];
|
|
// }
|
|
// }
|
|
|
|
// //
|
|
// // Draw MT ...
|
|
|
|
// //
|
|
// // Bullish ...
|
|
// has = iMTBull.IsValid();
|
|
// if (has)
|
|
// {
|
|
// //
|
|
// iMTBull.to = conditions.bars[zIDX].time;
|
|
|
|
// //
|
|
// XCBoxObject *iObj;
|
|
// has = drawer
|
|
// .drawer
|
|
// .DrawBox(
|
|
// iMTBull,
|
|
// iObj //
|
|
// );
|
|
// if (has)
|
|
// {
|
|
// drawer.ApplyMTBullishPivotStyle(iObj);
|
|
// }
|
|
// }
|
|
|
|
// //
|
|
// // Bearish ...
|
|
// has = iMTBear.IsValid();
|
|
// if (has)
|
|
// {
|
|
// //
|
|
// iMTBear.to = conditions.bars[zIDX].time;
|
|
|
|
// //
|
|
// XCBoxObject *iObj;
|
|
// has = drawer
|
|
// .drawer
|
|
// .DrawBox(
|
|
// iMTBear,
|
|
// iObj //
|
|
// );
|
|
// if (has)
|
|
// {
|
|
// drawer.ApplyMTBearishPivotStyle(iObj);
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
//
|
|
// Select Peak and Vale ...
|
|
// this used to Signalling Better ...
|
|
// if (result)
|
|
// {
|
|
// //
|
|
// // Select Peak ...
|
|
// idx = GetLowest(
|
|
// conditions.bars[cIDX],
|
|
// detector.peakPivots //
|
|
// );
|
|
// if (IsValidIndex(idx))
|
|
// {
|
|
// //
|
|
// iPeak = detector.peakPivots[idx];
|
|
// iPeak.to = conditions.bars[zIDX].time;
|
|
// }
|
|
|
|
// //
|
|
// // Select Vale ...
|
|
// idx = GetHighest(
|
|
// conditions.bars[cIDX],
|
|
// detector.valePivots //
|
|
// );
|
|
// if (IsValidIndex(idx))
|
|
// {
|
|
// //
|
|
// iVale = detector.valePivots[idx];
|
|
// iVale.to = conditions.bars[zIDX].time;
|
|
// }
|
|
|
|
// //
|
|
// // Checkig Result ...
|
|
// result =
|
|
// iPeak.IsValid() &&
|
|
// iVale.IsValid();
|
|
|
|
// //
|
|
// // Draw Peak and Vales ...
|
|
// if (result)
|
|
// {
|
|
// //
|
|
// // Object Definitions ...
|
|
// XCBoxObject *iObj;
|
|
|
|
// //
|
|
// // Draw Peak ...
|
|
// has = drawer
|
|
// .drawer
|
|
// .DrawBox(
|
|
// iPeak,
|
|
// iObj //
|
|
// );
|
|
// if (has)
|
|
// {
|
|
// drawer.ApplyPeakPivotStyle(iObj);
|
|
// }
|
|
// ZeroMemory(iObj);
|
|
|
|
// //
|
|
// // Draw Vale ...
|
|
// has = drawer
|
|
// .drawer
|
|
// .DrawBox(
|
|
// iVale,
|
|
// iObj //
|
|
// );
|
|
// if (has)
|
|
// {
|
|
// drawer.ApplyValePivotStyle(iObj);
|
|
// }
|
|
// ZeroMemory(iObj);
|
|
// }
|
|
// }
|
|
|
|
|
|
// //
|
|
// // We Have to Detect Youngest Order Block ...
|
|
// // or Mitigation Block ...
|
|
// if (isCond1Bullish)
|
|
// {
|
|
// // //
|
|
// // // OB ...
|
|
// // idx = GetYoungest(detector.obBullishPivots);
|
|
// // has = IsValidIndex(idx);
|
|
// // if (has)
|
|
// // {
|
|
// // iOB = detector.obBullishPivots[idx];
|
|
// // }
|
|
|
|
// //
|
|
// // MT ...
|
|
// idx = GetYoungest(detector.mtBullishPivots);
|
|
// has = IsValidIndex(idx);
|
|
// if (has)
|
|
// {
|
|
// iOB = detector.mtBullishPivots[idx];
|
|
// }
|
|
// }
|
|
// else if (isCond1Bearish)
|
|
// {
|
|
// //
|
|
// // OB
|
|
// // idx = GetYoungest(detector.obBearishPivots);
|
|
// // has = IsValidIndex(idx);
|
|
// // if (has)
|
|
// // {
|
|
// // iOB = detector.obBearishPivots[idx];
|
|
// // }
|
|
|
|
// //
|
|
// // MT
|
|
// idx = GetYoungest(detector.mtBearishPivots);
|
|
// has = IsValidIndex(idx);
|
|
// if (has)
|
|
// {
|
|
// iMT = detector.mtBearishPivots[idx];
|
|
// }
|
|
// }
|
|
|
|
// //
|
|
// // Now we can Do some Verifications Using these ...
|
|
// result =
|
|
// isCond1Bullish
|
|
// ? iMT.IsBullish()
|
|
// : iMT.IsBearish();
|
|
// if (!result)
|
|
// {
|
|
// //
|
|
// isCond1Bullish = false;
|
|
// isCond1Bearish = false;
|
|
// }
|
|
|
|
//
|
|
// All Requirements based on Cond 1 ...
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
XOHCL pBar;
|
|
has = bar.GetPreviousBar(pBar);
|
|
if (has)
|
|
{
|
|
//
|
|
ENUM_X_DIRECTION seqDir;
|
|
|
|
//
|
|
bool isSeqBreaked = barAnalyser
|
|
.IsSeqBreak(
|
|
pBar,
|
|
seqDir //
|
|
);
|
|
bool isBullishSeqBreaked =
|
|
isSeqBreaked &&
|
|
IsBullish(seqDir);
|
|
bool isBearishSeqBreaked =
|
|
isSeqBreaked &&
|
|
IsBearish(seqDir);
|
|
|
|
//
|
|
if (isSeqBreaked)
|
|
{
|
|
Print("Detect Sequence Breaker Bar ...");
|
|
}
|
|
}
|
|
pBar.Clean();
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
|
|
/**
|
|
* Detect Spike ...
|
|
*
|
|
* @param bar: XOHCL instance reference, Start Bar ...
|
|
* @param dir: ENUM_X_DIRECTION member, Event Direction ...
|
|
* @param type: ENUM_X_PRICE member, Price Type ...
|
|
* @param forcBodyInRange: bool, Use Body in Range Detection ...
|
|
* @param rangeExtendMultiplier: double, a Multiplier for Checking Price Range ...
|
|
* @param sameBars: int, Specified How Many Same Bars Required for an Spike ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSpike(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int &rootIDX,
|
|
ENUM_X_PRICE type = X_PRICE_CLOSE,
|
|
bool forcBodyInRange = true,
|
|
double rangeExtendMultiplier = 2.0,
|
|
int sameBars = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
sameBars = NormalizeInt(sameBars, 2);
|
|
|
|
//
|
|
result = IsValid(type) &&
|
|
bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// First We Have to Has a Big Change ...
|
|
int sharpRootIDX = -1;
|
|
result = IsSharp(
|
|
bar,
|
|
dir,
|
|
sharpRootIDX,
|
|
type,
|
|
forcBodyInRange,
|
|
rangeExtendMultiplier //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Has Same Bars ...
|
|
int sameBarsIndex = -1;
|
|
ENUM_X_DIRECTION sameBarsDir;
|
|
result = HasSameBars(
|
|
bar,
|
|
sameBarsDir,
|
|
sameBarsIndex,
|
|
sameBars //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Same Bars Direction sames To Price Change ...
|
|
result = sameBarsDir == dir;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
rootIDX = sharpRootIDX;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a Bar is Support Bar or not ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param supportBar: XOHCL instance, Provides Fouded Support Bar ...
|
|
* @param range: Integer, Specified Verifiation Range ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasSupport(
|
|
XOHCL &bar,
|
|
XOHCL &supportBar,
|
|
int range = 21 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int supportIDX = bar.Index() + range;
|
|
result = supportBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
supportIDX //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
supportBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = bar.low > supportBar.low;
|
|
if (!result)
|
|
{
|
|
//
|
|
supportBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Point ...
|
|
for (int i = 1; i < range; i++)
|
|
{
|
|
//
|
|
XOHCL iPBar;
|
|
XOHCL iNBar;
|
|
bool iHas = false;
|
|
|
|
//
|
|
iHas = iPBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
supportIDX + i //
|
|
);
|
|
result = iHas;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
iHas = iNBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
supportIDX - i //
|
|
);
|
|
result = iHas;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = supportBar.low < iPBar.low &&
|
|
supportBar.low < iNBar.low;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a Bar is Resistance Bar or not ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param resistanceBar: XOHCL instance, Provides Fouded Support Bar ...
|
|
* @param range: Integer, Specified Verifiation Range ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasResistance(
|
|
XOHCL &bar,
|
|
XOHCL &resistanceBar,
|
|
int range = 21 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int resistanceIDX = bar.Index() + range;
|
|
result = resistanceBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
resistanceIDX //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
resistanceBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = bar.high < resistanceBar.high;
|
|
if (!result)
|
|
{
|
|
//
|
|
resistanceBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Point ...
|
|
for (int i = 1; i < range; i++)
|
|
{
|
|
//
|
|
XOHCL iPBar;
|
|
XOHCL iNBar;
|
|
bool iHas = false;
|
|
|
|
//
|
|
iHas = iPBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
resistanceIDX + i //
|
|
);
|
|
result = iHas;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
iHas = iNBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
resistanceIDX - i //
|
|
);
|
|
result = iHas;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = resistanceBar.high > iPBar.high &&
|
|
resistanceBar.high > iNBar.high;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect a Fair Value Gap Based on Given Bar ...
|
|
*
|
|
* @param bar: XOHCL instance, Specified Start Bar ...
|
|
* @param fromBar: XOHCL instance, Provides Start Bar of FVG ...
|
|
* @param toBar: XOHCL instance, Provides End Bar of FVG ...
|
|
* @param dir: ENUM_X_DIRECTION member, Specified Founded Order Block Direction ...
|
|
* @param sameBars: Integer, Specified Min Same Bars for Detecting Order Block ...
|
|
* @return ( bool )
|
|
*/
|
|
bool HasFairValueGap(
|
|
XOHCL &bar,
|
|
XOHCL &fromBar,
|
|
XOHCL &toBar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int sameBars = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
toBar.Clean();
|
|
fromBar.Clean();
|
|
dir = X_DIRECTION_NONE;
|
|
sameBars = NormalizeInt(sameBars, 1);
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
//
|
|
toBar.Clean();
|
|
fromBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int index = 0;
|
|
result = HasSameBars(
|
|
bar,
|
|
dir,
|
|
index,
|
|
sameBars //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(dir);
|
|
|
|
//
|
|
int to = bar.Index();
|
|
int from =
|
|
index > (to + sameBars)
|
|
? to + sameBars
|
|
: index;
|
|
for (int i = from; i > to; i--)
|
|
{
|
|
//
|
|
result = fromBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = toBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i - 2 //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = isBullish
|
|
? fromBar.high < toBar.low
|
|
: fromBar.low > toBar.high;
|
|
if (result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
//
|
|
toBar.Clean();
|
|
fromBar.Clean();
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect an Order Block Based on Given Bar ...
|
|
*
|
|
* @param bar: XOHCL instance, Specified Start Bar ...
|
|
* @param ob: XOHCL instance, Fill it if Order Block Found ...
|
|
* @param dir: ENUM_X_DIRECTION member, Specified Founded Order Block Direction ...
|
|
* @param sameBars: Integer, Specified Min Same Bars for Detecting Order Block ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasOrderBlock(
|
|
XOHCL &bar,
|
|
XOHCL &ob,
|
|
ENUM_X_DIRECTION &dir,
|
|
int sameBars = 3,
|
|
bool forceSpike = true,
|
|
bool forceFairValueGap = true,
|
|
bool forceSupportResistance = true //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
ob.Clean();
|
|
dir = X_DIRECTION_NONE;
|
|
sameBars = NormalizeInt(sameBars, 1);
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL sBar;
|
|
if (bar.Index() == 0)
|
|
{
|
|
//
|
|
result = bar.GetPreviousBar(sBar);
|
|
if (!result)
|
|
{
|
|
//
|
|
sBar.Clean();
|
|
return result;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sBar = bar;
|
|
}
|
|
|
|
//
|
|
// First Step We Have to Check Same Bars ...
|
|
int spikeRootIDX = -1;
|
|
int sameBarsIndex = -1;
|
|
result = HasSameBars(
|
|
bar,
|
|
dir,
|
|
sameBarsIndex,
|
|
sameBars //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
ob.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Must an Spike Happens ...
|
|
if (forceSpike)
|
|
{
|
|
//
|
|
ENUM_X_DIRECTION spikeDir;
|
|
result = IsSpike(
|
|
bar,
|
|
spikeDir,
|
|
spikeRootIDX, // Spike Root Index ...
|
|
X_PRICE_CLOSE, // Price Type ...
|
|
true, // Force Body ...
|
|
1.5, // Range Extend Multiplier ...
|
|
sameBars //
|
|
);
|
|
result =
|
|
result &&
|
|
dir == spikeDir;
|
|
if (!result)
|
|
{
|
|
//
|
|
ob.Clean();
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Select OB Candidate Bars ...
|
|
|
|
XOHCL sameBar;
|
|
XOHCL rootBar;
|
|
XOHCL rootPBar;
|
|
result = sameBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
sameBarsIndex + 1 //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
sBar.Clean();
|
|
sameBar.Clean();
|
|
return result;
|
|
}
|
|
result = rootBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
spikeRootIDX //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
sBar.Clean();
|
|
rootBar.Clean();
|
|
sameBar.Clean();
|
|
return result;
|
|
}
|
|
result = rootBar.GetPreviousBar(rootPBar);
|
|
if (!result)
|
|
{
|
|
//
|
|
sBar.Clean();
|
|
rootBar.Clean();
|
|
sameBar.Clean();
|
|
rootPBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Select ob Bar ...
|
|
if (rootBar.GetDirection() == Opposit(dir))
|
|
{
|
|
ob = rootBar;
|
|
}
|
|
else if (rootPBar.GetDirection() == Opposit(dir))
|
|
{
|
|
ob = rootPBar;
|
|
}
|
|
else if (sameBar.GetDirection() == Opposit(dir))
|
|
{
|
|
ob = sameBar;
|
|
}
|
|
else
|
|
{
|
|
ob.Clean();
|
|
}
|
|
|
|
//
|
|
// Select Order Block Bar ...
|
|
result = ob.IsValid();
|
|
ENUM_X_DIRECTION obDir = ob.GetDirection();
|
|
result =
|
|
result &&
|
|
dir == Opposit(obDir);
|
|
if (!result)
|
|
{
|
|
//
|
|
sBar.Clean();
|
|
rootBar.Clean();
|
|
sameBar.Clean();
|
|
rootPBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// if Bullish OB => Supports ...
|
|
// if Bearish OB => Resistance ...
|
|
if (forceSupportResistance)
|
|
{
|
|
//
|
|
XOHCL supResBar;
|
|
|
|
//
|
|
// Check Support ...
|
|
bool isSupport = HasSupport(
|
|
ob,
|
|
supResBar //
|
|
);
|
|
|
|
//
|
|
// Check Resistance ...
|
|
bool isResistance = HasResistance(
|
|
ob,
|
|
supResBar //
|
|
);
|
|
|
|
//
|
|
supResBar.Clean();
|
|
|
|
//
|
|
result =
|
|
result &&
|
|
(IsBullish(dir)
|
|
? isSupport
|
|
: isResistance);
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
//
|
|
ob.Clean();
|
|
sBar.Clean();
|
|
rootBar.Clean();
|
|
sameBar.Clean();
|
|
rootPBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Force Check Fair ValueGaps ...
|
|
if (forceFairValueGap)
|
|
{
|
|
//
|
|
XOHCL toBar;
|
|
XOHCL fromBar;
|
|
ENUM_X_DIRECTION fvgDir;
|
|
bool isFVG = HasFairValueGap(
|
|
bar,
|
|
fromBar,
|
|
toBar,
|
|
fvgDir,
|
|
sameBars //
|
|
);
|
|
|
|
//
|
|
result =
|
|
isFVG &&
|
|
result &&
|
|
dir == fvgDir;
|
|
|
|
//
|
|
toBar.Clean();
|
|
fromBar.Clean();
|
|
}
|
|
|
|
//
|
|
// Cleanup Resource ...
|
|
|
|
//
|
|
sBar.Clean();
|
|
rootBar.Clean();
|
|
sameBar.Clean();
|
|
rootPBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a Bar has Consolidation Zone or not ...
|
|
*
|
|
* @param bar: XOHCL instance, Specified Start Bar ...
|
|
* @param zone: XConsolidationZone instance, consolidation Zone Object ...
|
|
* @param minLoopback: int, min Allowed Lopback for Consolidating ...
|
|
* @param range: double, Consolidation Range ...
|
|
* @param upperAppliedTo: ENUM_X_PRICE member, Upper Selection Price ...
|
|
* @param lowerAppliedTo: ENUM_X_PRICE member, Lower Selection Price ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasConsolidationZone(
|
|
XOHCL &bar,
|
|
XConsolidationZone &zone,
|
|
int minLoopback = 7,
|
|
double range = 50,
|
|
ENUM_X_PRICE upperAppliedTo = X_PRICE_HIGH,
|
|
ENUM_X_PRICE lowerAppliedTo = X_PRICE_LOW //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
zone.Clean();
|
|
range = NormalizeDouble(range, 50);
|
|
minLoopback = NormalizeInt(minLoopback, 7);
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double points = GetPoints(bar.symbol);
|
|
int index = bar.Index() + 1;
|
|
int length = minLoopback;
|
|
|
|
//
|
|
double upperPrice[];
|
|
int upperPriceCount = FillPrice(
|
|
upperPrice,
|
|
bar,
|
|
length,
|
|
upperAppliedTo //
|
|
);
|
|
|
|
//
|
|
double lowerPrice[];
|
|
int lowerPriceCount = FillPrice(
|
|
lowerPrice,
|
|
bar,
|
|
length,
|
|
lowerAppliedTo //
|
|
);
|
|
|
|
//
|
|
result = upperPriceCount == lowerPriceCount &&
|
|
lowerPriceCount == length;
|
|
if (!result)
|
|
{
|
|
//
|
|
Clean(upperPrice);
|
|
Clean(lowerPrice);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double upper = upperPrice[ArrayMaximum(upperPrice)];
|
|
double lower = lowerPrice[ArrayMinimum(lowerPrice)];
|
|
|
|
//
|
|
bool isBullishBreake =
|
|
bar.low > lower &&
|
|
bar.high > upper &&
|
|
bar.GetUp() > upper;
|
|
bool isBearishBreake =
|
|
bar.high < upper &&
|
|
bar.low < lower &&
|
|
bar.GetDown() < lower;
|
|
result = isBullishBreake ||
|
|
isBearishBreake;
|
|
if (!result)
|
|
{
|
|
//
|
|
Clean(upperPrice);
|
|
Clean(lowerPrice);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double delta = upper - lower;
|
|
result = delta <= range * points;
|
|
if (!result)
|
|
{
|
|
//
|
|
Clean(upperPrice);
|
|
Clean(lowerPrice);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
while (delta <= range * points)
|
|
{
|
|
//
|
|
length++;
|
|
|
|
//
|
|
upperPriceCount = FillPrice(
|
|
upperPrice,
|
|
bar,
|
|
length,
|
|
upperAppliedTo //
|
|
);
|
|
|
|
//
|
|
lowerPriceCount = FillPrice(
|
|
lowerPrice,
|
|
bar,
|
|
length,
|
|
lowerAppliedTo //
|
|
);
|
|
|
|
//
|
|
bool isValid = upperPriceCount == lowerPriceCount &&
|
|
lowerPriceCount == length;
|
|
if (!isValid)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
double iUpper = upperPrice[ArrayMaximum(upperPrice)];
|
|
double iLower = lowerPrice[ArrayMinimum(lowerPrice)];
|
|
|
|
//
|
|
delta = iUpper - iLower;
|
|
if (delta <= range * points)
|
|
{
|
|
//
|
|
upper = iUpper;
|
|
lower = iLower;
|
|
}
|
|
}
|
|
|
|
//
|
|
Clean(upperPrice);
|
|
Clean(lowerPrice);
|
|
|
|
//
|
|
// Filling Zone ...
|
|
zone.upper = upper;
|
|
zone.lower = lower;
|
|
zone.symbol = bar.symbol;
|
|
zone.period = bar.period;
|
|
zone.to = iTime(
|
|
bar.symbol,
|
|
bar.period,
|
|
bar.Index() + 1 //
|
|
);
|
|
zone.from = iTime(
|
|
bar.symbol,
|
|
bar.period,
|
|
bar.Index() + length //
|
|
);
|
|
zone.dir = isBullishBreake
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
result = zone.IsValid();
|
|
if (!result)
|
|
{
|
|
zone.Clean();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// DOJI ...
|
|
bool isDoji = IsDoji(
|
|
bar,
|
|
iDir //
|
|
);
|
|
bool isBullishDoji =
|
|
isDoji &&
|
|
IsBullish(iDir);
|
|
bool isBearishDoji =
|
|
isDoji &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// SWING ...
|
|
bool isSwing = IsSwing(
|
|
bar,
|
|
iDir //
|
|
);
|
|
bool isBullishSwing =
|
|
isSwing &&
|
|
IsBullish(iDir);
|
|
bool isBearishSwing =
|
|
isSwing &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// HAMMER ...
|
|
bool isHammer = IsHammer(
|
|
bar,
|
|
iDir //
|
|
);
|
|
bool isBullishHammer =
|
|
isHammer &&
|
|
IsBullish(iDir);
|
|
bool isBearishHammer =
|
|
isHammer &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// ENGULF ...
|
|
bool isEngulfed = IsEngulfed(
|
|
bar,
|
|
iDir //
|
|
);
|
|
bool isBullishEngulfed =
|
|
isEngulfed &&
|
|
IsBullish(iDir);
|
|
bool isBearishEngulfed =
|
|
isEngulfed &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// REJECTED ...
|
|
bool isRejected = IsRejected(
|
|
bar,
|
|
iDir //
|
|
);
|
|
bool isBullishRejected =
|
|
isRejected &&
|
|
IsBullish(iDir);
|
|
bool isBearishRejected =
|
|
isRejected &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// MOMENTUM ...
|
|
bool isMomentum = IsMomentum(
|
|
bar,
|
|
iDir //
|
|
);
|
|
bool isBullishMomentum =
|
|
isMomentum &&
|
|
IsBullish(iDir);
|
|
bool isBearishMomentum =
|
|
isMomentum &&
|
|
IsBearish(iDir);
|
|
|
|
//
|
|
// Summarize Conditions ...
|
|
|
|
//
|
|
bool isBullishOr =
|
|
isBullishDoji ||
|
|
isBullishSwing ||
|
|
isBullishHammer ||
|
|
isBullishEngulfed ||
|
|
isBullishRejected ||
|
|
isBullishMomentum;
|
|
|
|
//
|
|
bool isBearishOr =
|
|
isBearishDoji ||
|
|
isBearishSwing ||
|
|
isBearishHammer ||
|
|
isBearishEngulfed ||
|
|
isBearishRejected ||
|
|
isBearishMomentum;
|
|
|
|
//
|
|
bool isBullish =
|
|
isBullishOr &&
|
|
!isBearishOr;
|
|
|
|
//
|
|
bool isBearish =
|
|
!isBullishOr &&
|
|
isBearishOr;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
bool IsVPattern(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
ENUM_X_PRICE pType = X_PRICE_CLOSE,
|
|
int loopback = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Args ...
|
|
dir = X_DIRECTION_NONE;
|
|
loopback = NormalizeInt(loopback, 3);
|
|
|
|
//
|
|
// Loopback Must an Odd Number ...
|
|
// here we Validate and Normalize it ...
|
|
double iLoopbackCheck = ((double)(loopback - 1)) / 2;
|
|
if (iLoopbackCheck != 0)
|
|
{
|
|
loopback++;
|
|
}
|
|
|
|
//
|
|
// Validate Args ...
|
|
result =
|
|
bar.IsValid() &&
|
|
IsValid(pType);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL iBar;
|
|
int index = -1;
|
|
XOHCL iSwingBar;
|
|
double prices[];
|
|
bool has = false;
|
|
double iPrice = 0;
|
|
int pricesCount = 0;
|
|
int swingBarIDX = -1;
|
|
int loopbackHalf = 0;
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
bool hasBullishSeq = false;
|
|
bool hasBearishSeq = false;
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
// Retrieve Price Type Collection ...
|
|
index = bar.Index();
|
|
pricesCount = FillPrice(
|
|
prices,
|
|
bar,
|
|
loopback,
|
|
pType //
|
|
);
|
|
result = pricesCount == loopback;
|
|
if (result)
|
|
{
|
|
//
|
|
loopbackHalf = (loopback - 1) / 2;
|
|
swingBarIDX = index + loopbackHalf + 1;
|
|
has = IsValidIndex(swingBarIDX);
|
|
|
|
//
|
|
// Check for Bullish and Bearish ...
|
|
if (has)
|
|
{
|
|
//
|
|
hasBullishSeq = true;
|
|
hasBearishSeq = true;
|
|
iPrice = prices[swingBarIDX];
|
|
for (int i = 0; i < loopbackHalf - 1; i++)
|
|
{
|
|
//
|
|
// Side Values ...
|
|
|
|
//
|
|
// Prev ...
|
|
double iPPrice = prices[swingBarIDX + i];
|
|
double iP2Price = prices[swingBarIDX + i + 1];
|
|
|
|
//
|
|
// Next ...
|
|
double iNPrice = prices[swingBarIDX - i];
|
|
double iN2Price = prices[swingBarIDX - i - 1];
|
|
|
|
//
|
|
if (hasBullishSeq)
|
|
{
|
|
//
|
|
// For Bullish Seq ...
|
|
// Prevs Must: iPPrice < iP2Price
|
|
// Nexts Must: iNPrice < iN2Price
|
|
hasBullishSeq =
|
|
iPrice < iPPrice &&
|
|
iPrice < iNPrice &&
|
|
iPPrice <= iP2Price &&
|
|
iNPrice <= iN2Price;
|
|
}
|
|
|
|
//
|
|
if (hasBearishSeq)
|
|
{
|
|
//
|
|
// For Bearish Seq ...
|
|
// Prevs Must: iPPrice > iP2Price
|
|
// Nexts Must: iNPrice > iN2Price
|
|
hasBearishSeq =
|
|
iPrice > iPPrice &&
|
|
iPrice > iNPrice &&
|
|
iPPrice >= iP2Price &&
|
|
iNPrice >= iN2Price;
|
|
}
|
|
|
|
//
|
|
if (!hasBullishSeq &&
|
|
!hasBearishSeq)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
result =
|
|
has &&
|
|
(hasBullishSeq ||
|
|
hasBearishSeq);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Here we Make Sure the Propper Sequence is Exists ...
|
|
if (result)
|
|
{
|
|
//
|
|
// Try to Check onther Conditions ...
|
|
has = iSwingBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
swingBarIDX //
|
|
);
|
|
|
|
//
|
|
if (has)
|
|
{
|
|
//
|
|
// Draw Requirement to Now ...
|
|
string iName = "S_1";
|
|
datetime iTime = iSwingBar.time;
|
|
|
|
//
|
|
CChartObjectVLine *iObj = new CChartObjectVLine();
|
|
has = iObj.Create(
|
|
0,
|
|
iName,
|
|
0,
|
|
iTime //
|
|
);
|
|
|
|
//
|
|
iName = "SP_1";
|
|
iTime = GetBarTime(
|
|
bar.symbol,
|
|
bar.period,
|
|
swingBarIDX + loopbackHalf);
|
|
CChartObjectVLine *iObj1 = new CChartObjectVLine();
|
|
has = iObj1.Create(
|
|
0,
|
|
iName,
|
|
0,
|
|
iTime //
|
|
);
|
|
|
|
//
|
|
Print("Salam ...");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = isBullish ||
|
|
isBearish;
|
|
if (result)
|
|
{
|
|
//
|
|
dir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
}
|
|
|
|
//
|
|
// Cleanup Resource ...
|
|
iBar.Clean();
|
|
iSwingBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
template <typename T>
|
|
bool IsBoolean(T value)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
string normalizedValue = ToString(value);
|
|
StringToLower(normalizedValue);
|
|
normalizedValue = Trim(normalizedValue);
|
|
|
|
//
|
|
result =
|
|
!IsValid(normalizedValue)
|
|
? false
|
|
: (normalizedValue == "true" ||
|
|
normalizedValue == "false");
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|