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