1582 lines
32 KiB
Plaintext
1582 lines
32 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 X121 SMC Signal Class
|
|
// -------------------------------------------------
|
|
// Name: XWZ
|
|
// 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_XWZ_PROVIDERS
|
|
{
|
|
X121SMC_XWZ_PROVIDER_NONE,
|
|
X121SMC_XWZ_PROVIDER_ACTIVATED_ZONE,
|
|
X121SMC_XWZ_PROVIDER_ACTIVATED_CHOCH,
|
|
X121SMC_XWZ_PROVIDER_PRICE_INSIDE_ZONE,
|
|
};
|
|
|
|
//
|
|
enum ENUM_X121SMC_XWZ_PRIORITY
|
|
{
|
|
X121SMC_XWZ_PRIORITY_NONE,
|
|
X121SMC_XWZ_PRIORITY_WEAK,
|
|
X121SMC_XWZ_PRIORITY_LOW,
|
|
X121SMC_XWZ_PRIORITY_REGULAR,
|
|
X121SMC_XWZ_PRIORITY_HIGH,
|
|
X121SMC_XWZ_PRIORITY_STRONG_HIGH,
|
|
};
|
|
|
|
//
|
|
struct X121SMCStrategyXWZWorkingZone
|
|
{
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
XCSupplyZone *supplyZone;
|
|
XCDemandZone *demandZone;
|
|
|
|
//
|
|
double quarter1;
|
|
double quarter2;
|
|
double quarter3;
|
|
|
|
//
|
|
XOBFVG orderFlow[];
|
|
XOBFVGPivot swings[];
|
|
XOBFVG brokenOrderFlow[];
|
|
CChartObjectTrend *orderFlowTrend;
|
|
|
|
//
|
|
XCSupplyZone *supplyZones[];
|
|
XCDemandZone *demandZones[];
|
|
|
|
//
|
|
// Constructor ...
|
|
X121SMCStrategyXWZWorkingZone()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
void Clean()
|
|
{
|
|
//
|
|
quarter1 = 0;
|
|
quarter2 = 0;
|
|
quarter3 = 0;
|
|
|
|
//
|
|
symbol = NULL;
|
|
period = NULL;
|
|
|
|
//
|
|
Clean(orderFlow);
|
|
Clean(brokenOrderFlow);
|
|
|
|
//
|
|
Clean(swings);
|
|
ZeroMemory(supplyZone);
|
|
ZeroMemory(demandZone);
|
|
|
|
//
|
|
if (orderFlowTrend != NULL)
|
|
{
|
|
orderFlowTrend.Delete();
|
|
}
|
|
ZeroMemory(orderFlowTrend);
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
//
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
quarter1 > 0 &&
|
|
quarter2 > 0 &&
|
|
quarter3 > 0 &&
|
|
HasSupplyZone() &&
|
|
HasDemandZone() &&
|
|
quarter1 > quarter2 &&
|
|
quarter2 > quarter3
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool HasSupplyZone()
|
|
{
|
|
return supplyZone != NULL &&
|
|
supplyZone.IsValid();
|
|
}
|
|
|
|
//
|
|
bool HasDemandZone()
|
|
{
|
|
return demandZone != NULL &&
|
|
demandZone.IsValid();
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
bool HasOrderFlow()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
HasChild(orderFlow);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool HasOrderFlow(
|
|
ENUM_X_DIRECTION &orderFlowDir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
HasChild(orderFlow);
|
|
if (result)
|
|
{
|
|
orderFlowDir = orderFlow[0].GetDirection();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountOrderFlow()
|
|
{
|
|
return ArraySize(orderFlow);
|
|
}
|
|
|
|
//
|
|
int GetSwings(
|
|
XOBFVGPivot &pivots[] //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(pivots);
|
|
|
|
//
|
|
int count = 0;
|
|
bool has = false;
|
|
|
|
//
|
|
has = HasOrderFlow();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
count = CountOrderFlow();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XOBFVGPivot iPivots[];
|
|
int iPivotsCount = orderFlow[i]
|
|
.GetSwings(iPivots);
|
|
bool hasPivots = IsValidSize(iPivotsCount);
|
|
if (hasPivots)
|
|
{
|
|
//
|
|
Copy(
|
|
iPivots,
|
|
pivots,
|
|
false //
|
|
);
|
|
}
|
|
|
|
//
|
|
Clean(iPivots);
|
|
}
|
|
|
|
//
|
|
result = ArraySize(pivots);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double GetOrderFlowTrendLinePrice(
|
|
int barIndex = 0,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
if (!IsValid() ||
|
|
!HasOrderFlow() ||
|
|
orderFlowTrend == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
datetime time = iTime(
|
|
symbol,
|
|
forPeriod,
|
|
barIndex //
|
|
);
|
|
|
|
//
|
|
result = ObjectGetValueByTime(
|
|
orderFlowTrend.ChartId(),
|
|
orderFlowTrend.Name(),
|
|
time //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int DetectOrderFlow(
|
|
string forSymbol,
|
|
ENUM_TIMEFRAMES forPeriod,
|
|
ENUM_X_DIRECTION &orderFlowDir,
|
|
XPOIState <fState,
|
|
XPOIState &htfState,
|
|
XPOIState &mtfState,
|
|
XPOIState &stfState //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(orderFlow);
|
|
orderFlowDir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
bool isValid =
|
|
//
|
|
IsValid(forSymbol) &&
|
|
IsValid(forPeriod) &&
|
|
ltfState.HasChild() &&
|
|
htfState.HasChild() &&
|
|
mtfState.HasChild() &&
|
|
stfState.HasChild()
|
|
//
|
|
;
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Working Zone ...
|
|
bool hasWorkingZone = IsValid();
|
|
if (!hasWorkingZone)
|
|
{
|
|
//
|
|
symbol = forSymbol;
|
|
period = forPeriod;
|
|
|
|
//
|
|
int idx = -1;
|
|
bool has = false;
|
|
|
|
//
|
|
has = ltfState.HasSupplyZones();
|
|
if (has)
|
|
{
|
|
//
|
|
idx = GetHighest(ltfState.supplyZones);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
supplyZone = ltfState.supplyZones[idx];
|
|
}
|
|
}
|
|
|
|
//
|
|
has = ltfState.HasDemandZones();
|
|
if (has)
|
|
{
|
|
//
|
|
idx = GetLowest(ltfState.demandZones);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
demandZone = ltfState.demandZones[idx];
|
|
}
|
|
}
|
|
|
|
//
|
|
hasWorkingZone = HasSupplyZone() &&
|
|
HasDemandZone();
|
|
if (hasWorkingZone)
|
|
{
|
|
//
|
|
double upper = supplyZone.Lower();
|
|
double lower = demandZone.Upper();
|
|
|
|
//
|
|
double delta = ((upper - lower) / 100) * 25;
|
|
|
|
//
|
|
quarter1 = upper - (1 * delta);
|
|
quarter2 = upper - (2 * delta);
|
|
quarter3 = upper - (3 * delta);
|
|
|
|
//
|
|
hasWorkingZone = IsValid();
|
|
}
|
|
}
|
|
|
|
//
|
|
if (!hasWorkingZone)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Bullish OBFVGs ...
|
|
XOBFVG bullOBFVGs[];
|
|
int bullOBFVGsCount = ExtractOBFVGZones(
|
|
htfState,
|
|
mtfState,
|
|
stfState,
|
|
bullOBFVGs,
|
|
X_DIRECTION_BULLISH,
|
|
NULL, // For Period ...
|
|
//
|
|
// Start ...
|
|
XZONE_STATE_PASSED,
|
|
true, // Force Body Out ...
|
|
//
|
|
// Activation ...
|
|
XZONE_STATE_PASSED,
|
|
true, // Force Body In ...
|
|
//
|
|
// Breaktion ...
|
|
XZONE_STATE_FAILED,
|
|
false, // Force Body In ...
|
|
//
|
|
// Works ...
|
|
XZONE_STATE_PASSED,
|
|
true, // Force Body Out ...
|
|
//
|
|
true, // Apply Sort ...
|
|
true, // From Filter ...
|
|
true, // Place Filter ...
|
|
//
|
|
true, // Ignore Inside in Place Filter ...
|
|
//
|
|
true, // Detect Inside OB POI(s) ...
|
|
true, // Detect Inside FVG POI(s) ...
|
|
true // Apply From Filter to Selected POI(s) ...
|
|
);
|
|
bool hasBullOBFVGs = IsValidSize(bullOBFVGsCount);
|
|
|
|
//
|
|
// Bearish OBFVGs ...
|
|
XOBFVG bearOBFVGs[];
|
|
int bearOBFVGsCount = ExtractOBFVGZones(
|
|
htfState,
|
|
mtfState,
|
|
stfState,
|
|
bearOBFVGs,
|
|
X_DIRECTION_BEARISH,
|
|
NULL, // For Period ...
|
|
//
|
|
// Start ...
|
|
XZONE_STATE_PASSED,
|
|
true, // Force Body Out ...
|
|
//
|
|
// Activation ...
|
|
XZONE_STATE_PASSED,
|
|
true, // Force Body In ...
|
|
//
|
|
// Breaktion ...
|
|
XZONE_STATE_FAILED,
|
|
false, // Force Body In ...
|
|
//
|
|
// Works ...
|
|
XZONE_STATE_PASSED,
|
|
true, // Force Body Out ...
|
|
//
|
|
true, // Apply Sort ...
|
|
true, // From Filter ...
|
|
true, // Place Filter ...
|
|
//
|
|
true, // Ignore Inside in Place Filter ...
|
|
//
|
|
true, // Detect Inside OB POI(s) ...
|
|
true, // Detect Inside FVG POI(s) ...
|
|
true // Apply From Filter to Selected POI(s) ...
|
|
);
|
|
bool hasBearOBFVGs = IsValidSize(bearOBFVGsCount);
|
|
|
|
//
|
|
XOBFVG lastBroken;
|
|
bool hasBroken = false;
|
|
int idx = GetYoungest(brokenOrderFlow);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
lastBroken = brokenOrderFlow[idx];
|
|
hasBroken = lastBroken.IsValid();
|
|
}
|
|
|
|
//
|
|
bool hasOrderFlow = hasBearOBFVGs ||
|
|
hasBullOBFVGs;
|
|
if (hasOrderFlow)
|
|
{
|
|
//
|
|
// Vlidate ...
|
|
isValid =
|
|
//
|
|
(hasBullOBFVGs &&
|
|
!hasBearOBFVGs &&
|
|
bullOBFVGsCount >= 1)
|
|
//
|
|
||
|
|
//
|
|
(hasBearOBFVGs &&
|
|
!hasBullOBFVGs &&
|
|
bearOBFVGsCount >= 1)
|
|
//
|
|
;
|
|
|
|
//
|
|
if (isValid)
|
|
{
|
|
//
|
|
if (hasBullOBFVGs)
|
|
{
|
|
//
|
|
Copy(
|
|
bullOBFVGs,
|
|
orderFlow //
|
|
);
|
|
}
|
|
else if (hasBearOBFVGs)
|
|
{
|
|
//
|
|
Copy(
|
|
bearOBFVGs,
|
|
orderFlow //
|
|
);
|
|
}
|
|
|
|
//
|
|
orderFlowDir =
|
|
hasBullOBFVGs
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
bool isPlacePassed = true;
|
|
if (hasBroken)
|
|
{
|
|
//
|
|
bool isBullish = IsBullish(orderFlowDir);
|
|
|
|
//
|
|
idx = GetYoungest(orderFlow);
|
|
bool hasYounget = IsValidIndex(idx);
|
|
|
|
//
|
|
isPlacePassed =
|
|
ArraySize(orderFlow) > 1
|
|
? true
|
|
: isBullish
|
|
? (IsAbove(
|
|
orderFlow[idx].ob,
|
|
lastBroken.ob,
|
|
true // Ignore Inside ...
|
|
))
|
|
: (IsBelow(
|
|
orderFlow[idx].ob,
|
|
lastBroken.ob,
|
|
true // Ignore Inside
|
|
));
|
|
|
|
//
|
|
Clean(brokenOrderFlow);
|
|
AddRef(
|
|
orderFlow[idx],
|
|
brokenOrderFlow //
|
|
);
|
|
}
|
|
|
|
//
|
|
if (!isPlacePassed)
|
|
{
|
|
//
|
|
Clean(orderFlow);
|
|
orderFlowDir = X_DIRECTION_NONE;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(orderFlow);
|
|
}
|
|
}
|
|
|
|
//
|
|
Clean(bullOBFVGs);
|
|
Clean(bearOBFVGs);
|
|
|
|
//
|
|
lastBroken.Clean();
|
|
|
|
//
|
|
if (IsValidSize(result))
|
|
{
|
|
//
|
|
int count = GetSwings(swings);
|
|
bool has = count >= 2;
|
|
bool isBullish = IsBullish(orderFlowDir);
|
|
if (has)
|
|
{
|
|
//
|
|
// Get Max / Min ...
|
|
double max = 0;
|
|
double min = 0;
|
|
datetime maxAt = NULL;
|
|
datetime minAt = NULL;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XOBFVGPivot iPivot = swings[i];
|
|
|
|
//
|
|
if (!iPivot.IsValid())
|
|
{
|
|
//
|
|
iPivot.Clean();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Min ...
|
|
bool canSetMin =
|
|
min == 0
|
|
? true
|
|
: min > iPivot.value;
|
|
if (canSetMin)
|
|
{
|
|
//
|
|
minAt = iPivot.at;
|
|
min = iPivot.value;
|
|
}
|
|
|
|
//
|
|
// Max ...
|
|
bool canSetMax =
|
|
max == 0
|
|
? true
|
|
: max < iPivot.value;
|
|
if (canSetMax)
|
|
{
|
|
//
|
|
maxAt = iPivot.at;
|
|
max = iPivot.value;
|
|
}
|
|
|
|
//
|
|
iPivot.Clean();
|
|
}
|
|
|
|
//
|
|
double price1 =
|
|
isBullish
|
|
? min
|
|
: max;
|
|
double price2 =
|
|
isBullish
|
|
? max
|
|
: min;
|
|
datetime time1 =
|
|
isBullish
|
|
? minAt
|
|
: maxAt;
|
|
datetime time2 =
|
|
isBullish
|
|
? maxAt
|
|
: minAt;
|
|
|
|
//
|
|
color clrTrend = clrNONE;
|
|
|
|
//
|
|
string trendName =
|
|
"XORDFLW" + ToString(orderFlowDir) + "_" + "XTRNDL_" +
|
|
ToString(period) + "_" +
|
|
ToString(price1) + "_" +
|
|
ToString(price2) + "_";
|
|
|
|
//
|
|
orderFlowTrend = new CChartObjectTrend();
|
|
has = orderFlowTrend.Create(
|
|
0,
|
|
trendName,
|
|
0,
|
|
time1,
|
|
price1,
|
|
time2,
|
|
price2 //
|
|
);
|
|
|
|
//
|
|
if (has)
|
|
{
|
|
//
|
|
orderFlowTrend.Width(1);
|
|
orderFlowTrend.Color(clrTrend);
|
|
orderFlowTrend.RayRight(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void AddOrderFlowItem(
|
|
XOBFVG &orderItem //
|
|
)
|
|
{
|
|
//
|
|
ENUM_X_DIRECTION trend;
|
|
if (!HasOrderFlow(trend))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool isSameDir = orderItem
|
|
.GetDirection() == trend;
|
|
if (!isSameDir)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(trend);
|
|
|
|
//
|
|
AddRef(
|
|
orderItem,
|
|
orderFlow //
|
|
);
|
|
|
|
//
|
|
Sort(
|
|
orderFlow,
|
|
trend,
|
|
true // Ignore Inside ...
|
|
);
|
|
}
|
|
|
|
//
|
|
bool IsDestroyed(
|
|
int barIndex = 0,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL bar;
|
|
result = bar.Init(
|
|
symbol,
|
|
period,
|
|
barIndex //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
bar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL cBar;
|
|
result = bar.GetPreviousBar(cBar);
|
|
if (!result)
|
|
{
|
|
//
|
|
bar.Clean();
|
|
cBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isSupplyZoneBreaked =
|
|
//
|
|
bar.low > supplyZone.Upper() &&
|
|
cBar.low > supplyZone.Upper()
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isDemandZoneBreaked =
|
|
//
|
|
bar.high < demandZone.Lower() &&
|
|
cBar.high < demandZone.Lower()
|
|
//
|
|
;
|
|
|
|
//
|
|
bar.Clean();
|
|
cBar.Clean();
|
|
|
|
//
|
|
result = isSupplyZoneBreaked ||
|
|
isDemandZoneBreaked;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool IsOrderFlowBreaked(
|
|
int &breakedIndex,
|
|
bool forceOBBreake = false,
|
|
bool forceFVGBreake = false,
|
|
int barIndex = 0,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
breakedIndex = -1;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION orderFlowDir;
|
|
result = HasOrderFlow(orderFlowDir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL bar;
|
|
result = bar.Init(
|
|
symbol,
|
|
forPeriod,
|
|
barIndex //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
bar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(orderFlowDir);
|
|
|
|
//
|
|
int idx =
|
|
isBullish
|
|
? GetHighest(orderFlow)
|
|
: GetLowest(orderFlow);
|
|
result = IsValidIndex(idx);
|
|
if (!result)
|
|
{
|
|
//
|
|
bar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL obBreakerBar;
|
|
bool isOBBodyOut = false;
|
|
bool isOBBreaked = orderFlow[idx].ob.IsBreaked(
|
|
orderFlowDir,
|
|
obBreakerBar,
|
|
isOBBodyOut,
|
|
false, // Ignore Start ...
|
|
false, // Started Bar Body Out ...
|
|
forPeriod //
|
|
);
|
|
|
|
//
|
|
if (!isOBBreaked)
|
|
{
|
|
obBreakerBar.Clean();
|
|
}
|
|
|
|
//
|
|
XOHCL fvgBreakerBar;
|
|
bool isFVGBodyOut = false;
|
|
bool isFVGBreaked = orderFlow[idx].fvg.IsBreaked(
|
|
orderFlowDir,
|
|
fvgBreakerBar,
|
|
isFVGBodyOut,
|
|
false, // Ignore Start ...
|
|
true, // Started Bar Body Out ...
|
|
forPeriod //
|
|
);
|
|
|
|
//
|
|
if (!isFVGBreaked)
|
|
{
|
|
fvgBreakerBar.Clean();
|
|
}
|
|
|
|
//
|
|
isOBBreaked =
|
|
obBreakerBar.IsValid();
|
|
|
|
//
|
|
isFVGBreaked =
|
|
fvgBreakerBar.IsValid();
|
|
|
|
//
|
|
if ((forceOBBreake && forceFVGBreake) ||
|
|
(!forceOBBreake && !forceFVGBreake))
|
|
{
|
|
//
|
|
result = isOBBreaked ||
|
|
isFVGBreaked;
|
|
}
|
|
else if (forceOBBreake)
|
|
{
|
|
result = isOBBreaked;
|
|
}
|
|
else if (forceFVGBreake)
|
|
{
|
|
result = isFVGBreaked;
|
|
}
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
breakedIndex = idx;
|
|
}
|
|
|
|
//
|
|
bar.Clean();
|
|
obBreakerBar.Clean();
|
|
fvgBreakerBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool DetectPriority(
|
|
ENUM_X121SMC_XWZ_PRIORITY &priority,
|
|
ENUM_X_DIRECTION forDir,
|
|
int barIndex = 0,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
priority = X121SMC_XWZ_PRIORITY_NONE;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
result = IsValid() &&
|
|
HasDirection(forDir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
XOHCL bar;
|
|
result = bar.Init(
|
|
symbol,
|
|
forPeriod,
|
|
barIndex //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
bar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (bar.high < supplyZone.Upper() &&
|
|
bar.low > supplyZone.Lower())
|
|
{
|
|
//
|
|
priority =
|
|
isBullish
|
|
? X121SMC_XWZ_PRIORITY_NONE
|
|
: X121SMC_XWZ_PRIORITY_STRONG_HIGH;
|
|
}
|
|
else if (bar.high < supplyZone.Lower() &&
|
|
bar.low > quarter1)
|
|
{
|
|
//
|
|
priority =
|
|
isBullish
|
|
? X121SMC_XWZ_PRIORITY_WEAK
|
|
: X121SMC_XWZ_PRIORITY_HIGH;
|
|
}
|
|
else if (bar.high < quarter1 &&
|
|
bar.low > quarter2)
|
|
{
|
|
//
|
|
priority =
|
|
isBullish
|
|
? X121SMC_XWZ_PRIORITY_LOW
|
|
: X121SMC_XWZ_PRIORITY_REGULAR;
|
|
}
|
|
else if (bar.high < quarter2 &&
|
|
bar.low > quarter3)
|
|
{
|
|
//
|
|
priority =
|
|
isBullish
|
|
? X121SMC_XWZ_PRIORITY_REGULAR
|
|
: X121SMC_XWZ_PRIORITY_LOW;
|
|
}
|
|
else if (bar.high < quarter3 &&
|
|
bar.low > demandZone.Upper())
|
|
{
|
|
//
|
|
priority =
|
|
isBullish
|
|
? X121SMC_XWZ_PRIORITY_HIGH
|
|
: X121SMC_XWZ_PRIORITY_WEAK;
|
|
}
|
|
else if (bar.high < demandZone.Upper() &&
|
|
bar.low > demandZone.Lower())
|
|
{
|
|
//
|
|
priority =
|
|
isBullish
|
|
? X121SMC_XWZ_PRIORITY_STRONG_HIGH
|
|
: X121SMC_XWZ_PRIORITY_NONE;
|
|
}
|
|
|
|
//
|
|
result = priority != X121SMC_XWZ_PRIORITY_NONE &&
|
|
priority != X121SMC_XWZ_PRIORITY_WEAK;
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
bool HasSupplyZones()
|
|
{
|
|
return HasChild(supplyZones);
|
|
}
|
|
|
|
//
|
|
int CountSupplyZones()
|
|
{
|
|
return ArraySize(supplyZones);
|
|
}
|
|
|
|
//
|
|
bool HasDemandZones()
|
|
{
|
|
return HasChild(demandZones);
|
|
}
|
|
|
|
//
|
|
int CountDemandZones()
|
|
{
|
|
return ArraySize(demandZones);
|
|
}
|
|
|
|
//
|
|
int DetectSupplyZones(
|
|
XPOIState &state //
|
|
)
|
|
{
|
|
//
|
|
int result = CountSupplyZones();
|
|
|
|
bool isValid = state.IsValid() &&
|
|
state.HasSupplyZones();
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XCSupplyZone *tmpZones[];
|
|
Copy(
|
|
state.supplyZones,
|
|
tmpZones //
|
|
);
|
|
int count = FilterZones(
|
|
//
|
|
tmpZones,
|
|
//
|
|
X_DIRECTION_BULLISH,
|
|
state.period,
|
|
NULL,
|
|
//
|
|
// Start ...
|
|
XZONE_STATE_IGNORED,
|
|
false,
|
|
//
|
|
// Activation ...
|
|
XZONE_STATE_IGNORED,
|
|
false,
|
|
//
|
|
// Breake ...
|
|
XZONE_STATE_FAILED,
|
|
false,
|
|
//
|
|
// Work ...
|
|
XZONE_STATE_IGNORED,
|
|
false,
|
|
//
|
|
true, // Apply Sore ...
|
|
true // Ignore Inside ...
|
|
);
|
|
bool has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int idx = -1;
|
|
while (HasChild(tmpZones))
|
|
{
|
|
//
|
|
XCSupplyZone *iZone;
|
|
idx = GetHighest(tmpZones);
|
|
has = IsValidIndex(idx);
|
|
if (!has)
|
|
{
|
|
//
|
|
ZeroMemory(iZone);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
iZone = tmpZones[idx];
|
|
|
|
//
|
|
ArrayRemove(
|
|
tmpZones,
|
|
idx,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
idx = FindIndex(
|
|
iZone,
|
|
supplyZones //
|
|
);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
//
|
|
ZeroMemory(iZone);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
Add(
|
|
iZone,
|
|
supplyZones //
|
|
);
|
|
}
|
|
|
|
//
|
|
int after = CountSupplyZones();
|
|
result = after;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int DetectDemandZones(
|
|
XPOIState &state //
|
|
)
|
|
{
|
|
//
|
|
int result = CountDemandZones();
|
|
|
|
bool isValid = state.IsValid() &&
|
|
state.HasDemandZones();
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XCDemandZone *tmpZones[];
|
|
Copy(
|
|
state.demandZones,
|
|
tmpZones //
|
|
);
|
|
int count = FilterZones(
|
|
//
|
|
tmpZones,
|
|
//
|
|
X_DIRECTION_BEARISH,
|
|
state.period,
|
|
NULL,
|
|
//
|
|
// Start ...
|
|
XZONE_STATE_IGNORED,
|
|
false,
|
|
//
|
|
// Activation ...
|
|
XZONE_STATE_IGNORED,
|
|
false,
|
|
//
|
|
// Breake ...
|
|
XZONE_STATE_FAILED,
|
|
false,
|
|
//
|
|
// Work ...
|
|
XZONE_STATE_IGNORED,
|
|
false,
|
|
//
|
|
true, // Apply Sore ...
|
|
true // Ignore Inside ...
|
|
);
|
|
bool has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int idx = -1;
|
|
while (HasChild(tmpZones))
|
|
{
|
|
//
|
|
XCDemandZone *iZone;
|
|
idx = GetLowest(tmpZones);
|
|
has = IsValidIndex(idx);
|
|
if (!has)
|
|
{
|
|
//
|
|
ZeroMemory(iZone);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
iZone = tmpZones[idx];
|
|
|
|
//
|
|
ArrayRemove(
|
|
tmpZones,
|
|
idx,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
idx = FindIndex(
|
|
iZone,
|
|
demandZones //
|
|
);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
//
|
|
ZeroMemory(iZone);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
Add(
|
|
iZone,
|
|
demandZones //
|
|
);
|
|
}
|
|
|
|
//
|
|
int after = CountDemandZones();
|
|
result = after;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
void UpdateTo(datetime value = NULL)
|
|
{
|
|
//
|
|
value = NormalizeTime(value);
|
|
|
|
//
|
|
int count = 0;
|
|
bool has = false;
|
|
|
|
//
|
|
has = HasSupplyZone();
|
|
if (has)
|
|
{
|
|
supplyZone.To(value);
|
|
}
|
|
|
|
//
|
|
has = HasDemandZone();
|
|
if (has)
|
|
{
|
|
demandZone.To(value);
|
|
}
|
|
|
|
//
|
|
// Order Flow ...
|
|
ENUM_X_DIRECTION orderFlowDir;
|
|
has = HasOrderFlow(orderFlowDir);
|
|
if (has)
|
|
{
|
|
//
|
|
count = CountOrderFlow();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
orderFlow[i].UpdateTo(value);
|
|
}
|
|
}
|
|
|
|
//
|
|
has = HasSupplyZones();
|
|
if (has)
|
|
{
|
|
//
|
|
count = CountSupplyZones();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
supplyZones[i].To(value);
|
|
}
|
|
}
|
|
|
|
//
|
|
has = HasDemandZones();
|
|
if (has)
|
|
{
|
|
//
|
|
count = CountDemandZones();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
demandZones[i].To(value);
|
|
}
|
|
}
|
|
|
|
//
|
|
}
|
|
};
|
|
|
|
//
|
|
// Definitions ...
|
|
struct X121SMCStrategyXWZSignalConditions
|
|
{
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
double sl;
|
|
double reward;
|
|
double amountPercent;
|
|
ENUM_X_DIRECTION dir;
|
|
ENUM_X_POSITION_TYPES type;
|
|
|
|
//
|
|
// Setup Props ...
|
|
|
|
//
|
|
datetime setupTime;
|
|
datetime triggerTime;
|
|
|
|
//
|
|
double pivot;
|
|
double point;
|
|
double targets[];
|
|
|
|
//
|
|
XOBFVG signalZone;
|
|
|
|
//
|
|
ENUM_X121SMC_XWZ_PRIORITY priority;
|
|
ENUM_X121SMC_XWZ_PROVIDERS provider;
|
|
|
|
//
|
|
// Constructor ...
|
|
X121SMCStrategyXWZSignalConditions()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Cleaning Up ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
sl = 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(targets);
|
|
signalZone.Clean();
|
|
|
|
//
|
|
provider = X121SMC_XWZ_PROVIDER_NONE;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
void UpdateTo(datetime value = NULL)
|
|
{
|
|
//
|
|
value = NormalizeTime(value);
|
|
|
|
//
|
|
int count = 0;
|
|
bool has = false;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
// |