/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Indicator // ------------------------------------------------- // Name: X121 X3MA // Description: X3MA ... // // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" #property description "SaherElm X121 XCZone Indicator" #property strict // // Definitions ... // #define ShortName "X121 XCZone" // // Includes Common Library ... #include "../Classes/x-saherelm.x-alert.class.mq5" #include "../Classes/x-saherelm.x-bar.analyser.class.mq5" #include "../Classes/x-saherelm.x-poi.drawer.class.mq5" #include "../Libraries/x-saherelm.common.lib.mq5" #include "../Libraries/x-saherelm.x-poi.lib.mq5" // // Inputs ... input group "Market"; input ENUM_X_PERIOD_METHOD trendPeriodMethod = X_PERIOD_AUTO; // How to Find Trend Period input ENUM_TIMEFRAMES trendPeriod = NULL; // Trend Time Period input ENUM_MA_METHOD trendMode = MODE_SMA; // Trend Mode input ENUM_APPLIED_PRICE trendAppliedTo = PRICE_CLOSE; // Trend Applied To input double sarStep = 0.02; // Sar Step input double sarMax = 0.2; // Sar Maximum input int adxLength = 14; // ADX Length input double adxThreshold = 25.0; // ADX Threshold input int rsiLength = 14; // RSI Length input double rsiOBLevel = 70.0; // RSI OB Level input double rsiOSLevel = 30.0; // RSI OS Level input ENUM_APPLIED_PRICE rsiAppliedTo = PRICE_CLOSE; // RSI Applied To input int deltaSignalLength = 14; // Delta Signal Length input ENUM_X_MA_METHOD deltaSignalMethod = X_MA_MODE_EMA; // Delta Signalling Method input int volumeSignalLength = 14; // Volume Signal Length input ENUM_X_MA_METHOD volumeSignalMethod = X_MA_MODE_EMA; // Volume Signalling Method // // Validating ... input group "Validating"; input int minZoneLength = 7; // Minimum Length of Consolidation Zone input double maxZoneRangeInPoints = 70; // Max Zone Range in Point input double maxAllowedEntryDistance = 30; // Max Allowed Entry Distance input bool forceGapBarsBreakout = true; // Force Zone's Gap Bar's Breakes Out input bool forceHasSwing = true; // Force Zone's Has Propper Swing input bool forceHasPinBarEntry = true; // Force Zone's Ends with a Pin Bar // // Filtering ... input group "Filtering"; input bool filterBasedOnSar = false; // Filter Pivots Based on Sar input bool filterBasedOnRSI = false; // Filter Pivots Based on RSI input bool filterBasedOnADX = false; // Filter Pivots Based on ADX input bool filterBasedOnTrend = false; // Filter Pivots Based on Trend // // Presentation ... input group "Presentation"; input bool showSar = false; // Show Sar input bool showTrend = false; // Show Trend input bool rayLeft = false; // Ray to Left input bool drawZones = true; // Draw Detected Zones input bool drawRRofZones = true; // Draw Zone's Risk Reward Ratios input int boxWidth = 2; // Box Width input color bullishColor = clrLime; // Bullish Color input color bearishColor = clrRed; // Bearish Color input ENUM_LINE_STYLE boxStyle = STYLE_SOLID; // Box Style // input int startCalculationForLastBars = 5000; // Calculate Last n Bars int sarArrowCode = 159; // Sar Arrow Code int rrZoneLength = 7; // Draw Risk Reward Ratio till n Bars // // Alert ... input group "Alerts"; input string alertPrefix = ""; // Alert Prefix input bool _logAlerts = true; // Log Alerts input bool _pushAlerts = true; // Push Alerts input bool _mailAlerts = false; // Mail Alerts input bool _terminalAlerts = true; // Terminal Alerts // // Buffers ... // #define hideColorIDX 0 #define bullishColorIDX 1 #define bearishColorIDX 2 #define neuturalColorIDX 3 // #define bullishState 1 #define neuturalState 0 #define bearishState -1 // #define emptyValue 0.0 // #property indicator_chart_window // #property indicator_buffers 16 #property indicator_plots 2 // // Plot Buffers ... // // TREND ... // #define trendBufferIndex 0 #define trendBufferPlotIndex 0 double trendBuffer[]; // #define trendColorBufferIndex 1 double trendColorBuffer[]; // #property indicator_label1 "X121 Trend" #property indicator_type1 DRAW_COLOR_LINE #property indicator_color1 CLR_NONE, clrAqua, clrMagenta, clrGray #property indicator_style1 STYLE_DASH #property indicator_width1 2 // // SAR ... // #define sarBufferIndex 2 #define sarBufferPlotIndex 2 double sarBuffer[]; // #define sarColorBufferIndex 3 double sarColorBuffer[]; // #property indicator_label2 "X121 SAR" #property indicator_type2 DRAW_COLOR_ARROW #property indicator_color2 CLR_NONE, clrAqua, clrMagenta, clrGray #property indicator_width2 2 // // Data Buffers ... #define mLastBufferIndex 3 // // TREND State ... // #define trendStateBufferIndex mLastBufferIndex + 1 double trendStateBuffer[]; // // SAR ... // #define sarStateBufferIndex mLastBufferIndex + 2 double sarStateBuffer[]; // // RSI ... // #define rsiBufferIndex mLastBufferIndex + 3 double rsiBuffer[]; // // ADX ... // #define adxBufferIndex mLastBufferIndex + 4 double adxBuffer[]; // #define adxpBufferIndex mLastBufferIndex + 5 double adxpBuffer[]; // #define adxnBufferIndex mLastBufferIndex + 6 double adxnBuffer[]; // // DELTA ... // #define deltaBufferIndex mLastBufferIndex + 7 double deltaBuffer[]; // #define deltaSignalBufferIndex mLastBufferIndex + 8 double deltaSignalBuffer[]; // // VOLUMES ... // #define bullishVolumeBufferIndex mLastBufferIndex + 9 double bullishVolumeBuffer[]; // #define bearishVolumeBufferIndex mLastBufferIndex + 10 double bearishVolumeBuffer[]; // #define bullishVolumeSignalBufferIndex mLastBufferIndex + 11 double bullishVolumeSignalBuffer[]; // #define bearishVolumeSignalBufferIndex mLastBufferIndex + 12 double bearishVolumeSignalBuffer[]; // // Variables, Properties and etc ... // int limit; // int maxLength; // int firstBarIndex; // XCAlert *alert; double mPoints = 0; CArrayObj mObjects; XCPOIDrawer *drawer; bool mEnableAlerts = false; XCBarAnalyser *barAnalyser; int mTrendPeriodLength = 0; int sarHandler = INVALID_HANDLE; int rsiHandler = INVALID_HANDLE; int adxHandler = INVALID_HANDLE; int trendHandler = INVALID_HANDLE; ENUM_TIMEFRAMES mTrendPeriod = NULL; // // Event Handlers ... /** * Initialize Indicator ... * * @return ( int ) */ int OnInit() { // // Validate Inputs ... if (!ValidateInputs()) { return INIT_PARAMETERS_INCORRECT; } // // Initialize Indicator Handlers ... // // Configure Alert ... alert = new XCAlert(); mEnableAlerts = _logAlerts || _pushAlerts || _mailAlerts || _terminalAlerts; string mPrefix = ShortName + (!IsValid(alertPrefix) ? "" : "[" + alertPrefix + "]"); alert.SetPrefix(mPrefix); alert.SetLogAlerts(_logAlerts); alert.SetMailAlerts(_mailAlerts); alert.SetPushAlerts(_pushAlerts); alert.SetEnableAlerts(mEnableAlerts); alert.SetTerminalAlerts(_terminalAlerts); // drawer = new XCPOIDrawer(); barAnalyser = new XCBarAnalyser(); // // Initializing TrendPeriod ... int cPeriodSeconds = PeriodSeconds(_Period); if (trendPeriodMethod == X_PERIOD_AUTO) { // // Select Period ... mTrendPeriod = GetCyclePeriod( X_MARKET_CYCLE_HIND, _Period // ); } else { mTrendPeriod = trendPeriod; } if (IsValid(mTrendPeriod)) { mTrendPeriodLength = PeriodSeconds(mTrendPeriod) / cPeriodSeconds; } // // SAR ... sarHandler = iSAR( _Symbol, _Period, sarStep, sarMax // ); bool isInited = sarHandler != INVALID_HANDLE; if (!isInited) { return INIT_FAILED; } // // RSI ... rsiHandler = iRSI( _Symbol, _Period, rsiLength, rsiAppliedTo // ); isInited = rsiHandler != INVALID_HANDLE; if (!isInited) { return INIT_FAILED; } // // ADX ... adxHandler = iADX( _Symbol, _Period, adxLength // ); isInited = adxHandler != INVALID_HANDLE; if (!isInited) { return INIT_FAILED; } // // TREND ... trendHandler = iMA( _Symbol, _Period, mTrendPeriodLength, 0, trendMode, trendAppliedTo // ); isInited = trendHandler != INVALID_HANDLE; if (!isInited) { return INIT_FAILED; } // mPoints = GetPoints(_Symbol); // // because in some cases we may have more than one input for // calculation and we must prevent any calculation // untill we pass the biggest input length, here we get max Input length // and then wait until pass it ... maxLength = ExtractMaxLengthOfInputs(); // // Define Index Buffers ... DefineBuffers(); // // Set Indicator ShortName ... SetIndicatorName(); // // Init Succeed ... return INIT_SUCCEEDED; } /** * De Initialize Indicator ... * * @param reason: Integer, De Initialization Reason ... */ void OnDeinit(const int reason) { // // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function // REASON_REMOVE 1 Program removed from a chart // REASON_RECOMPILE 2 Program recompiled // REASON_CHARTCHANGE 3 A symbol or a chart period is changed // REASON_CHARTCLOSE 4 Chart closed // REASON_PARAMETERS 5 Inputs changed by a user // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings // REASON_TEMPLATE 7 Another chart template applied // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value // REASON_CLOSE 9 Terminal closed // mObjects.Clear(); // delete alert; delete drawer; // ZeroMemory(alert); ZeroMemory(drawer); ZeroMemory(barAnalyser); // IndicatorRelease(sarHandler); IndicatorRelease(rsiHandler); IndicatorRelease(adxHandler); IndicatorRelease(trendHandler); } /** * Calculate Bars ... * * @param rates_total: Integer, Total Bars on Chart ... * @param prev_calculated: Integer, Total Calculated Bars on Charts ... * @param time: DateTime Array, History of Open Time ... * @param open: Double Array, History of Open Prices ... * @param high: Double Array, History of High Prices ... * @param low: Double Array, History of Low Prices ... * @param close: Double Array, History of Close Prices ... * @param tick_volume: Long, History of Tick Volumes on Bar ... * @param volume: Long, History of Trade Volumes ... * @param spread: Double, History of Spread Price ... * * @return ( int ) */ int OnCalculate( const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[] // ) { // // Prepare Buffers ... ArraySetAsSeries(time, true); ArraySetAsSeries(open, true); ArraySetAsSeries(high, true); ArraySetAsSeries(low, true); ArraySetAsSeries(close, true); ArraySetAsSeries(tick_volume, true); ArraySetAsSeries(volume, true); ArraySetAsSeries(spread, true); // // Validate Calculated Bars ... // // SAR ... int sarCalculatedBars = BarsCalculated(sarHandler); // // RSI ... int rsiCalculatedBars = BarsCalculated(rsiHandler); // // ADX ... int adxCalculatedBars = BarsCalculated(adxHandler); // // TREND ... int trendCalculatedBars = BarsCalculated(trendHandler); // bool isPassedRequiredCalculatedBars = // // SAR ... sarCalculatedBars >= maxLength && // // RSI ... rsiCalculatedBars >= maxLength && // // ADX ... adxCalculatedBars >= maxLength && // // TREND ... trendCalculatedBars >= maxLength // ; if (!isPassedRequiredCalculatedBars) { return prev_calculated; } // limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; // // Buffers Copy ... // // SAR ... int copiedSars = CopyBuffer(sarHandler, MAIN_LINE, 0, limit, sarBuffer); // // RSI ... int copiedRSIs = CopyBuffer(rsiHandler, MAIN_LINE, 0, limit, rsiBuffer); // // ADX ... int copiedADXs = CopyBuffer(adxHandler, MAIN_LINE, 0, limit, adxBuffer); // // ADX Plus ... int copiedADXPs = CopyBuffer(adxHandler, PLUSDI_LINE, 0, limit, adxpBuffer); // // ADX Negative ... int copiedADXNs = CopyBuffer(adxHandler, MINUSDI_LINE, 0, limit, adxnBuffer); // // TREND ... int copiedTrends = CopyBuffer(trendHandler, MAIN_LINE, 0, limit, trendBuffer); // // Validate Copied Items ... bool isPassedRequiredCopiedItems = // // SAR ... copiedSars >= limit && // // RSI ... copiedRSIs >= limit && // // TREND ... copiedTrends >= limit // ; if (!isPassedRequiredCopiedItems) { return prev_calculated; } // // Main Loop ... for (int i = limit - 1; i >= 0 && !IsStopped(); i--) { // CalculateBuffers( i, prev_calculated, rates_total, // open, high, close, low, tick_volume // ); } // return rates_total; } // // Functions ... /** * Validate Input Args for Initialization ... * * @return ( bool ) */ bool ValidateInputs() { // bool result = false; // result = // sarMax > 0 && sarStep > 0 && adxLength > 0 && rsiLength > 0 && rsiOBLevel > 0 && rsiOSLevel > 0 && sarMax > sarStep && minZoneLength > 2 && deltaSignalLength > 2 && volumeSignalLength > 2 && deltaSignalMethod != X_MA_MODE_NONE && volumeSignalMethod != X_MA_MODE_NONE && IsValid(trendPeriodMethod, trendPeriod) // ; // return result; } /** * Extract Max Length of Inputs ... * * @return ( int ) */ int ExtractMaxLengthOfInputs() { // int result = 0; // result = MathMax(minZoneLength, rsiLength); result = MathMax(result, adxLength); // return result; } /** * Define Required Buffers ... */ void DefineBuffers() { // // Plot Buffers ... // // TREND ... // ArraySetAsSeries(trendBuffer, true); SetIndexBuffer(trendBufferIndex, trendBuffer, INDICATOR_DATA); // PlotIndexSetInteger(trendBufferPlotIndex, PLOT_SHOW_DATA, showTrend); // PlotIndexSetDouble(trendBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); // ArraySetAsSeries(trendColorBuffer, true); SetIndexBuffer(trendColorBufferIndex, trendColorBuffer, INDICATOR_COLOR_INDEX); // // SAR ... // ArraySetAsSeries(sarBuffer, true); SetIndexBuffer(sarBufferIndex, sarBuffer, INDICATOR_DATA); // PlotIndexSetInteger(sarBufferPlotIndex, PLOT_SHOW_DATA, showSar); // PlotIndexSetDouble(sarBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); PlotIndexSetInteger(sarBufferPlotIndex, PLOT_ARROW, sarArrowCode); // ArraySetAsSeries(sarColorBuffer, true); SetIndexBuffer(sarColorBufferIndex, sarColorBuffer, INDICATOR_COLOR_INDEX); // // Data Buffers ... // ArraySetAsSeries(trendStateBuffer, true); SetIndexBuffer(trendStateBufferIndex, trendStateBuffer, INDICATOR_CALCULATIONS); // ArraySetAsSeries(sarStateBuffer, true); SetIndexBuffer(sarStateBufferIndex, sarStateBuffer, INDICATOR_CALCULATIONS); // ArraySetAsSeries(rsiBuffer, true); SetIndexBuffer(rsiBufferIndex, rsiBuffer, INDICATOR_CALCULATIONS); // ArraySetAsSeries(adxBuffer, true); SetIndexBuffer(adxBufferIndex, adxBuffer, INDICATOR_CALCULATIONS); // ArraySetAsSeries(adxpBuffer, true); SetIndexBuffer(adxpBufferIndex, adxpBuffer, INDICATOR_CALCULATIONS); // ArraySetAsSeries(adxnBuffer, true); SetIndexBuffer(adxnBufferIndex, adxnBuffer, INDICATOR_CALCULATIONS); // // DELTA ... // ArraySetAsSeries(deltaBuffer, true); SetIndexBuffer(deltaBufferIndex, deltaBuffer, INDICATOR_CALCULATIONS); // ArraySetAsSeries(deltaSignalBuffer, true); SetIndexBuffer(deltaSignalBufferIndex, deltaSignalBuffer, INDICATOR_CALCULATIONS); // // VOLUME ... // ArraySetAsSeries(bullishVolumeBuffer, true); SetIndexBuffer(bullishVolumeBufferIndex, bullishVolumeBuffer, INDICATOR_CALCULATIONS); // ArraySetAsSeries(bearishVolumeBuffer, true); SetIndexBuffer(bearishVolumeBufferIndex, bearishVolumeBuffer, INDICATOR_CALCULATIONS); // ArraySetAsSeries(bullishVolumeSignalBuffer, true); SetIndexBuffer(bullishVolumeSignalBufferIndex, bullishVolumeSignalBuffer, INDICATOR_CALCULATIONS); // ArraySetAsSeries(bearishVolumeSignalBuffer, true); SetIndexBuffer(bearishVolumeSignalBufferIndex, bearishVolumeSignalBuffer, INDICATOR_CALCULATIONS); } /** * Set Indicator Short Name and also we can define Buffers Labels ... */ void SetIndicatorName() { // IndicatorSetInteger(INDICATOR_DIGITS, _Digits); IndicatorSetString(INDICATOR_SHORTNAME, ShortName); } /** * Calculate Custom Buffers ... * * @param bar_index: Integer, Represent Current Bar ... * @param prevCalculated: Integer, Represent Previous Calculated Bars ... * @param ratesTotal: Integer, Represents All Available Bars ... * @param open: Double Array, History of Open Prices ... * @param high: Double Array, History of High Prices ... * @param close: Double Array, History of Close Prices ... * @param low: Double Array, History of Low Prices ... * @param tickVolume: Long, History of Tick Volumes on Bar ... */ void CalculateBuffers( int bar_index, // Selected Bar Index const int prevCalculated, const int ratesTotal, const double &open[], const double &high[], const double &close[], const double &low[], const long &tickVolume[] // ) { // int barsLimit = startCalculationForLastBars > 0 ? startCalculationForLastBars : 0; if (barsLimit == 0) { // barsLimit = ratesTotal; firstBarIndex = barsLimit - 1; } else { // firstBarIndex = startCalculationForLastBars; } // // bool canCalculate = true; bool canCalculate = bar_index <= barsLimit; if (canCalculate) { // // Calculate Values ... CalculateValues( bar_index, prevCalculated, ratesTotal, open, high, close, low, tickVolume // ); } else { FillBuffersZero(bar_index); } } /** * Fill All Bufers to Zero Vlue for Specified Bar Index ... * * @param barIndex: Integer ... */ void FillBuffersZero(int barIndex) { } /** * Calculate Values ... * * @param bar_index: int, Specified Bar Index ... * @param prevCalculated: int, Provides Previous Calculated Bars ... * @param ratesTotal: int, Provides All Availabled Bars ... * @param open: double Collection, Provides Open Prices Time Series ... * @param high: double Collection, Provides High Prices Time Series ... * @param close: double Collection, Provides Close Prices Time Series ... * @param low: double Collection, Provides Low Prices Time Series ... * @param tickVolume: long Collection, Provides Ticks Volume Prices Time Series ... */ void CalculateValues( int bar_index, // Selected Bar Index const int prevCalculated, const int ratesTotal, const double &open[], const double &high[], const double &close[], const double &low[], const long &tickVolume[] // ) { // int lastBarIndex = bar_index + 1; bool isFirstBar = startCalculationForLastBars > 0 ? bar_index == startCalculationForLastBars : bar_index == firstBarIndex; // // Bar Info ... double iLow = high[bar_index]; double iHigh = high[bar_index]; double iClose = close[bar_index]; double iOpen = open[bar_index]; double iVolume = (double)iVolume(_Symbol, _Period, bar_index); // bool isBullish = iClose > iOpen; bool isBearish = iClose < iOpen; // double points = GetPoints(_Symbol); // // Calculate Sar Color Buffer ... double iSar = sarBuffer[bar_index]; // double iSarState = neuturalState; double iSarColor = neuturalColorIDX; if (iLow > iSar) { // iSarState = bullishState; iSarColor = !showSar ? hideColorIDX : bullishColorIDX; } else if (iHigh < iSar) { // iSarState = bearishState; iSarColor = !showSar ? hideColorIDX : bearishColorIDX; } sarStateBuffer[bar_index] = iSarState; sarColorBuffer[bar_index] = iSarColor; // // Calculate Trend Color Buffer ... double iTrend = trendBuffer[bar_index]; // double iTrendState = neuturalState; double iTrendColor = neuturalColorIDX; if (iClose > iTrend) { // iTrendState = bullishState; iTrendColor = !showTrend ? hideColorIDX : bullishColorIDX; } else if (iClose < iTrend) { // iTrendState = bearishState; iTrendColor = !showTrend ? hideColorIDX : bearishColorIDX; } trendStateBuffer[bar_index] = iTrendState; trendColorBuffer[bar_index] = iTrendColor; // // DELTA ... double lastDelta = isFirstBar ? emptyValue : deltaBuffer[lastBarIndex]; double iAppliedVolume = isBullish ? iVolume : -1 * iVolume; double iDelta = lastDelta + iAppliedVolume; deltaBuffer[bar_index] = iDelta; // // Calculate Delta Signal ... int deltaSignalsCount = iMAOnBuffer( ratesTotal, prevCalculated, bar_index, deltaSignalLength, deltaBuffer, deltaSignalBuffer, deltaSignalMethod // ); // // VOLUME ... // double iBullishVolume = emptyValue; double iBearishVolume = emptyValue; if (isBullish) { iBullishVolume = iVolume; } else if (isBearish) { iBearishVolume = iVolume; } else { // double iHalfVolume = iVolume / 2; // iBullishVolume = iHalfVolume; iBearishVolume = iHalfVolume; } bullishVolumeBuffer[bar_index] = iBullishVolume; bearishVolumeBuffer[bar_index] = iBearishVolume; // // Calculate Volume Signals ... // int bullishVolumeSignalsCount = iMAOnBuffer( ratesTotal, prevCalculated, bar_index, volumeSignalLength, bullishVolumeBuffer, bullishVolumeSignalBuffer, volumeSignalMethod // ); // int bearishVolumeSignalsCount = iMAOnBuffer( ratesTotal, prevCalculated, bar_index, volumeSignalLength, bearishVolumeBuffer, bearishVolumeSignalBuffer, volumeSignalMethod // ); // // Detect Trigger Zone ... DetectTriggerZone( bar_index, prevCalculated, ratesTotal, open, high, close, low, tickVolume // ); } // void DetectTriggerZone( int bar_index, // Selected Bar Index const int prevCalculated, const int ratesTotal, const double &open[], const double &high[], const double &close[], const double &low[], const long &tickVolume[] // ) { // // Check Prev Bar ... // int lastBarIndex = bar_index + 1; int maxBarIndex = startCalculationForLastBars > 0 ? startCalculationForLastBars : ratesTotal; bool isFirstBar = bar_index == maxBarIndex; // // Prevent Calculation ... if (maxBarIndex - bar_index < minZoneLength) { return; } // int zIDX = 0; int cIDX = 0; int pIDX = 0; int p2IDX = 0; int p3IDX = 0; int p4IDX = 0; double ll = 0; double hh = 0; bool has = false; ENUM_X_DIRECTION iDir; // // Retrieve Required Bars ... // XOHCL zBar; // Current Start Checking Bar (Usually Used for Triggering) ... XOHCL cBar; // Current Finished Bar which Start Detecting Structures based on it ( End of Block and FVG Bar ) ... XOHCL pBar; // Determines Block Gap Bar (all Filtering must applied and Check using this Bar and it's Next Bar) ... XOHCL p2Bar; // Determines FVG's Start Bar in a Block ... XOHCL p3Bar; // First Verification of Block ... XOHCL p4Bar; // Seccond Verification of Block ... // has = zBar.Init( _Symbol, _Period, bar_index // ); has = has && zBar.GetPreviousBar(cBar); has = has && cBar.GetPreviousBar(pBar); has = has && pBar.GetPreviousBar(p2Bar); has = has && p2Bar.GetPreviousBar(p3Bar); has = has && p3Bar.GetPreviousBar(p4Bar); if (!has) { // zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } // // Define Zone Structure ... XBoxZone zone; // // Detect Based Order Block using CBar ... has = barAnalyser.IsOB( cBar, zone, true, // Force FVG Bar Type ... true // Force Block Two Bar Checking ... ); // // Ensure a Block is Detected ... if (!has) { // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } // zIDX = zBar.Index(); cIDX = cBar.Index(); pIDX = pBar.Index(); p2IDX = p2Bar.Index(); p3IDX = p3Bar.Index(); p4IDX = p4Bar.Index(); // bool isBullish = has && zone.IsBullish(); // bool isBearish = has && zone.IsBearish(); // int toIDX = zone.ToIndex(); int fromIDX = zone.FromIndex(); // // Validating p2Bar and p3Bar Direction ... if (has) { // iDir = Opposit(zone.dir); // has = iDir == p3Bar.GetDirection() || iDir == p4Bar.GetDirection(); if (!has) { // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } } // // Start Validating Block based on // Detected One ... // // Validating Using Max Range ... has = maxZoneRangeInPoints > 0; if (has) { // double range = zone.GetRange(); has = range <= maxZoneRangeInPoints * mPoints; if (!has) { // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } } // // Validate Gap Endup with PinBar ... has = forceHasPinBarEntry; if (has) { // bool isBullishRejected = isBullish && cBar.IsBullish() && cBar.GetLowShadow() > cBar.GetHighShadow(); // bool isBearishRejected = isBearish && cBar.IsBearish() && cBar.GetLowShadow() < cBar.GetHighShadow(); // has = isBullishRejected || isBearishRejected; if (!has) { // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } } // // Validating Gap Bar must a Momentum Bar and // Breakes out Zone's Directional Edge ... // for Bullish: Upper // for Bearish: Lower has = forceGapBarsBreakout; if (has) { // // Gap Bar is PBar ... // // Check Gap Bar is Momentum Bar ... has = barAnalyser.IsMomentum( pBar, iDir // ); bool isBullishMomentum = has && IsBullish(iDir); bool isBearishMomentum = has && IsBearish(iDir); // // Check Gap Bar's Breakout ... // bool isBullishBreakedout = isBullish && pBar.IsBullish() && isBullishMomentum && pBar.GetUp() > zone.upper && pBar.GetDown() < zone.upper; // bool isBearishBreakedout = isBearish && pBar.IsBearish() && isBearishMomentum && pBar.GetUp() > zone.lower && pBar.GetDown() < zone.lower; // has = isBullishBreakedout || isBearishBreakedout; if (!has) { // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } } // // Validate Zone Has Propper Swing ... // for Bullish: p2Bar or p3Bar must be a Swing Low ... // for Bearish: p2Bar or p3Bar must be a Swing High ... has = forceHasSwing; if (has) { // // p2Bar ... bool isP2BarSwing = barAnalyser .IsSimpleSwing( p2Bar, iDir // ); bool isP2BarSwingLow = isP2BarSwing && IsBullish(iDir); bool isP2BarSwingHigh = isP2BarSwing && IsBearish(iDir); // // p3Bar ... bool isP3BarSwing = barAnalyser .IsSimpleSwing( p3Bar, iDir // ); bool isP3BarSwingLow = isP3BarSwing && IsBullish(iDir); bool isP3BarSwingHigh = isP3BarSwing && IsBearish(iDir); // bool hasSwingLow = isBullish && (isP2BarSwingLow || isP3BarSwingLow); // bool hasSwingHigh = isBearish && (isP2BarSwingHigh || isP3BarSwingHigh); // has = hasSwingLow || hasSwingHigh; if (!has) { // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } } // // Validating Using Swing Length ... has = minZoneLength > 0; if (has) { // XOHCL fromBar; has = zone.FromBar(fromBar); if (has) { // // Retrieve HH and LL ... ll = fromBar.FindLowest(minZoneLength, MODE_LOW); hh = fromBar.FindHighest(minZoneLength, MODE_HIGH); // // Validate Using HH and LL ... // bool isBullishValid = isBullish && ll >= zone.lower; // bool isBearishValid = isBearish && hh <= zone.upper; // has = isBullishValid || isBearishValid; if (!has) { // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } // // Update Zone's From Time ... zone.from = GetBarTime( zone.symbol, zone.period, fromBar.Index() + minZoneLength // ); } // fromBar.Clean(); } // // Validate Max Allowed Entry Distance ... has = maxAllowedEntryDistance > 0; if (has) { // double base = isBullish ? zone.upper : zone.lower; double entryDistance = MathAbs(zBar.open - base); has = entryDistance <= maxAllowedEntryDistance * mPoints; if (!has) { // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } } // // Here we Ensure which have a Valid Zone using Different Applied Validations ... // from now we are Going to Filtered Validate Zones ... // // Check Exists Filters or not ... has = filterBasedOnSar || filterBasedOnRSI || filterBasedOnADX || filterBasedOnTrend; if (has) { // // Do Apply Several Exists Filters ... // // SAR Filter ... if (filterBasedOnSar) { // // Reading Conditions Values ... // double zSar = sarBuffer[zIDX]; double cSar = sarBuffer[cIDX]; double pSar = sarBuffer[pIDX]; double p2Sar = sarBuffer[p2IDX]; double p3Sar = sarBuffer[p3IDX]; double p4Sar = sarBuffer[p4IDX]; // // Create Required Conditions ... // bool isZSarBullish = zSar < zBar.low; bool isZSarBearish = zSar > zBar.high; // bool isCSarBullish = cSar < cBar.low; bool isCSarBearish = cSar > cBar.high; // bool isPSarBullish = pSar < pBar.low; bool isPSarBearish = pSar > pBar.high; // bool isP2SarBullish = p2Sar < p2Bar.low; bool isP2SarBearish = p2Sar > p2Bar.high; // bool isCSarSwitchedToBullish = isZSarBullish && isCSarBullish && !isPSarBullish && cBar.IsBullish() && cBar.GetUp() > pSar; // bool isCSarSwitchedToBearish = isZSarBearish && isCSarBearish && !isPSarBearish && cBar.IsBearish() && cBar.GetDown() < pSar; // bool isPSarSwitchedToBullish = isZSarBullish && isCSarBullish && isPSarBullish && !isP2SarBullish && pBar.IsBullish() && pBar.GetUp() > p2Sar; // bool isPSarSwitchedToBearish = isZSarBearish && isCSarBearish && isPSarBearish && !isP2SarBearish && pBar.IsBearish() && pBar.GetDown() < p2Sar; // // Summarize Filtering ... // bool isBullishFiltered = isBullish && (isCSarSwitchedToBullish || isPSarSwitchedToBullish); // bool isBearishFiltered = isBearish && (isCSarSwitchedToBearish || isPSarSwitchedToBearish); // has = isBullishFiltered || isBearishFiltered; if (!has) { // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } } // // RSI Filter ... if (filterBasedOnRSI) { // // Reading Conditions Values ... // double rsiTrend = (rsiOBLevel + rsiOSLevel) / 2; // double zRSI = rsiBuffer[zIDX]; double cRSI = rsiBuffer[cIDX]; double pRSI = rsiBuffer[pIDX]; double p2RSI = rsiBuffer[p2IDX]; double p3RSI = rsiBuffer[p3IDX]; double p4RSI = rsiBuffer[p4IDX]; // // Create Required Conditions ... // bool isZRSIBullish = zRSI > rsiTrend; bool isZRSIBearish = zRSI < rsiTrend; // bool isCRSIBullish = cRSI > rsiTrend; bool isCRSIBearish = cRSI < rsiTrend; // bool isPRSIBullish = pRSI > rsiTrend; bool isPRSIBearish = pRSI < rsiTrend; // bool isP2RSIBullish = p2RSI > rsiTrend; bool isP2RSIBearish = p2RSI < rsiTrend; // bool isP3RSIBullish = p3RSI > rsiTrend; bool isP3RSIBearish = p3RSI < rsiTrend; // // Trending Conditions ... // bool isCRSISwitchedToBullish = isZRSIBullish && isCRSIBullish && !isPRSIBullish; // bool isCRSISwitchedToBearish = isZRSIBearish && isCRSIBearish && !isPRSIBearish; // bool isPRSISwitchedToBullish = isZRSIBullish && isCRSIBullish && isPRSIBullish && !isP2RSIBullish; // bool isPRSISwitchedToBearish = isZRSIBearish && isCRSIBearish && isPRSIBearish && !isP2RSIBearish; // bool isP2RSISwitchedToBullish = isZRSIBullish && isCRSIBullish && isPRSIBullish && isP2RSIBullish && !isP3RSIBullish; // bool isP2RSISwitchedToBearish = isZRSIBearish && isCRSIBearish && isPRSIBearish && isP2RSIBearish && !isP3RSIBearish; // // Crosses Conditions ... // bool isCBarCrossedOverOS = zRSI > rsiOSLevel && cRSI > rsiOSLevel && pRSI <= rsiOSLevel; // bool isCBarCrossedUnderOB = zRSI < rsiOBLevel && cRSI < rsiOBLevel && pRSI >= rsiOBLevel; // bool isPBarCrossedOverOS = zRSI > rsiOSLevel && cRSI > rsiOSLevel && pRSI > rsiOSLevel && p2RSI <= rsiOSLevel; // bool isPBarCrossedUnderOB = zRSI < rsiOBLevel && cRSI < rsiOBLevel && pRSI < rsiOBLevel && p2RSI >= rsiOBLevel; // // V Pattern Conditions ... // bool isCRSIHasVBullishPattern = zRSI >= cRSI && cRSI > pRSI && p2RSI > pRSI && cRSI >= p2RSI; // bool isCRSIHasVBearishPattern = zRSI <= cRSI && cRSI < pRSI && p2RSI < pRSI && cRSI <= p2RSI; // // Continuation Conditions ... // bool isRSIUp = zRSI >= cRSI && (cRSI >= pRSI || pRSI >= p2RSI || p2RSI >= p3RSI); // bool isRSIDown = zRSI <= cRSI && (cRSI <= pRSI || pRSI <= p2RSI || p2RSI <= p3RSI); // // Summarize Filtering ... // bool isBullishFiltered = isBullish && ( // // Grows ... isRSIUp // || // // Crosses ... (isCBarCrossedOverOS || isPBarCrossedOverOS) // || // // V Pattern ... isCRSIHasVBullishPattern // || // // Trending ... (isCRSISwitchedToBullish || isPRSISwitchedToBullish || isP2RSISwitchedToBullish) // ); // bool isBearishFiltered = isBearish && ( // // Grows ... isRSIDown // || // // Crosses ... (isCBarCrossedUnderOB || isPBarCrossedUnderOB) // || // // V Pattern ... isCRSIHasVBearishPattern // || // // Trending ... (isCRSISwitchedToBearish || isPRSISwitchedToBearish || isP2RSISwitchedToBearish) // ); // has = isBullishFiltered || isBearishFiltered; if (!has) { // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } } // // ADX Filter ... if (filterBasedOnADX) { // // Reading Conditions Values ... // // ADX ... double zADX = adxBuffer[zIDX]; double cADX = adxBuffer[cIDX]; double pADX = adxBuffer[pIDX]; double p2ADX = adxBuffer[p2IDX]; double p3ADX = adxBuffer[p3IDX]; double p4ADX = adxBuffer[p4IDX]; // // ADX +DI ... double zADXP = adxpBuffer[zIDX]; double cADXP = adxpBuffer[cIDX]; double pADXP = adxpBuffer[pIDX]; double p2ADXP = adxpBuffer[p2IDX]; double p3ADXP = adxpBuffer[p3IDX]; double p4ADXP = adxpBuffer[p4IDX]; // // ADX -DI ... double zADXN = adxnBuffer[zIDX]; double cADXN = adxnBuffer[cIDX]; double pADXN = adxnBuffer[pIDX]; double p2ADXN = adxnBuffer[p2IDX]; double p3ADXN = adxnBuffer[p3IDX]; double p4ADXN = adxnBuffer[p4IDX]; // // Create Required Conditions ... // // Grows ... // bool isADXUp = zADX >= cADX && (cADX >= pADX || pADX >= p2ADX); // bool isADXDown = zADX <= cADX && (cADX <= pADX || pADX <= p2ADX); // // Trending ... // bool isZADXBullish = zADX > adxThreshold; bool isZADXBearish = zADX < adxThreshold; // bool isCADXBullish = cADX > adxThreshold; bool isCADXBearish = cADX < adxThreshold; // bool isPADXBullish = pADX > adxThreshold; bool isPADXBearish = pADX < adxThreshold; // bool isP2ADXBullish = p2ADX > adxThreshold; bool isP2ADXBearish = p2ADX < adxThreshold; // bool isP3ADXBullish = p3ADX > adxThreshold; bool isP3ADXBearish = p3ADX < adxThreshold; // bool isP4ADXBullish = p4ADX > adxThreshold; bool isP4ADXBearish = p4ADX < adxThreshold; // bool isCADXSwitchedToBullish = isZADXBullish && isCADXBullish && !isPADXBullish; // bool isCADXSwitchedToBearish = isZADXBearish && isCADXBearish && !isPADXBearish; // bool isPADXSwitchedToBullish = isZADXBullish && isCADXBullish && isPADXBullish && !isP2ADXBullish; // bool isPADXSwitchedToBearish = isZADXBearish && isCADXBearish && isPADXBearish && !isP2ADXBearish; // // Powering ... // bool isZADXHasBullishPower = zADXP > zADXN; bool isZADXHasBearishPower = zADXN > zADXP; // bool isCADXHasBullishPower = cADXP > cADXN; bool isCADXHasBearishPower = cADXN > cADXP; // bool isPADXHasBullishPower = pADXP > pADXN; bool isPADXHasBearishPower = pADXN > pADXP; // bool isP2ADXHasBullishPower = p2ADXP > p2ADXN; bool isP2ADXHasBearishPower = p2ADXN > p2ADXP; // bool isP3ADXHasBullishPower = p3ADXP > p3ADXN; bool isP3ADXHasBearishPower = p3ADXN > p3ADXP; // bool isP4ADXHasBullishPower = p4ADXP > p4ADXN; bool isP4ADXHasBearishPower = p4ADXN > p4ADXP; // bool isCADXSwitchedToBullishPower = isZADXHasBullishPower && isCADXHasBullishPower && !isPADXHasBullishPower; // bool isCADXSwitchedToBearishPower = isZADXHasBearishPower && isCADXHasBearishPower && !isPADXHasBearishPower; // bool isPADXSwitchedToBullishPower = isZADXHasBullishPower && isCADXHasBullishPower && isPADXHasBullishPower && !isP2ADXHasBullishPower; // bool isPADXSwitchedToBearishPower = isZADXHasBearishPower && isCADXHasBearishPower && isPADXHasBearishPower && !isP2ADXHasBearishPower; // // Summarize Filtering ... // bool isBullishFiltered = isBullish && ( // // Grows ... isADXUp // || // // Trending ... (isCADXSwitchedToBullish || isPADXSwitchedToBullish) // || // // Powering ... (isCADXSwitchedToBullishPower || isPADXSwitchedToBullishPower) // ); // bool isBearishFiltered = isBearish && ( // // Grows ... isADXDown // || // // Trending ... (isCADXSwitchedToBearish || isPADXSwitchedToBearish) // || // // Powering ... (isCADXSwitchedToBearishPower || isPADXSwitchedToBearishPower) // ); // has = isBullishFiltered || isBearishFiltered; if (!has) { // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } } // // TREND Filter ... if (filterBasedOnTrend) { // // Reading Conditions Values ... // double zTrend = trendBuffer[zIDX]; double cTrend = trendBuffer[cIDX]; double pTrend = trendBuffer[pIDX]; double p2Trend = trendBuffer[p2IDX]; double p3Trend = trendBuffer[p3IDX]; double p4Trend = trendBuffer[p4IDX]; // double trends[] = { zTrend, cTrend, pTrend, p2Trend, p3Trend, p4Trend // }; double trendsMin = GetMin(trends); double trendsMax = GetMax(trends); double trendsAVG = GetAverage(trends); // double zTrendState = trendStateBuffer[zIDX]; double cTrendState = trendStateBuffer[cIDX]; double pTrendState = trendStateBuffer[pIDX]; double p2TrendState = trendStateBuffer[p2IDX]; double p3TrendState = trendStateBuffer[p3IDX]; double p4TrendState = trendStateBuffer[p4IDX]; // // Create Required Conditions ... // // Grows ... // bool isTrendUp = zTrend >= cTrend && cTrend >= trendsAVG && cTrend > trendsMin; // bool isTrendDown = zTrend <= cTrend && cTrend <= trendsAVG && cTrend < trendsMax; // // Stating ... // bool isCTrendBullish = zTrendState > 0 && cTrendState > 0; // bool isCTrendBearish = zTrendState < 0 && cTrendState < 0; // bool isPTrendBullish = zTrendState > 0 && cTrendState > 0 && pTrendState > 0; // bool isPTrendBearish = zTrendState < 0 && cTrendState < 0 && pTrendState < 0; // bool isP2TrendBullish = zTrendState > 0 && cTrendState > 0 && pTrendState > 0 && p2TrendState > 0; // bool isP2TrendBearish = zTrendState < 0 && cTrendState < 0 && pTrendState < 0 && p2TrendState < 0; // bool isCTrendSwitchedToBullish = isCTrendBullish && !isPTrendBullish; // bool isCTrendSwitchedToBearish = isCTrendBearish && !isPTrendBearish; // bool isPTrendSwitchedToBullish = isCTrendBullish && isPTrendBullish && !isP2TrendBullish; // bool isPTrendSwitchedToBearish = isCTrendBearish && isPTrendBearish && !isP2TrendBearish; // // Summarize Filtering ... // bool isBullishFiltered = isBullish && ( // // Grows ... isTrendUp // || // // Trend Stating ... (isCTrendBullish && isPTrendBullish) // || // // Switching ... (isCTrendSwitchedToBullish || isPTrendSwitchedToBullish) // ); // bool isBearishFiltered = isBearish && ( // // Grows ... isTrendDown // || // // Trend Stating ... (isCTrendBearish && isPTrendBearish) // || // // Switching ... (isCTrendSwitchedToBearish || isPTrendSwitchedToBearish) // ); // has = isBullishFiltered || isBearishFiltered; if (!has) { // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); // return; } } // // SCORE Filter ... // // VOLUME Filter ... } // // Detect Left Side of Box ... XOHCL zoneLeftBar; int idx = fromIDX + 1; bool isBaseValid = true; while (isBaseValid) { // // Retrieve iteration Bar ... has = zoneLeftBar.Init( _Symbol, _Period, idx // ); if (!has) { // zoneLeftBar.Clean(); break; } // // Check Bar's Validation ... // bool isBullishPassed = isBullish && zoneLeftBar.low >= zone.lower; // bool isBearishPassed = isBearish && zoneLeftBar.high <= zone.upper; // // Summarize Conditions ... has = isBullishPassed || isBearishPassed; if (!has) { break; } // idx++; } // // Ray to Left Side Zone, if Provided ... if (rayLeft) { // // Update Value ... fromIDX = zone.FromIndex(); // // Check Last Iteration Bar is Valid Bar ... // then Update Zone from Time ... has = zoneLeftBar.IsValid(); if (has) { // zone.from = zoneLeftBar.time; fromIDX = zone.FromIndex(); } } // // Draw Detected Zone ... if (drawZones) { // XCBoxObject *iZoneObj; has = drawer.DrawBox( zone, iZoneObj // ); if (has) { // ApplyStyle(iZoneObj, zone.dir); // mObjects.Add(iZoneObj); // // TODO: Enable This for Debugging ... // string message = ToString(zone.dir) + " Zone Detected (" + cBar.time + ") ..."; // Print(message); } ZeroMemory(iZoneObj); } // // Draw RR Tool ... if (drawRRofZones) { // double rr[]{ 1, 1.5, 2, 3, 4, 5, 6, 7, 8, 9, 10 // }; XCRRObject *iRRObj; iRRObj = new XCRRObject(); has = iRRObj.CreateBoxRR( drawer.ChartIdentification(), drawer.SubWindowIdentification(), zone, rr, rrZoneLength // ); if (has) { // 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); // mObjects.Add(iRRObj); } ZeroMemory(iRRObj); } // // Handle Alerst ... bool canAlert = mEnableAlerts && prevCalculated > 0; bool canLogOnly = mEnableAlerts && prevCalculated == 0; if (canAlert || canLogOnly) { // string message = zone.symbol + "," + ToString(zone.period) + "> " + ToString(zone.dir) + " Zone Detected at: " + ToString(zone.to); // if (canLogOnly) { alert.LogAlert(message); } else if (canAlert) { alert.SendAlert(message); } } // // Cleanup Resources ... // zone.Clean(); zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); p4Bar.Clean(); zoneLeftBar.Clean(); } // void ApplyStyle( XCBoxObject *iObj, ENUM_X_DIRECTION dir // ) { // if (!HasDirection(dir) || iObj == NULL) { return; } // int width = boxWidth > 0 ? boxWidth : 1; int clr = IsBullish(dir) ? bullishColor : bearishColor; // iObj.BoxColor(clr); iObj.BoxWidth(width); iObj.BoxStyle(boxStyle); // } //