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