Indicator · Pine Script v6 · On the chart

Momentum Confluence Suite [MCS]

by kdricha0602

This indicator overlays an EMA stack, Supertrend, and ATR range bands on the price chart and scores long or short confluence from trend, WaveTrend, StochRSI, confirmed divergence, and volume.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code231
Settings33inputs
LicenceMIT
Last update5 weeks ago21 Sep 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

231 lines of Pine Script v6 from archive/Momentum-Confluence-Suite-v1.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

Momentum-Confluence-Suite-v1.pine
//@version=6
// Momentum Confluence Suite [MCS]
// EMA, Supertrend, ADX regime, WaveTrend, StochRSI, confirmed divergence,
// ATR range/stop, volume confirmation, and return-based beta.
// Signals are evaluated only on confirmed bar closes. No system guarantees profit;
// validate settings on the symbol/timeframe before risking capital.

indicator("Momentum Confluence Suite [MCS]", shorttitle="MCS", overlay=true, max_labels_count=500)

// ── Input groups ────────────────────────────────────────────────
string GRP_T   = "Trend (EMA)"
string GRP_ST  = "Supertrend"
string GRP_RG  = "Regime Filter"
string GRP_WT  = "WaveTrend"
string GRP_SR  = "StochRSI"
string GRP_DV  = "Divergence"
string GRP_ATR = "ATR Range & Stop"
string GRP_VL  = "Volume"
string GRP_BT  = "Beta"
string GRP_SG  = "Signals & Display"

int emaFastLen = input.int(21, "EMA Fast", minval=2, group=GRP_T)
int emaSlowLen = input.int(50, "EMA Slow", minval=3, group=GRP_T)
int emaLongLen = input.int(200, "EMA Long / Regime", minval=20, group=GRP_T)

int stLen = input.int(10, "ATR Length", minval=1, group=GRP_ST)
float stMult = input.float(3.0, "Multiplier", minval=0.1, step=0.1, group=GRP_ST)

int adxLen = input.int(14, "DI / ADX Length", minval=2, group=GRP_RG)
float adxThresh = input.float(20.0, "ADX Threshold", minval=5.0, step=0.5, group=GRP_RG)

int wtN1 = input.int(10, "Channel Length", minval=1, group=GRP_WT)
int wtN2 = input.int(21, "Average Length", minval=1, group=GRP_WT)

int rsiLen = input.int(14, "RSI Length", minval=2, group=GRP_SR)
int stochLen = input.int(14, "Stochastic Length", minval=2, group=GRP_SR)
int smoothK = input.int(3, "Smooth K", minval=1, group=GRP_SR)
int smoothD = input.int(3, "Smooth D", minval=1, group=GRP_SR)

int lbL = input.int(5, "Pivot Lookback Left", minval=1, group=GRP_DV)
int lbR = input.int(5, "Pivot Lookback Right", minval=1, group=GRP_DV)
int divMinBars = input.int(5, "Minimum Pivot Gap", minval=1, group=GRP_DV)
int divMaxBars = input.int(60, "Maximum Pivot Gap", minval=2, group=GRP_DV)

int atrLen = input.int(14, "ATR Length", minval=1, group=GRP_ATR)
float atrMult = input.float(2.0, "Stop Multiplier", minval=0.5, step=0.1, group=GRP_ATR)
float rngMult = input.float(1.5, "Range Band Multiplier", minval=0.1, step=0.1, group=GRP_ATR)
bool showBands = input.bool(true, "Show ATR Range Bands", group=GRP_ATR)

int volLen = input.int(20, "Volume SMA Length", minval=2, group=GRP_VL)
float volMult = input.float(1.5, "Volume Multiplier", minval=0.5, step=0.1, group=GRP_VL)
bool useVolFilter = input.bool(true, "Require Volume Confirmation", group=GRP_VL)

string benchSym = input.symbol("AMEX:SPY", "Benchmark Symbol", group=GRP_BT)
int betaLen = input.int(60, "Beta Lookback", minval=10, group=GRP_BT)
float betaMin = input.float(0.7, "Minimum Beta", minval=0.0, step=0.1, group=GRP_BT)
bool useBetaFilter = input.bool(false, "Require Minimum Beta", group=GRP_BT)

int longThresh = input.int(4, "Long Score >=", minval=1, maxval=7, group=GRP_SG)
int shortThresh = input.int(4, "Short Score >= (absolute)", minval=1, maxval=7, group=GRP_SG)
bool longOnly = input.bool(false, "Long Signals Only", group=GRP_SG)
bool showDash = input.bool(true, "Show Dashboard", group=GRP_SG)
bool showBg = input.bool(true, "Regime Background Tint", group=GRP_SG)

// ── 1. EMA stack ────────────────────────────────────────────────
float emaFast = ta.ema(close, emaFastLen)
float emaSlow = ta.ema(close, emaSlowLen)
float emaLong = ta.ema(close, emaLongLen)

// ── 2. Supertrend ───────────────────────────────────────────────
[stLine, stDir] = ta.supertrend(stMult, stLen)
bool stBull = stDir < 0
bool stBear = stDir > 0

// ── 3. Regime filter (EMA + ADX + directional movement) ─────────
[diPlus, diMinus, adxValue] = ta.dmi(adxLen, adxLen)
bool bullRegime = close > emaLong and adxValue > adxThresh and diPlus > diMinus
bool bearRegime = close < emaLong and adxValue > adxThresh and diMinus > diPlus
bool rangeRegime = not bullRegime and not bearRegime

// ── 4. WaveTrend ────────────────────────────────────────────────
float averagePrice = hlc3
float esa = ta.ema(averagePrice, wtN1)
float deviation = ta.ema(math.abs(averagePrice - esa), wtN1)
float channelIndex = deviation == 0.0 ? 0.0 : (averagePrice - esa) / (0.015 * deviation)
float wt1 = ta.ema(channelIndex, wtN2)
float wt2 = ta.sma(wt1, 4)

// ── 5. StochRSI ─────────────────────────────────────────────────
float rsiValue = ta.rsi(close, rsiLen)
float stochRsi = ta.stoch(rsiValue, rsiValue, rsiValue, stochLen)
float k = ta.sma(stochRsi, smoothK)
float d = ta.sma(k, smoothD)

// ── 6. Confirmed regular WaveTrend divergence ───────────────────
float pivotLowValue = ta.pivotlow(wt1, lbL, lbR)
float pivotHighValue = ta.pivothigh(wt1, lbL, lbR)
bool pivotLowFound = not na(pivotLowValue)
bool pivotHighFound = not na(pivotHighValue)

// barssince() is evaluated on every bar to keep history consistent.
int barsSincePriorLow = ta.barssince(pivotLowFound[1])
int barsSincePriorHigh = ta.barssince(pivotHighFound[1])
bool lowGapOk = not na(barsSincePriorLow) and barsSincePriorLow >= divMinBars and barsSincePriorLow <= divMaxBars
bool highGapOk = not na(barsSincePriorHigh) and barsSincePriorHigh >= divMinBars and barsSincePriorHigh <= divMaxBars

float previousLowOsc = ta.valuewhen(pivotLowFound, wt1[lbR], 1)
float previousLowPrice = ta.valuewhen(pivotLowFound, low[lbR], 1)
float previousHighOsc = ta.valuewhen(pivotHighFound, wt1[lbR], 1)
float previousHighPrice = ta.valuewhen(pivotHighFound, high[lbR], 1)

bool bullDiv = pivotLowFound and lowGapOk and not na(previousLowOsc) and not na(previousLowPrice) and wt1[lbR] > previousLowOsc and low[lbR] < previousLowPrice
bool bearDiv = pivotHighFound and highGapOk and not na(previousHighOsc) and not na(previousHighPrice) and wt1[lbR] < previousHighOsc and high[lbR] > previousHighPrice

// ── 7. ATR trailing stop and range ──────────────────────────────
float atrValue = ta.atr(atrLen)
float newLongStop = close - atrValue * atrMult
float newShortStop = close + atrValue * atrMult
var float longStop = na
var float shortStop = na

if stBull
    longStop := stBull[1] ? math.max(newLongStop, nz(longStop[1], newLongStop)) : newLongStop
else
    longStop := na

if stBear
    shortStop := stBear[1] ? math.min(newShortStop, nz(shortStop[1], newShortStop)) : newShortStop
else
    shortStop := na

float stopLine = stBull ? longStop : stBear ? shortStop : na
float rangeUpper = emaSlow + atrValue * rngMult
float rangeLower = emaSlow - atrValue * rngMult

// ── 8. Volume confirmation ──────────────────────────────────────
float volumeSma = ta.sma(volume, volLen)
bool volumeAvailable = not na(volume) and volume > 0
float volumeRatio = volumeAvailable and not na(volumeSma) and volumeSma > 0 ? volume / volumeSma : na
// Symbols without volume data are not blocked. Symbols with volume must meet the threshold.
bool volumeConfirmed = not volumeAvailable or (not na(volumeRatio) and volumeRatio >= volMult)
bool volumeOk = not useVolFilter or volumeConfirmed

// ── 9. Beta from percentage returns, not raw price levels ───────
float benchmarkClose = request.security(benchSym, timeframe.period, close, gaps=barmerge.gaps_off, lookahead=barmerge.lookahead_off)
float assetReturn = not na(close[1]) and close[1] != 0 ? close / close[1] - 1.0 : na
float benchmarkReturn = not na(benchmarkClose[1]) and benchmarkClose[1] != 0 ? benchmarkClose / benchmarkClose[1] - 1.0 : na
float returnCorrelation = ta.correlation(assetReturn, benchmarkReturn, betaLen)
float assetDeviation = ta.stdev(assetReturn, betaLen)
float benchmarkDeviation = ta.stdev(benchmarkReturn, betaLen)
float beta = not na(returnCorrelation) and not na(assetDeviation) and not na(benchmarkDeviation) and benchmarkDeviation != 0.0 ? returnCorrelation * assetDeviation / benchmarkDeviation : na
bool betaOk = not useBetaFilter or (not na(beta) and beta >= betaMin)

// ── Confluence score: seven directional engines (-7 to +7) ─────
bool emaBull = emaFast > emaSlow
bool emaBear = emaFast < emaSlow
int voteEma = emaBull ? 1 : emaBear ? -1 : 0
int voteSupertrend = stBull ? 1 : stBear ? -1 : 0
int voteRegime = bullRegime ? 1 : bearRegime ? -1 : 0
int voteWaveTrend = wt1 > wt2 ? 1 : wt1 < wt2 ? -1 : 0
int voteStochRsi = k > d ? 1 : k < d ? -1 : 0
int voteDivergence = bullDiv ? 1 : bearDiv ? -1 : 0
int voteAtr = not na(stopLine) and close > stopLine ? 1 : not na(stopLine) and close < stopLine ? -1 : 0
int score = voteEma + voteSupertrend + voteRegime + voteWaveTrend + voteStochRsi + voteDivergence + voteAtr

// Longs must be in a bullish regime; shorts must be in a bearish regime.
bool longSetup = bullRegime and score >= longThresh and volumeOk and betaOk
bool shortSetup = bearRegime and score <= -shortThresh and volumeOk and betaOk and not longOnly
int longState = longSetup ? 1 : 0
int shortState = shortSetup ? 1 : 0
bool longTrigger = barstate.isconfirmed and longState == 1 and nz(longState[1], 0) == 0
bool shortTrigger = barstate.isconfirmed and shortState == 1 and nz(shortState[1], 0) == 0

// ── Signals and alerts ──────────────────────────────────────────
if longTrigger
    label.new(bar_index, low, "BUY\n+" + str.tostring(score), style=label.style_label_up, color=color.new(#00E5A0, 0), textcolor=color.black, size=size.small)
if shortTrigger
    label.new(bar_index, high, "SELL\n" + str.tostring(score), style=label.style_label_down, color=color.new(#FF4D6D, 0), textcolor=color.white, size=size.small)

plotshape(bullDiv, title="Confirmed Bullish Divergence", style=shape.diamond, location=location.belowbar, color=color.new(#00E5A0, 0), size=size.tiny)
plotshape(bearDiv, title="Confirmed Bearish Divergence", style=shape.diamond, location=location.abovebar, color=color.new(#FF4D6D, 0), size=size.tiny)

alertcondition(longTrigger, title="MCS Long", message="MCS LONG signal on {{ticker}} ({{interval}}) at {{close}}")
alertcondition(shortTrigger, title="MCS Short", message="MCS SHORT signal on {{ticker}} ({{interval}}) at {{close}}")

// ── Chart plots ─────────────────────────────────────────────────
plot(emaFast, title="EMA Fast", color=color.new(#00D4FF, 0), linewidth=2)
plot(emaSlow, title="EMA Slow", color=color.new(#FF9F1C, 0), linewidth=2)
plot(stLine, title="Supertrend", color=stBull ? color.new(#00E5A0, 0) : color.new(#FF4D6D, 0), linewidth=2, style=plot.style_linebr)
plot(stopLine, title="ATR Stop", color=color.new(#FFD60A, 0), linewidth=2, style=plot.style_linebr)
pUpper = plot(showBands ? rangeUpper : na, title="ATR Range Upper", color=color.new(#9D4EDD, 85))
pLower = plot(showBands ? rangeLower : na, title="ATR Range Lower", color=color.new(#9D4EDD, 85))
fill(pUpper, pLower, color=color.new(#9D4EDD, 93), title="ATR Range Fill")
color regimeColor = bullRegime ? color.new(#00E5A0, 93) : bearRegime ? color.new(#FF4D6D, 93) : na
bgcolor(showBg ? regimeColor : na, title="Regime Background")

// ── Dashboard ───────────────────────────────────────────────────
var table dashboard = table.new(position.top_right, 2, 11, border_width=1, border_color=color.new(#FFFFFF, 85))
color bullColor = color.new(#00E5A0, 25)
color bearColor = color.new(#FF4D6D, 25)
color flatColor = color.new(#8A8F98, 25)
color textColor = #E8ECF1

f_dashboardRow(int row, string labelText, int state) =>
    color cellColor = state > 0 ? bullColor : state < 0 ? bearColor : flatColor
    string stateText = state > 0 ? "▲ BULL" : state < 0 ? "▼ BEAR" : "■ FLAT"
    table.cell(dashboard, 0, row, labelText, text_color=textColor, text_size=size.small)
    table.cell(dashboard, 1, row, stateText, bgcolor=cellColor, text_color=textColor, text_size=size.small)

if barstate.islast and showDash
    string scoreText = (score > 0 ? "+" : "") + str.tostring(score)
    color scoreColor = score >= longThresh ? bullColor : score <= -shortThresh ? bearColor : flatColor
    table.cell(dashboard, 0, 0, "MCS · " + syminfo.ticker, text_color=color.new(#00D4FF, 0), text_size=size.normal)
    table.cell(dashboard, 1, 0, "SCORE " + scoreText, bgcolor=scoreColor, text_color=textColor, text_size=size.normal)
    f_dashboardRow(1, "EMA " + str.tostring(emaFastLen) + "/" + str.tostring(emaSlowLen), voteEma)
    f_dashboardRow(2, "Supertrend", voteSupertrend)
    f_dashboardRow(3, "Regime", voteRegime)
    f_dashboardRow(4, "WaveTrend", voteWaveTrend)
    f_dashboardRow(5, "StochRSI " + str.tostring(math.round(nz(k, 50))), voteStochRsi)
    f_dashboardRow(6, "Divergence", voteDivergence)
    f_dashboardRow(7, "ATR Stop", voteAtr)
    string volumeText = not volumeAvailable ? "N/A" : volumeConfirmed ? "✓ " + str.tostring(volumeRatio, "#.##") + "x" : "✗ " + str.tostring(volumeRatio, "#.##") + "x"
    color volumeColor = not volumeAvailable ? flatColor : volumeConfirmed ? bullColor : bearColor
    table.cell(dashboard, 0, 8, "Volume", text_color=textColor, text_size=size.small)
    table.cell(dashboard, 1, 8, volumeText, bgcolor=volumeColor, text_color=textColor, text_size=size.small)
    table.cell(dashboard, 0, 9, "Beta vs " + benchSym, text_color=textColor, text_size=size.small)
    table.cell(dashboard, 1, 9, na(beta) ? "N/A" : str.tostring(beta, "#.##"), bgcolor=flatColor, text_color=textColor, text_size=size.small)
    string signalText = longSetup ? "BUY" : shortSetup ? "SELL" : rangeRegime ? "STAND ASIDE" : "WAIT"
    color signalColor = longSetup ? bullColor : shortSetup ? bearColor : flatColor
    table.cell(dashboard, 0, 10, "Signal", text_color=textColor, text_size=size.small)
    table.cell(dashboard, 1, 10, signalText, bgcolor=signalColor, text_color=textColor, text_size=size.small)

Overview

Labels mark when the score meets the long or short threshold, with ATR-derived targets and a plotted stop. Settings change EMA lengths, Supertrend and ATR multipliers, ADX and oscillator periods, pivot gaps, volume and optional beta filters, and score thresholds. A dashboard and regime tint can be shown. Signals wait for a confirmed bar close.

Details

Published by

kdricha0602 on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Trend, Oscillators & momentum, Moving averages, Volatility & bands

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Topics

pine-scripttradingview-pro-2026

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
EMA Fastint21emaFastLen
EMA Slowint50emaSlowLen
EMA Long / Regimeint200emaLongLen
ATR Lengthint10stLen
Multiplierfloat3.0stMult
DI / ADX Lengthint14adxLen
ADX Thresholdfloat20.0adxThresh
Channel Lengthint10wtN1
Average Lengthint21wtN2
RSI Lengthint14rsiLen
Stochastic Lengthint14stochLen
Smooth Kint3smoothK
Show all 33 settings
SettingTypeDefaultVariable
Smooth Dint3smoothD
Pivot Lookback Leftint5lbL
Pivot Lookback Rightint5lbR
Minimum Pivot Gapint5divMinBars
Maximum Pivot Gapint60divMaxBars
ATR Lengthint14atrLen
Stop Multiplierfloat2.0atrMult
Range Band Multiplierfloat1.5rngMult
Show ATR Range BandsbooltrueshowBands
Volume SMA Lengthint20volLen
Volume Multiplierfloat1.5volMult
Require Volume ConfirmationbooltrueuseVolFilter
Benchmark SymbolsymbolAMEX:SPYbenchSym
Beta Lookbackint60betaLen
Minimum Betafloat0.7betaMin
Require Minimum BetaboolfalseuseBetaFilter
Long Score >=int4longThresh
Short Score >= (absolute)int4shortThresh
Long Signals OnlyboolfalselongOnly
Show DashboardbooltrueshowDash
Regime Background TintbooltrueshowBg
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

114 stars

ADX Strategy (original) is an overlay indicator that identifies trend-following trade signals using the Average Directional Index (ADX) combined with a Simple Moving Average filter. A long signal is generated when the ADX rises above a user-defined trend level

Indicator v4 TrendOscillators & momentum
Updated 1 year ago · None stated GitHub repository of ADX Strategy (original)
56 stars

Double Screened Decision is a multi-timeframe trend and momentum indicator overlaid directly on the price chart. It dynamically selects a higher timeframe based on the active chart resolution to evaluate higher-timeframe MACD, Bollinger Bands, RSI, and Stochas

Indicator v5 TrendMoving averages Repaints
Updated 4 months ago · None stated GitHub repository of Double Screened Decision
24 stars

This indicator plots Bollinger Bands on the price chart alongside a baseline moving average to identify trend-aligned swing setups. It calculates trend bias by comparing the Bollinger Bands basis to a customizable moving average, such as a 200 EMA. Trade signa

Indicator v5 Volatility & bandsOscillators & momentum
Updated 4 years ago · MPL-2.0 GitHub repository of Bollinger Band Swing

Index Intraday Analyst

by chris-c-thomas
14 stars

Index Intraday Analyst overlays CBOE cash indices such as SPX, NDX, RUT, and DJX. It plots a multi-EMA ribbon, a session-anchored TWAP with standard-deviation bands, and session levels such as prior-day high, low, and close, the opening range, and the high and

Indicator v6 TrendOscillators & momentum
Updated 6 months ago · MIT GitHub repository of Index Intraday Analyst

RePaNoCHa V4

by wocclyl
9 stars

RePaNoCHa V4 is an overlay alert indicator that plots a Tillson T3 moving average on the price chart and colors it by whether the line is rising or falling. It combines that slope with a range filter, ADX, parabolic SAR, RSI, and MACD to mark long and short si

Indicator v4 TrendOscillators & momentum
Updated 7 years ago · MIT GitHub repository of RePaNoCHa V4

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers