diff --git a/Classes/x-saherelm.x-poi.class.mq5 b/Classes/x-saherelm.x-poi.class.mq5 index 0ea38681..0e9fcd6c 100644 --- a/Classes/x-saherelm.x-poi.class.mq5 +++ b/Classes/x-saherelm.x-poi.class.mq5 @@ -2657,8 +2657,8 @@ class XCPOI : public XSCBaseAlert int rejectionBarLoopBackBarIndex = RejectionBarLoopBack() + 1; XOHCL iRBar; bool isIRBarInited = iRBar.Init( - Symbol(), - Period(), + mSymbol, + mPeriod, rejectionBarLoopBackBarIndex // ); if (isIRBarInited) @@ -2808,7 +2808,7 @@ class XCPOI : public XSCBaseAlert datetime endTime = cBar.time; XOHCL cSupplyBar; bool isSupplyBarInited = cSupplyBar.Init( - Symbol(), + mSymbol, SupplyZonePeriod(), 0 // ); @@ -2816,14 +2816,14 @@ class XCPOI : public XSCBaseAlert { // datetime lastSupplyBarTime = cSupplyBar - .GetLastBarTimeOfPeriod(Period()); + .GetLastBarTimeOfPeriod(mPeriod); if (zBar.time == lastSupplyBarTime) { // datetime startTime = cSupplyBar.time; int cSupplyZonePeriodIndex = iBarShift( - Symbol(), - Period(), + mSymbol, + mPeriod, cSupplyBar.time // ); @@ -2835,8 +2835,8 @@ class XCPOI : public XSCBaseAlert // XOHCL iBar; bool isIBarInited = iBar.Init( - Symbol(), - Period(), + mSymbol, + mPeriod, i // ); if (!isIBarInited) @@ -2936,10 +2936,10 @@ class XCPOI : public XSCBaseAlert if (allowDemandZones) { // - endTime = cBar.time; + datetime endTime = cBar.time; XOHCL cDemandBar; bool isDemandBarInited = cDemandBar.Init( - Symbol(), + mSymbol, DemandZonePeriod(), 0 // ); @@ -2947,14 +2947,14 @@ class XCPOI : public XSCBaseAlert { // datetime lastDemandBarTime = cDemandBar - .GetLastBarTimeOfPeriod(Period()); + .GetLastBarTimeOfPeriod(mPeriod); if (zBar.time == lastDemandBarTime) { // datetime startTime = cDemandBar.time; int cDemandZonePeriodIndex = iBarShift( - Symbol(), - Period(), + mSymbol, + mPeriod, cDemandBar.time // ); @@ -2966,8 +2966,8 @@ class XCPOI : public XSCBaseAlert // XOHCL iBar; bool isIBarInited = iBar.Init( - Symbol(), - Period(), + mSymbol, + mPeriod, i // ); if (!isIBarInited) @@ -3281,7 +3281,7 @@ class XCPOI : public XSCBaseAlert /** * Set All POIs Detection States ... * - * @param state: Argument 1 + * @param state: Argument 1 */ void ChangePOIsState(bool state) { @@ -3370,8 +3370,8 @@ class XCPOI : public XSCBaseAlert state.Clean(); // - state.symbol = Symbol(); - state.period = Period(); + state.symbol = mSymbol; + state.period = mPeriod; state.reportedAt = TimeCurrent(); // @@ -3565,14 +3565,14 @@ class XCPOI : public XSCBaseAlert SupplyZoneWidth(1); SupplyZoneColor(clrDarkRed); SupplyZoneStyle(STYLE_DASH); - SupplyZonePeriod(GetHindMostPeriod(Period())); + SupplyZonePeriod(GetHindMostPeriod(mPeriod)); // // Demand Zones ... DemandZoneWidth(1); DemandZoneColor(clrDarkGreen); DemandZoneStyle(STYLE_DASH); - DemandZonePeriod(GetHindMostPeriod(Period())); + DemandZonePeriod(GetHindMostPeriod(mPeriod)); // // Order Blocks ... @@ -4496,7 +4496,7 @@ class XCPOI : public XSCBaseAlert // datetime cSupplyZoneStartTime = iTime( - Symbol(), + mSymbol, SupplyZonePeriod(), supplyZonesCount + 1 // ); @@ -4504,8 +4504,8 @@ class XCPOI : public XSCBaseAlert // int cSupplyZoneStartIndex = iBarShift( - Symbol(), - Period(), + mSymbol, + mPeriod, cSupplyZoneStartTime // ); @@ -4516,8 +4516,8 @@ class XCPOI : public XSCBaseAlert // XOHCL iBar; bool isIBarInited = iBar.Init( - Symbol(), - Period(), + mSymbol, + mPeriod, i // ); if (!isIBarInited) @@ -4596,7 +4596,7 @@ class XCPOI : public XSCBaseAlert // datetime cDemandZoneStartTime = iTime( - Symbol(), + mSymbol, DemandZonePeriod(), demandZonesCount + 1 // ); @@ -4604,8 +4604,8 @@ class XCPOI : public XSCBaseAlert // int cDemandZoneStartIndex = iBarShift( - Symbol(), - Period(), + mSymbol, + mPeriod, cDemandZoneStartTime // ); @@ -4616,8 +4616,8 @@ class XCPOI : public XSCBaseAlert // XOHCL iBar; bool isIBarInited = iBar.Init( - Symbol(), - Period(), + mSymbol, + mPeriod, i // ); if (!isIBarInited) @@ -4666,7 +4666,7 @@ class XCPOI : public XSCBaseAlert bool isInited = zone.Init( selectedSwing.high, selectedSwing.low, - ToString(X_POI_DEMAND_ZONE) + "_" + ToString(SupplyZonePeriod()), + ToString(X_POI_DEMAND_ZONE) + "_" + ToString(DemandZonePeriod()), startTime, endTime // ); @@ -7773,7 +7773,7 @@ class XCPOI : public XSCBaseAlert NormalizeTime(endTime); // - datetime startTime = (datetime)((int)ob.time - (PeriodSeconds(Period()) * 2)); + datetime startTime = (datetime)((int)ob.time - (PeriodSeconds(mPeriod) * 2)); // result = zone.Init( @@ -8641,8 +8641,8 @@ class XCPOI : public XSCBaseAlert { // cBarTime = iTime( - Symbol(), - Period(), + mSymbol, + mPeriod, bar.Index() - 10 // ); } @@ -8712,8 +8712,8 @@ class XCPOI : public XSCBaseAlert { // cBarTime = iTime( - Symbol(), - Period(), + mSymbol, + mPeriod, bar.Index() - 10 // ); } diff --git a/Libraries/x-saherelm.common.lib.mq5 b/Libraries/x-saherelm.common.lib.mq5 index c54bfd82..00c7e3de 100644 --- a/Libraries/x-saherelm.common.lib.mq5 +++ b/Libraries/x-saherelm.common.lib.mq5 @@ -191,6 +191,101 @@ enum ENUM_X_MARKET_CYCLES // // Structs ... +// +// Model Specified Ticks Info ... +struct XTick +{ + // + string symbol; // Symbol ... + datetime time; // Time ... + double bid; // Bid ... + double ask; // Ask ... + + // + // Constructor ... + void XTick() + { + Clean(); + } + + // + // Tools Functions ... + + /** + * Initial ... + * + * @param _symbol: Symbol ... + * @param _time: Time ... + * @param _bid: Bid Price ... + * @param _ask: Ask Price ... + */ + bool Init( + string _symbol, + datetime _time, + double _bid, + double _ask // + ) + { + // + bool result = false; + + // + result = IsValid(_symbol) && + IsValid(_time) && + _bid > 0 && + _ask > 0; + if (!result) { + return result; + } + + // + symbol = _symbol; + time = _time; + bid = _bid; + ask = _ask; + + // + result = IsValid(); + + // + return result; + } + + /** + * Cleanup ... + */ + void Clean() + { + // + bid = 0; + ask = 0; + time = NULL; + symbol = NULL; + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = IsValid(symbol) && + IsValid(time) && + bid > 0 && + ask > 0; + + // + return result; + } + + // +}; + // // Model a Bar Remains Time ... struct XBarRemainsTime @@ -1125,6 +1220,8 @@ struct XOHCL int destSeconds = PeriodSeconds(smallerPeriod); if (destSeconds >= sourceSeconds) { + // + result = time; return result; } diff --git a/Libraries/x-saherelm.x-poi.lib.mq5 b/Libraries/x-saherelm.x-poi.lib.mq5 index e47ba42d..a9d89520 100644 --- a/Libraries/x-saherelm.x-poi.lib.mq5 +++ b/Libraries/x-saherelm.x-poi.lib.mq5 @@ -1358,4 +1358,290 @@ string ToString(ENUM_XPOI_EVENTS value) // return result; -} \ No newline at end of file +} + +// +// XOHCL Extensions ... + +/** + * Check two Bar is Same or not ... + * + * @param source: XOHCL instance ... + * @param dest: XOHCL instance ... + * @param force: Check also it's Dates ... + * + * @return ( bool ) + */ +bool IsSame( + XOHCL &source, + XOHCL &dest // +) +{ + // + bool result = false; + + // + result = source.IsValid() && + dest.IsValid(); + if (!result) + { + return result; + } + + // + result = + source.open == dest.open && + source.close == dest.close && + source.high == dest.high && + source.low == dest.low; + if (!result) + { + return result; + } + + // + return result; +} + +/** + * Find Specific Items Index inside a Collection ... + * + * @param source: XOHCL instance ... + * @param dest: XOHCL instance Collection ... + * + * @return ( int ) + */ +int FindIndex( + XOHCL &source, + XOHCL &dest[] // +) +{ + // + int result = -1; + + // + if (!source.IsValid()) + { + return result; + } + + // + int count = ArraySize(dest); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = dest[i]; + + // + bool isSame = IsSame( + source, + iBar // + ); + if (isSame) + { + // + result = i; + break; + } + } + + // + return result; +} + +/** + * Add Specific Bar to List only if Not Exists ... + * + * @param source: XOHCL instance ... + * @param dest: XOHCL instance Collection ... + * + * @return ( bool ) + */ +bool AddIfNotExists( + XOHCL &source, + XOHCL &dest[] // +) +{ + // + bool result = false; + + // + int count = ArraySize(dest); + result = source.IsValid(); + if (!result) + { + return result; + } + + // + int idx = FindIndex(source, dest); + bool isExists = IsValidIndex(idx); + if (isExists) + { + // + AddRef( + source, + dest // + ); + + // + result = isExists; + } + + // + return result; +} + +// +// XZone Extensions ... + +/** + * Check two Zone is Same or not ... + * + * @param source: XZone instance ... + * @param dest: XZone instance ... + * @param force: Check also it's Dates ... + * + * @return ( bool ) + */ +bool IsSame( + XZone &source, + XZone &dest, + bool force = false // +) +{ + // + bool result = false; + + // + result = source.IsValid() && + dest.IsValid(); + if (!result) + { + return result; + } + + // + result = + source.upper == dest.upper && + source.lower == dest.lower; + if (!result) + { + return result; + } + + // + if (force) + { + // + result = + source.from == dest.from && + source.to == dest.to; + } + + // + return result; +} + +/** + * Find Specific Items Index inside a Collection ... + * + * @param source: XZone instance ... + * @param dest: XZone instance Collection ... + * + * @return ( int ) + */ +int FindIndex( + XZone &source, + XZone &dest[] // +) +{ + // + int result = -1; + + // + if (!source.IsValid()) + { + return result; + } + + // + int count = ArraySize(dest); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XZone iZone = dest[i]; + + // + bool isSame = IsSame( + source, + iZone // + ); + if (isSame) + { + // + result = i; + break; + } + } + + // + return result; +} + +/** + * Add Specific Zone to List only if Not Exists ... + * + * @param source: XZone instance ... + * @param dest: XZone instance Collection ... + * + * @return ( bool ) + */ +bool AddIfNotExists( + XZone &source, + XZone &dest[] // +) +{ + // + bool result = false; + + // + int count = ArraySize(dest); + result = source.IsValid(); + if (!result) + { + return result; + } + + // + int idx = FindIndex(source, dest); + bool isExists = IsValidIndex(idx); + if (isExists) + { + // + AddRef( + source, + dest // + ); + + // + result = isExists; + } + + // + return result; +} + +// \ No newline at end of file diff --git a/X121SMCEA/Libraries/x-121.smc.lib.mq5 b/X121SMCEA/Libraries/x-121.smc.lib.mq5 index bb951e1a..da4868de 100644 --- a/X121SMCEA/Libraries/x-121.smc.lib.mq5 +++ b/X121SMCEA/Libraries/x-121.smc.lib.mq5 @@ -47,7 +47,17 @@ struct X121SMCStrategyConditions datetime time; // - // Helper Conditions ... + // Conditions ... + + // + XZone supplyZone; + XZone bearishOrderBlock; + XZone bearishFVG; + + // + XZone demandZone; + XZone bullishOrderBlock; + XZone bullishFVG; // // Constructor ... diff --git a/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 b/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 index bc0c56c4..21f076fa 100644 --- a/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 +++ b/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 @@ -184,7 +184,7 @@ class XCX121SMCStrategy : public XSCBaseAlert /** * Set Short Signalling State ... * - * @param value: Argument 1 + * @param value: Argument 1 */ void AllowShort(bool value) { @@ -269,6 +269,27 @@ class XCX121SMCStrategy : public XSCBaseAlert // // 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 ... @@ -373,68 +394,13 @@ class XCX121SMCStrategy : public XSCBaseAlert conditions.period = mPeriod; conditions.time = cBar.time; - // - int pushers = 0; - string signallers[]; - - // - // Define Conditions ... - MqlTick ticks[]; - int ticksCount = CopyTicks( - mSymbol, - ticks, - COPY_TICKS_ALL, - 0, - 5 // - ); - - // - bool isTicksBullishForLong = false; - bool isTicksBearishForLong = false; - bool isTicksBullishForShort = false; - bool isTicksBearishForShort = false; - if (ticksCount == 5) - { - // - isTicksBullishForLong = - // - GetTickEntry(ticks[0], POSITION_TYPE_BUY, mSymbol) > GetTickEntry(ticks[1], POSITION_TYPE_BUY, mSymbol) && - GetTickEntry(ticks[1], POSITION_TYPE_BUY, mSymbol) > GetTickEntry(ticks[2], POSITION_TYPE_BUY, mSymbol) && - GetTickEntry(ticks[2], POSITION_TYPE_BUY, mSymbol) > GetTickEntry(ticks[3], POSITION_TYPE_BUY, mSymbol) - // - ; - - // - isTicksBearishForLong = - // - GetTickEntry(ticks[0], POSITION_TYPE_BUY, mSymbol) < GetTickEntry(ticks[1], POSITION_TYPE_BUY, mSymbol) && - GetTickEntry(ticks[1], POSITION_TYPE_BUY, mSymbol) < GetTickEntry(ticks[2], POSITION_TYPE_BUY, mSymbol) && - GetTickEntry(ticks[2], POSITION_TYPE_BUY, mSymbol) < GetTickEntry(ticks[3], POSITION_TYPE_BUY, mSymbol) - // - ; - - // - isTicksBullishForShort = - // - GetTickEntry(ticks[0], POSITION_TYPE_SELL, mSymbol) > GetTickEntry(ticks[1], POSITION_TYPE_SELL, mSymbol) && - GetTickEntry(ticks[1], POSITION_TYPE_SELL, mSymbol) > GetTickEntry(ticks[2], POSITION_TYPE_SELL, mSymbol) && - GetTickEntry(ticks[2], POSITION_TYPE_SELL, mSymbol) > GetTickEntry(ticks[3], POSITION_TYPE_SELL, mSymbol) - // - ; - - // - isTicksBearishForShort = - // - GetTickEntry(ticks[0], POSITION_TYPE_SELL, mSymbol) < GetTickEntry(ticks[1], POSITION_TYPE_SELL, mSymbol) && - GetTickEntry(ticks[1], POSITION_TYPE_SELL, mSymbol) < GetTickEntry(ticks[2], POSITION_TYPE_SELL, mSymbol) && - GetTickEntry(ticks[2], POSITION_TYPE_SELL, mSymbol) < GetTickEntry(ticks[3], POSITION_TYPE_SELL, mSymbol) - // - ; - } - // // Reading POI(s) ... + // + XPOIState _4HSupDemState; + m4HSupDemPOI.GetState(_4HSupDemState); + // // 4H ... XPOIState _4HState; @@ -459,201 +425,127 @@ class XCX121SMCStrategy : public XSCBaseAlert // - [] contains Engulfing ... // - [] has Order Block ... // - [] has FVG ... - XZone _4hSupplyZone; - XZone _4HDemandZone; - DetectSupplyAndDemandZones( + DetectImportantPOIs( + conditions, + _4HSupDemState, _4HState, - _4hSupplyZone, - _4HDemandZone // + _15MState, + _5MState // ); - - // - if (_4hSupplyZone.IsValid()) + if (conditions.supplyZone.IsValid() || + conditions.bearishFVG.IsValid() || + conditions.bearishOrderBlock.IsValid()) { // - // Update Supply Zone Time ... - string iName = _4hSupplyZone.GetTag(); - _4hSupplyZone.to = zBar.time; + 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 ... + for (int i = 0; i < conditionsCount; i++) + { + // + X121SMCStrategyConditions iConditions = mConditions[i]; // - int count = mDrawnObjects.Total(); - if (IsValidSize(count)) + // LONG ... + + // + bool isSoImportantLong = + conditions.demandZone.IsValid() && + conditions.bullishFVG.IsValid() && + conditions.bullishOrderBlock.IsValid(); + + // + bool isImportantLong = + conditions.demandZone.IsValid() && + (conditions.bullishFVG.IsValid() || + conditions.bullishOrderBlock.IsValid()); + + // + bool isRiskyLong = + conditions.demandZone.IsValid() && + (conditions.bullishFVG.IsValid() || + conditions.bullishOrderBlock.IsValid()); + + // + bool hasLongConditions = isSoImportantLong; + // || + // isImportantLong || + // isRiskyLong; + + // + if (hasLongConditions) { // - int idx = -1; - for (int i = 0; i < count; i++) - { - // - int type = ((CChartObject *)mDrawnObjects.At(i)).Type(); - if (type == (int)X_SUPPLY_ZONE) - { - // - string objName = ((XCZoneObject *)mDrawnObjects.At(i)).ObjName(); - if (objName == iName) - { - // - idx = i; - break; - } - } - } + DrawConditions(conditions); + Print("hasLongConditions"); + } + // + // SHORT ... + + // + bool isSoImportantShort = + conditions.supplyZone.IsValid() && + conditions.bearishFVG.IsValid() && + conditions.bearishOrderBlock.IsValid(); + + // + bool isImportantShort = + conditions.supplyZone.IsValid() && + (conditions.bearishFVG.IsValid() || + conditions.bearishOrderBlock.IsValid()); + + // + bool isRiskyShort = + conditions.supplyZone.IsValid() && + (!conditions.bearishFVG.IsValid() && + !conditions.bearishOrderBlock.IsValid()); + + // + bool hasShortConditions = isSoImportantShort; + // || + // isImportantShort || + // isRiskyShort; + + // + if (hasShortConditions) + { // - if (IsValidIndex(idx)) - { - mDrawnObjects.Delete(idx); - } + DrawConditions(conditions); + Print("hasShortConditions"); } // - iName = _4hSupplyZone.GetTag(); - XCZoneObject *iObj; - bool isCreated = iObj.CreateByZone( - ChartID(), - iName, - 0, - _4hSupplyZone, - NULL, - true // - ); } - // - // LONGS ... - - // - bool hasLong1 = - // - false - // - ; - if (hasLong1) - { - // - pushers++; - Add( - "LONG_1", - signallers // - ); - - // - // TODO: Implement SL/TP Calculation based on R2R ... - - // - // sl = 0; - type = POSITION_TYPE_BUY; - } - - // - // SHORTS ... - - // - bool hasShort1 = - // - // TODO: Implement Long Conditions ... - false - // - ; - if (hasShort1) - { - // - pushers++; - Add( - "SHORT_1", - signallers // - ); - - // - // TODO: Implement SL/TP Calculation based on R2R ... - - // - // sl = 0; - type = POSITION_TYPE_SELL; - } - - // - // Combine Signals ... - - // - hasLong = - // - hasLong1 || - // - // TODO: Attach other Conditions ... - false - // - ; - - // - hasShort = - // - hasShort1 || - // - // TODO: Attach other Conditions ... - false - // - ; - - // - result = hasLong || hasShort; - if (!result) - { - return result; - } - - // - // Retrieve Entry Price based on Position Type ... - entry = GetEntry(mSymbol, type); - - // - // Calculate TP and SL ... - // based on Strategy ... - // only when on of TP or SL Provides, using provided R2R ... - if ((tp <= 0 && sl > 0) || (tp > 0 && sl <= 0)) - { - // - CalculateTPSLByPrice( - sl, - tp, - type, - entry, - r2r // - ); - } - - // - // Prepare Signal ... - result = signal.Prepare( - mSymbol, - signallers[0], - mPeriod, - type, - mode, - entry, - volume, - sl, - tp // - ); - if (!result) - { - return result; - } - - // - signal.pushers = pushers; - - // - // Prepare and Normalize Signal for Execution in Strategy ... - result = PrepareSignal(signal); - if (!result) - { - return result; - } - - // - // Attach Strategy Lebel ... - signal.provider = X121SMCStrategyToken; - // return result; } @@ -692,12 +584,75 @@ class XCX121SMCStrategy : public XSCBaseAlert double mVolume; // Static Volume Per Trades ... // - MqlTick mLastTick; // Last Issued Tick ... + MqlTick mLastTick; // Last Issued Tick ... + XTick mTicks[]; // Hold Ticks Data ... + + /** + * 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() + { + // + datetime time = TimeCurrent(); + double ask = GetAsk(mSymbol); + double bid = GetBid(mSymbol); + + // + XTick tick; + bool isInited = tick.Init( + mSymbol, + time, + bid, + ask // + ); + if (!isInited) + { + return; + } + + // + AddRef( + tick, + mTicks // + ); + } + + // XBarTracker mBarTracker; // Strategy Time Tracker ... // // Point Of Interests ... XCPOI *m4HPOI; + XCPOI *m4HSupDemPOI; XCPOI *m15MPOI; XCPOI *m5MPOI; @@ -705,6 +660,77 @@ class XCX121SMCStrategy : public XSCBaseAlert // Collect all Drawn Objects ... CArrayObj mDrawnObjects; + /** + * 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 = ((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 ... @@ -730,8 +756,29 @@ class XCX121SMCStrategy : public XSCBaseAlert // // 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 // @@ -741,7 +788,6 @@ class XCX121SMCStrategy : public XSCBaseAlert m4HPOI.Window(0); m4HPOI.DisableDrawPOIs(); m4HPOI.ChartID(ChartID()); - m4HPOI.MaxNumberOfRequiredPOIs(0); m4HPOI.SupplyZonePeriod(PERIOD_H4); m4HPOI.DemandZonePeriod(PERIOD_H4); @@ -750,6 +796,7 @@ class XCX121SMCStrategy : public XSCBaseAlert // // 15M Period ... + // POI Detector ... m15MPOI = new XCPOI( symbol, PERIOD_M15 // @@ -768,9 +815,10 @@ class XCX121SMCStrategy : public XSCBaseAlert // // Trigger Period ... + // POI Detector ... m5MPOI = new XCPOI( symbol, - period // + PERIOD_M5 // ); // @@ -796,6 +844,7 @@ class XCX121SMCStrategy : public XSCBaseAlert delete m4HPOI; delete m5MPOI; delete m15MPOI; + // delete m4HSupDemPOI; } /** @@ -845,26 +894,62 @@ class XCX121SMCStrategy : public XSCBaseAlert } /** - * Detect Supply and Demand Zones ... + * Update Supply and Demand Zones ... * - * @param state: Argument 1 - * @param supplyZone: Argument 2 - * @param demandZone: Argument 3 + * @param state: Argument 1 */ - void DetectSupplyAndDemandZones( - XPOIState &state, - XZone &supplyZone, - XZone &demandZone // + void DetectImportantPOIs( + X121SMCStrategyConditions &conditions, + XPOIState &supplyAndDemandZoneState, + XPOIState &orderBlocksState, + XPOIState &fvgsState, + XPOIState &triggerState // ) { // - supplyZone.Clean(); - demandZone.Clean(); + int supplyZonesCount = ArraySize(supplyAndDemandZoneState.supplyZones); + int demandZonesCount = ArraySize(supplyAndDemandZoneState.demandZones); // - int supplyZonesCount = ArraySize(state.supplyZones); - int demandZonesCount = ArraySize(state.demandZones); - if (!IsValidSize(supplyZonesCount) && + 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; @@ -883,58 +968,236 @@ class XCX121SMCStrategy : public XSCBaseAlert } // - // Detect Supply Zone ... + // 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 iZone = state.supplyZones[i]; + XZone iSupplyZone = supplyAndDemandZoneState.supplyZones[i]; + conditions.supplyZone = iSupplyZone; // - // Retrieve Zone From Index Based On Current Period ... - int iZoneStartBarIndex = iBarShift( - Symbol(), - Period(), - iZone.from // - ); + XZone iBearishOrderBlock; + XZone iBearishFVG; // - // Check Zone is Fresh Or Not ... - bool isFreshZone = true; - for (int j = iZoneStartBarIndex - 1; j >= 0; j++) - { - // - XOHCL jBar; - bool isInited = jBar.Init( - Symbol(), - Period(), - j // - ); - if (!isInited) - { - continue; - } - - // - if (jBar.high > iZone.lower) - { - // - isFreshZone = false; - break; - } - - // - } - - // - if (!isFreshZone) + bool isPassed = false; + int orderBlocksCount = ArraySize(orderBlocksState.bearishOrderBlocks); + isPassed = IsValidSize(orderBlocksCount); + if (!isPassed) { continue; } // - supplyZone = iZone; - break; + // 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); + // } + } + + // } // @@ -977,6 +1240,648 @@ class XCX121SMCStrategy : public XSCBaseAlert } } + // + // 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); + // int idx = FindIndex(zone, mSupplyZones); + // if (IsValidIndex(idx)) + // { + // // // + // // ArrayRemove( + // // mSupplyZones, + // // idx, + // // 1 // + // // ); + + // // + // } + + // + zone.to = TimeCurrent(); + name = zone.GetTag(); + // AddRef( + // zone, + // mSupplyZones // + // ); + + // + 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); + // int idx = FindIndex(zone, mDemandZones); + // if (IsValidIndex(idx)) + // { + // // // + // // ArrayRemove( + // // mDemandZones, + // // idx, + // // 1 // + // // ); + + // // + // } + + // + zone.to = TimeCurrent(); + name = zone.GetTag(); + // AddRef( + // zone, + // mDemandZones // + // ); + + // + 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); + // int idx = FindIndex(zone, mBearishOrderBlocks); + // if (IsValidIndex(idx)) + // { + // // // + // // ArrayRemove( + // // mBearishOrderBlocks, + // // idx, + // // 1 // + // // ); + + // // + // } + + // + zone.to = TimeCurrent(); + name = zone.GetTag(); + // AddRef( + // zone, + // mBearishOrderBlocks // + // ); + + // + 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); + // int idx = FindIndex(zone, mBullishOrderBlocks); + // if (IsValidIndex(idx)) + // { + // // // + // // ArrayRemove( + // // mBullishOrderBlocks, + // // idx, + // // 1 // + // // ); + + // // + // } + + // + zone.to = TimeCurrent(); + name = zone.GetTag(); + // AddRef( + // zone, + // mBullishOrderBlocks // + // ); + + // + 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); + // int idx = FindIndex(zone, mBearishFVGs); + // if (IsValidIndex(idx)) + // { + // // + // // ArrayRemove( + // // mBearishFVGs, + // // idx, + // // 1 // + // // ); + + // // + // } + + // + zone.to = TimeCurrent(); + name = zone.GetTag(); + // AddRef( + // zone, + // mBearishFVGs // + // ); + + // + 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); + // int idx = FindIndex(zone, mBullishFVGs); + // if (IsValidIndex(idx)) + // { + // // // + // // ArrayRemove( + // // mBullishFVGs, + // // idx, + // // 1 // + // // ); + + // // + // } + + // + zone.to = TimeCurrent(); + name = zone.GetTag(); + // AddRef( + // zone, + // mBullishFVGs // + // ); + + // + 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 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); + } + } + // };