329 lines
12 KiB
MQL5
329 lines
12 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| QQE_Cross_v6.0_SubWindow.mq5 |
|
||
|
//| QQE Visualization SubWindow |
|
||
|
//| by JustUncleL |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#property copyright "Copyright 2024, Based on JustUncleL's work"
|
||
|
#property link "https://www.mql5.com"
|
||
|
#property version "6.00"
|
||
|
#property indicator_separate_window
|
||
|
#property indicator_minimum 0
|
||
|
#property indicator_maximum 100
|
||
|
#property indicator_buffers 5
|
||
|
#property indicator_plots 3
|
||
|
#property indicator_level1 40
|
||
|
#property indicator_level2 50
|
||
|
#property indicator_level3 60
|
||
|
#property indicator_levelcolor clrDarkSlateGray
|
||
|
#property indicator_levelstyle STYLE_DOT
|
||
|
#property indicator_height 150
|
||
|
|
||
|
// Input parameters
|
||
|
input int RSILen = 14; // RSI Length
|
||
|
input int SF = 8; // RSI Smoothing Factor
|
||
|
input double QQEfactor = 5.0; // Fast QQE Factor
|
||
|
input int threshhold = 10; // RSI Threshold
|
||
|
input bool showHistogram = true; // Show QQE Histogram
|
||
|
input color colorBullish = clrLime; // Bullish Color
|
||
|
input color colorNeutral = clrGray; // Neutral Color
|
||
|
input color colorBearish = clrRed; // Bearish Color
|
||
|
|
||
|
// Indicator buffers
|
||
|
double RSIndexBuffer[];
|
||
|
double FastAtrRsiTLBuffer[];
|
||
|
double HistogramBuffer[];
|
||
|
double HistogramColors[];
|
||
|
double RSIBuffer[];
|
||
|
|
||
|
// Internal arrays
|
||
|
double AtrRsi[];
|
||
|
double MaAtrRsi[];
|
||
|
double DeltaFastAtrRsi[];
|
||
|
double longband[];
|
||
|
double shortband[];
|
||
|
int trend[];
|
||
|
|
||
|
// Global variables
|
||
|
int rsi_handle;
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Custom indicator initialization function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int OnInit()
|
||
|
{
|
||
|
// Set indicator name
|
||
|
IndicatorSetString(INDICATOR_SHORTNAME, "QQE(" + IntegerToString(RSILen) + "," + IntegerToString(SF) + ")");
|
||
|
|
||
|
// Set buffers
|
||
|
SetIndexBuffer(0, RSIndexBuffer, INDICATOR_DATA);
|
||
|
SetIndexBuffer(1, FastAtrRsiTLBuffer, INDICATOR_DATA);
|
||
|
SetIndexBuffer(2, HistogramBuffer, INDICATOR_DATA);
|
||
|
SetIndexBuffer(3, HistogramColors, INDICATOR_COLOR_INDEX);
|
||
|
SetIndexBuffer(4, RSIBuffer, INDICATOR_CALCULATIONS);
|
||
|
|
||
|
// Configure RSI Line
|
||
|
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
|
||
|
PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrYellow);
|
||
|
PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 2);
|
||
|
PlotIndexSetString(0, PLOT_LABEL, "QQE RSI");
|
||
|
|
||
|
// Configure Fast ATR Line
|
||
|
PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE);
|
||
|
PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrAqua);
|
||
|
PlotIndexSetInteger(1, PLOT_LINE_STYLE, STYLE_DASH);
|
||
|
PlotIndexSetString(1, PLOT_LABEL, "QQE Line");
|
||
|
|
||
|
// Configure Histogram
|
||
|
PlotIndexSetInteger(2, PLOT_DRAW_TYPE, showHistogram ? DRAW_COLOR_HISTOGRAM : DRAW_NONE);
|
||
|
PlotIndexSetInteger(2, PLOT_LINE_WIDTH, 2);
|
||
|
PlotIndexSetString(2, PLOT_LABEL, "QQE Histogram");
|
||
|
PlotIndexSetInteger(2, PLOT_COLOR_INDEXES, 3);
|
||
|
PlotIndexSetInteger(2, PLOT_LINE_COLOR, 0, colorBullish);
|
||
|
PlotIndexSetInteger(2, PLOT_LINE_COLOR, 1, colorNeutral);
|
||
|
PlotIndexSetInteger(2, PLOT_LINE_COLOR, 2, colorBearish);
|
||
|
|
||
|
// Set arrays as series
|
||
|
ArraySetAsSeries(RSIndexBuffer, true);
|
||
|
ArraySetAsSeries(FastAtrRsiTLBuffer, true);
|
||
|
ArraySetAsSeries(HistogramBuffer, true);
|
||
|
ArraySetAsSeries(HistogramColors, true);
|
||
|
ArraySetAsSeries(RSIBuffer, true);
|
||
|
|
||
|
// Create RSI handle
|
||
|
rsi_handle = iRSI(NULL, 0, RSILen, PRICE_CLOSE);
|
||
|
if(rsi_handle == INVALID_HANDLE)
|
||
|
{
|
||
|
Print("Failed to create RSI handle");
|
||
|
return(INIT_FAILED);
|
||
|
}
|
||
|
|
||
|
// Resize arrays
|
||
|
int bars = Bars(_Symbol, _Period);
|
||
|
ArrayResize(AtrRsi, bars);
|
||
|
ArrayResize(MaAtrRsi, bars);
|
||
|
ArrayResize(DeltaFastAtrRsi, bars);
|
||
|
ArrayResize(longband, bars);
|
||
|
ArrayResize(shortband, bars);
|
||
|
ArrayResize(trend, bars);
|
||
|
|
||
|
return(INIT_SUCCEEDED);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Custom indicator deinitialization function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnDeinit(const int reason)
|
||
|
{
|
||
|
IndicatorRelease(rsi_handle);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Calculate EMA |
|
||
|
//+------------------------------------------------------------------+
|
||
|
double CalculateEMA(const double &price[], int period, int shift, double prev_ema)
|
||
|
{
|
||
|
if(shift >= ArraySize(price) - 1) return price[shift];
|
||
|
|
||
|
double alpha = 2.0 / (period + 1);
|
||
|
if(prev_ema == 0)
|
||
|
{
|
||
|
// Calculate SMA for first value
|
||
|
double sum = 0;
|
||
|
for(int i = 0; i < period && shift + i < ArraySize(price); i++)
|
||
|
sum += price[shift + i];
|
||
|
return sum / period;
|
||
|
}
|
||
|
|
||
|
return alpha * price[shift] + (1 - alpha) * prev_ema;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| 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[])
|
||
|
{
|
||
|
if(rates_total < RSILen + SF + 10) return(0);
|
||
|
|
||
|
// Copy RSI data
|
||
|
if(CopyBuffer(rsi_handle, 0, 0, rates_total, RSIBuffer) <= 0) return(0);
|
||
|
|
||
|
int limit = rates_total - prev_calculated;
|
||
|
if(prev_calculated > 0) limit++;
|
||
|
|
||
|
// Calculate QQE
|
||
|
int Wilders_Period = RSILen * 2 - 1;
|
||
|
|
||
|
// First pass: Calculate RSIndex
|
||
|
for(int i = rates_total - 1; i >= 0; i--)
|
||
|
{
|
||
|
if(i == rates_total - 1)
|
||
|
RSIndexBuffer[i] = RSIBuffer[i];
|
||
|
else
|
||
|
RSIndexBuffer[i] = CalculateEMA(RSIBuffer, SF, i, RSIndexBuffer[i+1]);
|
||
|
|
||
|
// Calculate AtrRsi
|
||
|
if(i < rates_total - 1)
|
||
|
AtrRsi[i] = MathAbs(RSIndexBuffer[i+1] - RSIndexBuffer[i]);
|
||
|
else
|
||
|
AtrRsi[i] = 0;
|
||
|
}
|
||
|
|
||
|
// Second pass: Calculate MaAtrRsi and DeltaFastAtrRsi
|
||
|
for(int i = rates_total - 1; i >= 0; i--)
|
||
|
{
|
||
|
if(i == rates_total - 1)
|
||
|
{
|
||
|
MaAtrRsi[i] = AtrRsi[i];
|
||
|
DeltaFastAtrRsi[i] = AtrRsi[i] * QQEfactor;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MaAtrRsi[i] = CalculateEMA(AtrRsi, Wilders_Period, i, MaAtrRsi[i+1]);
|
||
|
double temp = CalculateEMA(MaAtrRsi, Wilders_Period, i,
|
||
|
(i < rates_total - 2 ? DeltaFastAtrRsi[i+1] / QQEfactor : MaAtrRsi[i]));
|
||
|
DeltaFastAtrRsi[i] = temp * QQEfactor;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Third pass: Calculate bands and trend
|
||
|
for(int i = rates_total - 1; i >= 0; i--)
|
||
|
{
|
||
|
double newshortband = RSIndexBuffer[i] + DeltaFastAtrRsi[i];
|
||
|
double newlongband = RSIndexBuffer[i] - DeltaFastAtrRsi[i];
|
||
|
|
||
|
if(i == rates_total - 1)
|
||
|
{
|
||
|
longband[i] = newlongband;
|
||
|
shortband[i] = newshortband;
|
||
|
trend[i] = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Longband calculation
|
||
|
if(RSIndexBuffer[i+1] > longband[i+1] && RSIndexBuffer[i] > longband[i+1])
|
||
|
longband[i] = MathMax(longband[i+1], newlongband);
|
||
|
else
|
||
|
longband[i] = newlongband;
|
||
|
|
||
|
// Shortband calculation
|
||
|
if(RSIndexBuffer[i+1] < shortband[i+1] && RSIndexBuffer[i] < shortband[i+1])
|
||
|
shortband[i] = MathMin(shortband[i+1], newshortband);
|
||
|
else
|
||
|
shortband[i] = newshortband;
|
||
|
|
||
|
// Trend calculation
|
||
|
if(RSIndexBuffer[i] > shortband[i+1])
|
||
|
trend[i] = 1;
|
||
|
else if(RSIndexBuffer[i] < longband[i+1])
|
||
|
trend[i] = -1;
|
||
|
else
|
||
|
trend[i] = trend[i+1];
|
||
|
}
|
||
|
|
||
|
// Set Fast ATR line
|
||
|
FastAtrRsiTLBuffer[i] = (trend[i] == 1) ? longband[i] : shortband[i];
|
||
|
|
||
|
// Set Histogram
|
||
|
HistogramBuffer[i] = RSIndexBuffer[i];
|
||
|
|
||
|
// Color the histogram based on threshold levels
|
||
|
if(RSIndexBuffer[i] > 50 + threshhold)
|
||
|
HistogramColors[i] = 0; // Bullish
|
||
|
else if(RSIndexBuffer[i] < 50 - threshhold)
|
||
|
HistogramColors[i] = 2; // Bearish
|
||
|
else
|
||
|
HistogramColors[i] = 1; // Neutral
|
||
|
}
|
||
|
|
||
|
return(rates_total);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Get QQE values for external use |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool GetQQEValues(int shift, double &rsi_value, double &qqe_line, int &qqe_trend)
|
||
|
{
|
||
|
if(shift < 0 || shift >= ArraySize(RSIndexBuffer))
|
||
|
return false;
|
||
|
|
||
|
rsi_value = RSIndexBuffer[shift];
|
||
|
qqe_line = FastAtrRsiTLBuffer[shift];
|
||
|
qqe_trend = trend[shift];
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Check for QQE cross signals |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int CheckQQESignal(int shift)
|
||
|
{
|
||
|
if(shift < 1 || shift >= ArraySize(RSIndexBuffer))
|
||
|
return 0;
|
||
|
|
||
|
// Check for bullish cross
|
||
|
if(RSIndexBuffer[shift] > FastAtrRsiTLBuffer[shift] &&
|
||
|
RSIndexBuffer[shift+1] <= FastAtrRsiTLBuffer[shift+1])
|
||
|
return 1;
|
||
|
|
||
|
// Check for bearish cross
|
||
|
if(RSIndexBuffer[shift] < FastAtrRsiTLBuffer[shift] &&
|
||
|
RSIndexBuffer[shift+1] >= FastAtrRsiTLBuffer[shift+1])
|
||
|
return -1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Check for threshold crosses |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int CheckThresholdCross(int shift)
|
||
|
{
|
||
|
if(shift < 1 || shift >= ArraySize(RSIndexBuffer))
|
||
|
return 0;
|
||
|
|
||
|
double upper_threshold = 50 + threshhold;
|
||
|
double lower_threshold = 50 - threshhold;
|
||
|
|
||
|
// Check for exit above upper threshold
|
||
|
if(RSIndexBuffer[shift] > upper_threshold &&
|
||
|
RSIndexBuffer[shift+1] <= upper_threshold)
|
||
|
return 1;
|
||
|
|
||
|
// Check for exit below lower threshold
|
||
|
if(RSIndexBuffer[shift] < lower_threshold &&
|
||
|
RSIndexBuffer[shift+1] >= lower_threshold)
|
||
|
return -1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Check for zero line crosses |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int CheckZeroCross(int shift)
|
||
|
{
|
||
|
if(shift < 1 || shift >= ArraySize(RSIndexBuffer))
|
||
|
return 0;
|
||
|
|
||
|
// Check for bullish zero cross
|
||
|
if(RSIndexBuffer[shift] > 50 && RSIndexBuffer[shift+1] <= 50)
|
||
|
return 1;
|
||
|
|
||
|
// Check for bearish zero cross
|
||
|
if(RSIndexBuffer[shift] < 50 && RSIndexBuffer[shift+1] >= 50)
|
||
|
return -1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|