diff --git a/Classes/x-saherelm.x-bar.analyser.class.mq5 b/Classes/x-saherelm.x-bar.analyser.class.mq5 index d23284ab..f4aec983 100644 --- a/Classes/x-saherelm.x-bar.analyser.class.mq5 +++ b/Classes/x-saherelm.x-bar.analyser.class.mq5 @@ -2231,7 +2231,7 @@ class XCBarAnalyser : public XCBase * * @return ( bool ) */ - bool IsSwimpleSwing( + bool IsSimpleSwing( XOHCL &bar, ENUM_X_DIRECTION &dir // ) @@ -2286,6 +2286,13 @@ class XCBarAnalyser : public XCBase // result = isPBarSwingLow || isPBarSwingHigh; + if (result) + { + // + dir = isPBarSwingLow + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } // // Cleanup Resourses ... diff --git a/Indicators/test.mq5 b/Indicators/test.mq5 new file mode 100644 index 00000000..77dd77b9 --- /dev/null +++ b/Indicators/test.mq5 @@ -0,0 +1,181 @@ +#property copyright "Your Name" +#property link "https://www.yourwebsite.com" +#property version "1.02" +#property indicator_chart_window +#property indicator_buffers 2 +#property indicator_plots 2 + +//--- Input parameters +input int atr_period = 14; // ATR Period +input double atr_threshold = 0.0005; // ATR Threshold for Consolidation (e.g., 0.0005 for EURUSD, 5.0 for XAUUSD) +input int range_period = 20; // Period to check price range +input double range_multiplier = 2.0; // Price range multiplier (relative to ATR) +input bool enable_alerts = true; // Enable breakout alerts +input bool draw_rectangles = true; // Draw rectangles for consolidation zones + +//--- Indicator buffers +double UpperBuffer[]; +double LowerBuffer[]; + +//--- Global variables +int atr_handle = INVALID_HANDLE; +int zone_count = 0; // For unique rectangle names + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + //--- Set indicator buffers + SetIndexBuffer(0, UpperBuffer, INDICATOR_DATA); + SetIndexBuffer(1, LowerBuffer, INDICATOR_DATA); + PlotIndexSetString(0, PLOT_LABEL, "Upper Consolidation"); + PlotIndexSetString(1, PLOT_LABEL, "Lower Consolidation"); + PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE); + PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE); + PlotIndexSetInteger(0, PLOT_LINE_STYLE, STYLE_SOLID); + PlotIndexSetInteger(1, PLOT_LINE_STYLE, STYLE_SOLID); + PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrRed); + PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrBlue); + + //--- Create ATR handle + atr_handle = iATR(_Symbol, _Period, atr_period); + if(atr_handle == INVALID_HANDLE) + { + Print("Failed to create ATR handle, error: ", GetLastError()); + return(INIT_FAILED); + } + + //--- Check available bars + int available_bars = Bars(_Symbol, _Period); + if(available_bars < range_period + atr_period) + { + Print("Insufficient bars: ", available_bars, ", required: ", range_period + atr_period); + return(INIT_FAILED); + } + + //--- Log initialization + Print("Indicator initialized. Symbol: ", _Symbol, ", Timeframe: ", Period(), + ", ATR Period: ", atr_period, ", Range Period: ", range_period); + + return(INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Custom indicator deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + if(atr_handle != INVALID_HANDLE) + IndicatorRelease(atr_handle); + ObjectsDeleteAll(0, "Consolidation_"); // Remove all rectangles + Print("Indicator deinitialized, reason: ", reason); +} + +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +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[]) +{ + //--- Ensure enough bars + if(rates_total < range_period + atr_period) + { + Print("Not enough bars: ", rates_total, ", required: ", range_period + atr_period); + return(0); + } + + //--- Set arrays as series + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(time, true); + ArraySetAsSeries(UpperBuffer, true); + ArraySetAsSeries(LowerBuffer, true); + + //--- Calculate ATR + double atr[]; + ArraySetAsSeries(atr, true); + ArrayResize(atr, rates_total); + if(CopyBuffer(atr_handle, 0, 0, rates_total, atr) <= 0) + { + Print("Failed to copy ATR buffer, error: ", GetLastError()); + return(0); + } + + //--- Initialize buffers for first calculation + if(prev_calculated == 0) + { + ArrayInitialize(UpperBuffer, EMPTY_VALUE); + ArrayInitialize(LowerBuffer, EMPTY_VALUE); + } + + //--- Loop through bars + int start = prev_calculated == 0 ? range_period : MathMax(range_period, prev_calculated - 1); + for(int i = start; i < rates_total && !IsStopped(); i++) + { + //--- Calculate range over range_period + int max_idx = ArrayMaximum(high, i - range_period + 1, range_period); + int min_idx = ArrayMinimum(low, i - range_period + 1, range_period); + if(max_idx == -1 || min_idx == -1) + { + Print("Error: Invalid array index at bar ", i); + continue; + } + double max_high = high[max_idx]; + double min_low = low[min_idx]; + double price_range = max_high - min_low; + + //--- Log values for debugging + if(i == rates_total - 1) // Log only for the latest bar + { + Print("Bar ", i, ": ATR = ", DoubleToString(atr[i], _Digits), + ", Price Range = ", DoubleToString(price_range, _Digits), + ", Threshold = ", DoubleToString(atr_threshold, _Digits), + ", Range Limit = ", DoubleToString(atr[i] * range_multiplier, _Digits)); + } + + //--- Check for consolidation + if(atr[i] < atr_threshold && price_range < atr[i] * range_multiplier) + { + UpperBuffer[i] = max_high; + LowerBuffer[i] = min_low; + + //--- Draw rectangle for the consolidation zone + if(draw_rectangles && i >= range_period) + { + string obj_name = "Consolidation_" + IntegerToString(zone_count++) + "_" + TimeToString(time[i]); + ObjectCreate(0, obj_name, OBJ_RECTANGLE, 0, time[i], max_high, time[i - range_period + 1], min_low); + ObjectSetInteger(0, obj_name, OBJPROP_COLOR, clrRed); + ObjectSetInteger(0, obj_name, OBJPROP_STYLE, STYLE_SOLID); + ObjectSetInteger(0, obj_name, OBJPROP_WIDTH, 1); + ObjectSetInteger(0, obj_name, OBJPROP_FILL, false); + ObjectSetInteger(0, obj_name, OBJPROP_BACK, false); + } + + //--- Check for breakout (on latest bar only) + if(enable_alerts && i == rates_total - 1) + { + if(close[i] > UpperBuffer[i] && (i == 0 || close[i-1] <= UpperBuffer[i-1])) + Alert("Breakout Up at ", TimeToString(time[i]), ": Price = ", DoubleToString(close[i], _Digits)); + if(close[i] < LowerBuffer[i] && (i == 0 || close[i-1] >= LowerBuffer[i-1])) + Alert("Breakout Down at ", TimeToString(time[i]), ": Price = ", DoubleToString(close[i], _Digits)); + } + } + else + { + UpperBuffer[i] = EMPTY_VALUE; + LowerBuffer[i] = EMPTY_VALUE; + } + } + + return(rates_total); +} \ No newline at end of file diff --git a/Indicators/x-saherelm.x121.xczone.mq5 b/Indicators/x-saherelm.x121.xczone.mq5 new file mode 100644 index 00000000..62b40548 --- /dev/null +++ b/Indicators/x-saherelm.x121.xczone.mq5 @@ -0,0 +1,1178 @@ +/////////////////////////////////////////////////////// +// +// 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 X3MA Indicator" +#property strict + +// +// Definitions ... +// +#define ShortName "X121 XCZone" + +// +// Includes Common Library ... +#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 int minZoneLength = 7; // Minimum Length of Consolidation Zone +input double maxZoneRangeInPoints = 0; // Max Zone Range in Point +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 + +// +// Filtering ... +input group "Filtering"; +input bool filterBasedOnSar = true; // Filter Pivots Based on Sar +input bool filterBasedOnTrend = false; // Filter Pivots Based on Trend + +// +// Presentation ... +input group "Presentation"; +input bool showUpper = true; // Show Upper +input bool showLower = true; // Show Lower +input bool showTrend = false; // Show Trend +input bool showSar = false; // Show Sar + +// +input int startCalculationForLastBars = 1000; // Calculate Last n Bars +int sarArrowCode = 159; // Sar Arrow Code +int upperArrowCode = 117; // Upper Arrow Code +int lowerArrowCode = 117; // Lower Arrow Code + +// +// 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 8 +#property indicator_plots 4 + +// +// Plot Buffers ... + +// +// UPPER ... + +// +#define upperBufferIndex 0 +double upperBuffer[]; + +// +#property indicator_label1 "X121 Upper" +#property indicator_type1 DRAW_ARROW +#property indicator_color1 clrOrange +#property indicator_style1 STYLE_SOLID +#property indicator_width1 2 + +// +// LOWER ... + +// +#define lowerBufferIndex 1 +double lowerBuffer[]; + +// +#property indicator_label2 "X121 Lower" +#property indicator_type2 DRAW_ARROW +#property indicator_color2 clrOrange +#property indicator_style2 STYLE_DASHDOTDOT +#property indicator_width2 2 + +// +// TREND ... + +// +#define trendBufferIndex 2 +#define trendBufferPlotIndex 2 +double trendBuffer[]; + +// +#define trendColorBufferIndex 3 +double trendColorBuffer[]; + +// +#property indicator_label3 "X121 Trend" +#property indicator_type3 DRAW_COLOR_LINE +#property indicator_color3 CLR_NONE, clrAqua, clrMagenta, clrGray +#property indicator_style3 STYLE_DASH +#property indicator_width3 2 + +// +// SAR ... + +// +#define sarBufferIndex 4 +#define sarBufferPlotIndex 3 +double sarBuffer[]; + +// +#define sarColorBufferIndex 5 +double sarColorBuffer[]; + +// +#property indicator_label4 "X121 SAR" +#property indicator_type4 DRAW_COLOR_ARROW +#property indicator_color4 CLR_NONE, clrAqua, clrMagenta, clrGray +#property indicator_width4 2 + +// +// Data Buffers ... + +#define mLastBufferIndex 5 + +// +#define trendStateBufferIndex mLastBufferIndex + 1 +double trendStateBuffer[]; + +// +#define sarStateBufferIndex mLastBufferIndex + 2 +double sarStateBuffer[]; + +// +// Variables, Properties and etc ... + +// +int limit; + +// +int maxLength; + +// +XCPOIDrawer *drawer; +CArrayObj mObjects; +XCBarAnalyser *barAnalyser; +int mTrendPeriodLength = 0; +int sarHandler = 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 ... + + // + 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; + } + + // + // TREND ... + trendHandler = iMA( + _Symbol, + _Period, + mTrendPeriodLength, + 0, + trendMode, + trendAppliedTo // + ); + isInited = trendHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // 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(); + ZeroMemory(drawer); + ZeroMemory(barAnalyser); + + // + IndicatorRelease(sarHandler); + 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); + + // + // TREND ... + int trendCalculatedBars = BarsCalculated(trendHandler); + + // + bool isPassedRequiredCalculatedBars = + // + // SAR ... + sarCalculatedBars >= 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, 0, 0, limit, sarBuffer); + + // + // TREND ... + int copiedTrends = CopyBuffer(trendHandler, MAIN_LINE, 0, limit + 1, trendBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // SAR ... + copiedSars >= 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 && + sarMax > sarStep && + minZoneLength > 2 && + IsValid(trendPeriodMethod, trendPeriod) + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(minZoneLength, result); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // UPPER ... + + // + ENUM_DRAW_TYPE upperDrawType = showUpper ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(upperBuffer, true); + SetIndexBuffer(upperBufferIndex, upperBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(upperBufferIndex, PLOT_SHOW_DATA, showUpper); + PlotIndexSetInteger(upperBufferIndex, PLOT_DRAW_TYPE, upperDrawType); + + // + PlotIndexSetDouble(upperBufferIndex, PLOT_EMPTY_VALUE, emptyValue); + PlotIndexSetInteger(upperBufferIndex, PLOT_ARROW, upperArrowCode); + + // + // LOWER ... + + // + ENUM_DRAW_TYPE lowerDrawType = showLower ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(lowerBuffer, true); + SetIndexBuffer(lowerBufferIndex, lowerBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(lowerBufferIndex, PLOT_SHOW_DATA, showLower); + PlotIndexSetInteger(lowerBufferIndex, PLOT_DRAW_TYPE, lowerDrawType); + + // + PlotIndexSetDouble(lowerBufferIndex, PLOT_EMPTY_VALUE, emptyValue); + PlotIndexSetInteger(lowerBufferIndex, PLOT_ARROW, lowerArrowCode); + + // + // 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); +} + +/** + * 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; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + 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) +{ + // + // UPPER ... + upperBuffer[barIndex] = emptyValue; + + // + // LOWER ... + lowerBuffer[barIndex] = emptyValue; + + // + // SAR ... + sarBuffer[barIndex] = emptyValue; + sarColorBuffer[barIndex] = hideColorIDX; + sarStateBuffer[barIndex] = neuturalState; + + // + // TREND ... + trendBuffer[barIndex] = emptyValue; + trendColorBuffer[barIndex] = hideColorIDX; + trendStateBuffer[barIndex] = neuturalState; +} + +/** + * 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[] // +) +{ + // + // Check Prev Bar ... + + // + int lastBarIndex = bar_index + 1; + int maxBarIndex = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : ratesTotal; + bool isFirstBar = + bar_index == maxBarIndex; + + // + double iLow = high[bar_index]; + double iHigh = high[bar_index]; + double iClose = close[bar_index]; + + // + 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; + + // + // Prevent Calculation ... + if (maxBarIndex - bar_index < minZoneLength) + { + return; + } + + // + // Detect Consolidation Zone ... + XOHCL iBar; + bool has = iBar.Init( + _Symbol, + _Period, + bar_index // + ); + if (!has) + { + return; + } + + // + // Checking Base Zone Exists ... + XBoxZone iZone; + has = barAnalyser.IsOB( + iBar, + iZone, + true, // Force FVG Bar Type ... + true // Force Two Bar ... + ); + if (!has) + { + // + iBar.Clean(); + iZone.Clean(); + } + bool isBullish = + has && + iZone.IsBullish(); + bool isBearish = + has && + iZone.IsBearish(); + + // + // Apply Max Range ... + has = maxZoneRangeInPoints > 0; + if (has) + { + // + double range = iZone.GetRange(); + has = range <= maxZoneRangeInPoints * points; + if (!has) + { + // + iBar.Clean(); + iZone.Clean(); + } + } + + // + XOHCL iPBar; + has = iBar.GetPreviousBar(iPBar); + if (!has) + { + // + iBar.Clean(); + iPBar.Clean(); + iZone.Clean(); + + // + return; + } + + // + // Ensure we Have Order Block ... + ENUM_X_DIRECTION iDir; + + // + // Validate FVG Gap Candle Breakeout by Body ... + + // + // Check iPBar is Momentum Bar ... + has = barAnalyser.IsMomentum( + iPBar, + iDir // + ); + bool isBullishMomentum = + has && + IsBullish(iDir); + bool isBearishMomentum = + has && + IsBearish(iDir); + + // + bool isBullishBreakedOut = + isBullish && + iPBar.IsBullish() && + isBullishMomentum && + iPBar.GetUp() > iZone.upper && + iPBar.GetDown() < iZone.upper; + + // + bool isBearishBreakedOut = + isBearish && + iPBar.IsBearish() && + isBearishMomentum && + iPBar.GetUp() > iZone.lower && + iPBar.GetDown() < iZone.lower; + + // + has = + isBullishBreakedOut || + isBearishBreakedOut; + if (!has) + { + // + iBar.Clean(); + iPBar.Clean(); + iZone.Clean(); + + // + return; + } + + // + // Check Has Proper Swing ... + + // + bool isIBarSimpleSwing = + barAnalyser.IsSimpleSwing( + iBar, + iDir // + ); + bool isIBarBullishSimpleSwing = + isIBarSimpleSwing && + IsBullish(iDir); + bool isIBarBearishSimpleSwing = + isIBarSimpleSwing && + IsBearish(iDir); + + // + bool isIPBarSimpleSwing = + barAnalyser.IsSimpleSwing( + iPBar, + iDir // + ); + bool isIPBarBullishSimpleSwing = + isIPBarSimpleSwing && + IsBullish(iDir); + bool isIPBarBearishSimpleSwing = + isIPBarSimpleSwing && + IsBearish(iDir); + + // + bool isBullishSwimpleSwing = + isBullish && + (isIBarBullishSimpleSwing || + isIPBarBullishSimpleSwing); + + // + bool isBearishSwimpleSwing = + isBearish && + (isIBarBearishSimpleSwing || + isIPBarBearishSimpleSwing); + + // + has = isBullishSwimpleSwing || + isBearishSwimpleSwing; + if (!has) + { + // + iBar.Clean(); + iPBar.Clean(); + iZone.Clean(); + + // + return; + } + + // + int toIDX = iZone.ToIndex(); + int fromIDX = iZone.FromIndex(); + + // + // Retrieve Box From Bar ... + XOHCL fromBar; + has = iZone.FromBar(fromBar); + if (!has) + { + // + iBar.Clean(); + iPBar.Clean(); + iZone.Clean(); + fromBar.Clean(); + + // + return; + } + + // + // Retrieve Highest High and Lowest Low ... + double ll = fromBar.FindLowest(minZoneLength, MODE_LOW); + double hh = fromBar.FindHighest(minZoneLength, MODE_HIGH); + + // + // Validate Directional Based HH/LL Passed ... + + // + bool isBullishLLPassed = + isBullish && + ll >= iZone.lower; + + // + bool isBearishHHPassed = + isBearish && + hh <= iZone.upper; + + // + has = + isBullishLLPassed || + isBearishHHPassed; + if (!has) + { + // + iBar.Clean(); + iPBar.Clean(); + iZone.Clean(); + fromBar.Clean(); + + // + return; + } + + // + // Update Zone From ... + datetime iFrom = GetBarTime( + _Symbol, + _Period, + fromBar.Index() + minZoneLength // + ); + iZone.from = iFrom; + + // + // Apply Filters ... + has = filterBasedOnSar || + filterBasedOnTrend; + if (has) + { + // + // Retrieve Indexes ... + int iBarIndex = iBar.Index(); + int ipBarIndex = iPBar.Index(); + int iBarPrevIndex = iBarIndex + 1; + int ipBarPrevIndex = ipBarIndex + 1; + + // + // Apply Using Sar ... + if (filterBasedOnSar) + { + // + double iSarState = sarStateBuffer[iBarIndex]; + double iPSarState = sarStateBuffer[ipBarIndex]; + double iSarPrevState = sarStateBuffer[iBarPrevIndex]; + double iPSarPrevState = sarStateBuffer[ipBarPrevIndex]; + + // + bool isISarBullish = iSarState > 0; + bool isIPSarBullish = iPSarState > 0; + bool isISarPrevBullish = iSarPrevState > 0; + bool isIPSarPrevBullish = iPSarPrevState > 0; + + // + bool isISarBearish = iSarState < 0; + bool isIPSarBearish = iPSarState < 0; + bool isISarPrevBearish = iSarPrevState < 0; + bool isIPSarPrevBearish = iPSarPrevState < 0; + + // + bool isISarSwitchedToBullish = isISarBullish && + !isISarPrevBullish; + bool isISarSwitchedToBearish = isISarBearish && + !isISarPrevBearish; + + // + bool isIPSarSwitchedToBullish = isIPSarBullish && + !isIPSarPrevBullish; + bool isIPSarSwitchedToBearish = isIPSarBearish && + !isIPSarPrevBearish; + + // + // Check iPBar (Gap Bar which Breaks Edge and is a Momentum Bar) is Sar Change Bar ... + + // + bool isBullishSarFiltered = + isBullish && + (isISarSwitchedToBullish || + isIPSarSwitchedToBullish); + + // + bool isBearishSarFiltered = + isBearish && + (isISarSwitchedToBearish || + isIPSarSwitchedToBearish); + + // + has = isBullishSarFiltered || + isBearishSarFiltered; + if (!has) + { + // + iBar.Clean(); + iPBar.Clean(); + iZone.Clean(); + fromBar.Clean(); + + // + return; + } + } + + // + // Apply Using Trend ... + if (filterBasedOnTrend) + { + // + double iBarTrendState = trendStateBuffer[iBarIndex]; + double iBarPrevTrendState = trendStateBuffer[iBarPrevIndex]; + + // + double iPBarTrendState = trendStateBuffer[ipBarIndex]; + double iPBarPrevTrendState = trendStateBuffer[ipBarPrevIndex]; + + // + bool isIBarTrendBullish = iBarTrendState > 0; + bool isIBarPrevTrendBullish = iBarPrevTrendState > 0; + + // + bool isIBarTrendBearish = iBarTrendState < 0; + bool isIBarPrevTrendBearish = iBarPrevTrendState < 0; + + // + bool isITrendSwitchedToBullish = isIBarTrendBullish && + !isIBarPrevTrendBullish; + bool isITrendSwitchedToBearish = isIBarTrendBearish && + !isIBarPrevTrendBearish; + + // + bool isIPBarTrendBullish = iPBarTrendState > 0; + bool isIPBarPrevTrendBullish = iPBarPrevTrendState > 0; + + // + bool isIPBarTrendBearish = iPBarTrendState < 0; + bool isIPBarPrevTrendBearish = iPBarPrevTrendState < 0; + + // + bool isIPTrendSwitchedToBullish = isIPBarTrendBullish && + !isIPBarPrevTrendBullish; + bool isIPTrendSwitchedToBearish = isIPBarTrendBearish && + !isIPBarPrevTrendBearish; + + // + // Check iPBar (Gap Bar which Breaks Edge and is a Momentum Bar) is Trend Change Bar ... + + // + bool isBullishTrendFiltered = + isBullish && + (isITrendSwitchedToBullish || + isIPTrendSwitchedToBullish); + + // + bool isBearishTrendFiltered = + isBearish && + (isITrendSwitchedToBearish || + isIPTrendSwitchedToBearish); + + // + has = isBullishTrendFiltered || + isBearishTrendFiltered; + if (!has) + { + // + iBar.Clean(); + iPBar.Clean(); + iZone.Clean(); + fromBar.Clean(); + + // + return; + } + } + } + + // + // Fill Buffers Based on Object ... + toIDX = iZone.ToIndex(); + fromIDX = iZone.FromIndex(); + for (int i = fromIDX; i > toIDX; i--) + { + // + upperBuffer[i] = iZone.upper; + lowerBuffer[i] = iZone.lower; + } + + // + // Draw Object ... + XCBoxObject *iZoneObj; + has = drawer.DrawBox( + iZone, + iZoneObj // + ); + if (has) + { + mObjects.Add(iZoneObj); + } + ZeroMemory(iZoneObj); + + // + // Cleanup Resources ... + + // + iBar.Clean(); + iPBar.Clean(); + iZone.Clean(); +} + +// \ No newline at end of file