/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 X121 SMC Signal Class // ------------------------------------------------- // Name: XWZ // Description: provide all Signalling functions ... // // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://www.saherelm.ir" #property version "1.00" #property strict // // Imports ... // #include "../../Libraries/x-trade.lib" #include "../Classes/x-121.smc.market.cycle.helper.class.mq5" #include "../Libraries/x-121.smc.guard.lib.mq5" #include "../Libraries/x-121.smc.lib.mq5" // enum ENUM_X121SMC_XWZ_PRIORITY { X121SMC_XWZ_PRIORITY_NONE, X121SMC_XWZ_PRIORITY_WEAK, X121SMC_XWZ_PRIORITY_LOW, X121SMC_XWZ_PRIORITY_REGULAR, X121SMC_XWZ_PRIORITY_HIGH, }; // struct X121SMCXWZOBFVG { // // Props ... XCOrderBlock *ob; XCFVG *fvg; // // Constructor ... X121SMCXWZOBFVG() { Clean(); } // // Tools ... // void Clean() { // ZeroMemory(ob); ZeroMemory(fvg); } // bool IsValid() { // return ob != NULL && fvg != NULL && ob.IsValid() && fvg.IsValid(); } // }; // struct X121SMCXWZWorkingZone { // string symbol; ENUM_TIMEFRAMES period; // double upper; double lower; // double zoneUpper; double zoneLower; // double quarter1; double quarter2; double quarter3; // datetime from; // X121SMCXWZWorkingZone() { Clean(); } // void Clean() { // upper = 0; lower = 0; quarter1 = 0; quarter2 = 0; quarter3 = 0; zoneLower = 0; zoneUpper = 0; // from = NULL; symbol = NULL; period = NULL; // ZeroMemory(this); } // bool IsValid() { // bool result = false; // result = lower > 0 && upper > 0 && quarter1 > 0 && quarter2 > 0 && quarter3 > 0 && upper > lower && zoneLower > 0 && zoneUpper > 0 && IsValid(from) && IsValid(symbol) && IsValid(period) && zoneUpper > upper && zoneLower < lower; // return result; } // bool DetectOveralTrend( XOHCL &touchedBar, ENUM_X_DIRECTION &trendDir, int barIndex = 0 // ) { // bool result = false; // if (barIndex < 0) { barIndex = 0; } // trendDir = X_DIRECTION_NONE; // result = IsValid(); if (!result) { return result; } // int fromBarIndex = iBarShift( symbol, period, from // ); result = IsValidIndex(fromBarIndex); if (!result) { return result; } // XOHCL nearestUpperTouchedBar; XOHCL nearestLowerTouchedBar; bool hasNearestUpperTouchedBar = false; bool hasNearestLowerTouchedBar = false; for (int i = barIndex; i < fromBarIndex; i++) { // XOHCL iBar; bool isInited = iBar.Init( symbol, period, i // ); // hasNearestUpperTouchedBar = nearestUpperTouchedBar.IsValid(); if (!hasNearestUpperTouchedBar) { // bool isBarTouchedUpper = iBar.high > upper; if (isBarTouchedUpper) { // nearestUpperTouchedBar = iBar; hasNearestUpperTouchedBar = true; } } // hasNearestLowerTouchedBar = nearestLowerTouchedBar.IsValid(); if (!hasNearestLowerTouchedBar) { // bool isBarTouchedLower = iBar.low < lower; if (isBarTouchedLower) { // nearestLowerTouchedBar = iBar; hasNearestLowerTouchedBar = true; } } // if (hasNearestUpperTouchedBar && hasNearestLowerTouchedBar) { break; } } // result = hasNearestUpperTouchedBar || hasNearestLowerTouchedBar; if (result) { // if (hasNearestUpperTouchedBar && !hasNearestLowerTouchedBar) { // trendDir = X_DIRECTION_BEARISH; touchedBar = nearestUpperTouchedBar; } else if (!hasNearestUpperTouchedBar && hasNearestLowerTouchedBar) { // trendDir = X_DIRECTION_BULLISH; touchedBar = nearestLowerTouchedBar; } else if (hasNearestUpperTouchedBar && hasNearestLowerTouchedBar) { // trendDir = nearestUpperTouchedBar.time < nearestLowerTouchedBar.time ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // if (IsBullish(trendDir)) { touchedBar = nearestLowerTouchedBar; } else { touchedBar = nearestUpperTouchedBar; } } } // return result; } // bool IsDestroyed( ENUM_X_DIRECTION &destroyedDir, int barIndex = 0, ENUM_TIMEFRAMES forPeriod = NULL // ) { // bool result = false; // if (barIndex < 0) { barIndex = 0; } // if (!IsValid(forPeriod)) { forPeriod = period; } // destroyedDir = X_DIRECTION_NONE; // result = IsValid(); if (!result) { return result; } // XOHCL bar; result = bar.Init( symbol, forPeriod, barIndex // ); if (!result) { return result; } // bool isUpperBreaked = bar.high > zoneUpper && bar.close > zoneUpper; // bool isLowerBreaked = bar.low < zoneLower && bar.close < zoneLower; // result = isUpperBreaked || isLowerBreaked; if (result) { // destroyedDir = isUpperBreaked ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; } // return result; } // }; // // Definitions ... struct X121SMCStrategyXWZSignalConditions { // // Props ... // string symbol; ENUM_TIMEFRAMES period; // double sl; double target; double reward; double amountPercent; ENUM_X_DIRECTION dir; ENUM_X_POSITION_TYPES type; // // Setup Props ... // datetime setupTime; datetime triggerTime; // double pivot; double point; // ENUM_X121SMC_XWZ_PRIORITY priority; // // Working Zone ... // XCFVG *fairValueGap; XCOrderBlock *orderBlock; XCSupplyZone *supplyZone; XCDemandZone *demandZone; X121SMCXWZWorkingZone workingZone; // X121SMCXWZOBFVG startZones[]; // // Constructor ... X121SMCStrategyXWZSignalConditions() { Clean(); } // // Tools ... /** * Cleaning Up ... */ void Clean() { // sl = 0; target = 0; // dir = X_DIRECTION_NONE; type = X_POSITION_TYPE_NONE; // symbol = NULL; period = NULL; setupTime = NULL; triggerTime = NULL; // ExtensionClean(); // ZeroMemory(this); } /** * Check Condition is Setting Up ... * * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... * * @return ( bool ) */ bool IsSetuped() { // bool result = false; // result = IsValid(setupTime) && HasDirection(dir); if (!result) { return result; } // return result; } /** * Calculate Setup Age ... * * @return ( int ) */ int GetSetupAge() { // int result = 0; // if (!IsSetuped()) { return result; } // result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); // return result; } /** * Detect How we Can Trigger Signal ... * * @return ( bool ) */ bool CanTrigger() { // bool result = false; // result = // sl > 0 && IsValid(symbol) && IsValid(period) && IsValid(triggerTime) && type != X_POSITION_TYPE_ALL && type != X_POSITION_TYPE_NONE // ; // return result; } // // Extensions ... /** * Clean Additional Properties ... */ void ExtensionClean() { // pivot = 0; point = 0; // target = 0; reward = 0; amountPercent = 0; // ZeroMemory(supplyZone); // ZeroMemory(demandZone); // ZeroMemory(orderBlock); // ZeroMemory(fairValueGap); // Clean(startZones); // workingZone.Clean(); } // // // // bool HasWorkingZone() { return workingZone.IsValid(); } // // Working Zone is an Area which // we decide to trade inside it ... bool ExtractWorkingZone( XPOIState &htfState, XPOIState &mtfState, XPOIState &stfState, int barIndex = 0 // ) { // bool result = false; // if (barIndex < 0) { barIndex = 0; } int zIndex = barIndex; // result = !HasWorkingZone(); if (!result) { return result; } // result = IsValid(symbol) && IsValid(period); if (!result) { // Clean(); return result; } // datetime cTime = iTime( symbol, period, zIndex // ); // result = // htfState.IsValid() && htfState.HasChild() && htfState.HasSupplyZones() && htfState.HasDemandZones() && // mtfState.IsValid() && mtfState.HasChild() && mtfState.HasSupplyZones() && mtfState.HasDemandZones() && // stfState.IsValid() && stfState.HasChild() // ; if (!result) { return result; } // // Retrieve Highest Supply Zone ... int hSupplyIDX = GetHighest(htfState.supplyZones); int lDemandIDX = GetLowest(htfState.demandZones); // result = // IsValidIndex(hSupplyIDX) && IsValidIndex(lDemandIDX) // ; if (!result) { return result; } // supplyZone = htfState.supplyZones[hSupplyIDX]; demandZone = htfState.demandZones[lDemandIDX]; // result = // supplyZone != NULL && demandZone != NULL && supplyZone.IsValid() && demandZone.IsValid() // ; if (!result) { // Clean(); return result; } // // Check Validation of Supply and Demand Zones ... lDemandIDX = GetLowest(mtfState.demandZones); hSupplyIDX = GetHighest(mtfState.supplyZones); result = IsValidIndex(lDemandIDX) && IsValidIndex(hSupplyIDX); if (!result) { // Clean(); return result; } // // Validate Supply and Demand ... bool isMTFHSupplyInside = IsInside( mtfState.supplyZones[hSupplyIDX], supplyZone); bool isMTFLDemandInside = IsInside( mtfState.demandZones[lDemandIDX], demandZone // ); if (isMTFHSupplyInside && !isMTFLDemandInside) { demandZone = mtfState.demandZones[lDemandIDX]; } else if (!isMTFHSupplyInside && isMTFLDemandInside) { supplyZone = mtfState.supplyZones[hSupplyIDX]; } else if (isMTFHSupplyInside && isMTFLDemandInside) { // supplyZone = mtfState.supplyZones[hSupplyIDX]; demandZone = mtfState.demandZones[lDemandIDX]; } // // Check Zones Validation ... bool hasTrend = supplyZone != NULL && supplyZone.IsValid() && demandZone != NULL && demandZone.IsValid(); result = hasTrend; if (!result) { // Clean(); return result; } // datetime from = MathMax( supplyZone.From(), demandZone.From()); // int fromIndex = iBarShift( symbol, period, from // ); // // Detect Trend ... ENUM_X_DIRECTION trend = X_DIRECTION_NONE; datetime supplyTouch = NULL; datetime demandTouch = NULL; for (int i = zIndex; i < fromIndex; i++) { // XOHCL iBar; bool isInited = iBar.Init( symbol, period, i // ); if (!isInited) { continue; } // bool isTouchSupplyZone = // iBar.low < supplyZone.Lower() && iBar.GetUp() > supplyZone.Lower() // ; if (isTouchSupplyZone && !IsValid(supplyTouch)) { supplyTouch = iBar.time; } // bool isTouchDemandZone = // iBar.high > demandZone.Upper() && iBar.GetDown() < demandZone.Upper() // ; if (isTouchDemandZone && !IsValid(demandTouch)) { demandTouch = iBar.time; } // bool canBreak = IsValid(supplyTouch) && IsValid(demandTouch); // iBar.Clean(); // if (canBreak) { break; } } // hasTrend = // IsValid(supplyTouch) && IsValid(demandTouch) // ; if (hasTrend) { // trend = // supplyTouch > demandTouch ? X_DIRECTION_BEARISH : X_DIRECTION_BULLISH // ; } // // Check Trend ... result = hasTrend; if (!result) { // Clean(); return result; } // bool hasBullishTrend = IsBullish(trend); bool hasBearishTrend = IsBearish(trend); // // Find Order Block and FVG for Trend Approve ... // // Now We Have to Detect at least One OrderBlock with FVG ... // for Trend Approvement ... bool hasOrderBlock = HasOrderBlock(); bool hasFairValueGap = HasFairValueGap(); if (!hasOrderBlock && !hasFairValueGap) { // int count = 0; bool has = false; // XCFVG *fvg = NULL; XCOrderBlock *ob = NULL; // if (hasBullishTrend) { // has = mtfState.HasBullishOrderBlocks(); count = mtfState.CountBullishOrderBlocks(); // if (has) { // // Check Order Block ... for (int i = 0; i < count; i++) { // XCOrderBlock *iOB = mtfState.bullishOrderBlocks[i]; // iOB.To(cTime); // // Check From Passes ... bool isFromPassed = iOB.From() > demandZone.From(); if (!isFromPassed) { continue; } // // Must inside DemandZone ... bool isInsideDemand = IsInsideDiff( iOB, demandZone // ); if (!isInsideDemand) { continue; } // // Check Started ... XOHCL startedBar; ENUM_X_DIRECTION startedDir; bool isStarted = iOB.IsStarted( X_DIRECTION_BULLISH, startedBar, startedDir // ); if (!isStarted) { // startedBar.Clean(); continue; } // // Converts to Box ... XBoxZone obBox; bool hasOBBox = ToBox( obBox, iOB // ); if (!hasOBBox) { // obBox.Clean(); startedBar.Clean(); continue; } // // Check Zone Must not Used before ... bool isUsed = IsBoxUsed( obBox, startedBar.Index() - 1, zIndex // ); if (isUsed) { // obBox.Clean(); startedBar.Clean(); continue; } // ob = iOB; // obBox.Clean(); startedBar.Clean(); // break; } // // Detect Fair Value Gap ... if (ob != NULL && ob.IsValid()) { // has = stfState.HasBullishFairValueGaps(); count = stfState.CountBullishFairValueGaps(); if (has) { // // Check Fir Value Gap ... for (int i = 0; i < count; i++) { // XCFVG *iFVG = stfState.bullishFairValueGaps[i]; // iFVG.To(cTime); // // Check From Passes ... bool isFromPassed = iFVG.From() > ob.From(); if (!isFromPassed) { continue; } // // Check Started ... XOHCL startedBar; ENUM_X_DIRECTION startedDir; bool isStarted = iFVG.IsStarted( X_DIRECTION_BULLISH, startedBar, startedDir // ); if (!isStarted) { // startedBar.Clean(); continue; } // // Converts to Box ... XBoxZone fvgBox; bool hasFVGBox = ToBox( fvgBox, iFVG // ); if (!hasFVGBox) { // fvgBox.Clean(); startedBar.Clean(); continue; } // // Check Inside Order Block ... bool isInside = IsInsideDiff( iFVG, ob, true // Force Side Out ... ); if (!isInside) { continue; } // fvg = iFVG; // fvgBox.Clean(); startedBar.Clean(); // break; } } else { // ob = NULL; } } } } else if (hasBearishTrend) { // has = mtfState.HasBearishOrderBlocks(); count = mtfState.CountBearishOrderBlocks(); // if (has) { // // Check Order Block ... for (int i = 0; i < count; i++) { // XCOrderBlock *iOB = mtfState.bearishOrderBlocks[i]; // iOB.To(cTime); // // Check From Passes ... bool isFromPassed = iOB.From() > supplyZone.From(); if (!isFromPassed) { continue; } // // Must inside DemandZone ... bool isInsideDemand = IsInsideDiff( iOB, supplyZone // ); if (!isInsideDemand) { continue; } // // Check Started ... XOHCL startedBar; ENUM_X_DIRECTION startedDir; bool isStarted = iOB.IsStarted( X_DIRECTION_BEARISH, startedBar, startedDir // ); if (!isStarted) { // startedBar.Clean(); continue; } // // Converts to Box ... XBoxZone obBox; bool hasOBBox = ToBox( obBox, iOB // ); if (!hasOBBox) { // obBox.Clean(); startedBar.Clean(); continue; } // // Check Zone Must not Used before ... bool isUsed = IsBoxUsed( obBox, startedBar.Index() - 1, zIndex // ); if (isUsed) { // obBox.Clean(); startedBar.Clean(); continue; } // ob = iOB; // obBox.Clean(); startedBar.Clean(); // break; } // // Detect Fair Value Gap ... if (ob != NULL && ob.IsValid()) { // has = stfState.HasBearishFairValueGaps(); count = stfState.CountBearishFairValueGaps(); if (has) { // // Check Fir Value Gap ... for (int i = 0; i < count; i++) { // XCFVG *iFVG = stfState.bearishFairValueGaps[i]; // iFVG.To(cTime); // // Check From Passes ... bool isFromPassed = iFVG.From() > ob.From(); if (!isFromPassed) { continue; } // // Check Started ... XOHCL startedBar; ENUM_X_DIRECTION startedDir; bool isStarted = iFVG.IsStarted( X_DIRECTION_BEARISH, startedBar, startedDir // ); if (!isStarted) { // startedBar.Clean(); continue; } // // Converts to Box ... XBoxZone fvgBox; bool hasFVGBox = ToBox( fvgBox, iFVG // ); if (!hasFVGBox) { // fvgBox.Clean(); startedBar.Clean(); continue; } // // Check Inside Order Block ... bool isInside = IsInsideDiff( iFVG, ob, true // Force Side Out ... ); if (!isInside) { continue; } // fvg = iFVG; // fvgBox.Clean(); startedBar.Clean(); // break; } } else { // ob = NULL; } } } } // if (ob != NULL && fvg != NULL) { // orderBlock = ob; fairValueGap = fvg; } // hasOrderBlock = HasOrderBlock(); hasFairValueGap = HasFairValueGap(); } // // Check Trend Approved ... bool isTrendApproved = hasOrderBlock && hasFairValueGap; result = isTrendApproved; if (!result) { // Clean(); return result; } // // Prepare Working Zone ... workingZone.symbol = symbol; workingZone.period = period; // workingZone.upper = supplyZone.Lower(); workingZone.zoneUpper = supplyZone.Upper(); // workingZone.lower = demandZone.Upper(); workingZone.zoneLower = demandZone.Lower(); // workingZone.from = from; // double upper = workingZone.upper; double range = workingZone.upper - workingZone.lower; double ranegPercent = range / 100; double quarterValue = ranegPercent * 25; // workingZone.quarter1 = upper - (quarterValue * 1); workingZone.quarter2 = upper - (quarterValue * 2); workingZone.quarter3 = upper - (quarterValue * 3); // result = workingZone.IsValid(); if (!result) { Clean(); } // return result; } // bool IsWorkingZoneDestroyed( ENUM_X_DIRECTION &destroyedDir, int barIndex = 0, ENUM_TIMEFRAMES forPeriod = NULL // ) { // bool result = false; // if (barIndex < 0) { barIndex = 0; } // if (!IsValid(forPeriod)) { forPeriod = period; } // destroyedDir = X_DIRECTION_NONE; // result = workingZone.IsValid(); if (!result) { return result; } // result = workingZone.IsDestroyed( destroyedDir, barIndex, forPeriod // ); // return result; } // bool DetectTrend( ENUM_X_DIRECTION &trend, int barIndex = 0, ENUM_TIMEFRAMES forPeriod = NULL // ) { // bool result = false; // if (barIndex < 0) { barIndex = 0; } // if (forPeriod == NULL) { forPeriod = period; } // trend = X_DIRECTION_NONE; // result = HasWorkingZone(); if (!result) { return result; } // int FromIndex = iBarShift( symbol, forPeriod, workingZone.from // ); // datetime supplyTouch = NULL; datetime demandTouch = NULL; for (int i = barIndex; i < FromIndex; i++) { // XOHCL iBar; bool isInited = iBar.Init( symbol, forPeriod, i // ); if (!isInited) { continue; } // bool isTouchSupplyZone = // iBar.low < supplyZone.Lower() && iBar.GetUp() > supplyZone.Lower() // ; if (isTouchSupplyZone && !IsValid(supplyTouch)) { supplyTouch = iBar.time; } // bool isTouchDemandZone = // iBar.high > demandZone.Upper() && iBar.GetDown() < demandZone.Upper() // ; if (isTouchDemandZone && !IsValid(demandTouch)) { demandTouch = iBar.time; } // bool canBreak = IsValid(supplyTouch) && IsValid(demandTouch); // iBar.Clean(); // if (canBreak) { break; } } // result = // IsValid(supplyTouch) && IsValid(demandTouch) // ; if (result) { // trend = // supplyTouch > demandTouch ? X_DIRECTION_BEARISH : X_DIRECTION_BULLISH // ; } // return result; } // bool HasOrderBlock() { return orderBlock != NULL && orderBlock.IsValid(); } // bool HasFairValueGap() { return fairValueGap != NULL && fairValueGap.IsValid(); } // void UpdateTo(datetime value = NULL) { // value = NormalizeTime(value); // if (supplyZone != NULL) { supplyZone.To(value); } // if (demandZone != NULL) { demandZone.To(value); } // if (orderBlock != NULL) { orderBlock.To(value); } // if (fairValueGap != NULL) { fairValueGap.To(value); } } // };