//+------------------------------------------------------------------+ //| RSI_on_RSI_FAST_1441.mq4 | //| RSI(14) + RSI(5) on RSI(14) (fast, no iRSIOnArray per bar) | //+------------------------------------------------------------------+ #property strict #property indicator_separate_window #property indicator_buffers 2 #property indicator_color1 clrDodgerBlue #property indicator_color2 clrBlack #property indicator_width1 1 #property indicator_width2 1 #property indicator_style2 STYLE_DASH #property indicator_minimum 0 #property indicator_maximum 100 //==================== Inputs ==================== // RSI 14 input int InpRSI1Period = 14; // RSI(14) period input int InpRSI1Price = PRICE_CLOSE; // RSI(14) applied price input color InpRSI1Color = clrDodgerBlue; // RSI(14) line color <-- NEW // RSI 5 on previous indicator data input int InpRSI2Period = 5; // RSI(5) period on RSI(14) // Levels input double InpLevelLow = 20.0; // Level low input double InpLevelMid = 50.0; // Level middle input double InpLevelHigh = 80.0; // Level high input color InpLevelsColor = clrSilver; // Levels color input int InpLevelsWidth = 1; // Levels width input int InpLevelsStyle = STYLE_DOT; // Levels style // RSI(5) line style (defaults as requested) input color InpRSI2Color = clrWhite; // RSI(5) color input int InpRSI2Width = 1; // RSI(5) width input int InpRSI2Style = STYLE_DOT; // RSI(5) style //==================== Buffers ==================== double BufRSI14[]; double BufRSI5OnRSI14[]; //--- internal cache for smoothing double gAvgGain[]; double gAvgLoss[]; //+------------------------------------------------------------------+ //| Calculate RSI on array using Wilder smoothing (fast, one pass) | //| src[] must be series (0=current). out[] series too. | //+------------------------------------------------------------------+ void CalcRSIOnArrayWilder(const double &src[], double &out[], const int rates_total, const int period, double &avgGain[], double &avgLoss[], int start_index) { if(period <= 0) return; // Ensure internal arrays are sized ArrayResize(avgGain, rates_total); ArrayResize(avgLoss, rates_total); ArraySetAsSeries(avgGain, true); ArraySetAsSeries(avgLoss, true); // With series arrays, the "oldest" bar is at index rates_total-1. int oldest = rates_total - 1; // Seed only once or when we start from oldest if(start_index >= oldest) { // initialize everything to EMPTY for safety for(int i = oldest; i >= 0; i--) { out[i] = EMPTY_VALUE; avgGain[i] = 0.0; avgLoss[i] = 0.0; } // Seed at bar (oldest - period) int seed = oldest - period; if(seed <= 0) seed = 0; double gainSum = 0.0, lossSum = 0.0; // Build initial sums for 'period' differences for(int i = oldest; i > seed; i--) { double ch = src[i-1] - src[i]; if(ch > 0) gainSum += ch; else lossSum -= ch; } avgGain[seed] = gainSum / period; avgLoss[seed] = lossSum / period; if(avgLoss[seed] == 0.0 && avgGain[seed] == 0.0) out[seed] = 50.0; else if(avgLoss[seed] == 0.0) out[seed] = 100.0; else { double rs = avgGain[seed] / avgLoss[seed]; out[seed] = 100.0 - (100.0 / (1.0 + rs)); } // Now go from seed-1 down to current (0), smoothing for(int i = seed - 1; i >= 0; i--) { double ch2 = src[i] - src[i+1]; double g = (ch2 > 0) ? ch2 : 0.0; double l = (ch2 < 0) ? -ch2 : 0.0; avgGain[i] = (avgGain[i+1] * (period - 1) + g) / period; avgLoss[i] = (avgLoss[i+1] * (period - 1) + l) / period; if(avgLoss[i] == 0.0 && avgGain[i] == 0.0) out[i] = 50.0; else if(avgLoss[i] == 0.0) out[i] = 100.0; else { double rs2 = avgGain[i] / avgLoss[i]; out[i] = 100.0 - (100.0 / (1.0 + rs2)); } } return; } // Incremental update (new bars only) for(int i = start_index; i >= 0; i--) { if(i+1 >= rates_total) continue; // If previous value is empty, rebuild everything if(out[i+1] == EMPTY_VALUE) { CalcRSIOnArrayWilder(src, out, rates_total, period, avgGain, avgLoss, rates_total - 1); return; } double ch = src[i] - src[i+1]; double g = (ch > 0) ? ch : 0.0; double l = (ch < 0) ? -ch : 0.0; avgGain[i] = (avgGain[i+1] * (period - 1) + g) / period; avgLoss[i] = (avgLoss[i+1] * (period - 1) + l) / period; if(avgLoss[i] == 0.0 && avgGain[i] == 0.0) out[i] = 50.0; else if(avgLoss[i] == 0.0) out[i] = 100.0; else { double rs = avgGain[i] / avgLoss[i]; out[i] = 100.0 - (100.0 / (1.0 + rs)); } } } //+------------------------------------------------------------------+ int OnInit() { SetIndexBuffer(0, BufRSI14); SetIndexBuffer(1, BufRSI5OnRSI14); ArraySetAsSeries(BufRSI14, true); ArraySetAsSeries(BufRSI5OnRSI14, true); // RSI(14) style (color is now configurable) <-- UPDATED SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 1, InpRSI1Color); SetIndexLabel(0, "RSI(14)"); // RSI(5) on RSI(14) style SetIndexStyle(1, DRAW_LINE, InpRSI2Style, InpRSI2Width, InpRSI2Color); SetIndexLabel(1, "RSI(5) on RSI(14)"); IndicatorShortName(StringFormat("RSI(%d) + RSI(%d) on RSI(%d)", InpRSI1Period, InpRSI2Period, InpRSI1Period)); // Levels SetLevelStyle(InpLevelsStyle, InpLevelsWidth, InpLevelsColor); SetLevelValue(0, InpLevelLow); SetLevelValue(1, InpLevelMid); SetLevelValue(2, InpLevelHigh); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ 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 < (InpRSI1Period + InpRSI2Period + 10)) return(0); int start; if(prev_calculated <= 0) { // First run: compute all bars start = rates_total - 1; } else { // Only new bars + 1 bar back for stability start = rates_total - prev_calculated + 1; if(start > rates_total - 1) start = rates_total - 1; } // 1) RSI(14) built-in for(int i = start; i >= 0; i--) BufRSI14[i] = iRSI(NULL, 0, InpRSI1Period, InpRSI1Price, i); // 2) RSI(5) on RSI(14) (fast) CalcRSIOnArrayWilder(BufRSI14, BufRSI5OnRSI14, rates_total, InpRSI2Period, gAvgGain, gAvgLoss, start); return(rates_total); } //+------------------------------------------------------------------+