1687 lines
36 KiB
Plaintext
1687 lines
36 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 X121 SMC Signal Class
|
|
// -------------------------------------------------
|
|
// Name: XSupDemOBS
|
|
// Description: provide all Signalling functions ...
|
|
//
|
|
//
|
|
// 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 "../../Libraries/x-trade.lib"
|
|
#include "../Classes/x-121.smc.market.cycle.helper.class.mq5"
|
|
#include "../Libraries/x-121.smc.guard.lib.mq5"
|
|
#include "../Libraries/x-121.smc.lib.mq5"
|
|
|
|
//
|
|
enum ENUM_X121SMC_XSUPDEMOBS_PRIORITY
|
|
{
|
|
X121SMC_XSUPDEMOBS_PRIORITY_NONE,
|
|
X121SMC_XSUPDEMOBS_PRIORITY_WEAK,
|
|
X121SMC_XSUPDEMOBS_PRIORITY_LOW,
|
|
X121SMC_XSUPDEMOBS_PRIORITY_REGULAR,
|
|
X121SMC_XSUPDEMOBS_PRIORITY_HIGH,
|
|
};
|
|
|
|
//
|
|
struct XOBFVG
|
|
{
|
|
//
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
datetime time;
|
|
|
|
//
|
|
XCOrderBlock *ob;
|
|
XCFVG *fvg;
|
|
|
|
//
|
|
XCFVG *unActivatedFVGs[];
|
|
XCOrderBlock *unActivatedOBs[];
|
|
|
|
//
|
|
XOBFVG()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
void Clean()
|
|
{
|
|
//
|
|
ob = NULL;
|
|
fvg = NULL;
|
|
time = NULL;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
|
|
//
|
|
Clean(unActivatedOBs);
|
|
Clean(unActivatedFVGs);
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
//
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
ob != NULL &&
|
|
ob.IsValid() &&
|
|
fvg != NULL &&
|
|
fvg.IsValid() &&
|
|
ob.From() < fvg.From() &&
|
|
IsValid(time) &&
|
|
IsValid(symbol) &&
|
|
IsValid(period)
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION mDir = GetDirection();
|
|
|
|
//
|
|
// Validate Order Block ...
|
|
|
|
//
|
|
// Validate Started Zones ...
|
|
XOHCL obStartedBar;
|
|
ENUM_X_DIRECTION obStartedDir;
|
|
bool isStarted = ob.IsStarted(
|
|
mDir,
|
|
obStartedBar,
|
|
obStartedDir //
|
|
);
|
|
result = isStarted;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate InActive Zone ...
|
|
XOHCL obActivatedBar;
|
|
ENUM_X_DIRECTION obActivatedDir;
|
|
bool isActivated = ob.IsActivated(
|
|
mDir,
|
|
obActivatedBar,
|
|
obActivatedDir //
|
|
);
|
|
result = !isActivated;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Zone Iverse Breake ...
|
|
XOHCL obBreakedBar;
|
|
ENUM_X_DIRECTION obBreakedDir;
|
|
bool isBreaked = ob.IsBreaked(
|
|
Opposit(mDir),
|
|
obBreakedBar,
|
|
obBreakedDir,
|
|
true // Ignore Activation ...
|
|
);
|
|
result = !isBreaked;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Checking Dirction(s) ...
|
|
result =
|
|
HasDirection(mDir) &&
|
|
mDir == fvg.GetDirection();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate FVG From Date ...
|
|
|
|
//
|
|
// Checking FVG Place ...
|
|
|
|
//
|
|
bool isBullish = IsBullish(mDir);
|
|
|
|
//
|
|
bool isAbove = IsAboveDiff(
|
|
fvg,
|
|
ob,
|
|
true // Ignore Inside ...
|
|
);
|
|
|
|
//
|
|
bool isBelow = IsBelowDiff(
|
|
fvg,
|
|
ob,
|
|
true // Ignore Inside ...
|
|
);
|
|
|
|
//
|
|
result =
|
|
isBullish
|
|
? isAbove
|
|
: isBelow;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check FVG Must Be Started ...
|
|
XOHCL fvgStartedBar;
|
|
ENUM_X_DIRECTION fvgStartedDir;
|
|
isStarted = fvg.IsStarted(
|
|
mDir,
|
|
fvgStartedBar,
|
|
fvgStartedDir //
|
|
);
|
|
result = isStarted;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check FVg Not Breaked in Reversal Direction ...
|
|
XOHCL fvgBreakedBar;
|
|
ENUM_X_DIRECTION fvgBreakedDir;
|
|
isBreaked = fvg.IsBreaked(
|
|
Opposit(mDir),
|
|
fvgBreakedBar,
|
|
fvgBreakedDir,
|
|
true // Ignore Activation ...
|
|
);
|
|
result = !isBreaked;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION GetDirection()
|
|
{
|
|
return ob.GetDirection();
|
|
}
|
|
|
|
//
|
|
int CountUnActivatedOBs()
|
|
{
|
|
return ArraySize(unActivatedOBs);
|
|
}
|
|
|
|
//
|
|
bool HasUnActivatedOBs()
|
|
{
|
|
return IsValidSize(CountUnActivatedOBs());
|
|
}
|
|
|
|
//
|
|
bool AddUnActivatedOB(
|
|
XCOrderBlock *_ob,
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
bar.IsValid() &&
|
|
_ob != NULL &&
|
|
_ob.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Order Block is not Same as Current OB ...
|
|
bool isSame = IsSame(
|
|
_ob,
|
|
ob //
|
|
);
|
|
result = !isSame;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION mDir = GetDirection();
|
|
bool isBullish = IsBullish(mDir);
|
|
|
|
//
|
|
// Check Bars ...
|
|
XOHCL pBar;
|
|
result = bar.GetPreviousBar(pBar);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isPricePassed =
|
|
isBullish
|
|
? IsAbove(
|
|
bar.low,
|
|
_ob //
|
|
) &&
|
|
IsAbove(
|
|
pBar.low,
|
|
_ob //
|
|
)
|
|
: IsBelow(
|
|
bar.high,
|
|
_ob //
|
|
) &&
|
|
IsBelow(
|
|
pBar.high,
|
|
_ob //
|
|
);
|
|
result = isPricePassed;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Order Block is Not Activated ...
|
|
|
|
//
|
|
// Validate Started Zones ...
|
|
XOHCL obStartedBar;
|
|
ENUM_X_DIRECTION obStartedDir;
|
|
bool isStarted = _ob.IsStarted(
|
|
mDir,
|
|
obStartedBar,
|
|
obStartedDir //
|
|
);
|
|
result = isStarted;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate InActive Zone ...
|
|
XOHCL obActivatedBar;
|
|
ENUM_X_DIRECTION obActivatedDir;
|
|
bool isActivated = _ob.IsActivated(
|
|
mDir,
|
|
obActivatedBar,
|
|
obActivatedDir //
|
|
);
|
|
result = !isActivated;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Zone Iverse Breake ...
|
|
XOHCL obBreakedBar;
|
|
ENUM_X_DIRECTION obBreakedDir;
|
|
bool isBreaked = _ob.IsBreaked(
|
|
Opposit(mDir),
|
|
obBreakedBar,
|
|
obBreakedDir,
|
|
true // Ignore Activation ...
|
|
);
|
|
result = !isBreaked;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int idx = FindIndex(
|
|
_ob,
|
|
unActivatedOBs //
|
|
);
|
|
result = !IsValidIndex(idx);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isLastPassed = true;
|
|
bool isAboveLast = false;
|
|
bool isBelowLast = false;
|
|
XCOrderBlock *lastOB = NULL;
|
|
int unActivatedOBsCount = CountUnActivatedOBs();
|
|
bool hasUnActivatedOBs = HasUnActivatedOBs();
|
|
if (hasUnActivatedOBs)
|
|
{
|
|
lastOB = unActivatedOBs[unActivatedOBsCount - 1];
|
|
}
|
|
bool hasLastOB = lastOB != NULL &&
|
|
lastOB.IsValid();
|
|
if (hasLastOB)
|
|
{
|
|
//
|
|
isAboveLast = IsAbove(
|
|
_ob,
|
|
lastOB,
|
|
true // Ignore Inside ...
|
|
);
|
|
|
|
//
|
|
isBelowLast = IsBelow(
|
|
_ob,
|
|
lastOB,
|
|
true // Ignore Inside ...
|
|
);
|
|
|
|
//
|
|
isLastPassed =
|
|
isBullish
|
|
? isAboveLast
|
|
: isBelowLast;
|
|
}
|
|
result = isLastPassed;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
Add(
|
|
_ob,
|
|
unActivatedOBs //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountUnActivatedFVGs()
|
|
{
|
|
return ArraySize(unActivatedFVGs);
|
|
}
|
|
|
|
//
|
|
bool HasUnActivatedFVGs()
|
|
{
|
|
return IsValidSize(CountUnActivatedFVGs());
|
|
}
|
|
|
|
//
|
|
bool AddUnActivatedFVG(
|
|
XCFVG *_fvg,
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
bar.IsValid() &&
|
|
_fvg != NULL &&
|
|
_fvg.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Order Block is not Same as Current OB ...
|
|
bool isSame = IsSame(
|
|
_fvg,
|
|
fvg //
|
|
);
|
|
result = !isSame;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION mDir = GetDirection();
|
|
bool isBullish = IsBullish(mDir);
|
|
|
|
//
|
|
// Check Bars ...
|
|
XOHCL pBar;
|
|
result = bar.GetPreviousBar(pBar);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isPricePassed =
|
|
isBullish
|
|
? IsAbove(
|
|
bar.low,
|
|
_fvg //
|
|
) &&
|
|
IsAbove(
|
|
pBar.low,
|
|
_fvg //
|
|
)
|
|
: IsBelow(
|
|
bar.high,
|
|
_fvg //
|
|
) &&
|
|
IsBelow(
|
|
pBar.high,
|
|
_fvg //
|
|
);
|
|
result = isPricePassed;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Order Block is Not Activated ...
|
|
|
|
//
|
|
// Validate Started Zones ...
|
|
XOHCL fvgStartedBar;
|
|
ENUM_X_DIRECTION fvgStartedDir;
|
|
bool isStarted = _fvg.IsStarted(
|
|
mDir,
|
|
fvgStartedBar,
|
|
fvgStartedDir //
|
|
);
|
|
result = isStarted;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate InActive Zone ...
|
|
XOHCL fvgActivatedBar;
|
|
ENUM_X_DIRECTION fvgActivatedDir;
|
|
bool isActivated = _fvg.IsActivated(
|
|
mDir,
|
|
fvgActivatedBar,
|
|
fvgActivatedDir //
|
|
);
|
|
result = !isActivated;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Zone Iverse Breake ...
|
|
XOHCL fvgBreakedBar;
|
|
ENUM_X_DIRECTION fvgBreakedDir;
|
|
bool isBreaked = _fvg.IsBreaked(
|
|
Opposit(mDir),
|
|
fvgBreakedBar,
|
|
fvgBreakedDir,
|
|
true // Ignore Activation ...
|
|
);
|
|
result = !isBreaked;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int idx = FindIndex(
|
|
_fvg,
|
|
unActivatedFVGs //
|
|
);
|
|
result = !IsValidIndex(idx);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XCFVG *lastFVG = NULL;
|
|
bool isLastPassed = true;
|
|
bool isAboveLast = false;
|
|
bool isBelowLast = false;
|
|
int unActivatedFVGsCount = CountUnActivatedFVGs();
|
|
bool hasUnActivatedFVGs = HasUnActivatedFVGs();
|
|
if (hasUnActivatedFVGs)
|
|
{
|
|
lastFVG = unActivatedFVGs[unActivatedFVGsCount - 1];
|
|
}
|
|
bool hasLastFVG = lastFVG != NULL &&
|
|
lastFVG.IsValid();
|
|
if (hasLastFVG)
|
|
{
|
|
//
|
|
isAboveLast = IsAbove(
|
|
_fvg,
|
|
lastFVG,
|
|
true // Ignore Inside ...
|
|
);
|
|
|
|
//
|
|
isBelowLast = IsBelow(
|
|
_fvg,
|
|
lastFVG,
|
|
true // Ignore Inside ...
|
|
);
|
|
|
|
//
|
|
isLastPassed =
|
|
isBullish
|
|
? isAboveLast
|
|
: isBelowLast;
|
|
}
|
|
result = isLastPassed;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
Add(
|
|
_fvg,
|
|
unActivatedFVGs //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
struct X121SMCXSupDemOBSWorkingZone
|
|
{
|
|
//
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
double upper;
|
|
double lower;
|
|
|
|
//
|
|
double zoneUpper;
|
|
double zoneLower;
|
|
|
|
//
|
|
double quarter1;
|
|
double quarter2;
|
|
double quarter3;
|
|
|
|
//
|
|
datetime from;
|
|
|
|
//
|
|
X121SMCXSupDemOBSWorkingZone()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
void Clean()
|
|
{
|
|
//
|
|
upper = 0;
|
|
lower = 0;
|
|
quarter1 = 0;
|
|
quarter2 = 0;
|
|
quarter3 = 0;
|
|
zoneLower = 0;
|
|
zoneUpper = 0;
|
|
|
|
//
|
|
from = NULL;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
//
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
lower > 0 &&
|
|
upper > 0 &&
|
|
quarter1 > 0 &&
|
|
quarter2 > 0 &&
|
|
quarter3 > 0 &&
|
|
upper > lower &&
|
|
zoneLower > 0 &&
|
|
zoneUpper > 0 &&
|
|
IsValid(from) &&
|
|
IsValid(symbol) &&
|
|
IsValid(period) &&
|
|
zoneUpper > upper &&
|
|
zoneLower < lower;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool DetectOveralTrend(
|
|
XOHCL &touchedBar,
|
|
ENUM_X_DIRECTION &trendDir,
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
trendDir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int fromBarIndex = iBarShift(
|
|
symbol,
|
|
period,
|
|
from //
|
|
);
|
|
result = IsValidIndex(fromBarIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL nearestUpperTouchedBar;
|
|
XOHCL nearestLowerTouchedBar;
|
|
bool hasNearestUpperTouchedBar = false;
|
|
bool hasNearestLowerTouchedBar = false;
|
|
for (int i = barIndex; i < fromBarIndex; i++)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
symbol,
|
|
period,
|
|
i //
|
|
);
|
|
|
|
//
|
|
hasNearestUpperTouchedBar = nearestUpperTouchedBar.IsValid();
|
|
if (!hasNearestUpperTouchedBar)
|
|
{
|
|
//
|
|
bool isBarTouchedUpper = iBar.high > upper;
|
|
if (isBarTouchedUpper)
|
|
{
|
|
//
|
|
nearestUpperTouchedBar = iBar;
|
|
hasNearestUpperTouchedBar = true;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasNearestLowerTouchedBar = nearestLowerTouchedBar.IsValid();
|
|
if (!hasNearestLowerTouchedBar)
|
|
{
|
|
//
|
|
bool isBarTouchedLower = iBar.low < lower;
|
|
if (isBarTouchedLower)
|
|
{
|
|
//
|
|
nearestLowerTouchedBar = iBar;
|
|
hasNearestLowerTouchedBar = true;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (hasNearestUpperTouchedBar &&
|
|
hasNearestLowerTouchedBar)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = hasNearestUpperTouchedBar ||
|
|
hasNearestLowerTouchedBar;
|
|
if (result)
|
|
{
|
|
//
|
|
if (hasNearestUpperTouchedBar &&
|
|
!hasNearestLowerTouchedBar)
|
|
{
|
|
//
|
|
trendDir = X_DIRECTION_BEARISH;
|
|
touchedBar = nearestUpperTouchedBar;
|
|
}
|
|
else if (!hasNearestUpperTouchedBar &&
|
|
hasNearestLowerTouchedBar)
|
|
{
|
|
//
|
|
trendDir = X_DIRECTION_BULLISH;
|
|
touchedBar = nearestLowerTouchedBar;
|
|
}
|
|
else if (hasNearestUpperTouchedBar &&
|
|
hasNearestLowerTouchedBar)
|
|
{
|
|
//
|
|
trendDir =
|
|
nearestUpperTouchedBar.time < nearestLowerTouchedBar.time
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
if (IsBullish(trendDir))
|
|
{
|
|
touchedBar = nearestLowerTouchedBar;
|
|
}
|
|
else
|
|
{
|
|
touchedBar = nearestUpperTouchedBar;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool IsDestroyed(
|
|
ENUM_X_DIRECTION &destroyedDir,
|
|
int barIndex = 0,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
destroyedDir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL bar;
|
|
result = bar.Init(
|
|
symbol,
|
|
forPeriod,
|
|
barIndex //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isUpperBreaked =
|
|
bar.high > zoneUpper &&
|
|
bar.close > zoneUpper;
|
|
|
|
//
|
|
bool isLowerBreaked =
|
|
bar.low < zoneLower &&
|
|
bar.close < zoneLower;
|
|
|
|
//
|
|
result = isUpperBreaked ||
|
|
isLowerBreaked;
|
|
if (result)
|
|
{
|
|
//
|
|
destroyedDir =
|
|
isUpperBreaked
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Definitions ...
|
|
struct X121SMCStrategyXSupDemOBSSignalConditions
|
|
{
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
double sl;
|
|
double target;
|
|
double reward;
|
|
double amountPercent;
|
|
ENUM_X_DIRECTION dir;
|
|
ENUM_X_POSITION_TYPES type;
|
|
|
|
//
|
|
// Setup Props ...
|
|
|
|
//
|
|
datetime setupTime;
|
|
datetime triggerTime;
|
|
|
|
//
|
|
double pivot;
|
|
double point;
|
|
|
|
//
|
|
ENUM_X121SMC_XSUPDEMOBS_PRIORITY priority;
|
|
|
|
//
|
|
// Working Zone ...
|
|
|
|
//
|
|
XCSupplyZone *visionHighestSupplyZone;
|
|
XCSupplyZone *consolidationHighestSupplyZone;
|
|
|
|
//
|
|
XCDemandZone *visionLowestDemandZone;
|
|
XCDemandZone *consolidationLowestDemandZone;
|
|
|
|
//
|
|
XCFVG *insideFVG;
|
|
XCOrderBlock *insideOB;
|
|
|
|
//
|
|
XCFVG *rejectedFVG;
|
|
XCOrderBlock *rejectedOB;
|
|
|
|
//
|
|
XCSupplyZone *insideSupplyZone;
|
|
XCDemandZone *insideDemandZone;
|
|
|
|
//
|
|
XConsolidationZone consolidationZone;
|
|
|
|
//
|
|
XOBFVG obFVGs[];
|
|
|
|
//
|
|
X121SMCXSupDemOBSWorkingZone workingZone;
|
|
|
|
//
|
|
// Constructor ...
|
|
X121SMCStrategyXSupDemOBSSignalConditions()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Cleaning Up ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
sl = 0;
|
|
target = 0;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
type = X_POSITION_TYPE_NONE;
|
|
|
|
//
|
|
symbol = NULL;
|
|
period = NULL;
|
|
setupTime = NULL;
|
|
triggerTime = NULL;
|
|
|
|
//
|
|
ExtensionClean();
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
/**
|
|
* Check Condition is Setting Up ...
|
|
*
|
|
* @param dir: ENUM_X_DIRECTION member, Setting Up Direction ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSetuped()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid(setupTime) &&
|
|
HasDirection(dir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Setup Age ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int GetSetupAge()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsSetuped())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect How we Can Trigger Signal ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool CanTrigger()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
sl > 0 &&
|
|
IsValid(symbol) &&
|
|
IsValid(period) &&
|
|
IsValid(triggerTime) &&
|
|
type != X_POSITION_TYPE_ALL &&
|
|
type != X_POSITION_TYPE_NONE
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extensions ...
|
|
|
|
/**
|
|
* Clean Additional Properties ...
|
|
*/
|
|
void ExtensionClean()
|
|
{
|
|
//
|
|
pivot = 0;
|
|
point = 0;
|
|
|
|
//
|
|
reward = 0;
|
|
amountPercent = 0;
|
|
|
|
//
|
|
Clean(obFVGs);
|
|
workingZone.Clean();
|
|
consolidationZone.Clean();
|
|
|
|
//
|
|
insideOB = NULL;
|
|
insideFVG = NULL;
|
|
rejectedOB = NULL;
|
|
rejectedFVG = NULL;
|
|
insideSupplyZone = NULL;
|
|
insideDemandZone = NULL;
|
|
|
|
//
|
|
visionLowestDemandZone = NULL;
|
|
visionHighestSupplyZone = NULL;
|
|
consolidationLowestDemandZone = NULL;
|
|
consolidationHighestSupplyZone = NULL;
|
|
|
|
//
|
|
ZeroMemory(visionLowestDemandZone);
|
|
ZeroMemory(visionHighestSupplyZone);
|
|
ZeroMemory(consolidationLowestDemandZone);
|
|
ZeroMemory(consolidationHighestSupplyZone);
|
|
|
|
//
|
|
priority = X121SMC_XSUPDEMOBS_PRIORITY_NONE;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
bool HasVisionHighestSupplyZone()
|
|
{
|
|
//
|
|
return visionHighestSupplyZone != NULL &&
|
|
visionHighestSupplyZone.IsValid();
|
|
}
|
|
|
|
//
|
|
bool HasConsolidationHighestSupplyZone()
|
|
{
|
|
//
|
|
return consolidationHighestSupplyZone != NULL &&
|
|
consolidationHighestSupplyZone.IsValid();
|
|
}
|
|
|
|
//
|
|
bool HasVisionLowestDemandZone()
|
|
{
|
|
//
|
|
return visionLowestDemandZone != NULL &&
|
|
visionLowestDemandZone.IsValid();
|
|
}
|
|
|
|
//
|
|
bool HasConsolidationLowestDemandZone()
|
|
{
|
|
//
|
|
return consolidationLowestDemandZone != NULL &&
|
|
consolidationLowestDemandZone.IsValid();
|
|
}
|
|
|
|
//
|
|
// X_DIRECTION_BULLISH:
|
|
// Supply Zone of Consolidation Cycle appears inside
|
|
// Supply Zone of Vision Cycle ...
|
|
//
|
|
// X_DIRECTION_BEARISH:
|
|
// Demnad Zone of Consolidation Cycle appears inside
|
|
// Demnad Zone of Vision Cycle ...
|
|
bool HasHighImpactSide(ENUM_X_DIRECTION &highImpactDir)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
highImpactDir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
bool isSupplyInside = false;
|
|
bool hasVisionHighestSupplyZone = HasVisionHighestSupplyZone();
|
|
bool hasConsolidationHighestSupplyZone = HasConsolidationHighestSupplyZone();
|
|
if (hasVisionHighestSupplyZone &&
|
|
hasConsolidationHighestSupplyZone)
|
|
{
|
|
isSupplyInside = IsInside(
|
|
consolidationHighestSupplyZone,
|
|
visionHighestSupplyZone //
|
|
);
|
|
}
|
|
|
|
//
|
|
bool isDemandInside = false;
|
|
bool hasVisionLowestDemandZone = HasVisionLowestDemandZone();
|
|
bool hasConsolidationLowestDemandZone = HasConsolidationLowestDemandZone();
|
|
if (hasVisionLowestDemandZone &&
|
|
hasConsolidationLowestDemandZone)
|
|
{
|
|
//
|
|
isDemandInside = IsInside(
|
|
consolidationLowestDemandZone,
|
|
visionLowestDemandZone //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = isSupplyInside ||
|
|
isDemandInside;
|
|
if (result)
|
|
{
|
|
//
|
|
highImpactDir =
|
|
isSupplyInside
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
datetime ExtractNearestFromDate()
|
|
{
|
|
//
|
|
datetime result = NULL;
|
|
|
|
//
|
|
bool hasVisionLowestDemandZone = HasVisionLowestDemandZone();
|
|
bool hasVisionHighestSupplyZone = HasVisionHighestSupplyZone();
|
|
bool hasConsolidationLowestDemandZone = HasConsolidationLowestDemandZone();
|
|
bool hasConsolidationHighestSupplyZone = HasConsolidationHighestSupplyZone();
|
|
if (hasVisionLowestDemandZone)
|
|
{
|
|
//
|
|
bool canSet =
|
|
!IsValid(result)
|
|
? true
|
|
: visionLowestDemandZone.From() > result;
|
|
if (canSet)
|
|
{
|
|
result = visionLowestDemandZone.From();
|
|
}
|
|
}
|
|
if (hasVisionHighestSupplyZone)
|
|
{
|
|
//
|
|
bool canSet =
|
|
!IsValid(result)
|
|
? true
|
|
: visionHighestSupplyZone.From() > result;
|
|
if (canSet)
|
|
{
|
|
result = visionHighestSupplyZone.From();
|
|
}
|
|
}
|
|
if (hasConsolidationLowestDemandZone)
|
|
{
|
|
//
|
|
bool canSet =
|
|
!IsValid(result)
|
|
? true
|
|
: consolidationLowestDemandZone.From() > result;
|
|
if (canSet)
|
|
{
|
|
result = consolidationLowestDemandZone.From();
|
|
}
|
|
}
|
|
if (hasConsolidationHighestSupplyZone)
|
|
{
|
|
//
|
|
bool canSet =
|
|
!IsValid(result)
|
|
? true
|
|
: consolidationHighestSupplyZone.From() > result;
|
|
if (canSet)
|
|
{
|
|
result = consolidationHighestSupplyZone.From();
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
datetime ExtractFarestFromDate()
|
|
{
|
|
//
|
|
datetime result = NULL;
|
|
|
|
//
|
|
bool hasVisionLowestDemandZone = HasVisionLowestDemandZone();
|
|
bool hasVisionHighestSupplyZone = HasVisionHighestSupplyZone();
|
|
bool hasConsolidationLowestDemandZone = HasConsolidationLowestDemandZone();
|
|
bool hasConsolidationHighestSupplyZone = HasConsolidationHighestSupplyZone();
|
|
if (hasVisionLowestDemandZone)
|
|
{
|
|
//
|
|
bool canSet =
|
|
!IsValid(result)
|
|
? true
|
|
: visionLowestDemandZone.From() < result;
|
|
if (canSet)
|
|
{
|
|
result = visionLowestDemandZone.From();
|
|
}
|
|
}
|
|
if (hasVisionHighestSupplyZone)
|
|
{
|
|
//
|
|
bool canSet =
|
|
!IsValid(result)
|
|
? true
|
|
: visionHighestSupplyZone.From() < result;
|
|
if (canSet)
|
|
{
|
|
result = visionHighestSupplyZone.From();
|
|
}
|
|
}
|
|
if (hasConsolidationLowestDemandZone)
|
|
{
|
|
//
|
|
bool canSet =
|
|
!IsValid(result)
|
|
? true
|
|
: consolidationLowestDemandZone.From() < result;
|
|
if (canSet)
|
|
{
|
|
result = consolidationLowestDemandZone.From();
|
|
}
|
|
}
|
|
if (hasConsolidationHighestSupplyZone)
|
|
{
|
|
//
|
|
bool canSet =
|
|
!IsValid(result)
|
|
? true
|
|
: consolidationHighestSupplyZone.From() < result;
|
|
if (canSet)
|
|
{
|
|
result = consolidationHighestSupplyZone.From();
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountOBFVGs()
|
|
{
|
|
return ArraySize(obFVGs);
|
|
}
|
|
|
|
//
|
|
bool HasOBFVGs()
|
|
{
|
|
return IsValidSize(CountOBFVGs());
|
|
}
|
|
|
|
//
|
|
// Working Zone is an Area which
|
|
// we decide to trade inside it ...
|
|
bool ExtractWorkingZone(
|
|
int barIndex = 0,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
result = workingZone.IsValid();
|
|
if (result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL bar;
|
|
result = bar.Init(
|
|
symbol,
|
|
forPeriod,
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
double upper = 0;
|
|
double lower = 0;
|
|
double quarter1 = 0;
|
|
double quarter2 = 0;
|
|
double quarter3 = 0;
|
|
double zoneUpper = 0;
|
|
double zoneLower = 0;
|
|
|
|
//
|
|
ENUM_X_DIRECTION highImpactDir;
|
|
bool hasHighImpactSide = HasHighImpactSide(highImpactDir);
|
|
result = hasHighImpactSide;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Select Newest Zone From time ...
|
|
datetime from = ExtractFarestFromDate();
|
|
|
|
//
|
|
bool isSupplyHighImpacted = IsBullish(highImpactDir);
|
|
bool isDemandHighImpacted = IsBearish(highImpactDir);
|
|
|
|
//
|
|
if (isSupplyHighImpacted)
|
|
{
|
|
//
|
|
upper = visionHighestSupplyZone.Lower();
|
|
if (HasConsolidationLowestDemandZone())
|
|
{
|
|
lower = consolidationLowestDemandZone.Upper();
|
|
}
|
|
else
|
|
{
|
|
lower = visionLowestDemandZone.Upper();
|
|
}
|
|
|
|
//
|
|
zoneUpper = visionHighestSupplyZone.Upper();
|
|
if (HasConsolidationLowestDemandZone())
|
|
{
|
|
zoneLower = consolidationLowestDemandZone.Lower();
|
|
}
|
|
else
|
|
{
|
|
zoneLower = visionLowestDemandZone.Lower();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
if (HasConsolidationHighestSupplyZone())
|
|
{
|
|
upper = consolidationHighestSupplyZone.Lower();
|
|
}
|
|
else
|
|
{
|
|
upper = visionHighestSupplyZone.Lower();
|
|
}
|
|
lower = visionLowestDemandZone.Upper();
|
|
|
|
//
|
|
if (HasConsolidationHighestSupplyZone())
|
|
{
|
|
zoneUpper = consolidationHighestSupplyZone.Upper();
|
|
}
|
|
else
|
|
{
|
|
zoneUpper = visionHighestSupplyZone.Upper();
|
|
}
|
|
zoneLower = visionLowestDemandZone.Lower();
|
|
}
|
|
|
|
//
|
|
result =
|
|
lower > 0 &&
|
|
upper > 0 &&
|
|
upper > lower &&
|
|
zoneUpper > 0 &&
|
|
zoneLower > 0 &&
|
|
zoneUpper > upper &&
|
|
zoneLower < lower;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double range = (upper - lower) / 100;
|
|
double quarter = range * 25;
|
|
|
|
//
|
|
quarter1 = upper - (1 * quarter);
|
|
quarter2 = upper - (2 * quarter);
|
|
quarter3 = upper - (3 * quarter);
|
|
|
|
//
|
|
workingZone.from = from;
|
|
workingZone.upper = upper;
|
|
workingZone.lower = lower;
|
|
workingZone.symbol = symbol;
|
|
workingZone.period = period;
|
|
workingZone.quarter1 = quarter1;
|
|
workingZone.quarter2 = quarter2;
|
|
workingZone.quarter3 = quarter3;
|
|
workingZone.zoneUpper = zoneUpper;
|
|
workingZone.zoneLower = zoneLower;
|
|
|
|
//
|
|
result = workingZone.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool IsWorkingZoneDestroyed(
|
|
ENUM_X_DIRECTION &destroyedDir,
|
|
int barIndex = 0,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
destroyedDir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = workingZone.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = workingZone.IsDestroyed(
|
|
destroyedDir,
|
|
barIndex,
|
|
forPeriod //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool DetectOveralTrend(
|
|
XOHCL &touchedBar,
|
|
ENUM_X_DIRECTION &trendDir,
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
trendDir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = workingZone.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = workingZone.DetectOveralTrend(
|
|
touchedBar,
|
|
trendDir,
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void UpdateTo(datetime value = NULL)
|
|
{
|
|
//
|
|
value = NormalizeTime(value);
|
|
|
|
//
|
|
bool hasVisionLowestDemandZone = HasVisionLowestDemandZone();
|
|
if (hasVisionLowestDemandZone)
|
|
{
|
|
visionLowestDemandZone.To(value);
|
|
}
|
|
|
|
bool hasVisionHighestSupplyZone = HasVisionHighestSupplyZone();
|
|
if (hasVisionHighestSupplyZone)
|
|
{
|
|
visionHighestSupplyZone.To(value);
|
|
}
|
|
|
|
bool hasConsolidationLowestDemandZone = HasConsolidationLowestDemandZone();
|
|
if (hasConsolidationLowestDemandZone)
|
|
{
|
|
consolidationLowestDemandZone.To(value);
|
|
}
|
|
|
|
bool hasConsolidationHighestSupplyZone = HasConsolidationHighestSupplyZone();
|
|
if (hasConsolidationHighestSupplyZone)
|
|
{
|
|
consolidationHighestSupplyZone.To(value);
|
|
}
|
|
|
|
//
|
|
bool hasInsideOB = insideOB != NULL &&
|
|
insideOB.IsValid();
|
|
if (hasInsideOB)
|
|
{
|
|
insideOB.To(value);
|
|
}
|
|
|
|
//
|
|
bool hasInsideFVG = insideFVG != NULL &&
|
|
insideFVG.IsValid();
|
|
if (hasInsideFVG)
|
|
{
|
|
insideFVG.To(value);
|
|
}
|
|
|
|
//
|
|
bool hasOBFVGs = HasOBFVGs();
|
|
int obFVGsCount = CountOBFVGs();
|
|
if (hasOBFVGs)
|
|
{
|
|
//
|
|
for (int i = 0; i < obFVGsCount; i++)
|
|
{
|
|
//
|
|
obFVGs[i].ob.To(value);
|
|
obFVGs[i].fvg.To(value);
|
|
|
|
//
|
|
bool hasUnActivatedOBs = obFVGs[i].HasUnActivatedOBs();
|
|
int unActivatedOBsCount = obFVGs[i].CountUnActivatedOBs();
|
|
if (hasUnActivatedOBs)
|
|
{
|
|
//
|
|
for (int j = 0; j < unActivatedOBsCount; j++)
|
|
{
|
|
obFVGs[i].unActivatedOBs[j].To(value);
|
|
}
|
|
}
|
|
|
|
//
|
|
bool hasUnActivatedFVGs = obFVGs[i].HasUnActivatedFVGs();
|
|
int unActivatedFVGsCount = obFVGs[i].CountUnActivatedFVGs();
|
|
if (hasUnActivatedFVGs)
|
|
{
|
|
//
|
|
for (int j = 0; j < unActivatedFVGsCount; j++)
|
|
{
|
|
obFVGs[i].unActivatedFVGs[j].To(value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
};
|