Skip to content

[Indicator] SuperTrend Confluence Signals #11

@MDUYN

Description

@MDUYN

Indicator Name

SuperTrend Confluence Signals

Category

Trend

Description

OVERVIEW
This script enhances the classic SuperTrend indicator by integrating volume dynamics, retracement detection, and a multi-asset trend matrix—alongside an automatic mitigation-level drawing system. It's designed for traders who want to see not just trend direction, but the confluence of trend strength, volatility-adjusted retracements, and capital flow through volume pressure. It visually maps key transitions in market structure while offering a clean, color-coded overview of multiple symbols and timeframes in a single chart.

CONCEPTS
At the core is the traditional SuperTrend , which determines directional bias using Average True Range (ATR) with a volatility multiplier. This script overlays that with a dynamic volume histogram that scales relative to recent volume standard deviation, coloring volume bursts within the trend. Retracement signals are triggered when price pulls back toward the SuperTrend level but respects it—quantified through normalized distance sensitivity. On top of that, the indicator automatically draws and manages horizontal support/resistance zones that appear at key trend shifts. These levels persist and are cleared based on configurable rules such as wick/body sweeps or consecutive candle closes. A multi-asset, multi-timeframe table then gives an instant snapshot of trend status across five user-defined symbols and timeframes.

FEATURES

SuperTrend : Configurable ATR length and multiplier for flexible trend sensitivity.
snapshot
Volumetric Histogram: Gradient-filled candles anchored to SuperTrend bands, scaled by relative volume to indicate activity intensity during trends.
snapshot
Retracement Arrows: Signals printed when price nears the SuperTrend level without breaking it, allowing identification of high-probability continuation zones.
snapshot
Volume TP Markers: Diamond markers flag high-volume events, contextualizing price moves with liquidity bursts.
snapshot
Automatic Structure Levels: Draws clean horizontal lines at significant trend transitions, with optional volatility-based band fills. These levels self-update and clear based on price interaction logic.
snapshot
Trend Table: Displays trend direction (▲/▼) across five assets and five timeframes. Each cell is colored according to trend bias, providing a compact overview for multi-market confluence.
snapshot

USAGE
Start by loading the indicator on your main chart and adjusting the ATR Length and Multiplier to match your strategy timeframe. Use lower values for scalping and higher values for swing trading. The histogram bars will appear as colored candles above or below the SuperTrend level, indicating how strong volume is within that trend. Arrow signals suggest minor pullbacks within the trend, which can act as entry opportunities. The level system will automatically plot key price zones during trend flips; if "Body" is selected for mitigation, price must close through the level to invalidate it. If "Wick" is chosen, a single wick breach is enough. Adjust expiry and rejection settings to fine-tune how long levels stay on chart. Finally, enable the Multi-Asset Table to view live trend signals across popular symbols like AAPL or NVDA in different timeframes, helping spot macro-to-micro alignment for higher-confidence trades.

Reference Chart(s)

Image

Chart Description

See uploaded chart

Parameters

  • period (int, default=14):
  • source_column (str, default='Close'):

Source / Reference

No response

Expected Output Columns

No response

Deliverables Checklist

  • Implementation in pyindicators/indicators/ (pandas + polars support)
  • Exports in __init__.py and __all__
  • Unit tests in tests/indicators/ (pandas, polars, edge cases)
  • Documentation page in docs/content/indicators/ with chart image
  • Sidebar registration in docs/sidebars.js
  • Entry in README.md features list
  • Analysis notebook in analysis/indicators/ with plotly chart

Additional Context

//@Version=6
indicator("SuperTrend Confluence Signals [AlgoAlpha]", "AlgoAlpha - SuperTrend Confluence", overlay=true, max_bars_back=500, max_lines_count=500)

atrLength = input.int(10, "ATR Length", minval=1, maxval=100, group="Supertrend", tooltip="ATR calculation period. Decrease for more sensitive signals, increase for smoother trends.")
factor = input.float(3.0, "Multiplier", minval=0.1, maxval=10.0, step=0.1, group="Supertrend", tooltip="Band distance from price. Decrease for more frequent signals, increase for stronger trends.")
maxScale = input.float(4.0, "Volume Scale", minval=0.1, maxval=10.0, group="Volume", tooltip="Volume bar height. Increase for taller bars, decrease for compact display.")
volThreshold = input.float(3.0, "Volume TP", minval=0.7, maxval=10.0, step=0.5, group="Volume", tooltip="Volume alert level. Decrease for more markers, increase for only extreme volume.")
arrowThreshold = input.float(0.5, "Retracement Sensitivity", minval=0.1, maxval=3.0, step=0.1, group="Signals", tooltip="Retracement sensitivity. increase for more arrows, Decrease for fewer arrows.")
expiry_age = input.int(1000, "Max Level Age", minval=1, group="Level Management", tooltip="Number of bars after which a level will be automatically removed")
mitigate = input.string("body", "Sweep Type", options=["wick", "body"], group="Level Management", tooltip="Body: level removed when price body (close) crosses it; Wick: level removed when price wick crosses it")
allow_rejection = input.bool(false, "Allow Rejection", group="Level Management", tooltip="When enabled with body sweep type, requires two consecutive closes beyond level to remove it")
asset1 = input.symbol("AAPL", "Asset 1", group="Multi-Asset Table", inline="assets1")
asset2 = input.symbol("MSFT", "Asset 2", group="Multi-Asset Table", inline="assets1")
asset3 = input.symbol("GOOGL", "Asset 3", group="Multi-Asset Table", inline="assets2")
asset4 = input.symbol("TSLA", "Asset 4", group="Multi-Asset Table", inline="assets2")
asset5 = input.symbol("NVDA", "Asset 5", group="Multi-Asset Table", inline="assets3")
tf1 = input.timeframe("5", "Timeframe 1", group="Multi-Asset Table", inline="timeframes1")
tf2 = input.timeframe("15", "Timeframe 2", group="Multi-Asset Table", inline="timeframes1")
tf3 = input.timeframe("60", "Timeframe 3", group="Multi-Asset Table", inline="timeframes2")
tf4 = input.timeframe("240", "Timeframe 4", group="Multi-Asset Table", inline="timeframes2")
tf5 = input.timeframe("1D", "Timeframe 5", group="Multi-Asset Table", inline="timeframes3")
showTable = input.bool(true, "Show Table", group="Multi-Asset Table", tooltip="Display multi-asset trend table.")
colBull = input.color(#00FFBB, "Bull Color", group="Appearance", tooltip="Color for uptrend elements.")
colBear = input.color(#FF1100, "Bear Color", group="Appearance", tooltip="Color for downtrend elements.")
table_size = input.string("Tiny", "Table Size", options=["Tiny","Small","Medium","Large"], group="Multi-Asset Table", tooltip="Size of the multi-asset table.")
table_position = input.string("top_right", "Table Position", options=["bottom_center","bottom_left","bottom_right","middle_center","middle_left","middle_right","top_center","top_left","top_right"], group="Multi-Asset Table", tooltip="Position of the multi-asset table.")
enableZigzag = input.bool(true, "Enable Zigzag", group="Level Management", tooltip="Enable or disable zigzag level drawing")

// FIRST_EDIT: define tableSize helper function here
tableSize(table_size) =>
switch table_size
"Tiny" => size.tiny
"Small" => size.small
"Medium"=> size.normal
"Large" => size.large

posFromString(str) =>
switch str
"bottom_center" => position.bottom_center
"bottom_left" => position.bottom_left
"bottom_right" => position.bottom_right
"middle_center" => position.middle_center
"middle_left" => position.middle_left
"middle_right" => position.middle_right
"top_center" => position.top_center
"top_left" => position.top_left
"top_right" => position.top_right

[supertrend, direction] = ta.supertrend(factor, atrLength)
supertrend := barstate.isfirst ? na : supertrend

offset = ta.sma(ta.atr(14), 300) * 1.2
supertrend_u = supertrend + offset
supertrend_l = supertrend - offset

dist_to_upper = math.abs(((high + low) / 2) - supertrend_u)
dist_to_lower = math.abs(((high + low) / 2) - supertrend_l)
max_dist = ta.sma(ta.atr(14), 300) * 3

transp_up = math.min(90, 50 + math.round((dist_to_upper / max_dist) * 40))
transp_down = math.min(90, 50 + math.round((dist_to_lower / max_dist) * 40))

volLen = 200
heightMult = 1.5
minAlpha = 20
maxAlpha = 80

volumeAvailable = not na(volume)
hlRange = high - low
avgHLRange = ta.sma(hlRange, volLen)
hlVolatility = hlRange / ta.stdev(hlRange, volLen)

n_vol = volumeAvailable ? math.min(maxScale, volume / ta.stdev(volume, volLen)) : math.min(maxScale, hlVolatility)
step = offset * heightMult / maxScale
trendChange = direction != direction[1]
trend_col = direction < 0 ? colBull : colBear
alphaVol = math.round(maxAlpha - (n_vol / maxScale) * (maxAlpha - minAlpha))
histCol = color.new(trend_col, alphaVol)

var float histTop = na
var float histBottom = na
histTop := na
histBottom := na
if not trendChange
if direction < 0
histBottom := supertrend_l
histTop := supertrend_l + step * n_vol
else
histTop := supertrend_u
histBottom := supertrend_u - step * n_vol

dist_to_upper_norm = dist_to_upper / max_dist
dist_to_lower_norm = dist_to_lower / max_dist
volatility = ta.atr(14)

bullishRetracement = direction < 0 and dist_to_lower_norm <= arrowThreshold
bearishRetracement = direction >= 0 and dist_to_upper_norm <= arrowThreshold

highVolumeThreshold = n_vol >= volThreshold

bodyMiddle = plot(barstate.isfirst ? na : (open + close) / 2, display=display.none)
upTrend = plot(direction < 0 ? supertrend_l : na, "Up Trend", color=colBull, style=plot.style_linebr, linewidth=2)
downTrend = plot(direction >= 0 ? supertrend_u : na, "Down Trend", color=colBear, style=plot.style_linebr, linewidth=2)

fill(bodyMiddle, upTrend, color=color.new(colBull, transp_down), fillgaps=false)
fill(bodyMiddle, downTrend, color=color.new(colBear, transp_up), fillgaps=false)

plotcandle(
histTop,
histTop,
histBottom,
histBottom,
"",
histCol,
histCol,
bordercolor=histCol
)

plotchar(bullishRetracement ? supertrend_l - (volatility * 1.2) : na, "Bullish Retracements", "▲", location.absolute, colBull, size=size.tiny)
plotchar(bearishRetracement ? supertrend_u + (volatility * 1.2) : na, "Bearish Retracements", "▼", location.absolute, colBear, size=size.tiny)
plotchar(highVolumeThreshold and direction < 0 ? 1 : na, "High Volume - Uptrend", "◆", location.abovebar, color.new(color.orange, 30), size=size.tiny)
plotchar(highVolumeThreshold and direction >= 0 ? 1 : na, "High Volume - Downtrend", "◆", location.belowbar, color.new(color.orange, 30), size=size.tiny)

getTrend(asset, tf) =>
request.security(asset, tf, direction < 0 ? 1 : -1)

if barstate.islast and showTable
var multiAssetTable = table.new(position=posFromString(table_position), columns=6, rows=6, bgcolor=chart.bg_color, border_width=1, border_color=chart.fg_color, frame_color=chart.fg_color, frame_width=1)

table.cell(multiAssetTable, 0, 0, "TF\\Asset", text_color=chart.fg_color, text_halign=text.align_center, text_size=tableSize(table_size))
table.cell(multiAssetTable, 1, 0, array.get(str.split(asset1, ":"), 1), text_color=chart.fg_color, text_halign=text.align_center, text_size=tableSize(table_size))
table.cell(multiAssetTable, 2, 0, array.get(str.split(asset2, ":"), 1), text_color=chart.fg_color, text_halign=text.align_center, text_size=tableSize(table_size))
table.cell(multiAssetTable, 3, 0, array.get(str.split(asset3, ":"), 1), text_color=chart.fg_color, text_halign=text.align_center, text_size=tableSize(table_size))
table.cell(multiAssetTable, 4, 0, array.get(str.split(asset4, ":"), 1), text_color=chart.fg_color, text_halign=text.align_center, text_size=tableSize(table_size))
table.cell(multiAssetTable, 5, 0, array.get(str.split(asset5, ":"), 1), text_color=chart.fg_color, text_halign=text.align_center, text_size=tableSize(table_size))

timeframes = array.from(tf1, tf2, tf3, tf4, tf5)
assets = array.from(asset1, asset2, asset3, asset4, asset5)

for i = 0 to 4
    tf = array.get(timeframes, i)
    table.cell(multiAssetTable, 0, i + 1, tf, text_color=chart.fg_color, text_halign=text.align_center, text_size=tableSize(table_size))
    
    for j = 0 to 4
        asset = array.get(assets, j)
        trendValue = getTrend(asset, tf)
        trendText = trendValue == 1 ? "▲" : "▼"
        cellColor = trendValue == 1 ? color.new(colBull, 70) : color.new(colBear, 70)
        table.cell(multiAssetTable, j + 1, i + 1, trendText, text_color=chart.fg_color, bgcolor=cellColor, text_halign=text.align_center, text_size=tableSize(table_size))

var lowest = 0.0
var highest = 0.0

var lowest_ = 0
var highest_ = 0

var new = 1

var levelHighArray = array.new_line()
var levelLowArray = array.new_line()
var levelHighArray1 = array.new_line()
var levelLowArray1 = array.new_line()

timing = math.max(nz(ta.barssince(direction != direction[1])), 1)
timing := math.min(timing, 250)

x = ta.lowest(low, timing)
x_ = ta.highest(high, timing)

y = math.min(ta.lowestbars(low, timing)-1, 250)
y_ = math.min(ta.highestbars(high, timing)-1, 250)

if direction < 0 and direction[1] >= 0
if new == 1
new := 0
lowest := x[1]
lowest_ := bar_index + y[1]
else
lowest := x[1]
lowest_ := bar_index + y[1]
if enableZigzag
line.new(highest_,highest,lowest_,lowest, color = colBear, width = 1)
levelHighArray.unshift(line.new(highest_, highest, bar_index+1, highest, color = colBear, width = 1))
levelHighArray1.unshift(line.new(highest_, highest-volatility/2, bar_index+1, highest-volatility/2, color = color.new(colBear, 80), width = 1))
linefill.new(levelHighArray.first(), levelHighArray1.first(), color.new(colBear, 80))

if direction >= 0 and direction[1] < 0
if new == 1
new := 0
highest := x_[1]
highest_ := bar_index + y_[1]
else
highest := x_[1]
highest_ := bar_index + y_[1]
if enableZigzag
line.new(lowest_,lowest,highest_,highest, color = colBull, width = 1)
levelLowArray.unshift(line.new(lowest_, lowest, bar_index+1, lowest, color = colBull, width = 1))
levelLowArray1.unshift(line.new(lowest_, lowest+volatility/2, bar_index+1, lowest+volatility/2, color = color.new(colBull, 80), width = 1))
linefill.new(levelLowArray.first(), levelLowArray1.first(), color.new(colBull, 80))

if levelHighArray.size() > 0
for ln = levelHighArray.size() - 1 to 0
if ln < levelHighArray.size()
cL = levelHighArray.get(ln)
cL_ = levelHighArray1.get(ln)
yL = cL.get_y1()
x1 = cL.get_x1()
age = bar_index - x1
is_body = mitigate == "body"
cross_body = close > yL
cross_body_confirmed = close > yL and close[1] > yL
cross_wick = high > yL
remove_by_mitigation = is_body ? (allow_rejection ? cross_body_confirmed : cross_body) : cross_wick

        if remove_by_mitigation or age > expiry_age
            levelHighArray.remove(ln)
            levelHighArray1.remove(ln)
        else
            cL.set_x2(bar_index + 1)
            cL_.set_x2(bar_index + 1)

if levelLowArray.size() > 0
for ln = levelLowArray.size() - 1 to 0
if ln < levelLowArray.size()
cL = levelLowArray.get(ln)
cL_ = levelLowArray1.get(ln)
yL = cL.get_y1()
x1 = cL.get_x1()
age = bar_index - x1
is_body = mitigate == "body"
cross_body = close < yL
cross_body_confirmed = close < yL and close[1] < yL
cross_wick = low < yL
remove_by_mitigation = is_body ? (allow_rejection ? cross_body_confirmed : cross_body) : cross_wick

        if remove_by_mitigation or age > expiry_age
            levelLowArray.remove(ln)
            levelLowArray1.remove(ln)
        else
            cL.set_x2(bar_index + 1)
            cL_.set_x2(bar_index + 1)

// Alerts
alertcondition(direction[1] > direction, title="Downtrend to Uptrend")
alertcondition(direction[1] < direction, title="Uptrend to Downtrend")
alertcondition(direction[1] != direction, title="Universal Trend Change")
alertcondition(bullishRetracement, title="Bullish Retracement Entries")
alertcondition(bearishRetracement, title="Bearish Retracement Entries")
alertcondition(highVolumeThreshold and direction < 0, title="Uptrend Volume TP")
alertcondition(highVolumeThreshold and direction >= 0, title="Downtrend Volume TP")

Metadata

Metadata

Assignees

No one assigned

    Labels

    squadSquad triage inbox — Lead will assign to a member

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions