diff --git a/Documents/BKP/detect.block.base.trigger.mq5 b/Documents/BKP/detect.block.base.trigger.mq5 new file mode 100644 index 00000000..c05d7235 --- /dev/null +++ b/Documents/BKP/detect.block.base.trigger.mq5 @@ -0,0 +1,96 @@ + + // + // Detect Block Based Trigger ... + XBoxZone ob; + XOHCL swing; + XOHCL breaker; + XOHCL outSide; + ENUM_X_DIRECTION passedDir; + bool isPassed = helper.IsBlockBasedTriggerBar( + ob, + swing, + breaker, + outSide, + passedDir, + 1, // Bar Index ... + 50, // Loopback ... + 3 // Swing Length ... + ); + if (isPassed) + { + // + // Draw Block Based Trigger ... + + // + // Draw OB ... + XCBoxObject *obObject; + has = helper.poiDrawer.DrawBox( + ob, + obObject // + ); + if (has) + { + // + obObject.BoxWidth(2); + obObject.BoxStyle(STYLE_SOLID); + + // + color obColor = + ob.IsBullish() + ? clrAqua + : clrMagenta; + obObject.BoxColor(obColor); + + // + mObjects.Add(obObject); + + // + ZeroMemory(obObject); + } + + // + double breakPrice = + ob.IsBullish() + ? swing.high + : swing.low; + + // + // Draw Swing and Breake ... + CChartObjectTrend *tObj; + tObj = new CChartObjectTrend(); + string tName = "Swing_For_" + ToString(ob.dir) + "_" + ToString(breakPrice); + has = tObj.Create( + 0, + tName, + 0, + swing.time, + breakPrice, + breaker.time, + breakPrice // + ); + if (has) + { + // + tObj.Width(2); + tObj.Style(STYLE_SOLID); + + // + color tColor = ob.IsBullish() + ? clrRed + : clrLime; + tObj.Color(tColor); + + // + mObjects.Add(tObj); + + // + ZeroMemory(tObj); + } + + // + Print("Passed Bar ..."); + } + ob.Clean(); + swing.Clean(); + breaker.Clean(); + outSide.Clean(); diff --git a/Documents/BKP/rsi.divergence.2.mq5 b/Documents/BKP/rsi.divergence.2.mq5 new file mode 100644 index 00000000..5d728b50 --- /dev/null +++ b/Documents/BKP/rsi.divergence.2.mq5 @@ -0,0 +1,317 @@ +//+------------------------------------------------------------------+ +//| RSI_Div.mq5 | +//| Copyright 2023, MetaQuotes Software Corp. | +//| https://www.metaquotes.net/ | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Software Corp." +#property link "https://www.metaquotes.net/" +#property version "1.00" +#property indicator_separate_window +#property indicator_buffers 8 +#property indicator_plots 2 +#property indicator_label1 "RSI" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrDodgerBlue +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 +#property indicator_label2 "Signal" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrOrange +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 + +//--- Input parameters +input int InpRSIPeriod = 14; // RSI Period +input ENUM_APPLIED_PRICE InpRSIPrice = PRICE_CLOSE; // RSI Applied Price +input int InpLeftBars = 5; // Left bars to check +input int InpRightBars = 5; // Right bars to check +input double InpMinDivergence = 5.0; // Minimum divergence in % +input bool ShowRegularBullish = true; // Show Regular Bullish +input bool ShowRegularBearish = true; // Show Regular Bearish +input bool ShowHiddenBullish = true; // Show Hidden Bullish +input bool ShowHiddenBearish = true; // Show Hidden Bearish + +//--- Indicator buffers +double RSIBuffer[]; +double SignalBuffer[]; +double HighBuffer[]; +double LowBuffer[]; +double BullishDivBuffer[]; +double BearishDivBuffer[]; +double HiddenBullishDivBuffer[]; +double HiddenBearishDivBuffer[]; + +//--- Handles +int rsiHandle; + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + //--- Indicator buffers mapping + SetIndexBuffer(0, RSIBuffer, INDICATOR_DATA); + SetIndexBuffer(1, SignalBuffer, INDICATOR_DATA); + SetIndexBuffer(2, HighBuffer, INDICATOR_CALCULATIONS); + SetIndexBuffer(3, LowBuffer, INDICATOR_CALCULATIONS); + SetIndexBuffer(4, BullishDivBuffer, INDICATOR_CALCULATIONS); + SetIndexBuffer(5, BearishDivBuffer, INDICATOR_CALCULATIONS); + SetIndexBuffer(6, HiddenBullishDivBuffer, INDICATOR_CALCULATIONS); + SetIndexBuffer(7, HiddenBearishDivBuffer, INDICATOR_CALCULATIONS); + + //--- Set accuracy + IndicatorSetInteger(INDICATOR_DIGITS, 2); + + //--- Set first bar from what index will be drawn + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, InpRSIPeriod); + + //--- Create RSI handle + rsiHandle = iRSI(NULL, 0, InpRSIPeriod, InpRSIPrice); + + if (rsiHandle == INVALID_HANDLE) + { + Print("Failed to create RSI handle"); + return (INIT_FAILED); + } + + //--- Set buffer names + string short_name = "RSI Divergence(" + string(InpRSIPeriod) + ")"; + IndicatorSetString(INDICATOR_SHORTNAME, short_name); + + //--- Set empty value + PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0); + PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0); + + //--- Initialize arrays as series + ArraySetAsSeries(RSIBuffer, true); + ArraySetAsSeries(SignalBuffer, true); + ArraySetAsSeries(HighBuffer, true); + ArraySetAsSeries(LowBuffer, true); + ArraySetAsSeries(BullishDivBuffer, true); + ArraySetAsSeries(BearishDivBuffer, true); + ArraySetAsSeries(HiddenBullishDivBuffer, true); + ArraySetAsSeries(HiddenBearishDivBuffer, true); + + return (INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| 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[]) +{ + //--- Check for data sufficiency + if (rates_total < InpRSIPeriod + InpLeftBars + InpRightBars) + return (0); + + //--- Get RSI values + if (CopyBuffer(rsiHandle, 0, 0, rates_total, RSIBuffer) <= 0) + { + Print("Failed to copy RSI buffer"); + return (0); + } + + //--- Calculate signal line (just for visualization) + for (int i = 0; i < rates_total; i++) + SignalBuffer[i] = 30 + (70 - 30) / 2; + + //--- Find divergences + FindDivergences(rates_total, prev_calculated, high, low, close, time); + + return (rates_total); +} + +//+------------------------------------------------------------------+ +//| Find divergences between price and RSI | +//+------------------------------------------------------------------+ +void FindDivergences(const int rates_total, + const int prev_calculated, + const double &high[], + const double &low[], + const double &close[], + const datetime &time[]) +{ + int start_bar = MathMax(InpRSIPeriod + InpLeftBars + InpRightBars, prev_calculated); + + for (int i = start_bar; i < rates_total && !IsStopped(); i++) + { + //--- Reset buffers + BullishDivBuffer[i] = 0; + BearishDivBuffer[i] = 0; + HiddenBullishDivBuffer[i] = 0; + HiddenBearishDivBuffer[i] = 0; + + //--- Check array boundaries + if (i - InpLeftBars < 0 || i + InpRightBars >= rates_total) + continue; + + //--- Find highest high and lowest low in left bars + int highest_high_bar = Highest(high, i - InpLeftBars, InpLeftBars + InpRightBars + 1); + int lowest_low_bar = Lowest(low, i - InpLeftBars, InpLeftBars + InpRightBars + 1); + + //--- Check for regular bullish divergence + if (ShowRegularBullish && lowest_low_bar >= 0) + { + int rsi_lowest_bar = LowestRSI(i - InpLeftBars, InpLeftBars + InpRightBars + 1); + + if (rsi_lowest_bar >= 0 && rsi_lowest_bar != lowest_low_bar && + low[i - lowest_low_bar] < low[i] && + RSIBuffer[i - rsi_lowest_bar] > RSIBuffer[i] && + MathAbs(RSIBuffer[i - rsi_lowest_bar] - RSIBuffer[i]) >= InpMinDivergence) + { + BullishDivBuffer[i] = RSIBuffer[i] - 5; + if (i < ArraySize(time) && i < ArraySize(low)) + ObjectCreate(0, "BullDiv" + IntegerToString(i), OBJ_ARROW_UP, 0, time[i], low[i] - 50 * _Point); + } + } + + //--- Check for regular bearish divergence + if (ShowRegularBearish && highest_high_bar >= 0) + { + int rsi_highest_bar = HighestRSI(i - InpLeftBars, InpLeftBars + InpRightBars + 1); + + if (rsi_highest_bar >= 0 && rsi_highest_bar != highest_high_bar && + high[i - highest_high_bar] > high[i] && + RSIBuffer[i - rsi_highest_bar] < RSIBuffer[i] && + MathAbs(RSIBuffer[i - rsi_highest_bar] - RSIBuffer[i]) >= InpMinDivergence) + { + BearishDivBuffer[i] = RSIBuffer[i] + 5; + if (i < ArraySize(time) && i < ArraySize(high)) + ObjectCreate(0, "BearDiv" + IntegerToString(i), OBJ_ARROW_DOWN, 0, time[i], high[i] + 50 * _Point); + } + } + + //--- Check for hidden bullish divergence + if (ShowHiddenBullish && lowest_low_bar >= 0) + { + int rsi_lowest_bar = LowestRSI(i - InpLeftBars, InpLeftBars + InpRightBars + 1); + + if (rsi_lowest_bar >= 0 && rsi_lowest_bar != lowest_low_bar && + low[i - lowest_low_bar] > low[i] && + RSIBuffer[i - rsi_lowest_bar] < RSIBuffer[i] && + MathAbs(RSIBuffer[i - rsi_lowest_bar] - RSIBuffer[i]) >= InpMinDivergence) + { + HiddenBullishDivBuffer[i] = RSIBuffer[i] - 8; + if (i < ArraySize(time) && i < ArraySize(low)) + ObjectCreate(0, "HidBullDiv" + IntegerToString(i), OBJ_ARROW_UP, 0, time[i], low[i] - 80 * _Point); + } + } + + //--- Check for hidden bearish divergence + if (ShowHiddenBearish && highest_high_bar >= 0) + { + int rsi_highest_bar = HighestRSI(i - InpLeftBars, InpLeftBars + InpRightBars + 1); + + if (rsi_highest_bar >= 0 && rsi_highest_bar != highest_high_bar && + high[i - highest_high_bar] < high[i] && + RSIBuffer[i - rsi_highest_bar] > RSIBuffer[i] && + MathAbs(RSIBuffer[i - rsi_highest_bar] - RSIBuffer[i]) >= InpMinDivergence) + { + HiddenBearishDivBuffer[i] = RSIBuffer[i] + 8; + if (i < ArraySize(time) && i < ArraySize(high)) + ObjectCreate(0, "HidBearDiv" + IntegerToString(i), OBJ_ARROW_DOWN, 0, time[i], high[i] + 80 * _Point); + } + } + } +} + +//+------------------------------------------------------------------+ +//| Find bar with highest price in range | +//+------------------------------------------------------------------+ +int Highest(const double &price[], int start_pos, int count) +{ + if (start_pos < 0 || count <= 0 || start_pos + count > ArraySize(price)) + return -1; + + int highest_pos = start_pos; + double highest_val = price[start_pos]; + + for (int i = start_pos + 1; i < start_pos + count; i++) + { + if (price[i] > highest_val) + { + highest_val = price[i]; + highest_pos = i; + } + } + + return highest_pos - start_pos; +} + +//+------------------------------------------------------------------+ +//| Find bar with lowest price in range | +//+------------------------------------------------------------------+ +int Lowest(const double &price[], int start_pos, int count) +{ + if (start_pos < 0 || count <= 0 || start_pos + count > ArraySize(price)) + return -1; + + int lowest_pos = start_pos; + double lowest_val = price[start_pos]; + + for (int i = start_pos + 1; i < start_pos + count; i++) + { + if (price[i] < lowest_val) + { + lowest_val = price[i]; + lowest_pos = i; + } + } + + return lowest_pos - start_pos; +} + +//+------------------------------------------------------------------+ +//| Find bar with highest RSI in range | +//+------------------------------------------------------------------+ +int HighestRSI(int start_pos, int count) +{ + if (start_pos < 0 || count <= 0 || start_pos + count > ArraySize(RSIBuffer)) + return -1; + + int highest_pos = start_pos; + double highest_val = RSIBuffer[start_pos]; + + for (int i = start_pos + 1; i < start_pos + count; i++) + { + if (RSIBuffer[i] > highest_val) + { + highest_val = RSIBuffer[i]; + highest_pos = i; + } + } + + return highest_pos - start_pos; +} + +//+------------------------------------------------------------------+ +//| Find bar with lowest RSI in range | +//+------------------------------------------------------------------+ +int LowestRSI(int start_pos, int count) +{ + if (start_pos < 0 || count <= 0 || start_pos + count > ArraySize(RSIBuffer)) + return -1; + + int lowest_pos = start_pos; + double lowest_val = RSIBuffer[start_pos]; + + for (int i = start_pos + 1; i < start_pos + count; i++) + { + if (RSIBuffer[i] < lowest_val) + { + lowest_val = RSIBuffer[i]; + lowest_pos = i; + } + } + + return lowest_pos - start_pos; +} \ No newline at end of file diff --git a/Documents/BKP/rsi.divergence.mq5 b/Documents/BKP/rsi.divergence.mq5 new file mode 100644 index 00000000..afbfd8e7 --- /dev/null +++ b/Documents/BKP/rsi.divergence.mq5 @@ -0,0 +1,198 @@ +//+------------------------------------------------------------------+ +//| RSIDivergence.mq5| +//| Custom RSI Divergence Detection Indicator | +//+------------------------------------------------------------------+ +#property strict +#property indicator_chart_window +#property indicator_buffers 2 +#property indicator_plots 0 + +//--- Input parameters +input int RSI_Period = 14; // RSI Period +input double Deviation = 0.0001; // Minimum price move to consider a swing +input int MaxBarsBack = 300; // Number of bars to analyze + +//--- Global handles +double rsiBuffer[]; +int rsiHandle; + +//--- For divergence detection +struct SwingPoint +{ + int index; + double price; + double rsi; +}; + +SwingPoint priceSwings[]; +SwingPoint rsiSwings[]; + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + SetIndexBuffer(0, rsiBuffer, INDICATOR_DATA); + rsiHandle = iRSI(_Symbol, _Period, RSI_Period, PRICE_CLOSE); + if (rsiHandle == INVALID_HANDLE) + { + Print("Could not create RSI handle"); + return (INIT_FAILED); + } + return (INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Main 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[]) +{ + //--- Get RSI values + ArraySetAsSeries(rsiBuffer, true); + CopyBuffer(rsiHandle, 0, 0, MaxBarsBack, rsiBuffer); + + //--- Detect swings + DetectSwingPoints(close, priceSwings); + DetectSwingPoints(rsiBuffer, rsiSwings); + + //--- Find and draw divergences + FindAndDrawDivergences(time, close); + + return (rates_total); +} + +//+------------------------------------------------------------------+ +//| Detect swing highs/lows | +//+------------------------------------------------------------------+ +void DetectSwingPoints(const double &values[], SwingPoint &swings[]) +{ + ArrayResize(swings, 0); // Clear previous swings + int count = 0; + + int size = ArraySize(values); + if (size < 3) + return; // Not enough data + + // Pre-allocate a safe amount of space + ArrayResize(swings, size / 2); // Max possible swings ~50% of total bars + + for (int i = 2; i < size - 2; i++) + { + // Bounds check + if (i - 1 < 0 || i + 1 >= size) + continue; + + // Check for swing high + if (values[i] > values[i - 1] && values[i] > values[i + 1]) + { + // Ensure we have space in the swings array + if (count >= ArraySize(swings)) + ArrayResize(swings, ArraySize(swings) + 10); + + swings[count].index = i; + swings[count].price = values[i]; + count++; + } + // Check for swing low + else if (values[i] < values[i - 1] && values[i] < values[i + 1]) + { + // Ensure we have space in the swings array + if (count >= ArraySize(swings)) + ArrayResize(swings, ArraySize(swings) + 10); + + swings[count].index = i; + swings[count].price = values[i]; + count++; + } + } + + // Final resize to actual number of swings found + ArrayResize(swings, count); +} + +//+------------------------------------------------------------------+ +//| Find and draw divergence | +//+------------------------------------------------------------------+ +void FindAndDrawDivergences(const datetime &time[], const double &close[]) +{ + static int lastAlertBar = 0; + int limit = MathMin(MaxBarsBack - 2, Bars(_Symbol, _Period)); + + for (int i = 0; i < ArraySize(priceSwings) - 1; i++) + { + for (int j = 0; j < ArraySize(rsiSwings) - 1; j++) + { + int p1 = priceSwings[i].index; + int p2 = priceSwings[i + 1].index; + int r1 = rsiSwings[j].index; + int r2 = rsiSwings[j + 1].index; + + if (MathAbs(p1 - r1) < 3 && MathAbs(p2 - r2) < 3) + { + double price1 = close[p1]; + double price2 = close[p2]; + double rsi1 = rsiBuffer[r1]; + double rsi2 = rsiBuffer[r2]; + + // Bullish Divergence + if (price2 < price1 && rsi2 > rsi1) + { + string name; + StringConcatenate(name, "BullishDiv", IntegerToString(p2)); + DrawArrow(name, time[p2], close[p2], clrLime); + // DrawLine("BullishLineP" + IntegerToString(p2), time[p2], close[p2], time[p1], close[p1], clrLime); + // DrawLine("BullishLineR" + IntegerToString(p2), time[p2], rsi2, time[p1], rsi1, clrLime); + } + + // Bearish Divergence + if (price2 > price1 && rsi2 < rsi1) + { + string name; + StringConcatenate(name, "BearishDiv", IntegerToString(p2)); + DrawArrow(name, time[p2], close[p2], clrRed); + // DrawLine("BearishLineP" + IntegerToString(p2), time[p2], close[p2], time[p1], close[p1], clrRed); + // DrawLine("BearishLineR" + IntegerToString(p2), time[p2], rsi2, time[p1], rsi1, clrRed); + } + } + } + } +} + +//+------------------------------------------------------------------+ +//| Draw arrow on chart | +//+------------------------------------------------------------------+ +void DrawArrow(string name, datetime time, double price, color col) +{ + ObjectCreate(0, name, OBJ_ARROW, 0, time, price); + ObjectSetInteger(0, name, OBJPROP_ARROWCODE, 233); // Up arrow + ObjectSetInteger(0, name, OBJPROP_COLOR, col); + ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); +} + +//+------------------------------------------------------------------+ +//| Draw line | +//+------------------------------------------------------------------+ +void DrawLine(string name, datetime t1, double p1, datetime t2, double p2, color col) +{ + // Delete existing object if any + ObjectDelete(0, name); + + // Create trendline (use 1 for OBJ_TRENDLINE if undefined) + ObjectCreate(0, name, 1, 0, t1, p1, t2, p2); + + ObjectSetInteger(0, name, OBJPROP_COLOR, col); + ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASHDOT); + ObjectSetInteger(0, name, OBJPROP_WIDTH, 1); + ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); +} + +// \ No newline at end of file diff --git a/XCAEA/Helpers/xcaea.helper.mq5 b/XCAEA/Helpers/xcaea.helper.mq5 index b1845787..06dd2f45 100644 --- a/XCAEA/Helpers/xcaea.helper.mq5 +++ b/XCAEA/Helpers/xcaea.helper.mq5 @@ -4140,6 +4140,539 @@ class XCXCAEAHelper : XCBase return result; } + // + bool IsBlockBasedTriggerBar( + XBoxZone &ob, + XOHCL &swingBar, + XOHCL &breakerBar, + XOHCL &outSideBar, + ENUM_X_DIRECTION &dir, + int barIndex = 0, + int loopback = 40, + int swingLength = 3 // + ) + { + // + bool result = false; + + // + // Normalize Args ... + ob.Clean(); + swingBar.Clean(); + breakerBar.Clean(); + outSideBar.Clean(); + dir = X_DIRECTION_NONE; + barIndex = NormalizeInt(barIndex, 0); + loopback = NormalizeInt(loopback, 30); + + // + // Initializing Current Bar ... + XOHCL bar; + result = bar.Init( + GetSymbol(), + GetPeriod(), + barIndex // + ); + if (!result) + { + // + ob.Clean(); + bar.Clean(); + swingBar.Clean(); + breakerBar.Clean(); + outSideBar.Clean(); + dir = X_DIRECTION_NONE; + + // + return result; + } + + // + // Detecting Newest Block ... + XOHCL iBar; + bool has = false; + for (int i = barIndex; i < barIndex + loopback; i++) + { + // + // Initialize iBar ... + has = iBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!has) + { + // + iBar.Clean(); + + // + continue; + } + + // + // Check to Find OB ... + has = barAnalyser.IsOrderBlock( + iBar, + ob, + false, + true // + ); + if (has) + { + // + iBar.Clean(); + + // + break; + } + + // + ob.Clean(); + iBar.Clean(); + } + + // + // Ensure We Have a Block ... + result = ob.IsValid(); + if (!result) + { + // + ob.Clean(); + bar.Clean(); + iBar.Clean(); + swingBar.Clean(); + breakerBar.Clean(); + outSideBar.Clean(); + dir = X_DIRECTION_NONE; + + // + return result; + } + + // + // Set Direction ... + dir = ob.dir; + int toIDX = ob.ToIndex(); + int fromIDX = ob.FromIndex(); + bool isBullish = IsBullish(dir); + bool isBearish = IsBearish(dir); + + // + // Ensure a Swing Breaked in Block Formation ... + // for Bullish we have to Breake a Swing High ... + // for Bearish we have to Detect a Swing Low ... + // this Breaktion must appear after Block ... + ENUM_X_DIRECTION swingDir = X_DIRECTION_NONE; + for (int i = barIndex + loopback; i > barIndex; i--) + { + // + // Initialize iBar ... + has = iBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!has) + { + // + iBar.Clean(); + swingBar.Clean(); + swingDir = X_DIRECTION_NONE; + + // + continue; + } + + // + // Detecting Swing ... + has = barAnalyser.IsSwing( + iBar, + swingDir // + ); + if (!has) + { + // + iBar.Clean(); + swingBar.Clean(); + swingDir = X_DIRECTION_NONE; + + // + continue; + } + + // + // Validate Founded Swing ... + swingBar = iBar; + + // + bool isValidSwingLow = + isBearish && + IsBullish(swingDir); + + // + bool isValidSwingHigh = + isBullish && + IsBearish(swingDir); + + // + has = + isValidSwingLow || + isValidSwingHigh; + if (!has) + { + // + iBar.Clean(); + swingBar.Clean(); + swingDir = X_DIRECTION_NONE; + + // + continue; + } + + // + // Validating Swing Place ... + + // + bool isSwingLowHasValidPlace = + isBearish && + swingBar.low < ob.lower; + + // + bool isSwingHighHasValidPlace = + isBullish && + swingBar.high > ob.upper; + + // + has = + isSwingLowHasValidPlace || + isSwingHighHasValidPlace; + if (has) + { + // + iBar.Clean(); + + // + break; + } + + // + iBar.Clean(); + swingBar.Clean(); + swingDir = X_DIRECTION_NONE; + } + + // + result = + swingBar.IsValid() && + HasDirection(swingDir); + if (!result) + { + // + ob.Clean(); + bar.Clean(); + iBar.Clean(); + swingBar.Clean(); + breakerBar.Clean(); + outSideBar.Clean(); + dir = X_DIRECTION_NONE; + + // + return result; + } + + // + // now We have Proper Swing ... + // Validate Swing Breaktion ... + double breakPrice = + IsBullish(swingDir) + ? swingBar.low + : swingBar.high; + ENUM_X_DIRECTION breakedDir = + IsBullish(swingDir) + ? X_DIRECTION_BEARISH + : X_DIRECTION_BULLISH; + for (int i = swingBar.Index(); i > barIndex; i--) + { + // + // Initialize iBar ... + has = iBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!has) + { + // + iBar.Clean(); + breakerBar.Clean(); + + // + continue; + } + + // + // Check for Breakes ... + has = iBar.IsBreaked( + breakPrice, + breakedDir // + ); + if (!has) + { + // + iBar.Clean(); + breakerBar.Clean(); + + // + continue; + } + + // + // Validate Swing Break must be happens + // after Block Formation ... + has = iBar.time > ob.to; + if (has) + { + // + breakerBar = iBar; + + // + iBar.Clean(); + + // + break; + } + + // + iBar.Clean(); + breakerBar.Clean(); + } + + // + result = breakerBar.IsValid(); + if (!result) + { + // + ob.Clean(); + bar.Clean(); + iBar.Clean(); + swingBar.Clean(); + breakerBar.Clean(); + outSideBar.Clean(); + dir = X_DIRECTION_NONE; + + // + return result; + } + + // + // now we have a Valid Bloc ... + // which Breakes a Valid Swing ... + + // + // find at least on out side of Block Bar ... + for (int i = toIDX; i > barIndex; i--) + { + // + // Initialize iBar ... + has = iBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!has) + { + // + iBar.Clean(); + outSideBar.Clean(); + + // + continue; + } + + // + bool isBullishOutside = + isBullish && + iBar.high > ob.upper; + + // + bool isBearishOutside = + isBearish && + iBar.low < ob.lower; + + // + has = + isBullishOutside || + isBearishOutside; + if (has) + { + // + outSideBar = iBar; + + // + iBar.Clean(); + + // + break; + } + + // + iBar.Clean(); + outSideBar.Clean(); + } + + // + result = outSideBar.IsValid(); + if (!result) + { + // + ob.Clean(); + bar.Clean(); + iBar.Clean(); + swingBar.Clean(); + breakerBar.Clean(); + outSideBar.Clean(); + dir = X_DIRECTION_NONE; + + // + return result; + } + + // + // we Are Looking for Bar inside Block ... + + // + bool isBullishInside = + isBullish && + bar.low < ob.upper && + bar.low > ob.lower; + + // + bool isBearishInside = + isBearish && + bar.high > ob.lower && + bar.high < ob.upper; + + // + result = isBullishInside || + isBearishInside; + if (!result) + { + // + ob.Clean(); + bar.Clean(); + iBar.Clean(); + swingBar.Clean(); + breakerBar.Clean(); + outSideBar.Clean(); + dir = X_DIRECTION_NONE; + + // + return result; + } + + // + // Since we Ensure have an Inside Block Bar here ... + // must to detect a Bar Pattern verification for Triggering ... + + // + // Check Bar Pattern for Position ... + ENUM_X_DIRECTION patternDir; + + // + // Hammer ... + bool isHammer = barAnalyser.IsHammer( + bar, + patternDir // + ); + bool isBullishHammer = + isHammer && + IsBullish(patternDir); + bool isBearishHammer = + isHammer && + IsBearish(patternDir); + + // + // Reject ... + bool isReject = barAnalyser.IsRejected( + bar, + patternDir, + false, // Force Bar type ... + true // Force Fibo Pressure ... + ); + bool isBullishReject = + isReject && + IsBullish(patternDir); + bool isBearishReject = + isReject && + IsBearish(patternDir); + + // + // Engulf ... + bool isEngulf = barAnalyser.IsEngulfed( + bar, + patternDir // + ); + bool isBullishEngulf = + isEngulf && + IsBullish(patternDir); + bool isBearishEngulf = + isEngulf && + IsBearish(patternDir); + + // + bool isBarBullishPowered = + isBullishHammer || + isBullishReject || + isBullishEngulf; + + // + bool isBarBearishPowered = + isBearishHammer || + isBearishReject || + isBearishEngulf; + + // + // Summarizing Result ... + + // + bool isBullishTriggered = + isBullish && + isBullishInside && + isBarBullishPowered; + + // + bool isBearishTriggered = + isBearish && + isBearishInside && + isBarBearishPowered; + + // + result = isBullishTriggered || + isBearishTriggered; + + // + if (!result) + { + // + ob.Clean(); + bar.Clean(); + iBar.Clean(); + swingBar.Clean(); + breakerBar.Clean(); + outSideBar.Clean(); + dir = X_DIRECTION_NONE; + + // + return result; + } + + // + bar.Clean(); + + // + return result; + } + // // Protected ... protected: diff --git a/XCAEA/Libraries/xcaea.signaller.lib.mq5 b/XCAEA/Libraries/xcaea.signaller.lib.mq5 index 4c15ce5b..9c21ddaf 100644 --- a/XCAEA/Libraries/xcaea.signaller.lib.mq5 +++ b/XCAEA/Libraries/xcaea.signaller.lib.mq5 @@ -962,7 +962,7 @@ bool DetectDecisionZone( // // Custom Senarios ... - + // bool isCond1Bullish = // @@ -1627,6 +1627,126 @@ bool CanTriggerCond2( return result; } +// +// Detect Trigger Based On Decision Zone's +// Block Based Triggering ... +bool CanTriggerCond3( + XCXCAEAHelper *helper, + XBoxZone &box, + ENUM_X_DIRECTION &dir, + double &sl, + double &tp, + int barIndex = 0, + int loopback = 10 // +) +{ + // + bool result = false; + + // + // Normalize Args ... + sl = 0; + tp = 0; + dir = X_DIRECTION_NONE; + loopback = NormalizeInt(loopback, 5); + barIndex = NormalizeInt(barIndex, 0); + + // + // Validate Decision Box ... + result = box.IsValid() && + helper != NULL; + if (!result) + { + return result; + } + + // + // Detect At Least one Outside Bar ... + // TODO: Complete this ... + + // + // Add Support for a Breaked Swing as Liquidity ... + // for Improve Validations ... + // TODO: Complete this ... + + // + // Detect Block Based Trigger ... + XBoxZone ob; + XOHCL swing; + XOHCL breaker; + XOHCL outSide; + ENUM_X_DIRECTION passedDir; + bool isPassed = helper.IsBlockBasedTriggerBar( + ob, + swing, + breaker, + outSide, + passedDir, + barIndex + 1, // Bar Index ... + 30, // Loopback ... + 3 // Swing Length ... + ); + bool isBullishPassed = + isPassed && + ob.IsBullish() && + box.IsBullish() && + ob.upper < box.upper && + ob.lower > box.lower; + bool isBearishPassed = + isPassed && + ob.IsBearish() && + box.IsBearish() && + ob.upper < box.upper && + ob.lower > box.lower; + + // + // Summarizing ... + + // + bool canTriggerLong = + isBullishPassed; + + // + bool canTriggerShort = + isBearishPassed; + + // + result = canTriggerLong || + canTriggerShort; + if (result) + { + // + dir = canTriggerLong + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Preparing TP and SL ... + + // + sl = canTriggerLong + ? ob.lower + : ob.upper; + + // + // Since Here TP Must Calculated + // Using R2R we Ignore Target ... + tp = 0; + } + + // + // Cleanup Resources ... + + // + ob.Clean(); + swing.Clean(); + breaker.Clean(); + outSide.Clean(); + + // + return result; +} + // // Helper Functions ... diff --git a/XCAEA/Signals/xcaea.signaller.class.mq5 b/XCAEA/Signals/xcaea.signaller.class.mq5 index 833d3c78..9e0c14ad 100644 --- a/XCAEA/Signals/xcaea.signaller.class.mq5 +++ b/XCAEA/Signals/xcaea.signaller.class.mq5 @@ -591,6 +591,7 @@ class XCXCAEASignaller : XCBase int ppIndex = pIndex + 1; // + bool has = false; int loopback = 10; // @@ -618,16 +619,87 @@ class XCXCAEASignaller : XCBase double tp = 0; ENUM_X_DIRECTION triggerDir = X_DIRECTION_NONE; + // + // Detect All Inside Directional FVGs ... + XBoxZone fvgs[]; + int toIDX = conditions.decisionZone.ToIndex(); + int fromIDX = conditions.decisionZone.FromIndex(); + for (int i = fromIDX; i > toIDX; i--) + { + // + XOHCL iBar; + XBoxZone iFVG; + + // + // Initialize iBar ... + has = iBar.Init( + conditions.symbol, + conditions.period, + i // + ); + if (!has) + { + // + iFVG.Clean(); + iBar.Clean(); + + // + continue; + } + + // + // Check iBar has FVG ... + has = helper + .barAnalyser + .IsFVG( + iBar, + iFVG, + true // + ); + if (!has) + { + // + iBar.Clean(); + iFVG.Clean(); + + // + continue; + } + + // + // Check FVG Direction and Placement ... + has = + iFVG.dir == conditions.decisionZone.dir && + iFVG.upper < conditions.decisionZone.upper && + iFVG.lower > conditions.decisionZone.lower; + if (has) + { + // + iFVG.to = cTime; + AddRef( + iFVG, + fvgs // + ); + } + + // + iBar.Clean(); + iFVG.Clean(); + } + bool hasFVGs = HasChild(fvgs); + int fvgsCount = ArraySize(fvgs); + // // Checking Trigger Cond 0 ... - bool canTriggerCond0 = CanTriggerCond0( - helper, - conditions.decisionZone, - triggerDir, - sl, - tp, - barIndex // - ); + bool canTriggerCond0 = false; + // CanTriggerCond0( + // helper, + // conditions.decisionZone, + // triggerDir, + // sl, + // tp, + // barIndex // + // ); // // Checking Trigger Cond 1 ... @@ -653,13 +725,25 @@ class XCXCAEASignaller : XCBase // barIndex // // ); + // + // Checking Trigger Cond 3 ... + bool canTriggerCond3 = CanTriggerCond3( + helper, + conditions.decisionZone, + triggerDir, + sl, + tp, + barIndex // + ); + // // Update Signal Box To ... conditions.decisionZone.to = cTime; // + // Draw Decision Zone ... XCBoxObject *iObj; - bool has = helper.poiDrawer.DrawBox( + has = helper.poiDrawer.DrawBox( conditions.decisionZone, iObj // ); @@ -669,12 +753,37 @@ class XCXCAEASignaller : XCBase } ZeroMemory(iObj); + // + // Draw FVGs ... + if (hasFVGs) + { + // + for (int i = 0; i < fvgsCount; i++) + { + // + fvgs[i].to = cTime; + + // + XCBoxObject *iObj; + has = helper.poiDrawer.DrawBox( + fvgs[i], + iObj // + ); + if (has) + { + mObjects.Add(iObj); + } + ZeroMemory(iObj); + } + } + // // Summarizing Result ... result = canTriggerCond0 || canTriggerCond1 || - canTriggerCond2; + canTriggerCond2 || + canTriggerCond3; // isBullish = result &&