1875 lines
42 KiB
Plaintext
1875 lines
42 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_PV_ZONE,
|
|
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,
|
|
};
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
struct X121SMCStrategyXWZWorkingZone
|
|
{
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
double quarter1;
|
|
double quarter2;
|
|
double quarter3;
|
|
|
|
//
|
|
XCSupplyZone *supplyZone;
|
|
XCDemandZone *demandZone;
|
|
|
|
//
|
|
XOBFVG waitingZones[];
|
|
XOBFVG unavailableZones[];
|
|
|
|
//
|
|
CArrayObj mDrawnObjects;
|
|
CArrayObj mWorkingZoneObjects;
|
|
|
|
//
|
|
// Constructor ...
|
|
X121SMCStrategyXWZWorkingZone()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
void Clean()
|
|
{
|
|
//
|
|
quarter1 = 0;
|
|
quarter2 = 0;
|
|
quarter3 = 0;
|
|
|
|
//
|
|
symbol = NULL;
|
|
period = NULL;
|
|
|
|
//
|
|
Clean(waitingZones);
|
|
|
|
//
|
|
ZeroMemory(supplyZone);
|
|
ZeroMemory(demandZone);
|
|
|
|
//
|
|
mDrawnObjects.Clear();
|
|
mWorkingZoneObjects.Clear();
|
|
}
|
|
|
|
//
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
quarter1 > 0 &&
|
|
quarter2 > 0 &&
|
|
quarter3 > 0 &&
|
|
HasSupplyZone() &&
|
|
HasDemandZone() &&
|
|
quarter1 > quarter2 &&
|
|
quarter2 > quarter3
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool Init(
|
|
string _symbol,
|
|
ENUM_TIMEFRAMES _period,
|
|
int barIndex,
|
|
X121SMCStrategySignalProviderData &provider //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(_symbol) &&
|
|
IsValid(_period) &&
|
|
//
|
|
provider.IsValid()
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
symbol = _symbol;
|
|
period = _period;
|
|
|
|
//
|
|
int idx = -1;
|
|
int count = 0;
|
|
bool has = false;
|
|
|
|
//
|
|
XOHCL zBar;
|
|
has = zBar.Init(
|
|
symbol,
|
|
period,
|
|
barIndex //
|
|
);
|
|
result = has;
|
|
if (!result)
|
|
{
|
|
zBar.Clean();
|
|
return result;
|
|
}
|
|
double ll5 = zBar.FindLowest(5, MODE_LOW);
|
|
double hh5 = zBar.FindHighest(5, MODE_HIGH);
|
|
zBar.Clean();
|
|
|
|
//
|
|
// Supply Zone ...
|
|
has = HasSupplyZone();
|
|
if (!has)
|
|
{
|
|
//
|
|
idx = GetHighest(provider
|
|
.consolidationState
|
|
.supplyZones //
|
|
);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
//
|
|
supplyZone = provider
|
|
.consolidationState
|
|
.supplyZones[idx];
|
|
has = hh5 < supplyZone.Lower();
|
|
if (!has)
|
|
{
|
|
supplyZone = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Demand Zone ...
|
|
has = HasDemandZone();
|
|
if (!has)
|
|
{
|
|
//
|
|
idx = GetLowest(provider
|
|
.consolidationState
|
|
.demandZones //
|
|
);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
//
|
|
demandZone = provider
|
|
.consolidationState
|
|
.demandZones[idx];
|
|
has = ll5 > demandZone.Upper();
|
|
if (!has)
|
|
{
|
|
demandZone = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
if (supplyZone != NULL &&
|
|
demandZone != NULL &&
|
|
supplyZone.IsValid() &&
|
|
demandZone.IsValid())
|
|
{
|
|
//
|
|
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);
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool DetectZone(
|
|
X121SMCStrategySignalProviderData &provider //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
provider.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int idx = -1;
|
|
int count = 0;
|
|
bool has = false;
|
|
datetime cTime = TimeCurrent();
|
|
|
|
//
|
|
XOBFVG obFVG;
|
|
XBoxZone obBox;
|
|
XBoxZone fvgBox;
|
|
XBoxZone supplyBox;
|
|
XBoxZone demandBox;
|
|
|
|
//
|
|
XCFVG *fvg = NULL;
|
|
XCOrderBlock *ob = NULL;
|
|
XCSupplyZone *supply = NULL;
|
|
XCDemandZone *demand = NULL;
|
|
|
|
//
|
|
// Check New Supply Zone Detection ...
|
|
bool hasNewSupply =
|
|
Contains(
|
|
X_SUPPLY_ZONE_DETECTED,
|
|
provider.consolidationPoiEvents //
|
|
);
|
|
if (hasNewSupply)
|
|
{
|
|
//
|
|
idx = GetYoungest(provider
|
|
.consolidationState
|
|
.supplyZones //
|
|
);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
//
|
|
supply = provider
|
|
.consolidationState
|
|
.supplyZones[idx];
|
|
has = ToBox(
|
|
supplyBox,
|
|
supply //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
supply.To(cTime);
|
|
supplyBox.to = cTime;
|
|
hasNewSupply = supplyBox.IsValid();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check New Demand Zone Detection ...
|
|
bool hasNewDemand =
|
|
Contains(
|
|
X_DEMAND_ZONE_DETECTED,
|
|
provider
|
|
.consolidationPoiEvents //
|
|
);
|
|
if (hasNewDemand)
|
|
{
|
|
//
|
|
idx = GetYoungest(provider
|
|
.consolidationState
|
|
.demandZones //
|
|
);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
//
|
|
demand = provider
|
|
.consolidationState
|
|
.demandZones[idx];
|
|
has = ToBox(
|
|
demandBox,
|
|
demand //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
demand.To(cTime);
|
|
demandBox.to = cTime;
|
|
hasNewDemand = demandBox.IsValid();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check New Fair Value Gap Detection ...
|
|
bool hasNewFairValueGap =
|
|
Contains(
|
|
X_BULLISH_FVG_DETECTED,
|
|
provider
|
|
.analysePoiEvents //
|
|
) ||
|
|
Contains(
|
|
X_BEARISH_FVG_DETECTED,
|
|
provider
|
|
.analysePoiEvents //
|
|
);
|
|
if (hasNewFairValueGap)
|
|
{
|
|
//
|
|
idx = GetYoungest(provider
|
|
.analyseState
|
|
.fairValueGaps //
|
|
);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
//
|
|
fvg = provider
|
|
.analyseState
|
|
.fairValueGaps[idx];
|
|
has = ToBox(
|
|
fvgBox,
|
|
fvg //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
fvg.To(cTime);
|
|
fvgBox.to = cTime;
|
|
hasNewFairValueGap = fvgBox.IsValid();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check New Order Block Detection ...
|
|
bool hasNewOrderBlock =
|
|
Contains(
|
|
X_BULLISH_ORDERBLOCK_DETECTED,
|
|
provider
|
|
.consolidationPoiEvents //
|
|
) ||
|
|
Contains(
|
|
X_BEARISH_ORDERBLOCK_DETECTED,
|
|
provider
|
|
.consolidationPoiEvents //
|
|
);
|
|
if (hasNewOrderBlock)
|
|
{
|
|
//
|
|
idx = GetYoungest(provider
|
|
.consolidationState
|
|
.orderBlocks //
|
|
);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
//
|
|
ob = provider
|
|
.consolidationState
|
|
.orderBlocks[idx];
|
|
has = ToBox(
|
|
obBox,
|
|
ob //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
ob.To(cTime);
|
|
obBox.to = cTime;
|
|
hasNewOrderBlock = obBox.IsValid();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Detect OB FVG ...
|
|
if (hasNewOrderBlock)
|
|
{
|
|
//
|
|
XOHCL obStartedBar;
|
|
bool isOBStartedBodyOut = false;
|
|
bool isOBStarted = ob.IsStarted(
|
|
ob.GetDirection(),
|
|
obStartedBar,
|
|
isOBStartedBodyOut //
|
|
);
|
|
|
|
//
|
|
has = isOBStarted &&
|
|
isOBStartedBodyOut;
|
|
if (has)
|
|
{
|
|
//
|
|
obFVG.ob = ob;
|
|
|
|
//
|
|
// Select FVGs ...
|
|
count = provider
|
|
.analyseState
|
|
.CountFairValueGaps();
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
obFVG.Clean();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Select FVG ...
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCFVG *iFVG = provider
|
|
.analyseState
|
|
.fairValueGaps[i];
|
|
bool isBullish = iFVG.IsBullish();
|
|
|
|
//
|
|
XOHCL iStartedBar;
|
|
bool isBodyOut = false;
|
|
bool isStarted = iFVG.IsStarted(
|
|
iFVG.GetDirection(),
|
|
iStartedBar,
|
|
isBodyOut //
|
|
);
|
|
iStartedBar.Clean();
|
|
|
|
//
|
|
bool isKindPassed = isStarted &&
|
|
isBodyOut;
|
|
bool isSameDir = iFVG.GetDirection() == ob.GetDirection();
|
|
bool isFromPassed = iFVG.From() >= obStartedBar.time;
|
|
bool isPlacePassed =
|
|
//
|
|
IsInsideOrDiff(
|
|
iFVG,
|
|
ob //
|
|
)
|
|
//
|
|
||
|
|
//
|
|
(isBullish
|
|
? IsAboveDiff(
|
|
iFVG,
|
|
ob,
|
|
true // Ignore Inside ...
|
|
)
|
|
: IsBelowDiff(
|
|
iFVG,
|
|
ob,
|
|
true // Ignore Inside ...
|
|
)
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
has = isSameDir &&
|
|
isKindPassed &&
|
|
isFromPassed &&
|
|
isPlacePassed;
|
|
if (has)
|
|
{
|
|
obFVG.AddFVG(iFVG);
|
|
}
|
|
|
|
//
|
|
ZeroMemory(iFVG);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
has = obFVG.IsValid();
|
|
if (has)
|
|
{
|
|
//
|
|
has = IsExists(obFVG);
|
|
if (!has)
|
|
{
|
|
//
|
|
// New Waiting Zone ...
|
|
AddRef(
|
|
obFVG,
|
|
waitingZones //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Check Item Is not Exists ...
|
|
idx = FindIndex(
|
|
obFVG,
|
|
waitingZones //
|
|
);
|
|
has = !IsValidIndex(idx);
|
|
if (!has)
|
|
{
|
|
//
|
|
// Update Exists Waiting Zone ...
|
|
waitingZones[idx].AddFVG(fvg);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
obFVG.Clean();
|
|
obStartedBar.Clean();
|
|
}
|
|
|
|
//
|
|
result = HasWaitingZones();
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
obFVG.Clean();
|
|
obBox.Clean();
|
|
fvgBox.Clean();
|
|
supplyBox.Clean();
|
|
demandBox.Clean();
|
|
|
|
//
|
|
ZeroMemory(ob);
|
|
ZeroMemory(fvg);
|
|
ZeroMemory(supply);
|
|
ZeroMemory(demand);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int ValidateWaitingZones(
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (barIndex == 0)
|
|
{
|
|
barIndex = 1;
|
|
}
|
|
|
|
//
|
|
has = IsValid() &&
|
|
HasWaitingZones();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int removeIDX[];
|
|
result = CountWaitingZones();
|
|
for (int i = 0; i < result; i++)
|
|
{
|
|
//
|
|
has = waitingZones[i].IsValidZone(
|
|
barIndex //
|
|
);
|
|
if (!has)
|
|
{
|
|
//
|
|
Add(
|
|
i,
|
|
removeIDX //
|
|
);
|
|
|
|
//
|
|
AddRef(
|
|
waitingZones[i],
|
|
unavailableZones //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
has = HasChild(removeIDX);
|
|
if (has)
|
|
{
|
|
//
|
|
CleanupArray(
|
|
removeIDX,
|
|
waitingZones //
|
|
);
|
|
}
|
|
Clean(removeIDX);
|
|
|
|
//
|
|
result = CountWaitingZones();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool IsZoneActivated(
|
|
int &zoneIDX,
|
|
int &fvgIDX,
|
|
X121SMCStrategySignalProviderData &provider,
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
zoneIDX = -1;
|
|
|
|
//
|
|
fvgIDX = -1;
|
|
|
|
//
|
|
// Normalize Bar Index ...
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (barIndex == 0)
|
|
{
|
|
barIndex = 1;
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
result = IsValid() &&
|
|
HasWaitingZones();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL bar;
|
|
result = bar.Init(
|
|
symbol,
|
|
period,
|
|
barIndex //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double peak = provider.decisionXConditions.peaksBuffer[1];
|
|
double vale = provider.decisionXConditions.valesBuffer[1];
|
|
|
|
//
|
|
double analysePeak = provider.analyseXConditions.peaksBuffer[1];
|
|
double analyseVale = provider.analyseXConditions.valesBuffer[1];
|
|
|
|
//
|
|
double consolidationPeak = provider.consolidationXConditions.peaksBuffer[1];
|
|
double consolidationVale = provider.consolidationXConditions.valesBuffer[1];
|
|
|
|
//
|
|
double visionPeak = provider.visionXConditions.peaksBuffer[1];
|
|
double visionVale = provider.visionXConditions.valesBuffer[1];
|
|
|
|
//
|
|
bool isPeaksSame =
|
|
peak == analysePeak &&
|
|
analysePeak == consolidationPeak;
|
|
|
|
//
|
|
bool isValesSame =
|
|
vale == analyseVale &&
|
|
analyseVale == consolidationVale;
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
bool isDecisionScoreBullish =
|
|
provider.decisionBullishScore > provider.decisionBearishScore;
|
|
|
|
//
|
|
bool isDecisionScoreBearish =
|
|
provider.decisionBearishScore > provider.decisionBullishScore;
|
|
|
|
//
|
|
bool isAnalyseScoreBullish =
|
|
provider.analyseBullishScore > provider.analyseBearishScore;
|
|
|
|
//
|
|
bool isAnalyseScoreBearish =
|
|
provider.analyseBearishScore > provider.analyseBullishScore;
|
|
|
|
//
|
|
bool isConsolidationScoreBullish =
|
|
provider.consolidationBullishScore > provider.consolidationBearishScore;
|
|
|
|
//
|
|
bool isConsolidationScoreBearish =
|
|
provider.consolidationBearishScore > provider.consolidationBullishScore;
|
|
|
|
//
|
|
bool isVisionScoreBullish =
|
|
provider.visionBullishScore > provider.visionBearishScore;
|
|
|
|
//
|
|
bool isVisionScoreBearish =
|
|
provider.visionBearishScore > provider.visionBullishScore;
|
|
|
|
//
|
|
int count = CountWaitingZones();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XOBFVG iOBFVG = waitingZones[i];
|
|
|
|
//
|
|
ENUM_X_DIRECTION iDir = iOBFVG.GetDirection();
|
|
bool isBullish = iOBFVG.IsBullish();
|
|
|
|
//
|
|
int fvgsCount = iOBFVG.CountFVGs();
|
|
bool has = IsValidSize(fvgsCount);
|
|
if (has)
|
|
{
|
|
//
|
|
for (int j = 0; j < fvgsCount; j++)
|
|
{
|
|
//
|
|
XCFVG *jFVG = iOBFVG.fvgs[j];
|
|
|
|
//
|
|
XBoxZone iBox;
|
|
has = ToBox(
|
|
iBox,
|
|
jFVG //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
double iRange = iBox.lower + ((iBox.upper - iBox.lower) / 2);
|
|
|
|
//
|
|
// Activate Zone Using PV ...
|
|
bool isPVPassed =
|
|
isBullish
|
|
? vale < iBox.upper &&
|
|
vale > iBox.lower
|
|
: peak < iBox.upper &&
|
|
peak > iBox.lower;
|
|
bool isPV50Passed =
|
|
isBullish
|
|
? vale < iBox.upper &&
|
|
vale < iRange &&
|
|
vale > iBox.lower
|
|
: peak < iBox.upper &&
|
|
peak < iRange &&
|
|
peak > iBox.lower;
|
|
|
|
//
|
|
// Activate Zone using Rejection ...
|
|
bool isRejected =
|
|
isBullish
|
|
? bar.low <= iBox.upper &&
|
|
bar.GetDown() > iBox.upper
|
|
: bar.high >= iBox.lower &&
|
|
bar.GetUp() < iBox.lower;
|
|
|
|
//
|
|
// Combine Result ...
|
|
result = isPV50Passed;
|
|
// || isPV50Passed
|
|
// || isRejected;
|
|
if (result)
|
|
{
|
|
//
|
|
fvgIDX = j;
|
|
iBox.Clean();
|
|
zoneIDX = i;
|
|
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
iBox.Clean();
|
|
ZeroMemory(jFVG);
|
|
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
iBox.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
iOBFVG.Clean();
|
|
break;
|
|
}
|
|
|
|
//
|
|
iOBFVG.Clean();
|
|
}
|
|
|
|
//
|
|
result =
|
|
IsValidIndex(fvgIDX) &&
|
|
IsValidIndex(zoneIDX);
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
bar.Clean();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool IsExists(XOBFVG &zone)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Check Validation ...
|
|
result = HasWaitingZones() ||
|
|
HasUnavailableZones();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int idx = -1;
|
|
|
|
//
|
|
// Check Index in Waiting Zones ...
|
|
idx = FindIndex(
|
|
zone,
|
|
waitingZones //
|
|
);
|
|
result = IsValidIndex(idx);
|
|
if (result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Index in Unavailable Zones ...
|
|
idx = FindIndex(
|
|
zone,
|
|
unavailableZones //
|
|
);
|
|
result = IsValidIndex(idx);
|
|
if (result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
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 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 DetectOveralDirection(
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
HasSupplyZone() &&
|
|
HasDemandZone();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XBoxZone demBox;
|
|
XBoxZone supBox;
|
|
result = ToBox(
|
|
demBox,
|
|
demandZone //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
supBox.Clean();
|
|
demBox.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
result = ToBox(
|
|
supBox,
|
|
supplyZone //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
supBox.Clean();
|
|
demBox.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL supPriceOutBar;
|
|
XOHCL demPriceOutBar;
|
|
result = DetectBoxNearestPriceOut(
|
|
supBox,
|
|
supPriceOutBar,
|
|
period //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
demBox.Clean();
|
|
supBox.Clean();
|
|
supPriceOutBar.Clean();
|
|
demPriceOutBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
result = DetectBoxNearestPriceOut(
|
|
demBox,
|
|
demPriceOutBar,
|
|
period //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
demBox.Clean();
|
|
supBox.Clean();
|
|
supPriceOutBar.Clean();
|
|
demPriceOutBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Specified Direction ...
|
|
dir =
|
|
(supPriceOutBar.IsValid() &&
|
|
demPriceOutBar.IsValid())
|
|
? supPriceOutBar.time > demPriceOutBar.time
|
|
? X_DIRECTION_BEARISH
|
|
: demPriceOutBar.time > supPriceOutBar.time
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_NONE
|
|
: X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = HasDirection(dir);
|
|
|
|
//
|
|
// Clean Up Resources ...
|
|
|
|
//
|
|
demBox.Clean();
|
|
supBox.Clean();
|
|
supPriceOutBar.Clean();
|
|
demPriceOutBar.Clean();
|
|
|
|
//
|
|
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);
|
|
}
|
|
|
|
//
|
|
has = HasWaitingZones();
|
|
if (has)
|
|
{
|
|
//
|
|
count = CountWaitingZones();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
waitingZones[i].UpdateTo(value);
|
|
}
|
|
}
|
|
|
|
//
|
|
}
|
|
|
|
//
|
|
void Draw(
|
|
XCPOIDrawer *drawer,
|
|
bool drawSupplyZone = false,
|
|
bool drawDemandZone = false,
|
|
bool drawWaitingZones = false,
|
|
bool drawWaitingZonesBoxArea = false //
|
|
)
|
|
{
|
|
//
|
|
if (drawer == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int count = 0;
|
|
bool has = false;
|
|
bool isCreated = false;
|
|
|
|
//
|
|
ulong chartID = drawer.ChartIdentification();
|
|
int subWindow = drawer.SubWindowIdentification();
|
|
color bullishColor = drawer.BarBullishColor();
|
|
color bearishColor = drawer.BarBearishColor();
|
|
|
|
//
|
|
// Supply Zone ...
|
|
if (drawSupplyZone)
|
|
{
|
|
//
|
|
has = HasSupplyZone();
|
|
if (has)
|
|
{
|
|
//
|
|
XCSupplyZoneObject *iObj;
|
|
isCreated = drawer.CreateSupplyZone(
|
|
supplyZone,
|
|
iObj //
|
|
);
|
|
|
|
//
|
|
if (isCreated)
|
|
{
|
|
mWorkingZoneObjects.Add(iObj);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Demand Zone ...
|
|
if (drawDemandZone)
|
|
{
|
|
//
|
|
has = HasDemandZone();
|
|
if (has)
|
|
{
|
|
//
|
|
XCDemandZoneObject *iObj;
|
|
isCreated = drawer.CreateDemandZone(
|
|
demandZone,
|
|
iObj //
|
|
);
|
|
|
|
//
|
|
if (isCreated)
|
|
{
|
|
mWorkingZoneObjects.Add(iObj);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
// Quarters ...
|
|
has = IsValid();
|
|
if (has)
|
|
{
|
|
//
|
|
double zoneUpper = supplyZone.Upper();
|
|
double upper = supplyZone.Lower();
|
|
|
|
//
|
|
double lower = demandZone.Upper();
|
|
double zoneLower = demandZone.Lower();
|
|
|
|
//
|
|
string prefix = "X121WZone_" + symbol + "_" + ToString(period);
|
|
|
|
//
|
|
// Zone Upper ...
|
|
CChartObjectHLine *zoneUpperLine;
|
|
zoneUpperLine = new CChartObjectHLine();
|
|
isCreated = zoneUpperLine.Create(
|
|
chartID,
|
|
prefix + "_ZoneTop",
|
|
subWindow,
|
|
zoneUpper //
|
|
);
|
|
if (isCreated)
|
|
{
|
|
//
|
|
zoneUpperLine.Color(clrRed);
|
|
|
|
//
|
|
mWorkingZoneObjects.Add(zoneUpperLine);
|
|
}
|
|
|
|
//
|
|
// Zone Lower ...
|
|
CChartObjectHLine *zoneLowerLine;
|
|
zoneLowerLine = new CChartObjectHLine();
|
|
isCreated = zoneLowerLine.Create(
|
|
chartID,
|
|
prefix + "_ZoneDown",
|
|
subWindow,
|
|
zoneLower //
|
|
);
|
|
if (isCreated)
|
|
{
|
|
//
|
|
zoneLowerLine.Color(clrRed);
|
|
|
|
//
|
|
mWorkingZoneObjects.Add(zoneLowerLine);
|
|
}
|
|
|
|
//
|
|
// Upper ...
|
|
CChartObjectHLine *upperLine;
|
|
upperLine = new CChartObjectHLine();
|
|
isCreated = upperLine.Create(
|
|
chartID,
|
|
prefix + "_Upper",
|
|
subWindow,
|
|
upper //
|
|
);
|
|
if (isCreated)
|
|
{
|
|
//
|
|
upperLine.Color(clrLime);
|
|
|
|
//
|
|
mWorkingZoneObjects.Add(upperLine);
|
|
}
|
|
|
|
//
|
|
// Lower ...
|
|
CChartObjectHLine *lowerLine;
|
|
lowerLine = new CChartObjectHLine();
|
|
isCreated = lowerLine.Create(
|
|
chartID,
|
|
prefix + "_Lower",
|
|
subWindow,
|
|
lower //
|
|
);
|
|
if (isCreated)
|
|
{
|
|
//
|
|
lowerLine.Color(clrLime);
|
|
|
|
//
|
|
mWorkingZoneObjects.Add(lowerLine);
|
|
}
|
|
|
|
//
|
|
// Quarters ...
|
|
|
|
//
|
|
// Quarter 1 ...
|
|
CChartObjectHLine *q1Line;
|
|
q1Line = new CChartObjectHLine();
|
|
isCreated = q1Line.Create(
|
|
chartID,
|
|
prefix + "_Q1",
|
|
subWindow,
|
|
quarter1 //
|
|
);
|
|
if (isCreated)
|
|
{
|
|
//
|
|
q1Line.Color(clrYellow);
|
|
|
|
//
|
|
mWorkingZoneObjects.Add(q1Line);
|
|
}
|
|
|
|
//
|
|
// Quarter 2 ...
|
|
CChartObjectHLine *q2Line;
|
|
q2Line = new CChartObjectHLine();
|
|
isCreated = q2Line.Create(
|
|
chartID,
|
|
prefix + "_Q2",
|
|
subWindow,
|
|
quarter2 //
|
|
);
|
|
if (isCreated)
|
|
{
|
|
//
|
|
q2Line.Color(clrYellow);
|
|
|
|
//
|
|
mWorkingZoneObjects.Add(q2Line);
|
|
}
|
|
|
|
//
|
|
// Quarter 3 ...
|
|
CChartObjectHLine *q3Line;
|
|
q3Line = new CChartObjectHLine();
|
|
isCreated = q3Line.Create(
|
|
chartID,
|
|
prefix + "_Q3",
|
|
subWindow,
|
|
quarter3 //
|
|
);
|
|
if (isCreated)
|
|
{
|
|
//
|
|
q3Line.Color(clrYellow);
|
|
|
|
//
|
|
mWorkingZoneObjects.Add(q3Line);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Waiting Zones ...
|
|
if (drawWaitingZones)
|
|
{
|
|
//
|
|
has = HasWaitingZones();
|
|
if (has)
|
|
{
|
|
//
|
|
count = CountWaitingZones();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCBaseObject *iObjects[];
|
|
int iObjectsCount = drawer.DrawOBFVG(
|
|
waitingZones[i],
|
|
iObjects,
|
|
true, // Draw Order Block ...
|
|
true, // Draw Fair Value Gaps ...
|
|
true, // Draw All Fair Value Gaps ...
|
|
//
|
|
true, // Draw OB StartedBar ...
|
|
true, // Draw OB ActivatedBar ...
|
|
true, // Draw OB BreakedBar ...
|
|
true, // Draw OB WorkedBar ...
|
|
//
|
|
true, // Draw FVG StartedBar ...
|
|
true, // Draw FVG ActivatedBar ...
|
|
true, // Draw FVG BreakedBar ...
|
|
true // Draw FVG WorkedBar ...
|
|
//
|
|
);
|
|
has = IsValidSize(iObjectsCount);
|
|
if (has)
|
|
{
|
|
//
|
|
for (int j = 0; j < iObjectsCount; j++)
|
|
{
|
|
mDrawnObjects.Add(iObjects[j]);
|
|
}
|
|
}
|
|
|
|
//
|
|
if (drawWaitingZonesBoxArea)
|
|
{
|
|
//
|
|
XBoxZone iBox;
|
|
has = waitingZones[i].ToZone(
|
|
iBox //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
XCBoxObject *iBoxObj;
|
|
has = drawer.DrawBox(
|
|
iBox,
|
|
iBoxObj //
|
|
);
|
|
if (has)
|
|
{
|
|
mDrawnObjects.Add(iBoxObj);
|
|
}
|
|
}
|
|
|
|
//
|
|
iBox.Clean();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
bool HasSupplyZone()
|
|
{
|
|
return supplyZone != NULL &&
|
|
supplyZone.IsValid();
|
|
}
|
|
|
|
//
|
|
bool HasDemandZone()
|
|
{
|
|
return demandZone != NULL &&
|
|
demandZone.IsValid();
|
|
}
|
|
|
|
//
|
|
bool HasWaitingZones()
|
|
{
|
|
return HasChild(waitingZones);
|
|
}
|
|
|
|
//
|
|
int CountWaitingZones()
|
|
{
|
|
return ArraySize(waitingZones);
|
|
}
|
|
|
|
//
|
|
bool HasUnavailableZones()
|
|
{
|
|
return HasChild(unavailableZones);
|
|
}
|
|
|
|
//
|
|
int CounUnavailableZones()
|
|
{
|
|
return ArraySize(unavailableZones);
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
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 sls[];
|
|
double targets[];
|
|
|
|
//
|
|
XBoxZone signalBox;
|
|
|
|
//
|
|
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(sls);
|
|
Clean(targets);
|
|
signalBox.Clean();
|
|
|
|
//
|
|
provider = X121SMC_XWZ_PROVIDER_NONE;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
void UpdateTo(datetime value = NULL)
|
|
{
|
|
//
|
|
value = NormalizeTime(value);
|
|
|
|
//
|
|
int count = 0;
|
|
bool has = false;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Extension Functions ...
|
|
|
|
// |