Files
MQL5Data/X121SMCEA/Strategy/x-121.smc.test.strategy.class.mq5
T
2024-11-04 01:36:42 +03:30

2366 lines
137 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// --------------------------------------
// Name: XCX121SMCTestStrategy
// Description: provides all based classes for use ...
//
//
// 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 "../../Helpers/x-saherelm.xchvwap.helper.mq5"
#include "../Classes/x-121.smc.base.strategy.class.mq5"
//
// Helper(s) ...
//
// XStrategy Class Implementation(s) ...
class XCX121SMCTestStrategy : public XCX121SMCBaseStrategy
{
//
// Public ...
public:
//
//
// Constructor(s) ...
void XCX121SMCTestStrategy(
//
// Base ...
string _symbol, // Trading Symbol
ENUM_TIMEFRAMES _period // Trading TimeFrame
)
: XCX121SMCBaseStrategy(_symbol, _period)
{
InitialHelpers();
}
//
// Overrides Actions ...
//
// Check Conditions For Signal ...
bool HasSignal(
XSignal &signal,
X121SMCStrategyConditions &conditions //
) override
{
//
bool result = false;
//
signal.Clean();
conditions.Clean();
//
int pushers = 0;
//
double sl = 0;
double tp = 0;
double risk = 0;
double entry = 0;
double reward = 0;
double r2r = R2R();
double volume = Volume();
ENUM_POSITION_TYPE type = POSITION_TYPE_BUY;
ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET;
//
bool hasLong = false;
bool hasShort = false;
//
// Start Calculations ...
//
string _symbol = GetSymbol();
ENUM_TIMEFRAMES _period = GetPeriod();
//
double points = GetPoints(_symbol);
//
int zIndex = 0;
int cIndex = zIndex + 1;
int pIndex = cIndex + 1;
int ppIndex = pIndex + 1;
//
// Retrieve Bars ...
//
// Zero Bar ...
XOHCL zBar;
result = zBar.Init(
_symbol,
_period,
zIndex //
);
if (!result)
{
return result;
}
//
// Last Bar ...
XOHCL cBar;
result = cBar.Init(
_symbol,
_period,
cIndex //
);
if (!result)
{
return result;
}
//
// Previous Bar ...
XOHCL pBar;
result = pBar.Init(
_symbol,
_period,
pIndex //
);
if (!result)
{
return result;
}
//
bool isSpreadPassed = IsSpreadPass();
result = isSpreadPassed;
if (!result)
{
return result;
}
//
// Try to Implement SMC Based Conditions ...
//
// 1- First Step is Find a Supply and Demand Zone ...
// - [] this Zone must be Fresh ...
// - [] contains Engulfing ...
// - [] has Order Block ...
// - [] has FVG ...
bool isDetected = DetecConditions(conditions);
if (isDetected)
{
//
// Check Conditions for Removing Exists ...
RemoveConditionsIfExists(conditions);
//
// Add New Condition ...
AddRef(
conditions,
mConditions //
);
}
//
conditions.Clean();
//
// Check Conditions for Signal ...
int conditionsCount = ArraySize(mConditions);
if (!IsValidSize(conditionsCount))
{
//
result = false;
return result;
}
//
// Remove Invalid Conditions ...
X121SMCStrategyConditions tmpConditions[];
Copy(
mConditions,
tmpConditions //
);
for (int i = 0; i < conditionsCount; i++)
{
//
X121SMCStrategyConditions iConditions = tmpConditions[i];
//
// Check Demand ...
if (iConditions.ValidateDemand())
{
//
// Check Bars ...
bool isInValid =
pBar.high < iConditions.demandZone.lower &&
cBar.high < iConditions.demandZone.lower &&
zBar.high < iConditions.demandZone.lower;
//
if (isInValid)
{
iConditions.CleanDemand();
}
}
//
// Check Supply ...
if (iConditions.ValidateSupply())
{
//
// Check Bars ...
bool isInValid =
pBar.low > iConditions.demandZone.upper &&
cBar.low > iConditions.demandZone.upper &&
zBar.low > iConditions.demandZone.upper;
//
if (isInValid)
{
iConditions.CleanSupply();
}
}
//
bool isInValid = !iConditions.ValidateDemand() &&
iConditions.ValidateSupply();
if (isInValid)
{
//
ArrayRemove(
mConditions,
i,
1 //
);
}
}
//
Clean(tmpConditions);
conditionsCount = ArraySize(mConditions);
if (!IsValidSize(conditionsCount))
{
//
result = false;
return result;
}
//
// Loop through Conditions for Filter Based on POIs ...
int conditionsIDX = -1;
for (int i = 0; i < conditionsCount; i++)
{
//
result = false;
hasLong = false;
hasShort = false;
X121SMCStrategyConditions iConditions = mConditions[i];
//
X121SMCMarketStructure structure;
DetectMarketStructure(
structure,
iConditions //
);
//
bool isAllowLong = AllowLong();
bool isAllowShort = AllowShort();
result = isAllowLong || isAllowShort;
if (!result)
{
break;
}
//
bool hasValidDemand = iConditions.ValidateDemand();
bool hasValidSupply = iConditions.ValidateSupply();
result = hasValidDemand || hasValidSupply;
if (!result)
{
break;
}
//
// Reading Indicator's Conditions ...
XCHVWAPConditions chvwapConditions;
chvwapHelper.GetConditions(
chvwapConditions,
cIndex //
);
//
double selectedDemandUpper = MathMax(
iConditions.bullishOrderBlock.upper,
iConditions.bullishFVG.upper);
double selectedDemandLower = MathMax(
iConditions.bullishOrderBlock.lower,
iConditions.bullishFVG.lower);
//
double selectedSupplyUpper = MathMax(
iConditions.bearishOrderBlock.upper,
iConditions.bearishFVG.upper);
double selectedSupplyLower = MathMax(
iConditions.bearishOrderBlock.lower,
iConditions.bearishFVG.lower);
//
bool isPriceInsideDemandZone =
hasValidDemand &&
pBar.high < selectedDemandUpper &&
(pBar.low > selectedDemandLower ||
cBar.low > selectedDemandLower);
bool isPriceInsideSupplyZone =
hasValidSupply &&
pBar.low > selectedSupplyLower &&
(pBar.high < selectedSupplyUpper ||
cBar.high < selectedSupplyUpper);
//
bool isTicksBullish = IsTicksBullish();
bool isTicksBearish = IsTicksBearish();
bool isTicksHasMomentum = IsTicksHasMomentum();
//
double pricateChangeRate = 0.01;
double priceChange = GetPriceChanged(
GetSymbol(),
GetPeriod(),
0,
7 //
);
bool isBullishPriceChanged = priceChange >= pricateChangeRate;
bool isBearishPriceChanged = priceChange < 0 &&
MathAbs(priceChange) >= pricateChangeRate;
//
double _1Pip = GetPipPrice(iConditions.symbol);
//
// Longs ...
bool canCheckLong = isAllowLong &&
hasValidDemand &&
isTicksBullish &&
isTicksHasMomentum &&
isBullishPriceChanged &&
isPriceInsideDemandZone;
if (canCheckLong)
{
//
hasLong = false;
type = POSITION_TYPE_BUY;
entry = GetEntry(_symbol, type);
//
double slCandidates[];
int slCandidatesCount = DetectSLCandidates(
slCandidates,
entry,
iConditions,
X_POSITION_TYPE_LONG //
);
//
// Find Good Entry ...
hasLong = slCandidatesCount >= 3;
//
if (hasLong)
{
//
pushers = slCandidatesCount;
double selectedSL = GetMin(slCandidates);
sl = selectedSL - (5 * _1Pip);
risk = entry - sl;
reward = risk * r2r;
tp = entry + reward;
//
conditionsIDX = i;
conditions = mConditions[i];
mConditions[i].CleanDemand();
//
break;
}
}
//
// Shorts ...
bool canCheckShort = isAllowShort &&
hasValidSupply &&
isTicksBearish &&
isTicksHasMomentum &&
isBearishPriceChanged &&
isPriceInsideSupplyZone;
if (canCheckShort)
{
//
hasShort = false;
type = POSITION_TYPE_SELL;
entry = GetEntry(_symbol, type);
//
double slCandidates[];
int slCandidatesCount = DetectSLCandidates(
slCandidates,
entry,
iConditions,
X_POSITION_TYPE_SHORT //
);
//
// Find Good Entry ...
hasShort = slCandidatesCount >= 3;
//
if (hasShort)
{
//
pushers = slCandidatesCount;
double selectedSL = GetMin(slCandidates);
sl = selectedSL + (5 * _1Pip);
risk = sl - entry;
reward = risk * r2r;
tp = entry - reward;
//
conditionsIDX = i;
conditions = mConditions[i];
mConditions[i].CleanSupply();
//
break;
}
}
}
//
result = hasLong ||
hasShort;
//
// Rmove Signal Condition ...
if (result)
{
//
signal.sl = sl;
signal.tp = tp;
signal.type = type;
signal.mode = mode;
signal.entry = entry;
signal.volume = volume;
signal.symbol = _symbol;
signal.pushers = pushers;
signal.provider = GetTag();
signal.time = TimeCurrent();
signal.period = _5MState.period;
//
result = PrepareSignal(signal);
//
hasLong = false;
hasShort = false;
//
if (IsValidIndex(conditionsIDX))
{
//
ArrayRemove(
mConditions,
conditionsIDX,
1 //
);
}
//
DrawConditions(conditions);
}
//
return result;
}
/**
* Detect Valid Market Conditions ...
*
* @param conditions: X121SMCStrategyConditions instance ...
*/
bool DetecConditions(X121SMCStrategyConditions &conditions) override
{
//
bool result = false;
//
// Prepare Conditions ...
//
datetime time = TimeCurrent();
//
conditions.Clean();
conditions.time = time;
conditions.symbol = GetSymbol();
conditions.period = GetPeriod();
// //
// bool d1HasBullishTrend = HasBullishTrend(d1State);
// bool d1HasBearishTrend = HasBearishTrend(d1State);
// //
// bool h4HasBullishTrend = HasBullishTrend(h4State);
// bool h4HasBearishTrend = HasBearishTrend(h4State);
// //
// bool m15HasBullishTrend = HasBullishTrend(_15MState);
// bool m15HasBearishTrend = HasBearishTrend(_15MState);
// //
// bool m5HasBullishTrend = HasBullishTrend(m5State);
// bool m5HasBearishTrend = HasBearishTrend(m5State);
// //
// bool m1HasBullishTrend = HasBullishTrend(m1State);
// bool m1HasBearishTrend = HasBearishTrend(m1State);
// //
// bool isBullishTrendValid = h4HasBullishTrend &&
// m15HasBullishTrend &&
// m1HasBullishTrend;
// if (isBullishTrendValid)
// {
// Print("isBullishTrendValid");
// }
// //
// bool isBearishTrendValid = h4HasBearishTrend &&
// m15HasBearishTrend &&
// m1HasBearishTrend;
// if (isBearishTrendValid)
// {
// Print("isBearishTrendValid");
// }
//
int supplyZonesCount = ArraySize(_15MState.supplyZones);
int demandZonesCount = ArraySize(_15MState.demandZones);
result =
IsValidSize(demandZonesCount) ||
IsValidSize(supplyZonesCount);
if (!result)
{
return result;
}
//
bool checkDemands = true;
bool checkSupplies = true;
//
// Demand Zone ...
if (checkDemands)
{
//
for (int i = 0; i < demandZonesCount; i++)
{
//
// Demand Zone ...
XZone iDemandZone = _15MState.demandZones[i];
iDemandZone.to = time;
conditions.demandZone = iDemandZone;
conditions.bullishOrderBlock.Clean();
conditions.bullishFVG.Clean();
//
// Bullish Order Block ...
int obCount = ArraySize(_15MState.bullishOrderBlocks);
if (IsValidSize(obCount))
{
//
for (int j = 0; j < obCount; j++)
{
//
XZone jZone = _15MState.bullishOrderBlocks[j];
//
bool isBreaked = IsBreakeUpper(
jZone,
iDemandZone //
);
if (isBreaked)
{
//
jZone.to = time;
conditions.bullishOrderBlock = jZone;
//
break;
}
}
}
//
// Validate Order Block ...
bool isValidOrderBlock = conditions.bullishOrderBlock.IsValid();
if (!isValidOrderBlock)
{
continue;
}
//
// Bullish FVG ...
int fairValueGapsCount = ArraySize(_15MState.bullishFVGs);
if (IsValidSize(fairValueGapsCount))
{
//
for (int j = 0; j < fairValueGapsCount; j++)
{
//
XZone jZone = _15MState.bullishFVGs[j];
//
bool isBreaked = IsBreakeUpper(
jZone,
conditions.bullishOrderBlock //
);
if (isBreaked)
{
//
jZone.to = time;
conditions.bullishFVG = jZone;
//
break;
}
}
}
//
// Validate FVG ...
bool isValidFVG = conditions.bullishFVG.IsValid();
if (!isValidFVG)
{
continue;
}
//
// Detect Inside Demand POIs ...
//
// Order Blocks ...
// CState ...
int orderBlocksCount = ArraySize(_CombineState.bullishOrderBlocks);
if (IsValidSize(orderBlocksCount))
{
//
for (int j = 0; j < orderBlocksCount; j++)
{
//
XZone jZone = _CombineState.bullishOrderBlocks[j];
//
bool isInside = IsInside(
jZone,
iDemandZone,
X_ZONE_LOWER_EDGE,
true //
);
if (isInside)
{
//
jZone.to = TimeCurrent();
//
AddIfNotExists(
jZone,
conditions.bullishOrderBlocks //
);
}
}
}
//
// Support Zones ...
// CState ...
int supportsCount = ArraySize(_CombineState.supportZones);
if (IsValidSize(supportsCount))
{
//
for (int j = 0; j < supportsCount; j++)
{
//
XOHCL jBar = _CombineState.supportZones[j];
//
bool isInside = IsInside(
jBar,
iDemandZone,
X_ZONE_LOWER_EDGE,
true //
);
if (isInside)
{
//
AddIfNotExists(
jBar,
conditions.supports //
);
}
}
}
//
// Fair Value Gaps ...
// CState ...
int fvgsCount = ArraySize(_CombineState.bullishFVGs);
if (IsValidSize(fvgsCount))
{
//
for (int j = 0; j < fvgsCount; j++)
{
//
XZone jFVG = _CombineState.bullishFVGs[j];
//
bool isInside = IsInside(
jFVG,
iDemandZone,
X_ZONE_LOWER_EDGE,
true //
);
if (isInside)
{
//
jFVG.to = TimeCurrent();
//
AddIfNotExists(
jFVG,
conditions.bullishFVGs //
);
}
}
}
//
// Swings ...
// CState ...
int swingsCount = ArraySize(_CombineState.swingLows);
if (IsValidSize(swingsCount))
{
//
for (int j = 0; j < swingsCount; j++)
{
//
XOHCL jBar = _CombineState.swingLows[j];
//
bool isInside = IsInside(
jBar,
iDemandZone,
X_ZONE_LOWER_EDGE,
true //
);
if (isInside)
{
//
AddIfNotExists(
jBar,
conditions.swingLows //
);
}
}
}
//
// Momentum Bars ...
// CState ...
int momentumBarsCount = ArraySize(_CombineState.momentumBars);
if (IsValidSize(momentumBarsCount))
{
//
for (int j = 0; j < momentumBarsCount; j++)
{
//
XOHCL jBar = _CombineState.momentumBars[j];
//
bool isInside =
jBar.IsBullish() &&
jBar.time > iDemandZone.from &&
IsInside(
jBar,
iDemandZone,
X_ZONE_LOWER_EDGE,
true //
);
if (isInside)
{
//
AddIfNotExists(
jBar,
conditions.bullishMomentumBars //
);
}
}
}
//
// Rejection Bars ...
// CState ...
int rejectionBarsCount = ArraySize(_CombineState.rejectionBars);
if (IsValidSize(rejectionBarsCount))
{
//
for (int j = 0; j < rejectionBarsCount; j++)
{
//
XOHCL jBar = _CombineState.rejectionBars[j];
//
bool isInside =
jBar.GetLowShadow() > jBar.GetHighShadow() &&
jBar.time > iDemandZone.from &&
IsInside(
jBar,
iDemandZone,
X_ZONE_LOWER_EDGE,
true //
);
if (isInside)
{
//
AddIfNotExists(
jBar,
conditions.bullishRejectionBars //
);
}
}
}
//
bool hasValidDemandZone = conditions.ValidateDemand();
if (!hasValidDemandZone)
{
conditions.CleanDemand();
}
else
{
break;
}
}
}
//
// Supply Zone ...
if (checkSupplies)
{
//
for (int i = 0; i < supplyZonesCount; i++)
{
//
// Supply Zone ...
XZone iSupplyZone = _15MState.supplyZones[i];
iSupplyZone.to = time;
conditions.supplyZone = iSupplyZone;
conditions.bearishOrderBlock.Clean();
conditions.bearishFVG.Clean();
//
// Bearish Order Block ...
int obCount = ArraySize(_15MState.bearishOrderBlocks);
if (IsValidSize(obCount))
{
//
for (int j = 0; j < obCount; j++)
{
//
XZone jZone = _15MState.bearishOrderBlocks[j];
//
bool isBreaked = IsBreakeLower(
jZone,
iSupplyZone //
);
if (isBreaked)
{
//
jZone.to = time;
conditions.bearishOrderBlock = jZone;
//
break;
}
}
}
//
// Validate Order Block ...
bool isValidOrderBlock = conditions.bearishOrderBlock.IsValid();
if (!isValidOrderBlock)
{
continue;
}
//
// Bearish FVG ...
int fairValueGapsCount = ArraySize(_15MState.bearishFVGs);
if (IsValidSize(fairValueGapsCount))
{
//
for (int j = 0; j < fairValueGapsCount; j++)
{
//
XZone jZone = _15MState.bearishFVGs[j];
//
bool isBreaked = IsBreakeLower(
jZone,
conditions.bearishOrderBlock //
);
if (isBreaked)
{
//
jZone.to = time;
conditions.bearishFVG = jZone;
//
break;
}
}
}
//
// Validate FVG ...
bool isValidFVG = conditions.bearishFVG.IsValid();
if (!isValidFVG)
{
continue;
}
//
// Detect Inside Demand POIs ...
//
// Order Blocks ...
// CState ...
int orderBlocksCount = ArraySize(_CombineState.bearishOrderBlocks);
if (IsValidSize(orderBlocksCount))
{
//
for (int j = 0; j < orderBlocksCount; j++)
{
//
XZone jZone = _CombineState.bearishOrderBlocks[j];
//
bool isInside = IsInside(
jZone,
iSupplyZone,
X_ZONE_UPPER_EDGE,
true //
);
if (isInside)
{
//
jZone.to = TimeCurrent();
//
AddIfNotExists(
jZone,
conditions.bearishOrderBlocks //
);
}
}
}
//
// Resistance Zones ...
// CState ...
int resistancesCount = ArraySize(_CombineState.resistanceZones);
if (IsValidSize(resistancesCount))
{
//
for (int j = 0; j < resistancesCount; j++)
{
//
XOHCL jBar = _CombineState.resistanceZones[j];
//
bool isInside = IsInside(
jBar,
iSupplyZone,
X_ZONE_UPPER_EDGE,
true //
);
if (isInside)
{
//
AddIfNotExists(
jBar,
conditions.resistances //
);
}
}
}
//
// Fair Value Gaps ...
// CState ...
int fvgsCount = ArraySize(_CombineState.bearishFVGs);
if (IsValidSize(fvgsCount))
{
//
for (int j = 0; j < fvgsCount; j++)
{
//
XZone jFVG = _CombineState.bearishFVGs[j];
//
bool isInside = IsInside(
jFVG,
iSupplyZone,
X_ZONE_UPPER_EDGE,
true //
);
if (isInside)
{
//
jFVG.to = TimeCurrent();
//
AddIfNotExists(
jFVG,
conditions.bearishFVGs //
);
}
}
}
//
// Swings ...
// CState ...
int swingsCount = ArraySize(_CombineState.swingHighs);
if (IsValidSize(swingsCount))
{
//
for (int j = 0; j < swingsCount; j++)
{
//
XOHCL jBar = _CombineState.swingHighs[j];
//
bool isInside = IsInside(
jBar,
iSupplyZone,
X_ZONE_UPPER_EDGE,
true //
);
if (isInside)
{
//
AddIfNotExists(
jBar,
conditions.swingHighs //
);
}
}
}
//
// Momentum Bars ...
// CState ...
int momentumBarsCount = ArraySize(_CombineState.momentumBars);
if (IsValidSize(momentumBarsCount))
{
//
for (int j = 0; j < momentumBarsCount; j++)
{
//
XOHCL jBar = _CombineState.momentumBars[j];
//
bool isInside =
jBar.IsBearish() &&
jBar.time > iSupplyZone.from &&
IsInside(
jBar,
iSupplyZone,
X_ZONE_UPPER_EDGE,
true //
);
if (isInside)
{
//
AddIfNotExists(
jBar,
conditions.bearishMomentumBars //
);
}
}
}
//
// Rejection Bars ...
// CState ...
int rejectionBarsCount = ArraySize(_CombineState.rejectionBars);
if (IsValidSize(rejectionBarsCount))
{
//
for (int j = 0; j < rejectionBarsCount; j++)
{
//
XOHCL jBar = _CombineState.rejectionBars[j];
//
bool isInside =
jBar.GetLowShadow() < jBar.GetHighShadow() &&
jBar.time > iSupplyZone.from &&
IsInside(
jBar,
iSupplyZone,
X_ZONE_UPPER_EDGE,
true //
);
if (isInside)
{
//
AddIfNotExists(
jBar,
conditions.bearishRejectionBars //
);
}
}
}
//
bool hasValidSupplyZone = conditions.ValidateSupply();
if (!hasValidSupplyZone)
{
conditions.CleanSupply();
}
else
{
break;
}
}
}
//
// Demand ...
// Used for Long ...
bool hasValidDemandZone = conditions.ValidateDemand();
//
// Supply ...
// Used for Short ...
bool hasValidSupplyZone = conditions.ValidateSupply();
//
// Check Conditions is Valid or not ...
result = hasValidDemandZone ||
hasValidSupplyZone;
if (!result)
{
conditions.Clean();
}
//
return result;
}
/**
* Detect Market Structure for Specified Conditions ...
*
* @param structure: X121SMCMarketStructure instance ...
* @param conditions: X121SMCStrategyConditions instance ...
* @param d1State: XPOIState instance ...
* @param h4State: XPOIState instance ...
* @param _15MState: XPOIState instance ...
* @param m5State: XPOIState instance ...
* @param m1State: XPOIState instance ...
*/
void DetectMarketStructure(
X121SMCMarketStructure &structure,
X121SMCStrategyConditions &conditions //
) override
{
//
structure.Clean();
//
if (!conditions.IsValid())
{
return;
}
//
bool hasValidDemand = conditions.ValidateDemand();
bool hasValidSupply = conditions.ValidateSupply();
if (!hasValidDemand && !hasValidSupply)
{
return;
}
//
structure.supplyZone = conditions.supplyZone;
structure.demandZone = conditions.demandZone;
//
datetime cTime = TimeCurrent();
//
// Supply Zones ...
int supplysCount = ArraySize(_CombineState.supplyZones);
if (IsValidSize(supplysCount))
{
//
for (int i = 0; i < supplysCount; i++)
{
//
XZone iZone = _CombineState.supplyZones[i];
//
bool isBetween = IsBetween(
iZone,
structure.supplyZone,
structure.demandZone //
);
if (isBetween)
{
//
iZone.to = cTime;
//
AddIfNotExists(
iZone,
structure.supplyZones //
);
}
}
}
//
// Demand Zones ...
int demandsCount = ArraySize(_CombineState.demandZones);
if (IsValidSize(demandsCount))
{
//
for (int i = 0; i < demandsCount; i++)
{
//
XZone iZone = _CombineState.demandZones[i];
//
bool isBetween = IsBetween(
iZone,
structure.supplyZone,
structure.demandZone //
);
if (isBetween)
{
//
iZone.to = cTime;
//
AddIfNotExists(
iZone,
structure.demandZones //
);
}
}
}
//
// Order Blocks ...
//
// Bullish OBs ...
int bullishOBsCount = ArraySize(_CombineState.bullishOrderBlocks);
if (IsValidSize(bullishOBsCount))
{
//
for (int i = 0; i < bullishOBsCount; i++)
{
//
XZone iZone = _CombineState.bullishOrderBlocks[i];
//
bool isBetween = IsBetween(
iZone,
structure.supplyZone,
structure.demandZone //
);
if (isBetween)
{
//
iZone.to = cTime;
//
AddIfNotExists(
iZone,
structure.bullishOrderBlocks //
);
}
}
}
//
// Bearish OBs ...
int bearishOBsCount = ArraySize(_CombineState.bearishOrderBlocks);
if (IsValidSize(bearishOBsCount))
{
//
for (int i = 0; i < bearishOBsCount; i++)
{
//
XZone iZone = _CombineState.bearishOrderBlocks[i];
//
bool isBetween = IsBetween(
iZone,
structure.supplyZone,
structure.demandZone //
);
if (isBetween)
{
//
iZone.to = cTime;
//
AddIfNotExists(
iZone,
structure.bearishOrderBlocks //
);
}
}
}
//
// Fair Value Gaps ...
//
// Bullish FVGs ...
int bullishFVGsCount = ArraySize(_CombineState.bullishFVGs);
if (IsValidSize(bullishFVGsCount))
{
//
for (int i = 0; i < bullishFVGsCount; i++)
{
//
XZone iZone = _CombineState.bullishFVGs[i];
//
bool isBetween = IsBetween(
iZone,
structure.supplyZone,
structure.demandZone //
);
if (isBetween)
{
//
iZone.to = cTime;
//
AddIfNotExists(
iZone,
structure.bullishFVGs //
);
}
}
}
//
// Bearish FVGs ...
int bearishFVGsCount = ArraySize(_CombineState.bearishFVGs);
if (IsValidSize(bearishFVGsCount))
{
//
for (int i = 0; i < bearishFVGsCount; i++)
{
//
XZone iZone = _CombineState.bearishFVGs[i];
//
bool isBetween = IsBetween(
iZone,
structure.supplyZone,
structure.demandZone //
);
if (isBetween)
{
//
iZone.to = cTime;
//
AddIfNotExists(
iZone,
structure.bearishFVGs //
);
}
}
}
//
// Swing Highs ...
int swingHighsCount = ArraySize(_CombineState.swingHighs);
if (IsValidSize(swingHighsCount))
{
//
for (int i = 0; i < swingHighsCount; i++)
{
//
XOHCL iBar = _CombineState.swingHighs[i];
//
bool isBetween = IsBetween(
iBar,
structure.supplyZone,
structure.demandZone //
);
if (isBetween)
{
//
AddIfNotExists(
iBar,
structure.swingHighs //
);
}
}
}
//
// Swing Lows ...
int swingLowsCount = ArraySize(_CombineState.swingLows);
if (IsValidSize(swingLowsCount))
{
//
for (int i = 0; i < swingLowsCount; i++)
{
//
XOHCL iBar = _CombineState.swingLows[i];
//
bool isBetween = IsBetween(
iBar,
structure.supplyZone,
structure.demandZone //
);
if (isBetween)
{
//
AddIfNotExists(
iBar,
structure.swingLows //
);
}
}
}
//
// Support Zones ...
int supportsCount = ArraySize(_CombineState.supportZones);
if (IsValidSize(supportsCount))
{
//
for (int i = 0; i < supportsCount; i++)
{
//
XOHCL iBar = _CombineState.supportZones[i];
//
bool isBetween = IsBetween(
iBar,
structure.supplyZone,
structure.demandZone //
);
if (isBetween)
{
//
AddIfNotExists(
iBar,
structure.supports //
);
}
}
}
//
// Resistance Zones ...
int resistancesCount = ArraySize(_CombineState.resistanceZones);
if (IsValidSize(resistancesCount))
{
//
for (int i = 0; i < resistancesCount; i++)
{
//
XOHCL iBar = _CombineState.resistanceZones[i];
//
bool isBetween = IsBetween(
iBar,
structure.supplyZone,
structure.demandZone //
);
if (isBetween)
{
//
AddIfNotExists(
iBar,
structure.resistances //
);
}
}
}
//
// Momentum Bars ...
int momentumBarCount = ArraySize(_CombineState.momentumBars);
if (IsValidSize(momentumBarCount))
{
//
for (int i = 0; i < momentumBarCount; i++)
{
//
XOHCL iBar = _CombineState.momentumBars[i];
//
bool isBetween = IsBetween(
iBar,
structure.supplyZone,
structure.demandZone //
);
if (isBetween)
{
//
bool isBullish = iBar.IsBullish();
//
if (isBullish)
{
//
AddIfNotExists(
iBar,
structure.bullishMomentumBars //
);
}
else
{
//
AddIfNotExists(
iBar,
structure.bearishMomentumBars //
);
}
}
}
}
//
// Rejection Bars ...
int rejectionBarCount = ArraySize(_CombineState.rejectionBars);
if (IsValidSize(rejectionBarCount))
{
//
for (int i = 0; i < rejectionBarCount; i++)
{
//
XOHCL iBar = _CombineState.rejectionBars[i];
//
bool isBetween = IsBetween(
iBar,
structure.supplyZone,
structure.demandZone //
);
if (isBetween)
{
//
bool isBullish = iBar.GetLowShadow() > iBar.GetHighShadow();
//
if (isBullish)
{
//
AddIfNotExists(
iBar,
structure.bullishRejectionBars //
);
}
else
{
//
AddIfNotExists(
iBar,
structure.bearishRejectionBars //
);
}
}
}
}
}
/**
* Remove Specific Conditions if Exists ...
*
* @param conditions: X121SMCStrategyConditions instance ...
*/
void RemoveConditionsIfExists(X121SMCStrategyConditions &conditions) override
{
//
int count = ArraySize(mConditions);
if (!IsValidSize(count))
{
return;
}
//
bool hasValidSupply = conditions.ValidateSupply();
bool hasValidDemand = conditions.ValidateDemand();
if (!hasValidSupply && !hasValidDemand)
{
return;
}
//
int idx = -1;
for (int i = 0; i < count; i++)
{
//
X121SMCStrategyConditions iConditions = mConditions[i];
//
bool isSupplySame =
hasValidSupply &&
iConditions.ValidateSupply() &&
conditions.supplyZone.from == iConditions.supplyZone.from &&
conditions.supplyZone.upper == iConditions.supplyZone.upper &&
conditions.supplyZone.lower == iConditions.supplyZone.lower;
bool isDemandSame =
hasValidDemand &&
iConditions.ValidateDemand() &&
conditions.demandZone.from == iConditions.demandZone.from &&
conditions.demandZone.upper == iConditions.demandZone.upper &&
conditions.demandZone.lower == iConditions.demandZone.lower;
//
if (isSupplySame || isDemandSame)
{
//
idx = i;
break;
}
}
//
if (IsValidIndex(idx))
{
//
ArrayRemove(
mConditions,
idx,
1 //
);
}
}
//
// Customize Strategy Identifier ...
string GetTag() override
{
return X121SMCSUPDEMStrategyToken;
}
//
// Protected ...
protected:
//
//
// Props ...
//
// XCHVWAP ...
XCHVWAPInputs chvwapInputs;
XSCXCHVWAPHelper *chvwapHelper;
//
// Private ...
private:
//
// Props ...
/**
* Validate a Condition ...
*
* @param conditions: Argument 1
* @return ( bool )
*/
bool ValidateConditions(X121SMCStrategyConditions &conditions)
{
//
bool result = false;
//
result = conditions.IsValid();
if (!result)
{
return result;
}
//
bool hasValidDemnd = conditions.ValidateDemand();
bool hasValidSupply = conditions.ValidateSupply();
result = hasValidDemnd || hasValidSupply;
if (!result)
{
return result;
}
//
string _symbol = GetSymbol();
ENUM_TIMEFRAMES _period = GetPeriod();
//
int zIndex = 0;
int cIndex = zIndex + 1;
int pIndex = cIndex + 1;
//
XOHCL zBar;
result = zBar.Init(
_symbol,
_period,
zIndex //
);
if (!result)
{
return result;
}
//
XOHCL cBar;
result = cBar.Init(
_symbol,
_period,
cIndex //
);
if (!result)
{
return result;
}
//
result =
hasValidDemnd
? cBar.high < conditions.demandZone.upper &&
zBar.high < conditions.demandZone.upper &&
cBar.low > conditions.demandZone.lower &&
zBar.low > conditions.demandZone.lower
: hasValidSupply
? cBar.high < conditions.demandZone.upper &&
zBar.high < conditions.demandZone.upper &&
cBar.low > conditions.demandZone.lower &&
zBar.low > conditions.demandZone.lower
: false;
//
return result;
}
/**
* Initial Required Indicators Helper ...
*/
void InitialHelpers()
{
//
// XCHVWAP ...
//
// Short ...
ENUM_X_PERIOD_METHOD scMethod = X_PERIOD_MANUALLY; // How to Find Period
ENUM_TIMEFRAMES scPeriod = PERIOD_M15; // Time Period
//
// Medium ...
ENUM_X_PERIOD_METHOD mcMethod = X_PERIOD_MANUALLY; // How to Find Period
ENUM_TIMEFRAMES mcPeriod = PERIOD_H1; // Time Period
//
// Long ...
ENUM_X_PERIOD_METHOD lcMethod = X_PERIOD_MANUALLY; // How to Find Period
ENUM_TIMEFRAMES lcPeriod = PERIOD_H4; // Time Period
//
// Hind ...
ENUM_X_PERIOD_METHOD hcMethod = X_PERIOD_MANUALLY; // How to Find Period
ENUM_TIMEFRAMES hcPeriod = PERIOD_D1; // Time Period
//
chvwapInputs.Default();
//
chvwapInputs.scMethod = scMethod;
chvwapInputs.scPeriod = scPeriod;
chvwapInputs.mcMethod = mcMethod;
chvwapInputs.mcPeriod = mcPeriod;
chvwapInputs.lcMethod = lcMethod;
chvwapInputs.lcPeriod = lcPeriod;
chvwapInputs.hcMethod = hcMethod;
chvwapInputs.hcPeriod = hcPeriod;
//
chvwapInputs.showShort = true;
chvwapInputs.showMedium = true;
chvwapInputs.showLong = true;
chvwapInputs.showHind = true;
//
chvwapHelper = new XSCXCHVWAPHelper();
chvwapHelper.Init(
GetSymbol(),
GetPeriod(),
chvwapInputs //
);
}
//
// Override Draw Condition ...
/**
* Draw Specific Condition ...
*
* @param conditions: X121SMCStrategyConditions instance ...
*/
void DrawConditions(
X121SMCStrategyConditions &conditions //
)
{
//
// Draw Configurations ...
//
bool drawMainDemand = true;
bool drawMainSupply = true;
//
bool drawMainBullishOrderBlock = true;
bool drawMainBearishOrderBlock = true;
//
bool drawMainBullishFVG = true;
bool drawMainBearishFVG = true;
//
bool drawOrderBlocks = false;
bool drawFVGs = false;
bool drawSupportResistances = false;
bool drawSwings = false;
bool drawMomentumBars = false;
bool drawRejectionBars = false;
//
bool renewDates = true;
//
if (!conditions.IsValid())
{
return;
}
//
datetime time = TimeCurrent();
bool hasValidDemand = conditions.ValidateDemand();
bool hasValidSupply = conditions.ValidateSupply();
if (!hasValidDemand && !hasValidSupply)
{
return;
}
//
// Demand Zone ...
if (hasValidDemand)
{
//
// Demand ...
if (drawMainDemand)
{
//
if (renewDates)
{
conditions.demandZone.to = time;
}
//
XCDemandZoneObject *iObj;
bool isCreated = mPOIDrawer.CreateDemandZone(
conditions.demandZone,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
//
if (drawMainBullishOrderBlock)
{
//
if (renewDates)
{
conditions.bullishOrderBlock.to = time;
}
//
XCBullishOrderBlockObject *iObj;
bool isCreated = mPOIDrawer.CreateBullishOrderBlock(
conditions.bullishOrderBlock,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
//
if (drawMainBullishFVG)
{
//
if (renewDates)
{
conditions.bullishFVG.to = time;
}
//
XCBullishFVGObject *iObj;
bool isCreated = mPOIDrawer.CreateBullishFVG(
conditions.bullishFVG,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
//
// Order Blocks ...
int obsCount = ArraySize(conditions.bullishOrderBlocks);
if (drawOrderBlocks &&
IsValidSize(obsCount))
{
//
for (int i = 0; i < obsCount; i++)
{
//
XZone iZone = conditions.bullishOrderBlocks[i];
//
if (renewDates)
{
iZone.to = time;
}
//
XCBullishOrderBlockObject *iObj;
bool isCreated = mPOIDrawer.CreateBullishOrderBlock(
iZone,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
}
//
// Fair Value Gaps ...
int fvgsCount = ArraySize(conditions.bullishFVGs);
if (drawFVGs &&
IsValidSize(fvgsCount))
{
//
for (int i = 0; i < fvgsCount; i++)
{
//
XZone iZone = conditions.bullishFVGs[i];
//
if (renewDates)
{
iZone.to = time;
}
//
XCBullishFVGObject *iObj;
bool isCreated = mPOIDrawer.CreateBullishFVG(
iZone,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
}
//
// Supports ...
int supportsCount = ArraySize(conditions.supports);
if (drawSupportResistances &&
IsValidSize(supportsCount))
{
//
for (int i = 0; i < supportsCount; i++)
{
//
XOHCL iBar = conditions.supports[i];
//
XCSupportZoneObject *iObj;
bool isCreated = mPOIDrawer.CreateSupportZone(
iBar,
iObj,
time //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
}
//
// Swings ...
int swingsCount = ArraySize(conditions.swingLows);
if (drawSwings &&
IsValidSize(swingsCount))
{
//
for (int i = 0; i < swingsCount; i++)
{
//
XOHCL iBar = conditions.swingLows[i];
//
XCSwingLowObject *iObj;
bool isCreated = mPOIDrawer.CreateSwingLow(
iBar,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
}
//
// Momentum Bars ...
int momentumBarsCount = ArraySize(conditions.bullishMomentumBars);
if (drawMomentumBars &&
IsValidSize(momentumBarsCount))
{
//
for (int i = 0; i < momentumBarsCount; i++)
{
//
XOHCL iBar = conditions.bullishMomentumBars[i];
//
XCBullishMomentumBarObject *iObj;
bool isCreated = mPOIDrawer.CreateBullishMomentumBar(
iBar,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
}
//
// Rejection Bars ...
int rejectionBarsCount = ArraySize(conditions.bullishRejectionBars);
if (drawRejectionBars &&
IsValidSize(rejectionBarsCount))
{
//
for (int i = 0; i < rejectionBarsCount; i++)
{
//
XOHCL iBar = conditions.bullishRejectionBars[i];
//
XCBullishRejectionBarObject *iObj;
bool isCreated = mPOIDrawer.CreateBullishRejectionBar(
iBar,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
}
}
//
// Supply Zone ...
if (hasValidSupply)
{
//
// Supply ...
if (drawMainSupply)
{
//
if (renewDates)
{
conditions.supplyZone.to = time;
}
//
XCSupplyZoneObject *iObj;
bool isCreated = mPOIDrawer.CreateSupplyZone(
conditions.supplyZone,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
//
if (drawMainBearishOrderBlock)
{
//
if (renewDates)
{
conditions.bearishOrderBlock.to = time;
}
//
XCBearishOrderBlockObject *iObj;
bool isCreated = mPOIDrawer.CreateBearishOrderBlock(
conditions.bearishOrderBlock,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
//
if (drawMainBearishFVG)
{
//
if (renewDates)
{
conditions.bearishFVG.to = time;
}
//
XCBearishFVGObject *iObj;
bool isCreated = mPOIDrawer.CreateBearishFVG(
conditions.bearishFVG,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
//
// Order Blocks ...
int obsCount = ArraySize(conditions.bearishOrderBlocks);
if (drawOrderBlocks &&
IsValidSize(obsCount))
{
//
for (int i = 0; i < obsCount; i++)
{
//
XZone iZone = conditions.bearishOrderBlocks[i];
//
if (renewDates)
{
iZone.to = time;
}
//
XCBearishOrderBlockObject *iObj;
bool isCreated = mPOIDrawer.CreateBearishOrderBlock(
iZone,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
}
//
// Fair Value Gaps ...
int fvgsCount = ArraySize(conditions.bearishFVGs);
if (drawFVGs &&
IsValidSize(fvgsCount))
{
//
for (int i = 0; i < fvgsCount; i++)
{
//
XZone iZone = conditions.bearishFVGs[i];
//
if (renewDates)
{
iZone.to = time;
}
//
XCBearishFVGObject *iObj;
bool isCreated = mPOIDrawer.CreateBearishFVG(
iZone,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
}
//
// Resistances ...
int resistancesCount = ArraySize(conditions.resistances);
if (drawSupportResistances &&
IsValidSize(resistancesCount))
{
//
for (int i = 0; i < resistancesCount; i++)
{
//
XOHCL iBar = conditions.resistances[i];
//
XCResistanceZoneObject *iObj;
bool isCreated = mPOIDrawer.CreateResistanceZone(
iBar,
iObj,
time //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
}
//
// Swings ...
int swingsCount = ArraySize(conditions.swingHighs);
if (drawSwings &&
IsValidSize(swingsCount))
{
//
for (int i = 0; i < swingsCount; i++)
{
//
XOHCL iBar = conditions.swingHighs[i];
//
XCSwingHighObject *iObj;
bool isCreated = mPOIDrawer.CreateSwingHigh(
iBar,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
}
//
// Momentum Bars ...
int momentumBarsCount = ArraySize(conditions.bearishMomentumBars);
if (drawMomentumBars &&
IsValidSize(momentumBarsCount))
{
//
for (int i = 0; i < momentumBarsCount; i++)
{
//
XOHCL iBar = conditions.bearishMomentumBars[i];
//
XCBearishMomentumBarObject *iObj;
bool isCreated = mPOIDrawer.CreateBearishMomentumBar(
iBar,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
}
//
// Rejection Bars ...
int rejectionBarsCount = ArraySize(conditions.bearishRejectionBars);
if (drawRejectionBars &&
IsValidSize(rejectionBarsCount))
{
//
for (int i = 0; i < rejectionBarsCount; i++)
{
//
XOHCL iBar = conditions.bearishRejectionBars[i];
//
XCBearishRejectionBarObject *iObj;
bool isCreated = mPOIDrawer.CreateBearishRejectionBar(
iBar,
iObj //
);
if (isCreated)
{
mDrawnObjects.Add(iObj);
}
}
}
}
}
//
};
//