Files
xMQL5/BKPS/14040311/Documents/BKP/rsi.divergence.mq5
T
2025-06-01 14:02:48 +03:30

198 lines
6.9 KiB
Plaintext

//+------------------------------------------------------------------+
//| 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);
}
//