/////////////////////////////////////////////////////// // // 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); } } } } } // }; //