/////////////////////////////////////////////////////// // // 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_PROVIDERS { X121SMC_XWZ_PROVIDER_NONE, X121SMC_XWZ_PROVIDER_ACTIVATED_ZONE, X121SMC_XWZ_PROVIDER_ACTIVATED_CHOCH, X121SMC_XWZ_PROVIDER_PRICE_INSIDE_ZONE, }; // 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, X121SMC_XWZ_PRIORITY_STRONG_HIGH, }; // struct X121SMCStrategyXWZWorkingZone { // // Props ... // string symbol; ENUM_TIMEFRAMES period; // XCSupplyZone *supplyZone; XCDemandZone *demandZone; // double quarter1; double quarter2; double quarter3; // XOBFVG orderFlow[]; XOBFVGPivot swings[]; XOBFVG brokenOrderFlow[]; CChartObjectTrend *orderFlowTrend; // XCSupplyZone *supplyZones[]; XCDemandZone *demandZones[]; // // Constructor ... X121SMCStrategyXWZWorkingZone() { Clean(); } // // Tools ... // void Clean() { // quarter1 = 0; quarter2 = 0; quarter3 = 0; // symbol = NULL; period = NULL; // Clean(orderFlow); Clean(brokenOrderFlow); // Clean(swings); ZeroMemory(supplyZone); ZeroMemory(demandZone); // if (orderFlowTrend != NULL) { orderFlowTrend.Delete(); } ZeroMemory(orderFlowTrend); // ZeroMemory(this); } // bool IsValid() { // bool result = false; // result = // quarter1 > 0 && quarter2 > 0 && quarter3 > 0 && HasSupplyZone() && HasDemandZone() && quarter1 > quarter2 && quarter2 > quarter3 // ; // return result; } // bool HasSupplyZone() { return supplyZone != NULL && supplyZone.IsValid(); } // bool HasDemandZone() { return demandZone != NULL && demandZone.IsValid(); } // // // // bool HasOrderFlow() { // bool result = false; // result = IsValid() && HasChild(orderFlow); // return result; } // bool HasOrderFlow( ENUM_X_DIRECTION &orderFlowDir // ) { // bool result = false; // result = IsValid() && HasChild(orderFlow); if (result) { orderFlowDir = orderFlow[0].GetDirection(); } // return result; } // int CountOrderFlow() { return ArraySize(orderFlow); } // int GetSwings( XOBFVGPivot &pivots[] // ) { // int result = 0; // Clean(pivots); // int count = 0; bool has = false; // has = HasOrderFlow(); if (!has) { return result; } // count = CountOrderFlow(); for (int i = 0; i < count; i++) { // XOBFVGPivot iPivots[]; int iPivotsCount = orderFlow[i] .GetSwings(iPivots); bool hasPivots = IsValidSize(iPivotsCount); if (hasPivots) { // Copy( iPivots, pivots, false // ); } // Clean(iPivots); } // result = ArraySize(pivots); // return result; } // double GetOrderFlowTrendLinePrice( int barIndex = 0, ENUM_TIMEFRAMES forPeriod = NULL // ) { // double result = 0; // if (barIndex < 0) { barIndex = 0; } // if (!IsValid(forPeriod)) { forPeriod = period; } // if (!IsValid() || !HasOrderFlow() || orderFlowTrend == NULL) { return result; } // datetime time = iTime( symbol, forPeriod, barIndex // ); // result = ObjectGetValueByTime( orderFlowTrend.ChartId(), orderFlowTrend.Name(), time // ); // return result; } // int DetectOrderFlow( string forSymbol, ENUM_TIMEFRAMES forPeriod, ENUM_X_DIRECTION &orderFlowDir, XPOIState <fState, XPOIState &htfState, XPOIState &mtfState, XPOIState &stfState // ) { // int result = 0; // Clean(orderFlow); orderFlowDir = X_DIRECTION_NONE; // bool isValid = // IsValid(forSymbol) && IsValid(forPeriod) && ltfState.HasChild() && htfState.HasChild() && mtfState.HasChild() && stfState.HasChild() // ; if (!isValid) { return result; } // // Find Working Zone ... bool hasWorkingZone = IsValid(); if (!hasWorkingZone) { // symbol = forSymbol; period = forPeriod; // int idx = -1; bool has = false; // has = ltfState.HasSupplyZones(); if (has) { // idx = GetHighest(ltfState.supplyZones); if (IsValidIndex(idx)) { supplyZone = ltfState.supplyZones[idx]; } } // has = ltfState.HasDemandZones(); if (has) { // idx = GetLowest(ltfState.demandZones); if (IsValidIndex(idx)) { demandZone = ltfState.demandZones[idx]; } } // hasWorkingZone = HasSupplyZone() && HasDemandZone(); if (hasWorkingZone) { // double upper = supplyZone.Lower(); double lower = demandZone.Upper(); // double delta = ((upper - lower) / 100) * 25; // quarter1 = upper - (1 * delta); quarter2 = upper - (2 * delta); quarter3 = upper - (3 * delta); // hasWorkingZone = IsValid(); } } // if (!hasWorkingZone) { return result; } // // Bullish OBFVGs ... XOBFVG bullOBFVGs[]; int bullOBFVGsCount = ExtractOBFVGZones( htfState, mtfState, stfState, bullOBFVGs, X_DIRECTION_BULLISH, NULL, // For Period ... // // Start ... XZONE_STATE_PASSED, true, // Force Body Out ... // // Activation ... XZONE_STATE_PASSED, true, // Force Body In ... // // Breaktion ... XZONE_STATE_FAILED, false, // Force Body In ... // // Works ... XZONE_STATE_PASSED, true, // Force Body Out ... // true, // Apply Sort ... true, // From Filter ... true, // Place Filter ... // true, // Ignore Inside in Place Filter ... // true, // Detect Inside OB POI(s) ... true, // Detect Inside FVG POI(s) ... true // Apply From Filter to Selected POI(s) ... ); bool hasBullOBFVGs = IsValidSize(bullOBFVGsCount); // // Bearish OBFVGs ... XOBFVG bearOBFVGs[]; int bearOBFVGsCount = ExtractOBFVGZones( htfState, mtfState, stfState, bearOBFVGs, X_DIRECTION_BEARISH, NULL, // For Period ... // // Start ... XZONE_STATE_PASSED, true, // Force Body Out ... // // Activation ... XZONE_STATE_PASSED, true, // Force Body In ... // // Breaktion ... XZONE_STATE_FAILED, false, // Force Body In ... // // Works ... XZONE_STATE_PASSED, true, // Force Body Out ... // true, // Apply Sort ... true, // From Filter ... true, // Place Filter ... // true, // Ignore Inside in Place Filter ... // true, // Detect Inside OB POI(s) ... true, // Detect Inside FVG POI(s) ... true // Apply From Filter to Selected POI(s) ... ); bool hasBearOBFVGs = IsValidSize(bearOBFVGsCount); // XOBFVG lastBroken; bool hasBroken = false; int idx = GetYoungest(brokenOrderFlow); if (IsValidIndex(idx)) { // lastBroken = brokenOrderFlow[idx]; hasBroken = lastBroken.IsValid(); } // bool hasOrderFlow = hasBearOBFVGs || hasBullOBFVGs; if (hasOrderFlow) { // // Vlidate ... isValid = // (hasBullOBFVGs && !hasBearOBFVGs && bullOBFVGsCount >= 1) // || // (hasBearOBFVGs && !hasBullOBFVGs && bearOBFVGsCount >= 1) // ; // if (isValid) { // if (hasBullOBFVGs) { // Copy( bullOBFVGs, orderFlow // ); } else if (hasBearOBFVGs) { // Copy( bearOBFVGs, orderFlow // ); } // orderFlowDir = hasBullOBFVGs ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // bool isPlacePassed = true; if (hasBroken) { // bool isBullish = IsBullish(orderFlowDir); // idx = GetYoungest(orderFlow); bool hasYounget = IsValidIndex(idx); // isPlacePassed = ArraySize(orderFlow) > 1 ? true : isBullish ? (IsAbove( orderFlow[idx].ob, lastBroken.ob, true // Ignore Inside ... )) : (IsBelow( orderFlow[idx].ob, lastBroken.ob, true // Ignore Inside )); // Clean(brokenOrderFlow); AddRef( orderFlow[idx], brokenOrderFlow // ); } // if (!isPlacePassed) { // Clean(orderFlow); orderFlowDir = X_DIRECTION_NONE; } // result = ArraySize(orderFlow); } } // Clean(bullOBFVGs); Clean(bearOBFVGs); // lastBroken.Clean(); // if (IsValidSize(result)) { // int count = GetSwings(swings); bool has = count >= 2; bool isBullish = IsBullish(orderFlowDir); if (has) { // // Get Max / Min ... double max = 0; double min = 0; datetime maxAt = NULL; datetime minAt = NULL; for (int i = 0; i < count; i++) { // XOBFVGPivot iPivot = swings[i]; // if (!iPivot.IsValid()) { // iPivot.Clean(); continue; } // // Min ... bool canSetMin = min == 0 ? true : min > iPivot.value; if (canSetMin) { // minAt = iPivot.at; min = iPivot.value; } // // Max ... bool canSetMax = max == 0 ? true : max < iPivot.value; if (canSetMax) { // maxAt = iPivot.at; max = iPivot.value; } // iPivot.Clean(); } // double price1 = isBullish ? min : max; double price2 = isBullish ? max : min; datetime time1 = isBullish ? minAt : maxAt; datetime time2 = isBullish ? maxAt : minAt; // color clrTrend = clrNONE; // string trendName = "XORDFLW" + ToString(orderFlowDir) + "_" + "XTRNDL_" + ToString(period) + "_" + ToString(price1) + "_" + ToString(price2) + "_"; // orderFlowTrend = new CChartObjectTrend(); has = orderFlowTrend.Create( 0, trendName, 0, time1, price1, time2, price2 // ); // if (has) { // orderFlowTrend.Width(1); orderFlowTrend.Color(clrTrend); orderFlowTrend.RayRight(true); } } } // return result; } // void AddOrderFlowItem( XOBFVG &orderItem // ) { // ENUM_X_DIRECTION trend; if (!HasOrderFlow(trend)) { return; } // bool isSameDir = orderItem .GetDirection() == trend; if (!isSameDir) { return; } // bool isBullish = IsBullish(trend); // AddRef( orderItem, orderFlow // ); // Sort( orderFlow, trend, true // Ignore Inside ... ); } // bool IsDestroyed( int barIndex = 0, ENUM_TIMEFRAMES forPeriod = NULL // ) { // bool result = false; // if (barIndex < 0) { barIndex = 0; } // if (!IsValid(forPeriod)) { forPeriod = period; } // result = IsValid(); if (!result) { return result; } // XOHCL bar; result = bar.Init( symbol, period, barIndex // ); if (!result) { // bar.Clean(); return result; } // XOHCL cBar; result = bar.GetPreviousBar(cBar); if (!result) { // bar.Clean(); cBar.Clean(); // return result; } // bool isSupplyZoneBreaked = // bar.low > supplyZone.Upper() && cBar.low > supplyZone.Upper() // ; // bool isDemandZoneBreaked = // bar.high < demandZone.Lower() && cBar.high < demandZone.Lower() // ; // bar.Clean(); cBar.Clean(); // result = isSupplyZoneBreaked || isDemandZoneBreaked; // return result; } // bool IsOrderFlowBreaked( int &breakedIndex, bool forceOBBreake = false, bool forceFVGBreake = false, int barIndex = 0, ENUM_TIMEFRAMES forPeriod = NULL // ) { // bool result = false; // breakedIndex = -1; // if (barIndex < 0) { barIndex = 0; } // if (!IsValid(forPeriod)) { forPeriod = period; } // ENUM_X_DIRECTION orderFlowDir; result = HasOrderFlow(orderFlowDir); if (!result) { return result; } // XOHCL bar; result = bar.Init( symbol, forPeriod, barIndex // ); if (!result) { // bar.Clean(); return result; } // bool isBullish = IsBullish(orderFlowDir); // int idx = isBullish ? GetHighest(orderFlow) : GetLowest(orderFlow); result = IsValidIndex(idx); if (!result) { // bar.Clean(); return result; } // XOHCL obBreakerBar; bool isOBBodyOut = false; bool isOBBreaked = orderFlow[idx].ob.IsBreaked( orderFlowDir, obBreakerBar, isOBBodyOut, false, // Ignore Start ... false, // Started Bar Body Out ... forPeriod // ); // if (!isOBBreaked) { obBreakerBar.Clean(); } // XOHCL fvgBreakerBar; bool isFVGBodyOut = false; bool isFVGBreaked = orderFlow[idx].fvg.IsBreaked( orderFlowDir, fvgBreakerBar, isFVGBodyOut, false, // Ignore Start ... true, // Started Bar Body Out ... forPeriod // ); // if (!isFVGBreaked) { fvgBreakerBar.Clean(); } // isOBBreaked = obBreakerBar.IsValid(); // isFVGBreaked = fvgBreakerBar.IsValid(); // if ((forceOBBreake && forceFVGBreake) || (!forceOBBreake && !forceFVGBreake)) { // result = isOBBreaked || isFVGBreaked; } else if (forceOBBreake) { result = isOBBreaked; } else if (forceFVGBreake) { result = isFVGBreaked; } // if (result) { breakedIndex = idx; } // bar.Clean(); obBreakerBar.Clean(); fvgBreakerBar.Clean(); // return result; } // bool DetectPriority( ENUM_X121SMC_XWZ_PRIORITY &priority, ENUM_X_DIRECTION forDir, int barIndex = 0, ENUM_TIMEFRAMES forPeriod = NULL // ) { // bool result = false; // priority = X121SMC_XWZ_PRIORITY_NONE; // if (barIndex < 0) { barIndex = 0; } // if (!IsValid(forPeriod)) { forPeriod = period; } // result = IsValid() && HasDirection(forDir); if (!result) { return result; } // bool isBullish = IsBullish(forDir); // XOHCL bar; result = bar.Init( symbol, forPeriod, barIndex // ); if (!result) { // bar.Clean(); return result; } // if (bar.high < supplyZone.Upper() && bar.low > supplyZone.Lower()) { // priority = isBullish ? X121SMC_XWZ_PRIORITY_NONE : X121SMC_XWZ_PRIORITY_STRONG_HIGH; } else if (bar.high < supplyZone.Lower() && bar.low > quarter1) { // priority = isBullish ? X121SMC_XWZ_PRIORITY_WEAK : X121SMC_XWZ_PRIORITY_HIGH; } else if (bar.high < quarter1 && bar.low > quarter2) { // priority = isBullish ? X121SMC_XWZ_PRIORITY_LOW : X121SMC_XWZ_PRIORITY_REGULAR; } else if (bar.high < quarter2 && bar.low > quarter3) { // priority = isBullish ? X121SMC_XWZ_PRIORITY_REGULAR : X121SMC_XWZ_PRIORITY_LOW; } else if (bar.high < quarter3 && bar.low > demandZone.Upper()) { // priority = isBullish ? X121SMC_XWZ_PRIORITY_HIGH : X121SMC_XWZ_PRIORITY_WEAK; } else if (bar.high < demandZone.Upper() && bar.low > demandZone.Lower()) { // priority = isBullish ? X121SMC_XWZ_PRIORITY_STRONG_HIGH : X121SMC_XWZ_PRIORITY_NONE; } // result = priority != X121SMC_XWZ_PRIORITY_NONE && priority != X121SMC_XWZ_PRIORITY_WEAK; // bar.Clean(); // return result; } // // // // bool HasSupplyZones() { return HasChild(supplyZones); } // int CountSupplyZones() { return ArraySize(supplyZones); } // bool HasDemandZones() { return HasChild(demandZones); } // int CountDemandZones() { return ArraySize(demandZones); } // int DetectSupplyZones( XPOIState &state // ) { // int result = CountSupplyZones(); bool isValid = state.IsValid() && state.HasSupplyZones(); if (!isValid) { return result; } // XCSupplyZone *tmpZones[]; Copy( state.supplyZones, tmpZones // ); int count = FilterZones( // tmpZones, // X_DIRECTION_BULLISH, state.period, NULL, // // Start ... XZONE_STATE_IGNORED, false, // // Activation ... XZONE_STATE_IGNORED, false, // // Breake ... XZONE_STATE_FAILED, false, // // Work ... XZONE_STATE_IGNORED, false, // true, // Apply Sore ... true // Ignore Inside ... ); bool has = IsValidSize(count); if (!has) { return result; } // int idx = -1; while (HasChild(tmpZones)) { // XCSupplyZone *iZone; idx = GetHighest(tmpZones); has = IsValidIndex(idx); if (!has) { // ZeroMemory(iZone); continue; } // iZone = tmpZones[idx]; // ArrayRemove( tmpZones, idx, 1 // ); // idx = FindIndex( iZone, supplyZones // ); has = IsValidIndex(idx); if (has) { // ZeroMemory(iZone); continue; } // Add( iZone, supplyZones // ); } // int after = CountSupplyZones(); result = after; // return result; } // int DetectDemandZones( XPOIState &state // ) { // int result = CountDemandZones(); bool isValid = state.IsValid() && state.HasDemandZones(); if (!isValid) { return result; } // XCDemandZone *tmpZones[]; Copy( state.demandZones, tmpZones // ); int count = FilterZones( // tmpZones, // X_DIRECTION_BEARISH, state.period, NULL, // // Start ... XZONE_STATE_IGNORED, false, // // Activation ... XZONE_STATE_IGNORED, false, // // Breake ... XZONE_STATE_FAILED, false, // // Work ... XZONE_STATE_IGNORED, false, // true, // Apply Sore ... true // Ignore Inside ... ); bool has = IsValidSize(count); if (!has) { return result; } // int idx = -1; while (HasChild(tmpZones)) { // XCDemandZone *iZone; idx = GetLowest(tmpZones); has = IsValidIndex(idx); if (!has) { // ZeroMemory(iZone); continue; } // iZone = tmpZones[idx]; // ArrayRemove( tmpZones, idx, 1 // ); // idx = FindIndex( iZone, demandZones // ); has = IsValidIndex(idx); if (has) { // ZeroMemory(iZone); continue; } // Add( iZone, demandZones // ); } // int after = CountDemandZones(); result = after; // return result; } // // // // void UpdateTo(datetime value = NULL) { // value = NormalizeTime(value); // int count = 0; bool has = false; // has = HasSupplyZone(); if (has) { supplyZone.To(value); } // has = HasDemandZone(); if (has) { demandZone.To(value); } // // Order Flow ... ENUM_X_DIRECTION orderFlowDir; has = HasOrderFlow(orderFlowDir); if (has) { // count = CountOrderFlow(); for (int i = 0; i < count; i++) { orderFlow[i].UpdateTo(value); } } // has = HasSupplyZones(); if (has) { // count = CountSupplyZones(); for (int i = 0; i < count; i++) { supplyZones[i].To(value); } } // has = HasDemandZones(); if (has) { // count = CountDemandZones(); for (int i = 0; i < count; i++) { demandZones[i].To(value); } } // } }; // // Definitions ... struct X121SMCStrategyXWZSignalConditions { // // Props ... // string symbol; ENUM_TIMEFRAMES period; // double sl; double reward; double amountPercent; ENUM_X_DIRECTION dir; ENUM_X_POSITION_TYPES type; // // Setup Props ... // datetime setupTime; datetime triggerTime; // double pivot; double point; double targets[]; // XOBFVG signalZone; // ENUM_X121SMC_XWZ_PRIORITY priority; ENUM_X121SMC_XWZ_PROVIDERS provider; // // Constructor ... X121SMCStrategyXWZSignalConditions() { Clean(); } // // Tools ... /** * Cleaning Up ... */ void Clean() { // sl = 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; // reward = 0; amountPercent = 0; // Clean(targets); signalZone.Clean(); // provider = X121SMC_XWZ_PROVIDER_NONE; } // // // // void UpdateTo(datetime value = NULL) { // value = NormalizeTime(value); // int count = 0; bool has = false; } // }; //