last ...
This commit is contained in:
@@ -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();
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
@@ -4140,6 +4140,539 @@ class XCXCAEAHelper : XCBase
|
|||||||
return result;
|
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 ...
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -1627,6 +1627,126 @@ bool CanTriggerCond2(
|
|||||||
return result;
|
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 ...
|
// Helper Functions ...
|
||||||
|
|
||||||
|
|||||||
@@ -591,6 +591,7 @@ class XCXCAEASignaller : XCBase
|
|||||||
int ppIndex = pIndex + 1;
|
int ppIndex = pIndex + 1;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
bool has = false;
|
||||||
int loopback = 10;
|
int loopback = 10;
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -619,15 +620,86 @@ class XCXCAEASignaller : XCBase
|
|||||||
ENUM_X_DIRECTION triggerDir = X_DIRECTION_NONE;
|
ENUM_X_DIRECTION triggerDir = X_DIRECTION_NONE;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Checking Trigger Cond 0 ...
|
// Detect All Inside Directional FVGs ...
|
||||||
bool canTriggerCond0 = CanTriggerCond0(
|
XBoxZone fvgs[];
|
||||||
helper,
|
int toIDX = conditions.decisionZone.ToIndex();
|
||||||
conditions.decisionZone,
|
int fromIDX = conditions.decisionZone.FromIndex();
|
||||||
triggerDir,
|
for (int i = fromIDX; i > toIDX; i--)
|
||||||
sl,
|
{
|
||||||
tp,
|
//
|
||||||
barIndex //
|
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 = false;
|
||||||
|
// CanTriggerCond0(
|
||||||
|
// helper,
|
||||||
|
// conditions.decisionZone,
|
||||||
|
// triggerDir,
|
||||||
|
// sl,
|
||||||
|
// tp,
|
||||||
|
// barIndex //
|
||||||
|
// );
|
||||||
|
|
||||||
//
|
//
|
||||||
// Checking Trigger Cond 1 ...
|
// Checking Trigger Cond 1 ...
|
||||||
@@ -653,13 +725,25 @@ class XCXCAEASignaller : XCBase
|
|||||||
// barIndex //
|
// barIndex //
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
//
|
||||||
|
// Checking Trigger Cond 3 ...
|
||||||
|
bool canTriggerCond3 = CanTriggerCond3(
|
||||||
|
helper,
|
||||||
|
conditions.decisionZone,
|
||||||
|
triggerDir,
|
||||||
|
sl,
|
||||||
|
tp,
|
||||||
|
barIndex //
|
||||||
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Update Signal Box To ...
|
// Update Signal Box To ...
|
||||||
conditions.decisionZone.to = cTime;
|
conditions.decisionZone.to = cTime;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
// Draw Decision Zone ...
|
||||||
XCBoxObject *iObj;
|
XCBoxObject *iObj;
|
||||||
bool has = helper.poiDrawer.DrawBox(
|
has = helper.poiDrawer.DrawBox(
|
||||||
conditions.decisionZone,
|
conditions.decisionZone,
|
||||||
iObj //
|
iObj //
|
||||||
);
|
);
|
||||||
@@ -669,12 +753,37 @@ class XCXCAEASignaller : XCBase
|
|||||||
}
|
}
|
||||||
ZeroMemory(iObj);
|
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 ...
|
// Summarizing Result ...
|
||||||
result =
|
result =
|
||||||
canTriggerCond0 ||
|
canTriggerCond0 ||
|
||||||
canTriggerCond1 ||
|
canTriggerCond1 ||
|
||||||
canTriggerCond2;
|
canTriggerCond2 ||
|
||||||
|
canTriggerCond3;
|
||||||
|
|
||||||
//
|
//
|
||||||
isBullish = result &&
|
isBullish = result &&
|
||||||
|
|||||||
Reference in New Issue
Block a user