317 lines
12 KiB
Plaintext
317 lines
12 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| 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;
|
|
} |