last ...
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
//
|
||||
Reference in New Issue
Block a user