Files
MQL5Data/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5
T
2024-10-28 23:31:03 +03:30

2353 lines
48 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// --------------------------------------
// Name: XSCX121Strategy
// 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 "../../Classes/x-saherelm.x-poi.class.mq5"
#include "../../Classes/x-saherelm.xalert.class.mq5"
#include "../../Classes/x-saherelm.xtrade.class.mq5"
#include "../Libraries/x-121.smc.lib.mq5"
//
// Helper(s) ...
//
// XStrategy Class Implementation(s) ...
class XCX121SMCStrategy : public XSCBaseAlert
{
//
// Public ...
public:
//
//
// Constructor(s) ...
void XCX121SMCStrategy(
//
// Base ...
string _symbol, // Trading Symbol
ENUM_TIMEFRAMES _period // Trading TimeFrame
)
{
//
mSymbol = _symbol;
mPeriod = _period;
//
Init();
}
//
// Deconstructor ...
void ~XCX121SMCStrategy()
{
DeInit();
}
//
// Getter / Setter (s) ...
/**
* Retrieve Symbol ...
*
* @return ( string )
*/
string Symbol()
{
return mSymbol;
}
/**
* Retrieve TimeFrame ...
*
* @return ( ENUM_TIMEFRAMES )
*/
ENUM_TIMEFRAMES Period()
{
return mPeriod;
}
/**
* Check Strategy is Disabled or not ...
*
* @return ( bool )
*/
bool IsDisabled()
{
return mForceDisabled;
}
/**
* Get Signal Volume ...
*
* @return ( double )
*/
double Volume()
{
return mVolume;
}
/**
* Set Signal Volume ...
*
* @param value: Double ...
*/
void Volume(double value)
{
//
if (value < 0.01)
{
value = 0.01;
}
//
mVolume = value;
}
/**
* Get Risk/Reward Ratio ...
*
* @return ( double )
*/
double R2R()
{
return mR2R;
}
/**
* Set Risk/Reward Ratio ...
*
* @param value: Double ...
*/
void R2R(double value)
{
//
if (value < 0)
{
value = 1.5;
}
//
mR2R = value;
}
/**
* Get Max Allowed Spread ...
*
* @return ( double )
*/
double MaxAllowedSpread()
{
return mMaxAllowedSpread;
}
/**
* Set Max Allowed Spread ...
*
* @param value: Double ...
*/
void MaxAllowedSpread(double value)
{
mMaxAllowedSpread = value;
}
/**
* Get Long Signalling State ...
*
* @return ( bool )
*/
bool AllowLong()
{
return mAllowLong;
}
/**
* Set Long Signalling State ...
*
* @param value: Boolean ...
*/
void AllowLong(bool value)
{
mAllowLong = value;
}
/**
* Get Short Signalling State ...
*
* @return ( bool )
*/
bool AllowShort()
{
return mAllowShort;
}
/**
* Set Short Signalling State ...
*
* @param value: Argument 1
*/
void AllowShort(bool value)
{
mAllowShort = value;
}
//
// Actions ...
/**
* Disable Strategy ...
*/
void Disable()
{
mForceDisabled = true;
}
/**
* Enable Strategy ...
*/
void Enable()
{
mForceDisabled = false;
}
/**
* Register Signal Event Handler ...
*
* @param handler: an Instance of TOnXSignal ...
*/
void AddXSignalEventHandler(TOnX121SMCSignal handler)
{
//
Add(
handler,
mSignalEventHandlers //
);
}
//
// Virtual Actions ...
//
// Check Conditions For Signal and Execute Signal ...
virtual void HandleTick()
{
//
// Check State ...
if (IsDisabled())
{
return;
}
//
// Check Signalling State ...
if (!AllowLong() && !AllowShort())
{
return;
}
//
// Check Bar Tracker State ...
if (!mBarTracker.CanProcessBar())
{
return;
}
//
// Retrieve Current Tick and Check it's Time
// by Last Issued Tick ...
MqlTick cTick;
bool hasTick = GetTick(
mSymbol,
cTick //
);
bool isSameAsLast = cTick.time == mLastTick.time;
if (isSameAsLast)
{
return;
}
//
// Update Last Issued Tick ...
mLastTick = cTick;
SaveTickData();
CleanupTicks();
//
// Update POIs ...
//
ENUM_XPOI_EVENTS _4HStates[];
m4HPOI.Update(_4HStates);
//
ENUM_XPOI_EVENTS _4HSupDemStates[];
m4HSupDemPOI.Update(_4HSupDemStates);
//
ENUM_XPOI_EVENTS _15MStates[];
m15MPOI.Update(_15MStates);
//
ENUM_XPOI_EVENTS _5MStates[];
m5MPOI.Update(_5MStates);
//
// Check Current Processing Tick has Signal or not ...
XSignal signal;
X121SMCStrategyConditions conditions;
bool hasSignal = HasSignal(
signal,
conditions //
);
if (!hasSignal)
{
return;
}
//
// Waits Until Next Candle if Current Tick has Signal ...
mBarTracker.Waits();
//
// Notify Signal Event Handlers ...
NotifyOnSignalEventHandlers(
signal,
conditions //
);
//
DrawSignal(
signal,
conditions //
);
//
// ClearDraws();
}
//
// Check Conditions For Signal ...
virtual bool HasSignal(
XSignal &signal,
X121SMCStrategyConditions &conditions //
)
{
//
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 ...
//
double points = GetPoints(mSymbol);
//
int zIndex = 0;
int cIndex = zIndex + 1;
int pIndex = cIndex + 1;
int ppIndex = pIndex + 1;
//
// Retrieve Bars ...
//
// Zero Bar ...
XOHCL zBar;
result = zBar.Init(
mSymbol,
mPeriod,
zIndex //
);
if (!result)
{
return result;
}
//
// Last Bar ...
XOHCL cBar;
result = cBar.Init(
mSymbol,
mPeriod,
cIndex //
);
if (!result)
{
return result;
}
//
// Prepare Conditions ...
//
conditions.symbol = mSymbol;
conditions.period = mPeriod;
conditions.time = cBar.time;
//
// Reading POI(s) ...
//
XPOIState _4HSupDemState;
m4HSupDemPOI.GetState(_4HSupDemState);
//
// 4H ...
XPOIState _4HState;
m4HPOI.GetState(_4HState);
//
// 15M ...
XPOIState _15MState;
m15MPOI.GetState(_15MState);
//
// 5M ...
XPOIState _5MState;
m5MPOI.GetState(_5MState);
//
// 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 ...
DetectImportantPOIs(
conditions,
_4HSupDemState,
_4HState,
_15MState,
_5MState //
);
if (conditions.supplyZone.IsValid() ||
conditions.bearishFVG.IsValid() ||
conditions.bearishOrderBlock.IsValid())
{
//
AddRef(
conditions,
mConditions //
);
}
else if (conditions.demandZone.IsValid() ||
conditions.bullishFVG.IsValid() ||
conditions.bullishOrderBlock.IsValid())
{
//
AddRef(
conditions,
mConditions //
);
}
//
conditions.Clean();
//
// Check Conditions for Signal ...
int 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;
X121SMCStrategyConditions iConditions = mConditions[i];
//
bool isSpreadPassed = IsSpreadPass();
if (!isSpreadPassed)
{
break;
}
//
// Longs ...
bool isAllowLong = AllowLong();
if (isAllowLong)
{
//
hasLong = false;
//
if (hasLong)
{
//
conditionsIDX = i;
//
type = POSITION_TYPE_BUY;
entry = GetEntry(mSymbol, type);
sl = iConditions.demandZone.lower - (10 * points);
risk = entry - sl;
reward = risk * r2r;
tp = entry + reward;
//
break;
}
}
//
// Shorts ...
bool isAllowShort = AllowShort();
if (isAllowShort)
{
//
hasShort = false;
//
if (hasShort)
{
//
conditionsIDX = i;
//
type = POSITION_TYPE_SELL;
entry = GetEntry(mSymbol, type);
sl = iConditions.supplyZone.upper + (10 * points);
risk = sl - entry;
reward = risk * r2r;
tp = entry - reward;
//
break;
}
}
}
//
result = hasLong ||
hasShort;
//
// Rmove Signal Condition ...
if (result &&
IsValidIndex(conditionsIDX))
{
//
ArrayRemove(
mConditions,
conditionsIDX,
1 //
);
//
signal.sl = sl;
signal.tp = tp;
signal.type = type;
signal.mode = mode;
signal.entry = entry;
signal.volume = volume;
signal.symbol = mSymbol;
signal.pushers = pushers;
signal.provider = GetTag();
signal.time = TimeCurrent();
signal.period = _5MState.period;
//
result = PrepareSignal(signal);
//
hasLong = false;
hasShort = false;
}
//
return result;
}
//
// Overrides ...
//
// Customize Strategy Identifier ...
string GetTag() override
{
return X121SMCStrategyToken;
}
//
// Protected ...
protected:
//
//
// Props ...
//
// Private ...
private:
//
// Props ...
//
string mSymbol; // Trading Symbol ...
ENUM_TIMEFRAMES mPeriod; // Trading TimeFrame ...
bool mForceDisabled; // Force Disabled ...
bool mAllowLong; // Allow Long Signals
bool mAllowShort; // Allow Short Signals
double mR2R; // Risk/Rewar Ratio ...
double mVolume; // Static Volume Per Trades ...
double mMaxAllowedSpread; // Max Allowed Spread ...
//
XTick mTicks[]; // Hold Ticks Data ...
MqlTick mLastTick; // Last Issued Tick ...
/**
* Cleanup Ticks Size ...
*/
void CleanupTicks()
{
//
int maxRequiredTicks = 50;
int ticksCount = ArraySize(mTicks);
if (!IsValidSize(ticksCount) ||
ticksCount <= maxRequiredTicks)
{
return;
}
//
int removeCount = ticksCount - maxRequiredTicks;
if (!IsValidSize(removeCount))
{
return;
}
//
ArrayRemove(
mTicks,
0,
removeCount //
);
}
/**
* Add new Tick Data to Collection ...
*/
void SaveTickData()
{
//
XTick tick;
bool isInited = tick.Init(mSymbol);
if (!isInited)
{
return;
}
//
AddRef(
tick,
mTicks //
);
}
/**
* Check Spread Passed for Positions...
*
* @return ( bool )
*/
bool IsSpreadPass()
{
//
bool result = false;
//
int length = 5;
double pointValue = GetPoints(mSymbol);
double maxAllowedSpread = MaxAllowedSpread();
if (maxAllowedSpread > 0)
{
maxAllowedSpread *= pointValue;
}
//
int ticksCount = ArraySize(mTicks);
if (ticksCount <= length)
{
return result;
}
//
int start = -1;
int end = -1;
CalculateTicksParams(
start,
end,
length + 1 //
);
result = IsValidIndex(start) &&
IsValidIndex(end);
if (!result)
{
return result;
}
//
end -= 1;
double spreadAVG = 0;
for (int i = start; i < end; i++)
{
spreadAVG += mTicks[i].spread;
}
spreadAVG /= length;
//
double lastSpread = mTicks[ticksCount - 1].spread;
//
result = lastSpread <= spreadAVG &&
(maxAllowedSpread <= 0
? true
: lastSpread <= maxAllowedSpread);
//
return result;
}
/**
* Calculate Ticks Param for Looping through Last n items ...
*
* @param start: Integer Reference to Start ...
* @param end: Integer Reference to End ...
* @param numOfLastTicks: Integer Max Number of Required N Last Ticks ...
*/
void CalculateTicksParams(
int &start,
int &end,
int numOfLastTicks = 5 //
)
{
//
start = -1;
end = -1;
//
int count = ArraySize(mTicks);
//
start = count - numOfLastTicks;
if (start < 0)
{
start = 0;
}
//
end = start + numOfLastTicks;
if (end > count)
{
end = count;
}
}
/**
* Check Ticks is Bullish or not ...
*
* @return ( bool )
*/
bool IsTicksBullish()
{
//
bool result = false;
//
int start = -1;
int end = -1;
CalculateTicksParams(
start,
end //
);
result = IsValidIndex(start) &&
IsValidIndex(end);
if (!result)
{
return result;
}
//
result = true;
for (int i = start + 1; i < end; i++)
{
//
XTick iTick = mTicks[i];
XTick prevTick = mTicks[i - 1];
//
bool isBullish = iTick.bid >= prevTick.bid;
result = result && isBullish;
if (!result)
{
break;
}
}
//
return result;
}
/**
* Check Ticks is Bearish or not ...
*
* @return ( bool )
*/
bool IsTicksBearish()
{
//
bool result = false;
//
int start = -1;
int end = -1;
CalculateTicksParams(
start,
end //
);
result = IsValidIndex(start) &&
IsValidIndex(end);
if (!result)
{
return result;
}
//
result = true;
for (int i = start + 1; i < end; i++)
{
//
XTick iTick = mTicks[i];
XTick prevTick = mTicks[i - 1];
//
bool isBearish = iTick.bid <= prevTick.bid;
result = result && isBearish;
if (!result)
{
break;
}
}
//
return result;
}
/**
* Check Ticks Has Momentum or not ...
*
* @return ( bool )
*/
bool IsTicksHasMomentum()
{
//
bool result = false;
//
int start = -1;
int end = -1;
CalculateTicksParams(
start,
end //
);
result = IsValidIndex(start) &&
IsValidIndex(end);
if (!result)
{
return result;
}
//
result = true;
int lastDiff = 0;
for (int i = start + 1; i < end; i++)
{
//
XTick iTick = mTicks[i];
XTick prevTick = mTicks[i - 1];
//
int timeDiff = MathAbs((int)iTick.time - (int)prevTick.bid);
result = result && timeDiff >= lastDiff;
if (!result)
{
break;
}
//
lastDiff = timeDiff;
}
//
return result;
}
//
XBarTracker mBarTracker; // Strategy Time Tracker ...
//
// Point Of Interests ...
XCPOI *m4HPOI;
XCPOI *m4HSupDemPOI;
XCPOI *m15MPOI;
XCPOI *m5MPOI;
//
// Collect all Drawn Objects ...
CArrayObj mDrawnObjects;
/**
* Clear all Drawn Objects ...
*/
void ClearDraws()
{
mDrawnObjects.Clear();
}
/**
* Remove Specified Drawn Object ...
*
* @param name: Object name ...
*/
void RemoveObject(string name)
{
//
if (!IsValid(name))
{
return;
}
//
int count = mDrawnObjects.Total();
if (!IsValidSize(count))
{
return;
}
//
int idx = -1;
for (int i = 0; i < count; i++)
{
//
string iName = ((CChartObject *)mDrawnObjects.At(i)).Name();
string iObjName = NULL;
if (!IsValid(iName))
{
iObjName = ((XCBaseObject *)mDrawnObjects.At(i)).ObjName();
}
//
if ((IsValid(iName) &&
iName == name) ||
(IsValid(iObjName) &&
iObjName == name))
{
//
idx = i;
break;
}
}
//
if (IsValidIndex(idx))
{
mDrawnObjects.Delete(idx);
}
}
//
XOHCL mSwingHigh;
CChartObjectHLine *mSwingHighObject;
//
XOHCL mSwingLow;
CChartObjectHLine *mSwingLowObject;
//
// Holding Supply and Demand Zones ...
// XZone mSupplyZones[];
// XZone mDemandZones[];
//
// XZone mBearishOrderBlocks[];
// XZone mBullishOrderBlocks[];
//
// XZone mBearishFVGs[];
// XZone mBullishFVGs[];
//
X121SMCStrategyConditions mConditions[];
//
// Actions ...
/**
* Install all Helpers and Prepare all Configurations for required Indicators ...
*/
void Init()
{
//
mForceDisabled = false;
//
R2R(2);
Volume(0.01);
//
string symbol = Symbol();
ENUM_TIMEFRAMES period = Period();
//
// Initialize Bar Tracker ...
mBarTracker.Init(
symbol,
period //
);
//
// Initialize POIs ...
//
// this used only for Supply and
// Demand Zone for H4 Time Frame ..,
// POI Detector ...
m4HSupDemPOI = new XCPOI(
symbol,
PERIOD_M15 //
);
m4HSupDemPOI.Window(0);
m4HSupDemPOI.DisablePOIs();
m4HSupDemPOI.DisableDrawPOIs();
m4HSupDemPOI.ChartID(ChartID());
m4HSupDemPOI.AllowSupplyZones(true);
m4HSupDemPOI.AllowDemandZones(true);
m4HSupDemPOI.SupplyZonePeriod(PERIOD_H4);
m4HSupDemPOI.DemandZonePeriod(PERIOD_H4);
//
m4HSupDemPOI.Init();
//
// 4H Period ...
// POI Detector ...
m4HPOI = new XCPOI(
symbol,
PERIOD_H4 //
);
//
m4HPOI.Window(0);
m4HPOI.DisableDrawPOIs();
m4HPOI.ChartID(ChartID());
m4HPOI.SupplyZonePeriod(PERIOD_H4);
m4HPOI.DemandZonePeriod(PERIOD_H4);
//
m4HPOI.Init();
//
// 15M Period ...
// POI Detector ...
m15MPOI = new XCPOI(
symbol,
PERIOD_M15 //
);
//
m15MPOI.Window(0);
m15MPOI.DisableDrawPOIs();
m15MPOI.ChartID(ChartID());
m15MPOI.MaxNumberOfRequiredPOIs(2);
m15MPOI.SupplyZonePeriod(PERIOD_M15);
m15MPOI.DemandZonePeriod(PERIOD_M15);
//
m15MPOI.Init();
//
// Trigger Period ...
// POI Detector ...
m5MPOI = new XCPOI(
symbol,
PERIOD_M5 //
);
//
m5MPOI.Window(0);
m5MPOI.DisableDrawPOIs();
m5MPOI.ChartID(ChartID());
m5MPOI.MaxNumberOfRequiredPOIs(2);
m5MPOI.SupplyZonePeriod(PERIOD_M5);
m5MPOI.DemandZonePeriod(PERIOD_M5);
//
m5MPOI.Init();
//
}
/**
* De Initialize all Tools ...
*/
void DeInit()
{
//
delete m4HPOI;
delete m5MPOI;
delete m15MPOI;
// delete m4HSupDemPOI;
//
ClearDraws();
}
/**
* Reste Bar Tracker ...
*/
void ResetBarTracker()
{
mBarTracker.Clean();
}
/**
* Prepare and Normalize Signal for Execution in Strategy ...
*
* @param signal: XSignal instance ...
*
* @return ( bool )
*/
bool PrepareSignal(XSignal &signal)
{
//
bool result = false;
//
// Check Strategy Is Enables ...
result = !IsDisabled();
if (!result)
{
return result;
}
//
// Validate Signal ...
result = signal.IsValid();
if (!result)
{
return result;
}
//
bool isLong = IsLong(signal.type);
//
// TODO: Implement Signal Preparation Mechanism here ...
//
return result;
}
/**
* Update Supply and Demand Zones ...
*
* @param state: Argument 1
*/
void DetectImportantPOIs(
X121SMCStrategyConditions &conditions,
XPOIState &supplyAndDemandZoneState,
XPOIState &orderBlocksState,
XPOIState &fvgsState,
XPOIState &triggerState //
)
{
//
int supplyZonesCount = ArraySize(supplyAndDemandZoneState.supplyZones);
int demandZonesCount = ArraySize(supplyAndDemandZoneState.demandZones);
//
XOHCL swingHighs[];
Copy(
orderBlocksState.swingHighs,
swingHighs //
);
Copy(
fvgsState.swingHighs,
swingHighs,
false //
);
Copy(
triggerState.swingHighs,
swingHighs,
false //
);
//
XOHCL swingLows[];
Copy(
orderBlocksState.swingLows,
swingLows //
);
Copy(
fvgsState.swingLows,
swingLows,
false //
);
Copy(
triggerState.swingLows,
swingLows,
false //
);
//
int swingHighsCount = ArraySize(swingHighs);
int swingLowsCount = ArraySize(swingLows);
if (!IsValidSize(swingLowsCount) ||
!IsValidSize(swingHighsCount) ||
!IsValidSize(supplyZonesCount) ||
!IsValidSize(demandZonesCount))
{
return;
}
//
XOHCL zBar;
bool isInited = zBar.Init(
Symbol(),
Period(),
0 //
);
if (!isInited)
{
return;
}
//
// Detect Swing High and Low as Market Structure Boundaries ...
//
// Swing High ...
XOHCL tmpBar;
for (int i = 0; i < swingHighsCount; i++)
{
//
XOHCL iSwing = swingHighs[i];
//
if (!tmpBar.IsValid() ||
tmpBar.high < iSwing.high)
{
tmpBar = iSwing;
}
}
DrawSwingHigh(tmpBar);
//
// Swing Low ...
tmpBar.Clean();
for (int i = 0; i < swingLowsCount; i++)
{
//
XOHCL iSwing = swingLows[i];
//
if (!tmpBar.IsValid() ||
tmpBar.low > iSwing.low)
{
tmpBar = iSwing;
}
}
DrawSwingLow(tmpBar);
tmpBar.Clean();
//
// Supply Zone ...
for (int i = 0; i < supplyZonesCount; i++)
{
//
XZone iSupplyZone = supplyAndDemandZoneState.supplyZones[i];
conditions.supplyZone = iSupplyZone;
//
XZone iBearishOrderBlock;
XZone iBearishFVG;
//
bool isPassed = false;
int orderBlocksCount = ArraySize(orderBlocksState.bearishOrderBlocks);
isPassed = IsValidSize(orderBlocksCount);
if (!isPassed)
{
continue;
}
//
// Find Related Order Block ...
isPassed = false;
for (int j = 0; j < orderBlocksCount; j++)
{
//
XZone jOrderBlock = orderBlocksState.bearishOrderBlocks[j];
//
bool isOrderBlockInsideZone = IsSupplyZoneOrderBlock(
iSupplyZone,
jOrderBlock //
);
if (isOrderBlockInsideZone)
{
//
isPassed = true;
iBearishOrderBlock = jOrderBlock;
conditions.bearishOrderBlock = jOrderBlock;
break;
}
}
if (!isPassed)
{
continue;
}
//
isPassed = false;
int fairValueGapsCount = ArraySize(fvgsState.bearishFVGs);
isPassed = IsValidSize(fairValueGapsCount);
if (!isPassed)
{
continue;
}
//
// Find Related Fair Value Gaps ...
isPassed = false;
for (int j = 0; j < fairValueGapsCount; j++)
{
//
XZone jFVG = fvgsState.bearishFVGs[j];
//
bool isBelongs = IsBearishOrderBlockFVG(
iBearishOrderBlock,
jFVG //
);
if (isBelongs)
{
//
iBearishFVG = jFVG;
conditions.bearishFVG = jFVG;
//
isPassed = true;
break;
}
}
// if (!isPassed)
// {
// continue;
// }
// //
// if (isPassed)
// {
// //
// DrawSupplyZone(iSupplyZone);
// DrawBearishOrderBlock(iBearishOrderBlock);
// DrawBearishFVG(iBearishFVG);
// }
}
//
// Demand Zone ...
for (int i = 0; i < demandZonesCount; i++)
{
//
XZone iDemandZone = supplyAndDemandZoneState.demandZones[i];
conditions.demandZone = iDemandZone;
//
XZone iBullishOrderBlock;
XZone iBullishFVG;
//
bool isPassed = false;
int orderBlocksCount = ArraySize(orderBlocksState.bullishOrderBlocks);
isPassed = IsValidSize(orderBlocksCount);
if (!isPassed)
{
continue;
}
//
// Find Related Order Block ...
isPassed = false;
for (int j = 0; j < orderBlocksCount; j++)
{
//
XZone jOrderBlock = orderBlocksState.bullishOrderBlocks[j];
//
bool isOrderBlockInsideZone = IsDemandZoneOrderBlock(
iDemandZone,
jOrderBlock //
);
if (isOrderBlockInsideZone)
{
//
isPassed = true;
iBullishOrderBlock = jOrderBlock;
conditions.bullishOrderBlock = jOrderBlock;
break;
}
}
if (!isPassed)
{
continue;
}
//
isPassed = false;
int fairValueGapsCount = ArraySize(fvgsState.bullishFVGs);
isPassed = IsValidSize(fairValueGapsCount);
if (!isPassed)
{
continue;
}
//
// Find Related Fair Value Gaps ...
isPassed = false;
for (int j = 0; j < fairValueGapsCount; j++)
{
//
XZone jFVG = fvgsState.bullishFVGs[j];
//
bool isBelongs = IsBullishOrderBlockFVG(
iBullishOrderBlock,
jFVG //
);
if (isBelongs)
{
//
iBullishFVG = jFVG;
conditions.bullishFVG = jFVG;
//
isPassed = true;
break;
}
}
// if (!isPassed)
// {
// continue;
// }
// //
// if (isPassed)
// {
// //
// DrawDemandZone(iDemandZone);
// DrawBullishOrderBlock(iBullishOrderBlock);
// DrawBullishFVG(iBullishFVG);
// }
}
//
}
//
// On X121 Signal Recieved Event Handler(s) ...
TOnX121SMCSignal mSignalEventHandlers[];
//
/**
* Notified Signal Event Handler(s) ...
*
* @param signal: XSignal instance ...
* @param conditions: XStrategyConditions instance ...
*/
void NotifyOnSignalEventHandlers(
XSignal &signal,
X121SMCStrategyConditions &conditions //
)
{
//
if (!signal.IsValid() || !conditions.IsValid())
{
return;
}
//
int count = ArraySize(mSignalEventHandlers);
if (!IsValidSize(count))
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
mSignalEventHandlers[i](
signal,
conditions //
);
}
}
//
// Tools Functions ...
/**
* Check an Order Block belongs to a Supply Zone ...
*
* @param supply: XZone instance ...
* @param orderBlock: XZone instance ...
*
* @return ( bool )
*/
bool IsSupplyZoneOrderBlock(
XZone &supply,
XZone &orderBlock //
)
{
//
bool result = false;
//
result = supply.IsValid() &&
orderBlock.IsValid();
if (!result)
{
return result;
}
//
result =
orderBlock.upper <= supply.upper;
//
return result;
}
/**
* Check an Order Block belongs to a Demand Zone ...
*
* @param demand: XZone instance ...
* @param orderBlock: XZone instance ...
*
* @return ( bool )
*/
bool IsDemandZoneOrderBlock(
XZone &demand,
XZone &orderBlock //
)
{
//
bool result = false;
//
result = demand.IsValid() &&
orderBlock.IsValid();
if (!result)
{
return result;
}
//
result =
orderBlock.lower >= demand.lower;
//
return result;
}
/**
* Check a Bearish FVG belongs to a Bearish Order Block ...
*
* @param orderBlock: XZone instance ...
* @param fvg: XZone instance ...
*
* @return ( bool )
*/
bool IsBearishOrderBlockFVG(
XZone &orderBlock,
XZone &fvg //
)
{
//
bool result = false;
//
result = fvg.IsValid() &&
orderBlock.IsValid();
if (!result)
{
return result;
}
//
result =
fvg.upper <= orderBlock.upper &&
fvg.upper > orderBlock.lower;
//
return result;
}
/**
* Check a Bullish FVG belongs to a Bullish Order Block ...
*
* @param orderBlock: XZone instance ...
* @param fvg: XZone instance ...
*
* @return ( bool )
*/
bool IsBullishOrderBlockFVG(
XZone &orderBlock,
XZone &fvg //
)
{
//
bool result = false;
//
result = fvg.IsValid() &&
orderBlock.IsValid();
if (!result)
{
return result;
}
//
result =
fvg.lower >= orderBlock.lower &&
fvg.lower < orderBlock.upper;
//
return result;
}
//
// Draw Functions ...
/**
* Draw Specific Swing High ...
*
* @param swing: XOHCL instance which represents Swing Point ...
*/
void DrawSwingHigh(XOHCL &swing)
{
//
if (!swing.IsValid())
{
return;
}
//
string name = swing.GetTag(ToString(X_POI_SWING_HIGH));
//
if (mSwingHigh.IsValid())
{
//
mSwingHigh.Clean();
mSwingHighObject.Delete();
}
//
mSwingHigh = swing;
mSwingHighObject = new CChartObjectHLine();
bool isCreated = mSwingHighObject.Create(
ChartID(),
name,
0,
swing.high //
);
if (!isCreated)
{
return;
}
//
mSwingHighObject.Width(1);
mSwingHighObject.Color(clrBrown);
mSwingHighObject.Style(STYLE_SOLID);
}
/**
* Draw Specific Swing Low ...
*
* @param swing: XOHCL instance which represents Swing Point ...
*/
void DrawSwingLow(XOHCL &swing)
{
//
if (!swing.IsValid())
{
return;
}
//
string name = swing.GetTag(ToString(X_POI_SWING_LOW));
//
if (mSwingLow.IsValid())
{
//
mSwingLow.Clean();
mSwingLowObject.Delete();
}
//
mSwingLow = swing;
mSwingLowObject = new CChartObjectHLine();
//
bool isCreated = mSwingLowObject.Create(
ChartID(),
name,
0,
swing.low //
);
if (!isCreated)
{
return;
}
//
mSwingLowObject.Width(1);
mSwingLowObject.Color(clrGreen);
mSwingLowObject.Style(STYLE_SOLID);
}
/**
* Draw Supply Zone ...
*
* @param zone: XZone instance ...
*/
void DrawSupplyZone(XZone &zone)
{
//
if (!zone.IsValid())
{
return;
}
//
string name = zone.GetTag();
RemoveObject(name);
//
zone.to = TimeCurrent();
name = zone.GetTag();
//
XCSupplyZoneObject *iObj;
iObj = new XCSupplyZoneObject();
bool isCreated = iObj.CreateByZone(
ChartID(),
name,
0,
zone,
NULL,
true //
);
if (!isCreated)
{
return;
}
//
iObj.ZoneWidth(1);
iObj.ZoneStyle(STYLE_DOT);
iObj.ZoneColor(clrMagenta);
//
mDrawnObjects.Add(iObj);
}
/**
* Draw Demand Zone ...
*
* @param zone: XZone instance ...
*/
void DrawDemandZone(XZone &zone)
{
//
if (!zone.IsValid())
{
return;
}
//
string name = zone.GetTag();
RemoveObject(name);
//
zone.to = TimeCurrent();
name = zone.GetTag();
//
XCDemandZoneObject *iObj;
iObj = new XCDemandZoneObject();
bool isCreated = iObj.CreateByZone(
ChartID(),
name,
0,
zone,
NULL,
true //
);
if (!isCreated)
{
return;
}
//
iObj.ZoneWidth(1);
iObj.ZoneStyle(STYLE_DOT);
iObj.ZoneColor(clrAqua);
//
mDrawnObjects.Add(iObj);
}
/**
* Draw Specific Bearish Order Block ...
*
* @param zone: XZone instance ...
*/
void DrawBearishOrderBlock(XZone &zone)
{
//
if (!zone.IsValid())
{
return;
}
//
string name = zone.GetTag();
RemoveObject(name);
//
zone.to = TimeCurrent();
name = zone.GetTag();
//
XCBearishOrderBlockObject *iObj;
iObj = new XCBearishOrderBlockObject();
bool isCreated = iObj.CreateByZone(
ChartID(),
name,
0,
zone,
NULL,
true //
);
if (!isCreated)
{
return;
}
//
iObj.ZoneWidth(1);
iObj.ZoneColor(clrRed);
iObj.ZoneStyle(STYLE_DASH);
//
mDrawnObjects.Add(iObj);
}
/**
* Draw Specific Bullish Order Block ...
*
* @param zone: XZone instance ...
*/
void DrawBullishOrderBlock(XZone &zone)
{
//
if (!zone.IsValid())
{
return;
}
//
string name = zone.GetTag();
RemoveObject(name);
//
zone.to = TimeCurrent();
name = zone.GetTag();
//
XCBullishOrderBlockObject *iObj;
iObj = new XCBullishOrderBlockObject();
bool isCreated = iObj.CreateByZone(
ChartID(),
name,
0,
zone,
NULL,
true //
);
if (!isCreated)
{
return;
}
//
iObj.ZoneWidth(1);
iObj.ZoneColor(clrLime);
iObj.ZoneStyle(STYLE_DASH);
//
mDrawnObjects.Add(iObj);
}
/**
* Draw Specific Bearish FVG ...
*
* @param zone: XZone instance ...
*/
void DrawBearishFVG(XZone &zone)
{
//
if (!zone.IsValid())
{
return;
}
//
string name = zone.GetTag();
RemoveObject(name);
//
zone.to = TimeCurrent();
name = zone.GetTag();
//
XCBearishFVGObject *iObj;
iObj = new XCBearishFVGObject();
bool isCreated = iObj.CreateByZone(
ChartID(),
name,
0,
zone,
NULL,
true //
);
if (!isCreated)
{
return;
}
//
iObj.ZoneWidth(1);
iObj.ZoneColor(clrOrange);
iObj.ZoneStyle(STYLE_DASHDOT);
//
mDrawnObjects.Add(iObj);
}
/**
* Draw Specific Bullish FVG ...
*
* @param zone: XZone instance ...
*/
void DrawBullishFVG(XZone &zone)
{
//
if (!zone.IsValid())
{
return;
}
//
string name = zone.GetTag();
RemoveObject(name);
//
zone.to = TimeCurrent();
name = zone.GetTag();
//
XCBullishFVGObject *iObj;
iObj = new XCBullishFVGObject();
bool isCreated = iObj.CreateByZone(
ChartID(),
name,
0,
zone,
NULL,
true //
);
if (!isCreated)
{
return;
}
//
iObj.ZoneWidth(1);
iObj.ZoneColor(clrSteelBlue);
iObj.ZoneStyle(STYLE_DASHDOT);
//
mDrawnObjects.Add(iObj);
}
/**
* Draw Specified Swing Bars ...
*
* @param bar: XOHLC instance ...
* @param isLow: Boolean ...
*/
void DrawSwingBar(
XOHCL &bar,
bool isLow //
)
{
//
if (!bar.IsValid())
{
return;
}
//
string tagPref =
isLow
? ToString(X_POI_SWING_LOW)
: ToString(X_POI_SWING_HIGH);
string name = bar.GetTag(tagPref);
RemoveObject(name);
//
double price =
isLow
? bar.low
: bar.high;
char arrowCode =
isLow
? (char)188
: (char)108;
color clr =
isLow
? clrAqua
: clrMagenta;
ENUM_ARROW_ANCHOR anchor =
isLow
? ANCHOR_TOP
: ANCHOR_BOTTOM;
//
CChartObjectArrow *iObj;
iObj = new CChartObjectArrow();
bool isCreated = iObj.Create(
ChartID(),
name,
0,
bar.time,
price,
arrowCode //
);
if (!isCreated)
{
return;
}
//
// Configure Object ...
iObj.Width(1);
iObj.Color(clr);
iObj.Anchor(anchor);
//
mDrawnObjects.Add(iObj);
}
/**
* Draw Momentum Bar ...
*
* @param bar: XOHCL instance ...
*/
void DrawMomentumBar(XOHCL &bar)
{
//
if (!bar.IsValid())
{
return;
}
//
bool isBullish = bar.IsBullish();
string name = bar.GetTag(ToString(X_POI_MOMENTUM_BAR));
RemoveObject(name);
//
double price =
isBullish
? bar.low
: bar.high;
char arrowCode =
isBullish
? (char)225
: (char)226;
color clr =
isBullish
? clrAqua
: clrMagenta;
ENUM_ARROW_ANCHOR anchor =
isBullish
? ANCHOR_TOP
: ANCHOR_BOTTOM;
//
CChartObjectArrow *iObj;
iObj = new CChartObjectArrow();
bool isCreated = iObj.Create(
ChartID(),
name,
0,
bar.time,
price,
arrowCode //
);
if (!isCreated)
{
return;
}
//
// Configure Object ...
iObj.Width(1);
iObj.Color(clr);
iObj.Anchor(anchor);
//
mDrawnObjects.Add(iObj);
}
/**
* Draw Bullish Rejection Bar ...
*
* @param bar: XOHCL instance ...
*/
void DrawRejectionBar(XOHCL &bar)
{
//
if (!bar.IsValid())
{
return;
}
//
bool isBullish = bar.GetLowShadow() > bar.GetHighShadow();
string name = bar.GetTag(ToString(X_POI_REJECTION_BAR));
RemoveObject(name);
//
double price =
isBullish
? bar.low
: bar.high;
char arrowCode =
isBullish
? (char)217
: (char)218;
color clr =
isBullish
? clrAqua
: clrMagenta;
ENUM_ARROW_ANCHOR anchor =
isBullish
? ANCHOR_TOP
: ANCHOR_BOTTOM;
//
CChartObjectArrow *iObj;
iObj = new CChartObjectArrow();
bool isCreated = iObj.Create(
ChartID(),
name,
0,
bar.time,
price,
arrowCode //
);
if (!isCreated)
{
return;
}
//
// Configure Object ...
iObj.Width(1);
iObj.Color(clr);
iObj.Anchor(anchor);
//
mDrawnObjects.Add(iObj);
}
/**
* Draw Specific Condition ...
*
* @param conditions: Argument 1
*/
void DrawConditions(X121SMCStrategyConditions &conditions)
{
//
if (conditions.supplyZone.IsValid())
{
DrawSupplyZone(conditions.supplyZone);
}
//
if (conditions.bearishOrderBlock.IsValid())
{
DrawBearishOrderBlock(conditions.bearishOrderBlock);
}
//
if (conditions.bearishFVG.IsValid())
{
DrawBearishFVG(conditions.bearishFVG);
}
//
if (conditions.demandZone.IsValid())
{
DrawDemandZone(conditions.demandZone);
}
//
if (conditions.bullishOrderBlock.IsValid())
{
DrawBullishOrderBlock(conditions.bullishOrderBlock);
}
//
if (conditions.bullishFVG.IsValid())
{
DrawBullishFVG(conditions.bullishFVG);
}
}
/**
* Draw Specified Signal ...
*
* @param signal: XSignal instance ...
* @param conditions: X121SMCStrategyConditions instance ...
*/
void DrawSignal(
XSignal &signal,
X121SMCStrategyConditions &conditions //
)
{
//
if (!signal.IsValid() ||
!conditions.IsValid())
{
//
return;
}
//
// DrawConditions(conditions);
//
string name = signal.GetTag();
RemoveObject(name);
//
XCSignalObject *iObj;
iObj = new XCSignalObject();
//
bool isCreated = iObj.Create(
ChartID(),
name,
0,
signal //
);
if (!isCreated)
{
return;
}
//
iObj.TPWidth(1);
iObj.TPColor(clrGreen);
iObj.TPWidth(STYLE_DOT);
//
iObj.SLWidth(1);
iObj.SLColor(clrRed);
iObj.SLWidth(STYLE_DOT);
//
iObj.EntryWidth(1);
iObj.EntryColor(clrYellow);
iObj.EntryWidth(STYLE_DOT);
//
mDrawnObjects.Add(iObj);
}
//
};
//