/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Indicator // ------------------------------------------------- // Name: XCATBEA Lib // Description: Library for XCATBEA ... // // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" #property description "SaherElm Library for XCATBEA Signaller" #property strict // // Imports ... #include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" #include "../../Classes/x-saherelm.x-poi.drawer.class.mq5" // // Definiions ... // #define XLiquidityToken "XLQ"; #define XTriggerBlockToken "XTRG"; // struct XTriggerBlock { // // Props ... XBoxZone ob; // Order Block XBoxZone fvg; // Fair Value Gap XOHCL swingBar; // Swing of Trigger XBoxZone trigger; // Trigger Block XBoxZone rLiquidity; // Reversal Liquidity XBoxZone fLiquidity; // Following Liquidity // XSignal signal; // Pepared Signal // // Constructor ... XTriggerBlock() { Clean(); } // // Tools ... // // Cleanup ... void Clean() { // ob.Clean(); fvg.Clean(); signal.Clean(); trigger.Clean(); swingBar.Clean(); rLiquidity.Clean(); fLiquidity.Clean(); // ZeroMemory(this); } // // Validate ... bool IsValid() { // bool result = false; // result = ob.IsValid() && fvg.IsValid() && trigger.IsValid(); // return result; } // bool IsBullish() { return IsValid() && ob.IsBullish(); } // bool IsBearish() { return IsValid() && ob.IsBearish(); } // int ToIndex() { return trigger.ToIndex(); } // int FromIndex() { return trigger.FromIndex(); } // ENUM_X_DIRECTION GetDirection() { // ENUM_X_DIRECTION result = X_DIRECTION_NONE; // if (IsValid()) { result = ob.dir; } // return result; } // }; // // Trigger Block Validation Rules ... struct XTriggerBlockValidationRules { // // Props ... bool forceHasSwing; // Force Block to Has Propper Swing ... bool forceOBBarType; // Force Order Block to Has InDirectional Bars ... int minRequiredOBBar; // Min Required OB Bar ... bool forceFVGBarType; // Force Fair Value Gaps Bars Type ... int liquidityLoopback; // Liquidity Detection Loopback ... double maxAllowedRange; // Max Allowed Order Block Range ... double minAllowedRange; // Min Allowed Order Block Range ... bool forceHasFLiquidity; // Force Order Block To Has Reversal Liquidity ... bool forceHasRLiquidity; // Force Order Block to Has Following Liquidity ... bool validateGapSequence; // Validate Fair Value Gaps Bar Sequences ... int minAllowedBlockLength; // Min Allowed Block Length ... bool validateBlockEdgeBreakout; // Validate Order Block Edge Breakeout ... // // Constructor(s) ... XTriggerBlockValidationRules() { Clean(); } // // Tools ... // // Cleanup ... void Clean() { // maxAllowedRange = 0; minAllowedRange = 0; minRequiredOBBar = 0; liquidityLoopback = 0; forceHasSwing = false; forceOBBarType = false; forceFVGBarType = false; minAllowedBlockLength = 0; forceHasFLiquidity = false; forceHasRLiquidity = false; validateGapSequence = false; validateBlockEdgeBreakout = false; // ZeroMemory(this); } }; // // Trigger Block Filters ... struct XTriggerBlockFilters { // // Props ... bool filterBasedOnKI; // Filter Based On KI Flats ... bool filterBasedOnPV; // Filter Based On PV ... bool filterBasedOnSar; // Filter Based On SAR ... bool filterBasedOnRSI; // Filter Based On RSI ... bool filterBasedOnADX; // Filter Based On ADX ... bool filterBasedOnATR; // Filter Based On ATR ... bool filterBasedOnTrend; // Filter Based On Trend ... bool filterBasedOnDelta; // Filter Based On Delta ... bool filterBasedOnVolume; // Filter Based On Volume ... bool filterBasedOnSignalBar; // Filter Based on Signal Bar ... bool filterBasedOnRoundPrice; // Filter Based On Round Prices ... bool filterBasedOnHKSignalBar; // Filter Based On HK Signal Bar ... // int bosLoopback; // PV Based Filtering BOS Lookup ... // bool forceSarSwitched; // SAR Switched on Sides for Filtering ... bool forceSarOnBothSide; // SAR Check on Both Sides for Filtering ... bool forceSarHasBreakout; // SAR Must SAR Must Breakout ... bool forceSarHasReversalSide; // SAR Must SAR Must Has Reversal Direction ... // bool forceHasRSITrending; // RSI Must Has Trending ... bool forceHasRSIVPattern; // RSI Must Has Pattern ... bool forceHasRSICrossing; // RSI Must Has Crossing Levels ... // bool forceHasADXTrending; // ADX Must Has Trending ... bool forceHasADXCrossing; // ADX Must Has Crossing +DI/-DI ... // bool forceHasATRTrending; // ATR Must Has Trending ... bool forceHasATRBreakout; // ATR Must Has Breakout ... // bool forceHasTrendDir; // TREND Must Has Following Direction ... bool forceHasTrendPlace; // TREND Place Based Filtering ... bool forceHasTrendChange; // TREND Change Filtering ... bool forceHasTrendTrending; // TREND Must Has Trending ... bool forceHasTrendRejection; // TREND Line Must Rejected ... bool forceHasTrendLineInside; // TREND Line has Inside ... bool forceHasTrendDirOnBothSide; // TREND Must Has Following Direction in Both Side ... // // Constructor(s) ... XTriggerBlockFilters() { Clean(); } // // Tools ... // // Cleanup ... void Clean() { // filterBasedOnKI = false; filterBasedOnPV = false; filterBasedOnSar = false; filterBasedOnRSI = false; filterBasedOnADX = false; filterBasedOnATR = false; filterBasedOnTrend = false; filterBasedOnDelta = false; filterBasedOnVolume = false; filterBasedOnSignalBar = false; filterBasedOnRoundPrice = false; filterBasedOnHKSignalBar = false; // bosLoopback = 0; // forceSarSwitched = false; forceSarOnBothSide = false; forceSarHasBreakout = false; forceSarHasReversalSide = false; // forceHasRSITrending = false; forceHasRSIVPattern = false; forceHasRSICrossing = false; // forceHasADXTrending = false; forceHasADXCrossing = false; // forceHasATRTrending = false; forceHasATRBreakout = false; // forceHasTrendDir = false; forceHasTrendPlace = false; forceHasTrendChange = false; forceHasTrendTrending = false; forceHasTrendRejection = false; forceHasTrendLineInside = false; forceHasTrendDirOnBothSide = false; // ZeroMemory(this); } }; // // Extensions ... /** * Detect Trigger Block ... * * @param helper: XCX121XCatbHelper instance pointer ... * @param barAnalyser: XCBarAnalyser instance pointer ... * @param triggerBlock: XTriggerBlock Refrence, holds Detected Trigger Block ... * @param conditions: X121XCatbConditions Refrence, holds Trigger Block Conditions ... * @param validations: XTriggerBlockValidationRules Refrence, Provides Trigger Block Validation Rules ... * @param filters: XTriggerBlockFilters Refrence, Provides Trigger Block Filters ... * @param barIndex: int, Bar Index ... * @param loopback: int, Loopback for Conditions reading ... * * @return ( bool ) */ bool DetectTriggerBlock1( XCX121XCatbHelper *helper, XCBarAnalyser *barAnalyser, XTriggerBlock &triggerBlock, X121XCatbConditions &conditions, XTriggerBlockValidationRules &validations, XTriggerBlockFilters &filters, int barIndex = 0, int loopback = 10 // ) { // bool result = false; // // Normalize Args ... conditions.Clean(); triggerBlock.Clean(); barIndex = NormalizeInt(barIndex, 0); loopback = NormalizeInt(loopback, 0); // // Validate Args ... result = helper != NULL && barAnalyser != NULL; if (!result) { return result; } // int zIDX = 0; int cIDX = zIDX + 1; int pIDX = cIDX + 1; int p2IDX = pIDX + 1; int p3IDX = p2IDX + 1; int p4IDX = p3IDX + 1; // bool has = false; string symbol = helper.GetSymbol(); ENUM_TIMEFRAMES period = helper.GetPeriod(); // // Initial Requirements ... // // Required Bars ... XOHCL zBar; XOHCL cBar; result = result && zBar.Init( symbol, period, barIndex // ); result = result && zBar.GetPreviousBar(cBar); // // Here we Must Detect Order Block ... // then Detect FVG ... // then Prepare Trigger Box ... // // Select Application Bar ... XOHCL iBar; if (barIndex == 0) { iBar = cBar; } else if (barIndex > 0) { iBar = zBar; } iBar = cBar; result = result && iBar.IsValid(); // // Detect Order Block ... result = result && barAnalyser .IsOB( iBar, triggerBlock.ob, false, false // ); // // Detect Fair Value Gap ... result = result && barAnalyser .IsFVG( iBar, triggerBlock.fvg, false // ); // // Check Result and Create Trigger Box based on it ... if (result) { // triggerBlock.trigger = triggerBlock.ob; triggerBlock.trigger.type = XTriggerBlockToken; // // Update Upper and Lower ... int toIDX = triggerBlock.ob.ToIndex(); int fromIDX = triggerBlock.ob.FromIndex(); // iBar.Clean(); result = iBar.Init( symbol, period, toIDX // ); if (result) { // double iLL = iBar.FindLowest(fromIDX - toIDX, MODE_LOW); double iHH = iBar.FindHighest(fromIDX - toIDX, MODE_HIGH); // triggerBlock.trigger.upper = MathMax(iHH, triggerBlock.trigger.upper); triggerBlock.trigger.lower = MathMin(iLL, triggerBlock.trigger.lower); } // iBar.Clean(); } // // Apply Validations ... if (result) { // result = ValidateTriggerBlock( helper, barAnalyser, triggerBlock, conditions, validations, barIndex, loopback // ); // if (!result) { triggerBlock.Clean(); } } // // Apply Filtering ... if (result) { // result = FilterTriggerBlock( helper, barAnalyser, triggerBlock, conditions, filters, barIndex, loopback // ); // if (!result) { triggerBlock.Clean(); } } // // Summarizing Result ... result = result && triggerBlock.IsValid(); // // Preparing Signal ... if (result) { // } // // Cleanup Resources ... // iBar.Clean(); zBar.Clean(); cBar.Clean(); // if (!result) { triggerBlock.Clean(); } // return result; } /** * Validate a Trigger Block ... * * @param helper: XCX121XCatbHelper instance pointer ... * @param barAnalyser: XCBarAnalyser instance pointer ... * @param triggerBlock: XTriggerBlock Refrence, Trigger Block ... * @param conditions: X121XCatbConditions Refrence, Trigger Block Conditions ... * @param validations: XTriggerBlockValidationRules Refrence, Provides Trigger Block Validation Rules ... * @param barIndex: int, Bar Index ... * @param loopback: int, Loopback for Conditions reading ... * * @return ( bool ) */ bool ValidateTriggerBlock( XCX121XCatbHelper *helper, XCBarAnalyser *barAnalyser, XTriggerBlock &triggerBlock, X121XCatbConditions &conditions, XTriggerBlockValidationRules &validations, int barIndex = 0, int loopback = 10 // ) { // bool result = false; // // Checking Conditions ... // // Normalize Args ... conditions.Clean(); barIndex = NormalizeInt(barIndex, 0); loopback = NormalizeInt(loopback, 0); // // Validate Args ... result = helper != NULL && barAnalyser != NULL && triggerBlock.IsValid(); if (!result) { return result; } // // Reading Market Conditions ... result = helper.GetConditions( conditions, barIndex, loopback // ); if (!result) { // conditions.Clean(); // return result; } // int zIDX = 0; int cIDX = zIDX + 1; int pIDX = cIDX + 1; int p2IDX = pIDX + 1; int p3IDX = p2IDX + 1; int p4IDX = p3IDX + 1; // XOHCL iBar; int count = 0; int toIDX = -1; int fromIDX = -1; bool has = false; bool isBullish = triggerBlock.IsBullish(); bool isBearish = triggerBlock.IsBearish(); double points = GetPoints(triggerBlock.ob.symbol); ENUM_X_DIRECTION iDir = triggerBlock.GetDirection(); // // Checking Conditions ... // // Range Validation ... // // Max Allowed OB Range ... if (result && validations.maxAllowedRange > 0) { // double iRange = triggerBlock.ob.GetRange(); result = iRange <= (validations.maxAllowedRange * points); } // // Min Allowed OB Range ... if (result && validations.minAllowedRange > 0) { // double iRange = triggerBlock.ob.GetRange(); result = iRange >= (validations.maxAllowedRange * points); } // // Has Swing ... if (result && validations.forceHasSwing) { // bool isSwing = false; toIDX = triggerBlock.ToIndex(); fromIDX = triggerBlock.FromIndex(); ENUM_X_DIRECTION swingDir = X_DIRECTION_NONE; for (int i = toIDX; i <= fromIDX; i++) { // // Initialize iBar ... has = iBar.Init( conditions.symbol, conditions.period, i // ); isSwing = has && barAnalyser .IsSimpleSwing( iBar, swingDir // ); if (isSwing && swingDir == iDir) { break; } // iBar.Clean(); } // result = isSwing && iBar.IsValid() && swingDir == iDir; if (result) { // // Initialize Swing Bar ... result = triggerBlock .swingBar .Init( iBar.symbol, iBar.period, iBar.Index() + 2 // ); } // iBar.Clean(); } // // Force FVG Bar Types ... if (result && validations.forceFVGBarType) { // toIDX = triggerBlock.fvg.ToIndex(); fromIDX = triggerBlock.fvg.FromIndex(); for (int i = toIDX; i < fromIDX; i++) { // // Initialize iBar ... result = iBar.Init( conditions.symbol, conditions.period, i // ); result = result && iDir == iBar.GetDirection(); // iBar.Clean(); // if (!result) { break; } } // iBar.Clean(); } // // Force OB Start By InDirectional Bars ... if (result && validations.forceOBBarType) { // count = 0; fromIDX = triggerBlock.fvg.FromIndex() + 1; int sIDX = fromIDX; has = true; while (has) { // // Initialize iBar .. has = iBar.Init( conditions.symbol, conditions.period, fromIDX // ); has = has && iDir == Opposit(iBar.GetDirection()); if (has) { count++; } // fromIDX++; } // int required = validations.minRequiredOBBar > 0 ? validations.minRequiredOBBar : 1; // result = count >= required; // // Update Trigger Block Box based on OB Bar Types ... if (result) { // result = iBar.Init( conditions.symbol, conditions.period, sIDX // ); if (result) { // datetime iFrom = GetBarTime( conditions.symbol, conditions.period, sIDX + count // ); double iLL = iBar.FindLowest(count, MODE_LOW); double iHH = iBar.FindHighest(count, MODE_HIGH); // triggerBlock.trigger.from = iFrom; triggerBlock.trigger.upper = MathMax(iHH, triggerBlock.trigger.upper); triggerBlock.trigger.lower = MathMin(iLL, triggerBlock.trigger.lower); } } // iBar.Clean(); } // // Force Fair Value Gap to Following Sequence ... if (result && validations.validateGapSequence) { // XOHCL iPBar; toIDX = triggerBlock.fvg.ToIndex(); fromIDX = triggerBlock.fvg.FromIndex() - 1; for (int i = toIDX; i < fromIDX; i++) { // result = iBar.Init( conditions.symbol, conditions.period, i // ); result = result && iBar.GetPreviousBar(iPBar); result = result && (isBullish ? iBar.low > iPBar.low : iBar.high < iPBar.high); if (!result) { break; } // iBar.Clean(); iPBar.Clean(); } // iBar.Clean(); iPBar.Clean(); } // // Validate OB Edge Breakeout Using Gaps End Bar ... if (result && validations.validateBlockEdgeBreakout) { // // Initialize Gap End Bar ... toIDX = triggerBlock.fvg.ToIndex(); result = iBar.Init( conditions.symbol, conditions.period, toIDX // ); // result = result && (isBullish ? iBar.open < triggerBlock.ob.upper && iBar.close > triggerBlock.ob.upper : iBar.open > triggerBlock.ob.lower && iBar.close < triggerBlock.ob.lower); // // Here we Can Apply Edge Breakout Using Fibo ... // iBar.Clean(); } // // Force Block to Has Liquidity ... if (result && validations.liquidityLoopback > 0 && (validations.forceHasFLiquidity || validations.forceHasRLiquidity)) { // toIDX = triggerBlock.ToIndex(); fromIDX = triggerBlock.FromIndex(); ENUM_X_DIRECTION iLiqDir = X_DIRECTION_NONE; for (int i = toIDX; i < fromIDX + validations.liquidityLoopback; i++) { // // Initialize iBar ... has = iBar.Init( conditions.symbol, conditions.period, i // ); has = has && barAnalyser .IsRejected( iBar, iLiqDir, false, // Force Bar Type ... true // Force Fibo Pressure ... ); // bool isFLiq = has && iLiqDir == iDir; if (isFLiq && validations.forceHasFLiquidity && !triggerBlock.fLiquidity.IsValid()) { // FillLiquidity( iBar, iLiqDir, triggerBlock.fLiquidity, triggerBlock.trigger.to // ); } // bool isRLiq = has && iLiqDir == Opposit(iDir); if (isRLiq && validations.forceHasRLiquidity && !triggerBlock.rLiquidity.IsValid()) { // FillLiquidity( iBar, iLiqDir, triggerBlock.rLiquidity, triggerBlock.trigger.to // ); } // // Here We Can Apply Liquidity Validations ... ValidateTriggerBlockLiquidities( helper, barAnalyser, triggerBlock, conditions, validations // ); // // Check Liquidities ... has = (!validations.forceHasFLiquidity ? true : triggerBlock.fLiquidity.IsValid()) && (!validations.forceHasRLiquidity ? true : triggerBlock.rLiquidity.IsValid()); // iBar.Clean(); // if (has) { break; } } // // Check Result ... result = (!validations.forceHasFLiquidity ? true : triggerBlock.fLiquidity.IsValid()) && (!validations.forceHasRLiquidity ? true : triggerBlock.rLiquidity.IsValid()); // iBar.Clean(); } // // Validating Block Length Based on Direction ... if (result && validations.minAllowedBlockLength) { // count = 0; fromIDX = triggerBlock.FromIndex(); int sIDX = fromIDX; has = true; while (has) { // // Initialize iBar ... has = iBar.Init( conditions.symbol, conditions.period, sIDX // ); // has = has && (isBullish ? iBar.low > triggerBlock.trigger.lower : iBar.high < triggerBlock.trigger.upper); // if (!has) { break; } // sIDX++; count++; iBar.Clean(); } // result = iBar.IsValid() && count >= validations.minAllowedBlockLength; if (result) { // // Update Trigger Block ... bool usaMinAllowedForBlockLength = false; if (usaMinAllowedForBlockLength) { fromIDX = fromIDX + validations.minAllowedBlockLength; } else { fromIDX = sIDX - 1; } // triggerBlock.trigger.from = GetBarTime( conditions.symbol, conditions.period, fromIDX // ); } // iBar.Clean(); } // if (!result) { triggerBlock.Clean(); } // // Summarize result ... result = triggerBlock.IsValid(); // // Cleanup Resources ... // iBar.Clean(); // if (!result) { // conditions.Clean(); triggerBlock.Clean(); } // return result; } /** * Filter a Trigger Block ... * * @param helper: XCX121XCatbHelper instance pointer ... * @param barAnalyser: XCBarAnalyser instance pointer ... * @param triggerBlock: XTriggerBlock Refrence, Trigger Block ... * @param conditions: X121XCatbConditions Refrence, Trigger Block Conditions ... * @param filters: XTriggerBlockFilters Refrence, Provides Trigger Block Filters ... * @param barIndex: int, Bar Index ... * @param loopback: int, Loopback for Conditions reading ... * * @return ( bool ) */ bool FilterTriggerBlock( XCX121XCatbHelper *helper, XCBarAnalyser *barAnalyser, XTriggerBlock &triggerBlock, X121XCatbConditions &conditions, XTriggerBlockFilters &filters, int barIndex = 0, int loopback = 10 // ) { // bool result = false; // // Checking Conditions ... // // Normalize Args ... conditions.Clean(); barIndex = NormalizeInt(barIndex, 0); loopback = NormalizeInt(loopback, 0); // // Validate Args ... result = helper != NULL && barAnalyser != NULL && triggerBlock.IsValid(); if (!result) { return result; } // // Reading Market Conditions ... result = helper.GetConditions( conditions, barIndex, loopback // ); if (!result) { // conditions.Clean(); // return result; } // int zIDX = 0; int cIDX = zIDX + 1; int pIDX = cIDX + 1; int p2IDX = pIDX + 1; int p3IDX = p2IDX + 1; int p4IDX = p3IDX + 1; // XOHCL iBar; int toIDX = -1; int fromIDX = -1; bool has = false; bool isBullish = triggerBlock.IsBullish(); bool isBearish = triggerBlock.IsBearish(); double points = GetPoints(triggerBlock.ob.symbol); ENUM_X_DIRECTION iDir = triggerBlock.GetDirection(); // // Checking Conditions ... // // Filter Based KI ... if (result && filters.filterBasedOnKI) { // int count = 0; toIDX = triggerBlock.ob.ToIndex(); fromIDX = triggerBlock.ob.FromIndex(); double lKI = conditions.kiBuffer[zIDX]; for (int i = toIDX; i < fromIDX; i++) { // double iKI = helper.GetKI(i); if (iKI == lKI) { count++; } else { break; } } // result = count >= 3; } // // Filter Based On PV ... if (result && filters.filterBasedOnPV) { // // For PV Filtering ... // // Detect BOS ... // // When Loopback for BOS has Specified Value ... // we Lookup for BOS on Specific Period ... if (filters.bosLoopback > 0) { // has = true; int fBOSIDX = -1; int rBOSIDX = -1; bool isBOS = false; bool isFBOS = false; bool isRBOS = false; bool isPeakOverLast = false; bool isValeUnderLast = false; toIDX = triggerBlock.ob.ToIndex(); fromIDX = triggerBlock.ob.FromIndex(); int sIDX = fromIDX; while (has) { // double iPeak = helper.GetPeak(sIDX); double iPPeak = helper.GetPeak(sIDX + 1); // double iVale = helper.GetVale(sIDX); double iPVale = helper.GetVale(sIDX + 1); // isPeakOverLast = iPeak > 0 && iPeak > iPPeak; // isValeUnderLast = iVale > 0 && iVale < iPVale; // isFBOS = isBullish ? isPeakOverLast : isValeUnderLast; if (isFBOS) { fBOSIDX = sIDX; } // isRBOS = isBullish ? isValeUnderLast : isPeakOverLast; if (isRBOS) { rBOSIDX = sIDX; } // isBOS = (isBullish && isPeakOverLast) || (isBearish && isValeUnderLast); if (isBOS) { break; } // sIDX++; has = !isBOS && sIDX < fromIDX + filters.bosLoopback; } // isFBOS = IsValidIndex(fBOSIDX); isRBOS = IsValidIndex(rBOSIDX); // result = isBOS && isFBOS && !isRBOS; } // // When Loopback for BOS has not Specified Value ... // we Lookup for BOS on GAP End Bar ... if (filters.bosLoopback <= 0) { // toIDX = triggerBlock.ToIndex(); // // Initialize iBar ... result = iBar.Init( conditions.symbol, conditions.period, toIDX // ); result = result && (isBullish ? iBar.high > helper.GetPeak(toIDX + 1) : iBar.low < helper.GetVale(toIDX + 1)); } } // // Filter Based on SAR ... if (result && filters.filterBasedOnSar) { // toIDX = triggerBlock.ToIndex(); fromIDX = triggerBlock.FromIndex(); // double iSarState = helper.GetSarState(toIDX); double iPSarState = helper.GetSarState(toIDX + 1); // double iFSarState = helper.GetSarState(fromIDX); double iPFSarState = helper.GetSarState(fromIDX + 1); // bool isSarBullish = iSarState > 0; // bool isSarBearish = iSarState < 0; // bool isFSarBullish = iFSarState > 0; // bool isFSarBearish = iFSarState < 0; // bool isSarSwitchedToBullish = iSarState > 0 && iPSarState <= 0; // bool isSarSwitchedToBearish = iSarState < 0 && iPSarState >= 0; // bool isFSarSwitchedToBullish = iFSarState > 0 && iPFSarState <= 0; // bool isFSarSwitchedToBearish = iFSarState < 0 && iPFSarState >= 0; // // Creating Filters ... // bool isToFilterPassed = !filters.forceSarSwitched ? (isBullish ? isSarBullish : isSarBearish) : (isBullish ? isSarSwitchedToBullish : isSarSwitchedToBearish); // bool isFromFilterPassed = !filters.forceSarSwitched ? (isBullish ? isFSarBullish : isFSarBearish) : (isBullish ? isFSarSwitchedToBullish : isFSarSwitchedToBearish); // result = !filters.forceSarOnBothSide ? isToFilterPassed : isToFilterPassed && isFromFilterPassed; // // Check Sar Has Reversal Direction inside Trigger Block ... if (result && filters.forceSarHasReversalSide) { // toIDX = triggerBlock.ToIndex(); fromIDX = triggerBlock.FromIndex(); for (int i = toIDX; i < fromIDX; i++) { // double iSarState = helper.GetSarState(i); // has = isBullish ? iSarState > 0 : iSarState < 0; if (has) { break; } } // result = has; } // // Force Sar Breakouts ... // in this Senario Sar must in following Direction and // there is not any Switches ... // but must breakout Bar the last in Reversal Direction // of Sar ... if (result && filters.forceSarHasBreakout) { // bool isSarBullishStart = // ( // // Current SAR is Directional ... conditions.isSarBullish && // // Previous InDirectional Sar Exists ... helper.lastSarBearish.IsValid() && // // Current Close is Over previous Sar ... conditions.bars[cIDX].close > helper.lastSarBearish.after && // // Before Close is not Over previous Sar ... conditions.bars[pIDX].close <= helper.lastSarBearish.after // ) // ; // bool isSarBearishStart = // ( // // Current SAR is Directional ... conditions.isSarBearish && // // Previous InDirectional Sar Exists ... helper.lastSarBullish.IsValid() && // // Current Close is Under previous ... conditions.bars[cIDX].close < helper.lastSarBullish.after && // // Before Close is not Under previous ... conditions.bars[pIDX].close >= helper.lastSarBullish.after // ) // ; // result = isBullish ? isSarBullishStart : isSarBearishStart; } } // // Filter Based On RSI ... if (result && filters.filterBasedOnRSI) { // // Here We Can Apply RSI Filters ... // Since RSI Filters must be Check on FVG Bars ... // we Have to Loop back Based on FVG Bars to Detect Conditions ... double rsiTrend = (conditions.rsiOBLevel + conditions.rsiOSLevel) / 2; // toIDX = triggerBlock.fvg.ToIndex(); fromIDX = triggerBlock.fvg.FromIndex(); // // Filter Using RSI Trending ... if (result && filters.forceHasRSITrending) { // for (int i = toIDX; i < fromIDX; i++) { // double iRSI = helper.GetRSI(i); double iPRSI = helper.GetRSI(i + 1); // has = (isBullish ? (iRSI > rsiTrend && iRSI > iPRSI) : (iRSI < rsiTrend && iRSI < iPRSI)); if (has) { break; } } // result = has; } // // Filter Using RSI V Pattern ... if (result && filters.forceHasRSIVPattern) { // for (int i = toIDX; i < fromIDX; i++) { // double iRSI = helper.GetRSI(i); double iPRSI = helper.GetRSI(i + 1); double iP2RSI = helper.GetRSI(i + 2); // bool isRSIVBullish = iRSI > iPRSI && iP2RSI > iPRSI; // bool isRSIVBearish = iRSI < iPRSI && iP2RSI < iPRSI; // has = (isBullish ? isRSIVBullish : isRSIVBearish); if (has) { break; } } // result = has; } // // Filter Using RSI Crossing on OB/OS Levels ... if (result && filters.forceHasRSICrossing) { // for (int i = toIDX; i < fromIDX; i++) { // double iRSI = helper.GetRSI(i); double iPRSI = helper.GetRSI(i + 1); // bool isRSICrossedOverOS = iRSI > conditions.rsiOSLevel && iPRSI <= conditions.rsiOSLevel; // bool isRSICrossedUnderOB = iRSI < conditions.rsiOBLevel && iPRSI >= conditions.rsiOBLevel; // has = (isBullish ? isRSICrossedOverOS : isRSICrossedUnderOB); if (has) { break; } } // result = has; } } // // Filter Based On ADX ... if (result && filters.filterBasedOnADX) { // // Here We Can Apply ADX Filters ... // Since ADX Filters must be Check on FVG Bars ... // we Have to Loop back Based on FVG Bars to Detect Conditions ... // toIDX = triggerBlock.fvg.ToIndex(); fromIDX = triggerBlock.fvg.FromIndex(); // // Filter Using ADX Trending ... if (result && filters.forceHasADXTrending) { // for (int i = toIDX; i < fromIDX; i++) { // double iADX = helper.GetADX(i); double iPADX = helper.GetADX(i + 1); // has = iADX > conditions.adxThreshold && iADX > iPADX; if (has) { break; } } // result = has; } // // Filter Using ADX Crossing on +DI/-DI ... if (result && filters.forceHasADXCrossing) { // for (int i = toIDX; i < fromIDX; i++) { // double iDIPlus = helper.GetADXP(i); double iPDIPlus = helper.GetADXP(i + 1); // double iDIMinus = helper.GetADXN(i); double iPDIMinus = helper.GetADXN(i + 1); // bool isADXPlusCrossedOverMinus = iDIPlus > iDIMinus && iPDIPlus <= iDIMinus; // bool isADXMinusCrossedOverPlus = iDIMinus > iDIPlus && iPDIMinus <= iDIPlus; // has = isBullish ? isADXPlusCrossedOverMinus : isADXMinusCrossedOverPlus; if (has) { break; } } // result = has; } } // // Filter Based On ATR Band ... if (result && filters.filterBasedOnATR) { // // Here We Can Apply ATR Filters ... // Since ATR Filters must be Check on OB Bars ... // we Have to Loop back Based on OB Bars to Detect Conditions ... // toIDX = triggerBlock.ob.ToIndex(); fromIDX = triggerBlock.ob.FromIndex(); // // Filter Using ATR Trending ... if (result && filters.forceHasATRTrending) { // for (int i = toIDX; i < fromIDX; i++) { // double iATRUpper = helper.GetATRUpper(i); double iPATRUpper = helper.GetATRUpper(i + 1); // double iATRLower = helper.GetATRLower(i); double iPATRLower = helper.GetATRLower(i + 1); // bool isATRUp = iATRLower > iPATRLower; // bool isATRDown = iATRUpper < iPATRUpper; // has = isBullish ? isATRUp : isATRDown; if (has) { break; } } // result = has; } // // Filter Using ATR Breakout ... if (result && filters.forceHasATRBreakout) { // for (int i = toIDX; i < fromIDX; i++) { // double iATRUpper = helper.GetATRUpper(i); double iATRLower = helper.GetATRLower(i); // has = isBullish ? triggerBlock.ob.lower < iATRLower : triggerBlock.ob.upper > iATRUpper; if (has) { break; } } // result = has; } } // // Filter Based On Trend ... if (result && filters.filterBasedOnTrend) { // toIDX = triggerBlock.fvg.ToIndex(); fromIDX = triggerBlock.fvg.FromIndex(); // // Filter Using Trend Direction ... if (result && filters.forceHasTrendDir) { // result = result && isBullish ? conditions.isTrendBullish : conditions.isTrendBearish; } // // Filter Using Trend Direction On Both Side ... if (result && filters.forceHasTrendDirOnBothSide) { // // Side To ... result = result && isBullish ? conditions.isTrendBullish : conditions.isTrendBearish; // // Side From ... int sFIDX = triggerBlock.ob.FromIndex(); double sFTrendState = helper.GetTrendState(sFIDX); result = result && isBullish ? sFTrendState > 0 : sFTrendState < 0; } // // Filter Using Trend Change ... if (result && filters.forceHasTrendChange) { // for (int i = toIDX; i < fromIDX; i++) { // double iTrendState = helper.GetTrendState(i); double iPTrendState = helper.GetTrendState(i + 1); // bool isTrendSwitchedToBullish = iTrendState > 0 && iPTrendState <= 0; // bool isTrendSwitchedToBearish = iTrendState < 0 && iPTrendState >= 0; // has = isBullish ? isTrendSwitchedToBullish : isTrendSwitchedToBearish; if (has) { break; } } // result = has; } // // Filter Using Trend Trending ... if (result && filters.forceHasTrendTrending) { // result = result && (isBullish ? conditions.trendBuffer[cIDX] > conditions.trendBuffer[pIDX] : conditions.trendBuffer[cIDX] < conditions.trendBuffer[pIDX]); } // // Filter Using Trend Rejection ... if (result && filters.forceHasTrendRejection) { // toIDX = triggerBlock.ob.ToIndex(); fromIDX = triggerBlock.ob.FromIndex(); for (int i = toIDX; i < fromIDX; i++) { // // Initialize iBar ... has = iBar.Init( conditions.symbol, conditions.period, i // ); // // Read Trend Value ... double iTrend = helper.GetTrend(i); // bool isTrendBullishRejected = has && iBar.low < iTrend && iBar.GetDown() > iTrend; // bool isTrendBearishRejected = has && iBar.high > iTrend && iBar.GetUp() < iTrend; // has = has && (isBullish ? isTrendBullishRejected : isTrendBearishRejected); if (has) { break; } } // result = has; } // // Filter Using Trend Inside ... if (result && filters.forceHasTrendLineInside) { // result = result && conditions.trendBuffer[cIDX] > triggerBlock.ob.lower && conditions.trendBuffer[cIDX] < triggerBlock.ob.upper; } // // Filter Using Trend Place ... if (result && filters.forceHasTrendPlace) { // toIDX = triggerBlock.ob.ToIndex(); fromIDX = triggerBlock.ob.FromIndex(); double mult = isBullish ? 1 : -1; double edge = isBullish ? triggerBlock.ob.lower : triggerBlock.ob.upper; double factor = edge + (mult * (triggerBlock.ob.GetRange() / 4)); for (int i = toIDX; i < fromIDX; i++) { // double iTrend = helper.GetTrend(i); // has = isBullish ? factor >= iTrend : factor <= iTrend; if (has) { break; } } // result = has; } } // // Filter Using Delta ... if (result && filters.filterBasedOnDelta) { // toIDX = triggerBlock.ob.ToIndex(); fromIDX = triggerBlock.ob.FromIndex(); // for (int i = toIDX; i < fromIDX; i++) { // double iDelta = helper.GetDelta(i); double iPDelta = helper.GetDelta(i + 1); // double iDeltaSignal = helper.GetDeltaSignal(i); double iPDeltaSignal = helper.GetDeltaSignal(i + 1); // bool isDeltaUp = iDelta > iPDelta; // bool isDeltaDown = iDelta < iPDelta; // bool isDeltaSignalUp = iDeltaSignal > iPDeltaSignal; // bool isDeltaSignalDown = iDeltaSignal < iPDeltaSignal; // bool isDeltaCrossedOverSignal = iDelta > iDeltaSignal && iPDelta <= iPDeltaSignal; // bool isDeltaCrossedUnderSignal = iDelta < iDeltaSignal && iPDelta >= iPDeltaSignal; // has = isBullish ? (isDeltaUp && isDeltaSignalUp && isDeltaCrossedOverSignal) : (isDeltaDown && isDeltaSignalDown && isDeltaCrossedUnderSignal); if (has) { break; } } // result = has; } // // Filter Using Volume ... if (result && filters.filterBasedOnVolume) { // toIDX = triggerBlock.ob.ToIndex(); fromIDX = triggerBlock.ob.FromIndex(); // for (int i = toIDX; i < fromIDX; i++) { // double iBullVolume = helper.GetBullishVolume(i); double iPBullVolume = helper.GetBullishVolume(i + 1); // double iBullVolumeSignal = helper.GetBullishVolumeSignal(i); double iPBullVolumeSignal = helper.GetBullishVolumeSignal(i + 1); // double iBearVolume = helper.GetBearishVolume(i); double iPBearVolume = helper.GetBearishVolume(i + 1); // double iBearVolumeSignal = helper.GetBearishVolumeSignal(i); double iPBearVolumeSignal = helper.GetBearishVolumeSignal(i + 1); // bool isBullVolumeUp = iBullVolume > iPBullVolume; // bool isBullVolumeSignalUp = iBullVolumeSignal > iPBullVolumeSignal; // bool isBearVolumeUp = iBearVolume > iPBearVolume; // bool isBearVolumeSignalUp = iBearVolumeSignal > iPBearVolumeSignal; // bool isVolumeSwitchedToBullish = iBullVolumeSignal > iBearVolumeSignal && iPBullVolumeSignal <= iPBearVolumeSignal; // bool isVolumeSwitchedToBearish = iBearVolumeSignal > iBullVolumeSignal && iPBearVolumeSignal <= iPBullVolumeSignal; // has = isBullish ? (isBullVolumeUp && isBullVolumeSignalUp && isVolumeSwitchedToBullish) : (isBearVolumeUp && isBearVolumeSignalUp && isVolumeSwitchedToBearish); if (has) { break; } } // result = has; } // // Filter Using Signal Bar ... if (result && filters.filterBasedOnSignalBar) { // toIDX = triggerBlock.ob.ToIndex(); fromIDX = triggerBlock.ob.FromIndex(); // double iSOpen = helper.GetSBarOpen(toIDX); double iPSOpen = helper.GetSBarOpen(toIDX + 1); // double iSClose = helper.GetSBarClose(toIDX); double iPSClose = helper.GetSBarClose(toIDX + 1); // double iSPow = MathAbs(iSOpen - iSClose); double iPSPow = MathAbs(iPSOpen - iPSClose); // result = result && iSPow > iPSPow && (isBullish ? iSClose > iSOpen : iSClose < iSOpen); // // Now Looking for Dir Change ... if (result) { // for (int i = toIDX; i < fromIDX; i++) { // iSOpen = helper.GetSBarOpen(toIDX); iPSOpen = helper.GetSBarOpen(toIDX + 1); // iSClose = helper.GetSBarClose(toIDX); iPSClose = helper.GetSBarClose(toIDX + 1); // bool isSBullish = iSClose > iSOpen; // bool isPSBullish = iPSClose > iPSOpen; // bool isSBearish = iSClose < iSOpen; // bool isPSBearish = iPSClose < iPSOpen; // bool isSSwitchedToBullish = isSBullish && !isPSBullish; // bool isSSwitchedToBearish = isSBearish && !isPSBearish; // has = isBullish ? isSSwitchedToBullish : isSSwitchedToBearish; if (has) { break; } } // result = has; } } // // Filter Using Signal Bar ... if (result && filters.filterBasedOnHKSignalBar) { // toIDX = triggerBlock.ob.ToIndex(); fromIDX = triggerBlock.ob.FromIndex(); // double iSOpen = helper.GetHKSBarOpen(toIDX); double iPSOpen = helper.GetHKSBarOpen(toIDX + 1); // double iSClose = helper.GetHKSBarClose(toIDX); double iPSClose = helper.GetHKSBarClose(toIDX + 1); // double iSPow = MathAbs(iSOpen - iSClose); double iPSPow = MathAbs(iPSOpen - iPSClose); // result = result && iSPow > iPSPow && (isBullish ? iSClose > iSOpen : iSClose < iSOpen); // // Now Looking for Dir Change ... if (result) { // for (int i = toIDX; i < fromIDX; i++) { // iSOpen = helper.GetHKSBarOpen(toIDX); iPSOpen = helper.GetHKSBarOpen(toIDX + 1); // iSClose = helper.GetHKSBarClose(toIDX); iPSClose = helper.GetHKSBarClose(toIDX + 1); // bool isSBullish = iSClose > iSOpen; // bool isPSBullish = iPSClose > iPSOpen; // bool isSBearish = iSClose < iSOpen; // bool isPSBearish = iPSClose < iPSOpen; // bool isSSwitchedToBullish = isSBullish && !isPSBullish; // bool isSSwitchedToBearish = isSBearish && !isPSBearish; // has = isBullish ? isSSwitchedToBullish : isSSwitchedToBearish; if (has) { break; } } // result = has; } } // // Filter Based Round Price ... if (result && filters.filterBasedOnRoundPrice) { // // TODO: Implement this ... } // if (!result) { triggerBlock.Clean(); } // // Summarize result ... result = triggerBlock.IsValid(); // // Cleanup Resources ... // iBar.Clean(); // if (!result) { // conditions.Clean(); triggerBlock.Clean(); } // return result; } // void ValidateTriggerBlockLiquidities( XCX121XCatbHelper *helper, XCBarAnalyser *barAnalyser, XTriggerBlock &triggerBlock, X121XCatbConditions &conditions, XTriggerBlockValidationRules &validations // ) { // bool has = false; // has = helper != NULL && barAnalyser != NULL && triggerBlock.IsValid() && (triggerBlock.fLiquidity.IsValid() || triggerBlock.rLiquidity.IsValid()); if (!has) { return; } // bool hasFLiq = triggerBlock.fLiquidity.IsValid(); bool hasRLiq = triggerBlock.rLiquidity.IsValid(); // // TODO: Implement Liquidity Validation ... } // bool DetectSignalZone( XCPOIDrawer *&drawer, XCX121XCatbHelper *helper, XCBarAnalyser *barAnalyser, XBoxZone &signalZone, X121XCatbConditions &conditions, int barIndex = 0, int loopback = 10 // ) { // bool result = false; // // Checking Conditions ... // // Normalize Args ... signalZone.Clean(); conditions.Clean(); barIndex = NormalizeInt(barIndex, 0); loopback = NormalizeInt(loopback, 0); // // Validate Args ... result = helper != NULL && barAnalyser != NULL; if (!result) { return result; } // // Reading Market Conditions ... result = helper.GetConditions( conditions, barIndex, loopback // ); if (!result) { // signalZone.Clean(); conditions.Clean(); // return result; } // int zIDX = 0; int cIDX = zIDX + 1; int pIDX = cIDX + 1; int p2IDX = pIDX + 1; int p3IDX = p2IDX + 1; int p4IDX = p3IDX + 1; // double sl = 0; double tp = 0; double upper = 0; double lower = 0; datetime to = NULL; datetime from = NULL; string signalProvider = NULL; // // Checking Conditions ... // // Detect Bar Verifications ... // ENUM_X_DIRECTION iDir; // // Rejected ... bool isRejected = barAnalyser .IsRejected( conditions.bars[cIDX], iDir // ); bool isBullishRejected = isRejected && IsBullish(iDir); bool isBearishRejected = isRejected && IsBearish(iDir); // // Engulfed ... bool isEngulfed = barAnalyser .IsEngulfed( conditions.bars[cIDX], iDir // ); bool isBullishEngulfed = isEngulfed && IsBullish(iDir); bool isBearishEngulfed = isEngulfed && IsBearish(iDir); // // Momentum ... bool isMomentum = barAnalyser .IsMomentum( conditions.bars[cIDX], iDir // ); bool isBullishMomentum = isMomentum && IsBullish(iDir); bool isBearishMomentum = isMomentum && IsBearish(iDir); // bool isBarBullishPressured = isBullishRejected || isBullishEngulfed || isBullishMomentum; // bool isBarBearishPressured = isBearishRejected || isBearishEngulfed || isBearishMomentum; // // Detect Indicator Base Start Directional Movement ... // // SAR ... // bool isSarBullishStart = // ( // // Current SAR is Directional ... conditions.isSarBullish && // // Previous InDirectional Sar Exists ... helper.lastSarBearish.IsValid() && // // Current Close is Over previous Sar ... conditions.bars[cIDX].close > helper.lastSarBearish.after && // // Before Close is not Over previous Sar ... conditions.bars[pIDX].close <= helper.lastSarBearish.after // ) // ; // bool isSarBearishStart = // ( // // Current SAR is Directional ... conditions.isSarBearish && // // Previous InDirectional Sar Exists ... helper.lastSarBullish.IsValid() && // // Current Close is Under previous ... conditions.bars[cIDX].close < helper.lastSarBullish.after && // // Before Close is not Under previous ... conditions.bars[pIDX].close >= helper.lastSarBullish.after // ) // ; // // TREND ... // bool isTrendBullishStart = // ( // // Current Trend is Directional ... conditions.isTrendBullish && // // Previous InDirectiona; Trend Exists ... helper.lastTrendBearish.IsValid() && // // Current Close is Over previous ... conditions.bars[cIDX].close > helper.lastTrendBearish.after && // // Before close is not Over previous ... conditions.bars[pIDX].close <= helper.lastTrendBearish.after // ) // ; // bool isTrendBearishStart = // ( // // Current Trend is Directional ... conditions.isTrendBearish && // // Previous InDirectiona; Trend Exists ... helper.lastTrendBullish.IsValid() && // // Current Close is Under previous ... conditions.bars[cIDX].close < helper.lastTrendBullish.after && // // Before close is not Under previous ... conditions.bars[pIDX].close >= helper.lastTrendBullish.after // ) // ; // // ADX ... // bool isADXBullishStart = // ( // // ADX Value is Switched to Strong ... conditions.adxBuffer[cIDX] > conditions.adxThreshold && conditions.adxBuffer[pIDX] <= conditions.adxThreshold && // // ADX must Up ... conditions.adxBuffer[cIDX] > conditions.adxBuffer[pIDX] && // // ADX +DI is Bigger than -DI ... conditions.adxpBuffer[cIDX] > conditions.adxnBuffer[cIDX] && // // ADX +DI is Up ... conditions.adxpBuffer[cIDX] > conditions.adxpBuffer[pIDX] // ) // ; // bool isADXBearishStart = // ( // // ADX Value is Switched to Strong ... conditions.adxBuffer[cIDX] > conditions.adxThreshold && conditions.adxBuffer[pIDX] <= conditions.adxThreshold && // // ADX must Up ... conditions.adxBuffer[cIDX] > conditions.adxBuffer[pIDX] && // // ADX -DI is Bigger than +DI ... conditions.adxnBuffer[cIDX] > conditions.adxpBuffer[cIDX] && // // ADX -DI is Up ... conditions.adxnBuffer[cIDX] > conditions.adxnBuffer[pIDX] // ) // ; // // DELTA ... // bool isDeltaBullishStart = // // Check State ... ( // // Delta is Up ... conditions.deltaBuffer[cIDX] > conditions.deltaBuffer[pIDX] && // // Delta Signal is Up ... conditions.deltaSignalBuffer[cIDX] > conditions.deltaSignalBuffer[pIDX] && // // Delta Crossed Over Delta Signal ... conditions.deltaBuffer[cIDX] > conditions.deltaSignalBuffer[cIDX] // ) // && // // Check Last InDirectional Exists ... helper.lastDeltaBearish.IsValid() && // // Current Close is Over last ... conditions.bars[cIDX].close > helper.lastDeltaBearish.after && // // Before Close is not Over last ... conditions.bars[pIDX].close <= helper.lastDeltaBearish.after // ; // bool isDeltaBearishStart = // // Check State ... ( // // Delta is Down ... conditions.deltaBuffer[cIDX] < conditions.deltaBuffer[pIDX] && // // Delta Signal is Down ... conditions.deltaSignalBuffer[cIDX] < conditions.deltaSignalBuffer[pIDX] && // // Delta Crossed Under Delta Signal ... conditions.deltaBuffer[cIDX] < conditions.deltaSignalBuffer[cIDX] // ) // && // // Check Last InDirectional Exists ... helper.lastDeltaBullish.IsValid() && // // Current Close is Under last ... conditions.bars[cIDX].close < helper.lastDeltaBullish.after && // // Before Close is not Under last ... conditions.bars[pIDX].close >= helper.lastDeltaBullish.after // ; // // VOLUME ... // bool isVolumeBullishStart = // ( // // // Volume is Up ... conditions.bullishVolumeBuffer[1] > conditions.bullishVolumeBuffer[2] && // // Volume Signal is Up ... conditions.bullishVolumeSignalBuffer[1] > conditions.bullishVolumeSignalBuffer[2] && // // Volume Signals Crossed Over ... conditions.bullishVolumeSignalBuffer[1] > conditions.bearishVolumeSignalBuffer[1] // ) // && // // Check Last InDirectional Exists ... helper.lastVolumeBearish.IsValid() && // // Current Close is Over last ... conditions.bars[cIDX].close > helper.lastVolumeBearish.after && // // Before Close is not Over last ... conditions.bars[pIDX].close <= helper.lastVolumeBearish.after // ; // bool isVolumeBearishStart = // ( // // // Volume is Up ... conditions.bearishVolumeBuffer[1] > conditions.bearishVolumeBuffer[2] && // // Volume Signal is Up ... conditions.bearishVolumeSignalBuffer[1] > conditions.bearishVolumeSignalBuffer[2] && // // Volume Signals Crossed Over ... conditions.bearishVolumeSignalBuffer[1] > conditions.bullishVolumeSignalBuffer[1] // ) // && // // Check Last InDirectional Exists ... helper.lastVolumeBullish.IsValid() && // // Current Close is Over last ... conditions.bars[cIDX].close < helper.lastVolumeBullish.after && // // Before Close is not Over last ... conditions.bars[pIDX].close >= helper.lastVolumeBullish.after // ; // // SIGNAL Bar ... // bool isSBarBullishStart = // ( // // Check Direction ... conditions.isSBarBullish && // // Previous InDirectional Exists ... helper.lastSignalBarBearish.IsValid() && // // Current Signal Bar close over prev ... conditions.sBarCloseBuffer[cIDX] > helper.lastSignalBarBearish.after && // // Prev Signal Bar not close over prev ... conditions.sBarCloseBuffer[pIDX] <= helper.lastSignalBarBearish.after // ) // ; // bool isSBarBearishStart = // ( // // Check Direction ... conditions.isSBarBearish && // // Previous InDirectional Exists ... helper.lastSignalBarBullish.IsValid() && // // Current Signal Bar close over prev ... conditions.sBarCloseBuffer[cIDX] < helper.lastSignalBarBullish.after && // // Prev Signal Bar not close over prev ... conditions.sBarCloseBuffer[pIDX] >= helper.lastSignalBarBullish.after // ) // ; // // HKSIGNAL Bar ... // bool isHKSBarBullishStart = // ( // // Check Direction ... conditions.isHKSBarBullish && // // Previous InDirectional Exists ... helper.lastHKSignalBarBearish.IsValid() && // // Current Signal Bar close over prev ... conditions.hkSBarCloseBuffer[cIDX] > helper.lastHKSignalBarBearish.after && // // Prev Signal Bar not close over prev ... conditions.hkSBarCloseBuffer[pIDX] <= helper.lastHKSignalBarBearish.after // ) // ; // bool isHKSBarBearishStart = // ( // // Check Direction ... conditions.isHKSBarBearish && // // Previous InDirectional Exists ... helper.lastHKSignalBarBullish.IsValid() && // // Current Signal Bar close over prev ... conditions.hkSBarCloseBuffer[cIDX] < helper.lastHKSignalBarBullish.after && // // Prev Signal Bar not close over prev ... conditions.hkSBarCloseBuffer[pIDX] >= helper.lastHKSignalBarBullish.after // ) // ; // // Check for Vale and Peak ... // bool isPeakOverLast = // (conditions.peakBuffer[cIDX] > conditions.peakBuffer[pIDX] && conditions.peakBuffer[pIDX] <= conditions.peakBuffer[p2IDX] && conditions.bars[cIDX].close > conditions.peakBuffer[pIDX]) // ; // bool isValeUnderLast = // (conditions.valeBuffer[cIDX] < conditions.valeBuffer[pIDX] && conditions.valeBuffer[pIDX] >= conditions.valeBuffer[p2IDX] && conditions.bars[cIDX].close < conditions.valeBuffer[pIDX]) // ; // // Start Different Conditions Implemntation ... // // Condition 1: // --------------------------- // Descriptions: // // // --------------------------- // // Bullish ... bool isCond1Bullish = false; // // Bearish ... bool isCond1Bearish = false; // bool isCond1 = isCond1Bullish || isCond1Bearish; if (isCond1) { // // Prepare Cond1 Based Requirements ... // to = NULL; upper = 0; lower = 0; from = NULL; // // Provider Definition ... signalProvider = "Cond1"; } // // Try to Summarize Conditions ... // bool isBullish = // isCond1Bullish // ; // bool isBearish = // isCond1Bearish // ; // // Summarize Result ... result = isBullish || isBearish; if (result) { // // Prepare Signal Zone ... // signalZone.to = to; signalZone.from = from; signalZone.upper = upper; signalZone.lower = lower; signalZone.type = signalProvider; signalZone.symbol = conditions.symbol; signalZone.period = conditions.period; // signalZone.dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // // Validate Signal Zone ... result = signalZone.IsValid(); } // // Cleanup Resources ... // if (!result) { // signalZone.Clean(); conditions.Clean(); } // return result; } // // Draw Specific Trigger Block ... bool DrawTriggerBlock( XTriggerBlock &trigger, XCPOIDrawer *drawer, CArrayObj &objects, datetime to = NULL, // bool _drawSignals = false, int rrZoneLength = 10, // Styles ... // // Trigger Block ... int tbWidth = 1, // Trigger Block Width color tbBullishColor = clrAqua, // Trigger Block Bullish Color color tbBearishColor = clrMagenta, // Trigger Block Bearish Color ENUM_LINE_STYLE tbStyle = STYLE_DASHDOTDOT, // Trigger Block Style // // OB ... int obWidth = 1, // OB Width color obBullishColor = clrLime, // OB Bullish Color color obBearishColor = clrRed, // OB Bearish Color ENUM_LINE_STYLE obStyle = STYLE_DOT, // OB Style // // FVG ... int fvgWidth = 2, // FVG Width color fvgBullishColor = clrLime, // FVG Bullish Color color fvgBearishColor = clrRed, // FVG Bearish Color ENUM_LINE_STYLE fvgStyle = STYLE_SOLID // FVG Style ) { // bool result = false; // // Validate Args ... result = trigger.IsValid() && drawer != NULL; if (!result) { return result; } // XTriggerBlock _trigger = trigger; // // Update To ... bool canUpdateTo = IsValid(to); if (canUpdateTo) { // _trigger.trigger.to = to; _trigger.rLiquidity.to = to; _trigger.fLiquidity.to = to; } // bool isBullish = _trigger.IsBullish(); // // Draw OB ... if (_trigger.ob.IsValid()) { // XCBoxObject *iOBObj; result = drawer.DrawBox( _trigger.ob, iOBObj // ); if (result) { // // Style Object ... // color iClr = isBullish ? obBullishColor : obBearishColor; // iOBObj.BoxColor(iClr); iOBObj.BoxWidth(obWidth); iOBObj.BoxStyle(obStyle); // // Store Object ... objects.Add(iOBObj); } ZeroMemory(iOBObj); // if (!result) { return result; } } // // Draw FVG ... if (_trigger.fvg.IsValid()) { // XCBoxObject *iFVGObj; result = drawer.DrawBox( _trigger.fvg, iFVGObj // ); if (result) { // // Style Object ... // color iClr = isBullish ? fvgBullishColor : fvgBearishColor; // iFVGObj.BoxColor(iClr); iFVGObj.BoxWidth(fvgWidth); iFVGObj.BoxStyle(fvgStyle); // // Store Object ... objects.Add(iFVGObj); } ZeroMemory(iFVGObj); // if (!result) { return result; } } // // Draw Trigger ... if (_trigger.trigger.IsValid()) { // XCBoxObject *iTriggerObj; result = drawer.DrawBox( _trigger.trigger, iTriggerObj // ); if (result) { // // Style Object ... // color iClr = isBullish ? tbBullishColor : tbBearishColor; // iTriggerObj.BoxColor(iClr); iTriggerObj.BoxWidth(tbWidth); iTriggerObj.BoxStyle(tbStyle); // // Store Object ... objects.Add(iTriggerObj); } ZeroMemory(iTriggerObj); // if (!result) { return result; } } // // Draw Liquidities ... // // Reversla Liquidity ... if (_trigger.rLiquidity.IsValid()) { // XCBoxObject *iLiqObj; result = drawer.DrawBox( _trigger.rLiquidity, iLiqObj // ); if (result) { objects.Add(iLiqObj); } ZeroMemory(iLiqObj); // if (!result) { return result; } } // // Following Liquidity ... if (_trigger.fLiquidity.IsValid()) { // XCBoxObject *iLiqObj; result = drawer.DrawBox( _trigger.fLiquidity, iLiqObj // ); if (result) { objects.Add(iLiqObj); } ZeroMemory(iLiqObj); // if (!result) { return result; } } // // Draw Swing Bar ... if (_trigger.swingBar.IsValid()) { // color swingColor = _trigger.fvg.IsBullish() ? clrAqua : clrMagenta; ENUM_X_PRICE swingPType = _trigger.fvg.IsBullish() ? X_PRICE_LOW : X_PRICE_HIGH; // XCBarArrowObject *swingObj; result = drawer.CreateBarArrow( _trigger.swingBar, swingObj, swingPType, 159, swingColor // ); if (result) { objects.Add(swingObj); } ZeroMemory(swingObj); // if (!result) { return result; } } // // Draw RR of Signal ... if (_drawSignals && _trigger.signal.IsValid() && rrZoneLength > 0) { // XCRRObject *iRRObj; iRRObj = new XCRRObject(); result = iRRObj.Create( drawer.ChartIdentification(), drawer.SubWindowIdentification(), _trigger.signal, rrZoneLength // ); if (result) { // int iWidth = 2; ENUM_LINE_STYLE iStyle = STYLE_SOLID; // iRRObj.TPWidth(iWidth); iRRObj.SLWidth(iWidth); iRRObj.EntryWidth(iWidth); iRRObj.TargetWidth(iWidth); // iRRObj.TPStyle(iStyle); iRRObj.SLStyle(iStyle); iRRObj.EntryStyle(iStyle); iRRObj.TargetStyle(iStyle); // iRRObj.TPColor(clrLime); iRRObj.SLColor(clrRed); iRRObj.EntryColor(clrYellow); iRRObj.TargetColor(clrLightBlue); // objects.Add(iRRObj); } ZeroMemory(iRRObj); // if (result) { return result; } } // return result; }