Multi-timeframe confluence oscillator combining Stochastic, RSI and MACD across 3 timeframes. Used to identify trend entries as a confirmation for trend-continuation setups, support/resistance reactions, and exhaustion conditions
Instead of normalizing the values, we are simply assigning a score. I can’t fully explain why, but in my personal use it is surprisingly effective, especially for detecting divergences.
Instead of normalizing the values, we are simply assigning a score. I can’t fully explain why, but in my personal use it is surprisingly effective, especially for detecting divergences.


//+------------------------------------------------------------------+ //| MultiConfluence_Index.mq5 | //| Confluence Index Stoch+RSI+MACD | //+------------------------------------------------------------------+ #property copyright "Multi-Confluence Index" #property version "1.00" #property indicator_separate_window #property indicator_buffers 6 #property indicator_plots 4 // Ligne principale de l'indice #property indicator_label1 "Confluence Index" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_width1 3 // Ligne zéro #property indicator_label2 "Zero Line" #property indicator_type2 DRAW_LINE #property indicator_color2 clrGray #property indicator_width2 1 #property indicator_style2 STYLE_DOT // Zone bullish extrême #property indicator_label3 "Zone Bullish" #property indicator_type3 DRAW_FILLING #property indicator_color3 clrDarkGreen // Zone bearish extrême #property indicator_label4 "Zone Bearish" #property indicator_type4 DRAW_FILLING #property indicator_color4 clrDarkRed //+------------------------------------------------------------------+ //| Input parameters | //+------------------------------------------------------------------+ input group "=== TIMEFRAMES ===" input ENUM_TIMEFRAMES TF1 = PERIOD_CURRENT; // Timeframe 1 (Fast) input ENUM_TIMEFRAMES TF2 = PERIOD_H1; // Timeframe 2 (Medium) input ENUM_TIMEFRAMES TF3 = PERIOD_H4; // Timeframe 3 (Slow) input group "=== PARAMETRES ===" input int Stoch_K = 14; // Stochastic K input int Stoch_D = 3; // Stochastic D input int Stoch_Slowing = 3; // Stochastic Slowing input int RSI_Period = 14; // RSI Period input int MACD_Fast = 12; // MACD EMA Fast input int MACD_Slow = 26; // MACD EMA Slow input int MACD_Signal = 9; // MACD Signal //+------------------------------------------------------------------+ //| Buffers | //+------------------------------------------------------------------+ double IndexBuffer[]; double ZeroBuffer[]; double BullishZoneTop[]; double BullishZoneBottom[]; double BearishZoneTop[]; double BearishZoneBottom[]; // Handles for indicators int handle_stoch_tf1, handle_stoch_tf2, handle_stoch_tf3; int handle_rsi_tf1, handle_rsi_tf2, handle_rsi_tf3; int handle_macd_tf1, handle_macd_tf2, handle_macd_tf3; //+------------------------------------------------------------------+ //| Initialization | //+------------------------------------------------------------------+ int OnInit() { // Buffers SetIndexBuffer(0, IndexBuffer, INDICATOR_DATA); SetIndexBuffer(1, ZeroBuffer, INDICATOR_DATA); SetIndexBuffer(2, BullishZoneTop, INDICATOR_DATA); SetIndexBuffer(3, BullishZoneBottom, INDICATOR_DATA); SetIndexBuffer(4, BearishZoneTop, INDICATOR_DATA); SetIndexBuffer(5, BearishZoneBottom, INDICATOR_DATA); // Configuration ArraySetAsSeries(IndexBuffer, true); ArraySetAsSeries(ZeroBuffer, true); ArraySetAsSeries(BullishZoneTop, true); ArraySetAsSeries(BullishZoneBottom, true); ArraySetAsSeries(BearishZoneTop, true); ArraySetAsSeries(BearishZoneBottom, true); // Ligne zéro ArrayInitialize(ZeroBuffer, 0.0); // Configuration of fill zones PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, 0); PlotIndexSetInteger(3, PLOT_DRAW_BEGIN, 0); // Creation of handles - STOCHASTIC handle_stoch_tf1 = iStochastic(_Symbol, TF1, Stoch_K, Stoch_D, Stoch_Slowing, MODE_SMA, STO_LOWHIGH); handle_stoch_tf2 = iStochastic(_Symbol, TF2, Stoch_K, Stoch_D, Stoch_Slowing, MODE_SMA, STO_LOWHIGH); handle_stoch_tf3 = iStochastic(_Symbol, TF3, Stoch_K, Stoch_D, Stoch_Slowing, MODE_SMA, STO_LOWHIGH); // Creation of handles - RSI handle_rsi_tf1 = iRSI(_Symbol, TF1, RSI_Period, PRICE_CLOSE); handle_rsi_tf2 = iRSI(_Symbol, TF2, RSI_Period, PRICE_CLOSE); handle_rsi_tf3 = iRSI(_Symbol, TF3, RSI_Period, PRICE_CLOSE); // Creation of handles - MACD handle_macd_tf1 = iMACD(_Symbol, TF1, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE); handle_macd_tf2 = iMACD(_Symbol, TF2, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE); handle_macd_tf3 = iMACD(_Symbol, TF3, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE); // Verification of handles if(handle_stoch_tf1 == INVALID_HANDLE || handle_stoch_tf2 == INVALID_HANDLE || handle_stoch_tf3 == INVALID_HANDLE || handle_rsi_tf1 == INVALID_HANDLE || handle_rsi_tf2 == INVALID_HANDLE || handle_rsi_tf3 == INVALID_HANDLE || handle_macd_tf1 == INVALID_HANDLE || handle_macd_tf2 == INVALID_HANDLE || handle_macd_tf3 == INVALID_HANDLE) { Print("ERROR: Impossible to create handles"); return(INIT_FAILED); } // Name and scale IndicatorSetString(INDICATOR_SHORTNAME, "Multi-Confluence Index"); IndicatorSetInteger(INDICATOR_DIGITS, 1); IndicatorSetDouble(INDICATOR_MINIMUM, -100); IndicatorSetDouble(INDICATOR_MAXIMUM, 100); // Levels IndicatorSetInteger(INDICATOR_LEVELS, 3); IndicatorSetDouble(INDICATOR_LEVELVALUE, 0, 0); IndicatorSetDouble(INDICATOR_LEVELVALUE, 1, 50); IndicatorSetDouble(INDICATOR_LEVELVALUE, 2, -50); IndicatorSetInteger(INDICATOR_LEVELCOLOR, 0, clrGray); IndicatorSetInteger(INDICATOR_LEVELCOLOR, 1, clrGreen); IndicatorSetInteger(INDICATOR_LEVELCOLOR, 2, clrRed); IndicatorSetInteger(INDICATOR_LEVELSTYLE, 0, STYLE_SOLID); IndicatorSetInteger(INDICATOR_LEVELSTYLE, 1, STYLE_DOT); IndicatorSetInteger(INDICATOR_LEVELSTYLE, 2, STYLE_DOT); Print("Multi-Confluence Index initialized - TF:", EnumToString(TF1), "/", EnumToString(TF2), "/", EnumToString(TF3)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Deinitialization | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(handle_stoch_tf1 != INVALID_HANDLE) IndicatorRelease(handle_stoch_tf1); if(handle_stoch_tf2 != INVALID_HANDLE) IndicatorRelease(handle_stoch_tf2); if(handle_stoch_tf3 != INVALID_HANDLE) IndicatorRelease(handle_stoch_tf3); if(handle_rsi_tf1 != INVALID_HANDLE) IndicatorRelease(handle_rsi_tf1); if(handle_rsi_tf2 != INVALID_HANDLE) IndicatorRelease(handle_rsi_tf2); if(handle_rsi_tf3 != INVALID_HANDLE) IndicatorRelease(handle_rsi_tf3); if(handle_macd_tf1 != INVALID_HANDLE) IndicatorRelease(handle_macd_tf1); if(handle_macd_tf2 != INVALID_HANDLE) IndicatorRelease(handle_macd_tf2); if(handle_macd_tf3 != INVALID_HANDLE) IndicatorRelease(handle_macd_tf3); Comment(""); } //+------------------------------------------------------------------+ //| Main calculation | //+------------------------------------------------------------------+ 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 < 100) return(0); int limit = rates_total - prev_calculated; if(limit == 0) limit = 1; if(prev_calculated == 0) limit = rates_total - 100; // Arrays for data (as series to match buffer indexing) double stoch_k1[], stoch_d1[], stoch_k2[], stoch_d2[], stoch_k3[], stoch_d3[]; double rsi1[], rsi2[], rsi3[]; double macd_main1[], macd_sig1[], macd_main2[], macd_sig2[], macd_main3[], macd_sig3[]; ArraySetAsSeries(stoch_k1, true); ArraySetAsSeries(stoch_d1, true); ArraySetAsSeries(stoch_k2, true); ArraySetAsSeries(stoch_d2, true); ArraySetAsSeries(stoch_k3, true); ArraySetAsSeries(stoch_d3, true); ArraySetAsSeries(rsi1, true); ArraySetAsSeries(rsi2, true); ArraySetAsSeries(rsi3, true); ArraySetAsSeries(macd_main1, true); ArraySetAsSeries(macd_sig1, true); ArraySetAsSeries(macd_main2, true); ArraySetAsSeries(macd_sig2, true); ArraySetAsSeries(macd_main3, true); ArraySetAsSeries(macd_sig3, true); // Copy of data - copy enough bars int bars_to_copy = limit + 50; int copied = 0; copied = CopyBuffer(handle_stoch_tf1, 0, 0, bars_to_copy, stoch_k1); if(copied <= 0) { Print("ERROR: Failed to copy stoch_k1, code:", GetLastError()); return(prev_calculated); } if(CopyBuffer(handle_stoch_tf1, 1, 0, bars_to_copy, stoch_d1) <= 0) { Print("ERROR: Failed to copy stoch_d1"); return(prev_calculated); } if(CopyBuffer(handle_stoch_tf2, 0, 0, bars_to_copy, stoch_k2) <= 0) { Print("ERROR: Failed to copy stoch_k2"); return(prev_calculated); } if(CopyBuffer(handle_stoch_tf2, 1, 0, bars_to_copy, stoch_d2) <= 0) { Print("ERROR: Failed to copy stoch_d2"); return(prev_calculated); } if(CopyBuffer(handle_stoch_tf3, 0, 0, bars_to_copy, stoch_k3) <= 0) { Print("ERROR: Failed to copy stoch_k3"); return(prev_calculated); } if(CopyBuffer(handle_stoch_tf3, 1, 0, bars_to_copy, stoch_d3) <= 0) { Print("ERROR: Failed to copy stoch_d3"); return(prev_calculated); } if(CopyBuffer(handle_rsi_tf1, 0, 0, bars_to_copy, rsi1) <= 0) { Print("ERROR: Failed to copy rsi1"); return(prev_calculated); } if(CopyBuffer(handle_rsi_tf2, 0, 0, bars_to_copy, rsi2) <= 0) { Print("ERROR: Failed to copy rsi2"); return(prev_calculated); } if(CopyBuffer(handle_rsi_tf3, 0, 0, bars_to_copy, rsi3) <= 0) { Print("ERROR: Failed to copy rsi3"); return(prev_calculated); } if(CopyBuffer(handle_macd_tf1, 0, 0, bars_to_copy, macd_main1) <= 0) { Print("ERROR: Failed to copy macd_main1"); return(prev_calculated); } if(CopyBuffer(handle_macd_tf1, 1, 0, bars_to_copy, macd_sig1) <= 0) { Print("ERROR: Failed to copy macd_sig1"); return(prev_calculated); } if(CopyBuffer(handle_macd_tf2, 0, 0, bars_to_copy, macd_main2) <= 0) { Print("ERROR: Failed to copy macd_main2"); return(prev_calculated); } if(CopyBuffer(handle_macd_tf2, 1, 0, bars_to_copy, macd_sig2) <= 0) { Print("ERROR: Failed to copy macd_sig2"); return(prev_calculated); } if(CopyBuffer(handle_macd_tf3, 0, 0, bars_to_copy, macd_main3) <= 0) { Print("ERROR: Failed to copy macd_main3"); return(prev_calculated); } if(CopyBuffer(handle_macd_tf3, 1, 0, bars_to_copy, macd_sig3) <= 0) { Print("ERROR: Failed to copy macd_sig3"); return(prev_calculated); } Print("DEBUG: Copied ", copied, " bars, limit=", limit, " rates_total=", rates_total); // Calcul of the index - now i=0 is most recent bar int calculated = 0; for(int i = 0; i < limit; i++) { // Security check for array access if(i >= ArraySize(stoch_k1) || i >= ArraySize(stoch_k2) || i >= ArraySize(stoch_k3)) { Print("DEBUG: Skipping i=", i, " - stoch arrays too small"); continue; } if(i >= ArraySize(rsi1) || i >= ArraySize(rsi2) || i >= ArraySize(rsi3)) { Print("DEBUG: Skipping i=", i, " - rsi arrays too small"); continue; } if(i >= ArraySize(macd_main1) || i >= ArraySize(macd_main2) || i >= ArraySize(macd_main3)) { Print("DEBUG: Skipping i=", i, " - macd arrays too small"); continue; } double score = 0.0; //=== STOCHASTIQUE === // TF1 if(stoch_k1[i] > stoch_d1[i]) score += 11.0; else score -= 11.0; // TF2 if(stoch_k2[i] > stoch_d2[i]) score += 17.0; else score -= 17.0; // TF3 if(stoch_k3[i] > stoch_d3[i]) score += 17.0; else score -= 17.0; //=== RSI === // TF1 if(rsi1[i] > 50) score += 7.0; else score -= 7.0; // TF2 if(rsi2[i] > 50) score += 11.0; else score -= 11.0; // TF3 if(rsi3[i] > 50) score += 11.0; else score -= 11.0; //=== MACD === // TF1 if(macd_main1[i] > macd_sig1[i]) score += 6.0; else score -= 6.0; // TF2 if(macd_main2[i] > macd_sig2[i]) score += 10.0; else score -= 10.0; // TF3 if(macd_main3[i] > macd_sig3[i]) score += 10.0; else score -= 10.0; // Stockage - i=0 is current bar IndexBuffer[i] = score; calculated++; if(i < 3) // Debug pour les 3 premières barres { Print("DEBUG: Bar[", i, "] score=", score, " stoch1=", stoch_k1[i], " rsi1=", rsi1[i], " macd1=", macd_main1[i]); } // Colored zones if(score > 50) { BullishZoneTop[i] = 100; BullishZoneBottom[i] = 50; } else { BullishZoneTop[i] = EMPTY_VALUE; BullishZoneBottom[i] = EMPTY_VALUE; } if(score < -50) { BearishZoneTop[i] = -50; BearishZoneBottom[i] = -100; } else { BearishZoneTop[i] = EMPTY_VALUE; BearishZoneBottom[i] = EMPTY_VALUE; } } Print("DEBUG: Calculated ", calculated, " bars out of ", limit); // Debug info at first calculation if(prev_calculated == 0) { string info = StringFormat("Calculation completed | Current index: %.1f", IndexBuffer[0]); Print(info); Comment(info); } return(rates_total); } //+------------------------------------------------------------------+