mtf_trend_alignment.pine
Copy
//@version=6
// ============================================================================
// MTF Trend Alignment Dashboard [WavesUnchained]
// Version: 1.0.0
// Author: WavesUnchained
// Build: 2026-02-23 00:00:00
// ============================================================================
// Scores trend alignment across up to four timeframes using Supertrend and
// volatility regime classification, combining results into a 0–100 confluence score.
//
// Features:
// ✓ Four timeframe analysis (current + three configurable HTFs)
// ✓ Supertrend direction and strength per timeframe
// ✓ Volatility regime classification per timeframe
// ✓ Overall alignment score (0–100)
// ✓ Visual trend matrix dashboard
// ✓ Entry quality signals from cross-timeframe confluence
//
// ============================================================================
indicator("MTF Trend Alignment Dashboard [WavesUnchained]", "📊 MTF Alignment", overlay=false, max_boxes_count=50)
import WavesUnchained/RTAFramework/1 as RTA
// ============================================================================
// USER INPUTS
// ============================================================================
// --- Timeframe Settings ---
var g1 = "⏰ Timeframes"
timeframe1 = input.timeframe("60", "HTF 1", group=g1)
timeframe2 = input.timeframe("240", "HTF 2", group=g1)
timeframe3 = input.timeframe("D", "HTF 3", group=g1)
// --- Supertrend Settings ---
var g2 = "📈 Supertrend"
stFactor = input.float(3.0, "Factor", minval=1.0, maxval=10.0, step=0.1, group=g2)
stLength = input.int(10, "ATR Length", minval=5, maxval=50, group=g2)
// --- Volatility Regime ---
var g3 = "💨 Volatility"
enableVolatility = input.bool(true, "Show Volatility Regime", group=g3)
volLookback = input.int(100, "Lookback Period", minval=20, maxval=500, group=g3)
// --- Alignment Scoring ---
var g4 = "🎯 Alignment"
minAlignmentScore = input.int(75, "Min Score for Signal", minval=0, maxval=100, group=g4)
requireAllAligned = input.bool(false, "Require All Timeframes", group=g4)
// --- Display ---
var g5 = "🎨 Display"
showMatrix = input.bool(true, "Show Trend Matrix", group=g5)
showScorePlot = input.bool(true, "Plot Alignment Score", group=g5)
dashboardSize = input.string("normal", "Dashboard Size",
options=["tiny", "small", "normal", "large"], group=g5)
// ============================================================================
// CALCULATE LOCAL TIMEFRAME
// ============================================================================
var ltfRegime = RTA.newVolatilityRegime()
RTA.updateVolatilityRegime(ltfRegime, 14, volLookback)
ltfConfig = RTA.newSupertrendConfig(stFactor, stLength)
[ltfLine, ltfDir] = RTA.calculateSupertrend(ltfConfig)
ltfTrend = ltfDir == 1 ? "BULLISH" : "BEARISH"
ltfColor = ltfDir == 1 ? color.new(color.green, 0) : color.new(color.red, 0)
// ============================================================================
// CALCULATE HIGHER TIMEFRAMES
// ============================================================================
// HTF 1
htf1Dir = request.security(syminfo.tickerid, timeframe1,
RTA.getSupertrendDirection(stFactor, stLength),
lookahead=barmerge.lookahead_off)
htf1Trend = htf1Dir == 1 ? "BULLISH" : "BEARISH"
htf1Color = htf1Dir == 1 ? color.new(color.green, 0) : color.new(color.red, 0)
// HTF 2
htf2Dir = request.security(syminfo.tickerid, timeframe2,
RTA.getSupertrendDirection(stFactor, stLength),
lookahead=barmerge.lookahead_off)
htf2Trend = htf2Dir == 1 ? "BULLISH" : "BEARISH"
htf2Color = htf2Dir == 1 ? color.new(color.green, 0) : color.new(color.red, 0)
// HTF 3
htf3Dir = request.security(syminfo.tickerid, timeframe3,
RTA.getSupertrendDirection(stFactor, stLength),
lookahead=barmerge.lookahead_off)
htf3Trend = htf3Dir == 1 ? "BULLISH" : "BEARISH"
htf3Color = htf3Dir == 1 ? color.new(color.green, 0) : color.new(color.red, 0)
// ============================================================================
// CALCULATE ALIGNMENT SCORE
// ============================================================================
// Count bullish timeframes
bullishCount = (ltfDir == 1 ? 1 : 0) +
(htf1Dir == 1 ? 1 : 0) +
(htf2Dir == 1 ? 1 : 0) +
(htf3Dir == 1 ? 1 : 0)
// Calculate alignment score (0-100)
// 100 = all aligned, 50 = mixed, 0 = opposite alignment
alignmentScore = 0.0
if bullishCount == 4 or bullishCount == 0
// Perfect alignment (all bullish or all bearish)
alignmentScore := 100.0
else if bullishCount == 3 or bullishCount == 1
// Strong alignment (3 of 4)
alignmentScore := 75.0
else
// No alignment (2-2 split)
alignmentScore := 50.0
// Determine overall direction
overallDirection = bullishCount >= 3 ? "BULLISH" :
bullishCount <= 1 ? "BEARISH" : "MIXED"
// ============================================================================
// CONFLUENCE CALCULATION
// ============================================================================
// Weight higher timeframes more
ltfWeight = 1.0
htf1Weight = 1.5
htf2Weight = 2.0
htf3Weight = 2.5
totalWeight = ltfWeight + htf1Weight + htf2Weight + htf3Weight
// Calculate weighted bullish percentage
bullishWeighted = (ltfDir == 1 ? ltfWeight : 0) +
(htf1Dir == 1 ? htf1Weight : 0) +
(htf2Dir == 1 ? htf2Weight : 0) +
(htf3Dir == 1 ? htf3Weight : 0)
confluenceScore = (bullishWeighted / totalWeight) * 100
// ============================================================================
// ENTRY SIGNAL LOGIC
// ============================================================================
// Strong bullish signal
strongBullish = alignmentScore >= minAlignmentScore and
overallDirection == "BULLISH" and
(not requireAllAligned or bullishCount == 4)
// Strong bearish signal
strongBearish = alignmentScore >= minAlignmentScore and
overallDirection == "BEARISH" and
(not requireAllAligned or bullishCount == 0)
// Entry quality (0-100)
entryQuality = 0.0
if strongBullish or strongBearish
// Base quality from alignment
baseQuality = alignmentScore
// Bonus from volatility regime
volBonus = 0.0
if enableVolatility
if ltfRegime.isExpansion
volBonus := 10.0 // Trending conditions
else if ltfRegime.isCompression and ltfRegime.breakoutProbability > 70
volBonus := 15.0 // Breakout setup
entryQuality := math.min(100, baseQuality + volBonus)
// ============================================================================
// PLOTS - ALIGNMENT SCORE
// ============================================================================
if showScorePlot
plot(alignmentScore, "Alignment Score", color.new(color.blue, 0), 2)
plot(confluenceScore, "Confluence Score", color.new(color.purple, 30), 1)
hline(100, "Perfect", color.new(color.gray, 80), hline.style_dotted)
hline(75, "Strong", color.new(color.gray, 80), hline.style_dotted)
hline(50, "Neutral", color.new(color.gray, 60), hline.style_solid)
hline(minAlignmentScore, "Min Signal", color.new(color.orange, 50), hline.style_dashed)
// Background color for signals
bgcolor(strongBullish ? color.new(color.green, 90) :
strongBearish ? color.new(color.red, 90) : na)
// ============================================================================
// DASHBOARD - TREND MATRIX
// ============================================================================
if showMatrix and barstate.islast
// Determine size
cellSize = dashboardSize == "tiny" ? size.tiny :
dashboardSize == "small" ? size.small :
dashboardSize == "large" ? size.large : size.normal
var table matrix = table.new(position.top_right, 3, 7,
border_width=2,
border_color=color.new(color.gray, 50),
frame_width=1,
frame_color=color.new(color.gray, 70))
// === HEADER ===
table.cell(matrix, 0, 0, "📊 MTF ALIGNMENT",
text_color=color.white,
bgcolor=color.new(color.blue, 20),
text_size=cellSize,
text_halign=text.align_center)
table.merge_cells(matrix, 0, 0, 2, 0)
// === TIMEFRAME LABELS ===
table.cell(matrix, 0, 1, "Timeframe", text_color=color.gray, text_size=cellSize)
table.cell(matrix, 1, 1, "Trend", text_color=color.gray, text_size=cellSize)
table.cell(matrix, 2, 1, "Status", text_color=color.gray, text_size=cellSize)
// === LOCAL TIMEFRAME ===
table.cell(matrix, 0, 2, timeframe.period, text_color=color.white, text_size=cellSize)
table.cell(matrix, 1, 2, ltfTrend, text_color=ltfColor, text_size=cellSize)
table.cell(matrix, 2, 2, ltfDir == 1 ? "🟢" : "🔴",
text_color=color.white, text_size=cellSize)
// === HTF 1 ===
table.cell(matrix, 0, 3, timeframe1, text_color=color.white, text_size=cellSize)
table.cell(matrix, 1, 3, htf1Trend, text_color=htf1Color, text_size=cellSize)
table.cell(matrix, 2, 3, htf1Dir == 1 ? "🟢" : "🔴",
text_color=color.white, text_size=cellSize)
// === HTF 2 ===
table.cell(matrix, 0, 4, timeframe2, text_color=color.white, text_size=cellSize)
table.cell(matrix, 1, 4, htf2Trend, text_color=htf2Color, text_size=cellSize)
table.cell(matrix, 2, 4, htf2Dir == 1 ? "🟢" : "🔴",
text_color=color.white, text_size=cellSize)
// === HTF 3 ===
table.cell(matrix, 0, 5, timeframe3, text_color=color.white, text_size=cellSize)
table.cell(matrix, 1, 5, htf3Trend, text_color=htf3Color, text_size=cellSize)
table.cell(matrix, 2, 5, htf3Dir == 1 ? "🟢" : "🔴",
text_color=color.white, text_size=cellSize)
// === SEPARATOR ===
table.cell(matrix, 0, 6, "", bgcolor=color.new(color.gray, 80))
table.merge_cells(matrix, 0, 6, 2, 6)
// === ALIGNMENT SCORE ===
table.cell(matrix, 0, 7, "Alignment",
text_color=color.gray, text_size=cellSize)
table.cell(matrix, 1, 7,
str.format("{0}/100", str.tostring(alignmentScore, "#")),
text_color=alignmentScore >= 75 ? color.lime :
alignmentScore >= 50 ? color.yellow : color.red,
text_size=cellSize)
table.merge_cells(matrix, 1, 7, 2, 7)
// ============================================================================
// DASHBOARD - DETAILS
// ============================================================================
if barstate.islast
cellSize = dashboardSize == "tiny" ? size.tiny :
dashboardSize == "small" ? size.small :
dashboardSize == "large" ? size.large : size.normal
var table details = table.new(position.bottom_right, 2, 6,
border_width=1,
border_color=color.new(color.gray, 60),
frame_width=1,
frame_color=color.new(color.gray, 70))
// === OVERALL DIRECTION ===
directionColor = overallDirection == "BULLISH" ? color.new(color.green, 20) :
overallDirection == "BEARISH" ? color.new(color.red, 20) :
color.new(color.gray, 50)
table.cell(details, 0, 0, "Direction",
text_color=color.gray, text_size=cellSize)
table.cell(details, 1, 0, overallDirection,
text_color=color.white,
bgcolor=directionColor,
text_size=cellSize,
text_halign=text.align_center)
// === CONFLUENCE ===
table.cell(details, 0, 1, "Confluence",
text_color=color.gray, text_size=cellSize)
table.cell(details, 1, 1,
str.format("{0}%", str.tostring(confluenceScore, "#.#")),
text_color=color.white, text_size=cellSize)
// === ENTRY QUALITY ===
if entryQuality > 0
table.cell(details, 0, 2, "Entry Quality",
text_color=color.gray, text_size=cellSize)
table.cell(details, 1, 2,
str.format("{0}/100", str.tostring(entryQuality, "#")),
text_color=entryQuality >= 80 ? color.lime :
entryQuality >= 60 ? color.yellow : color.orange,
text_size=cellSize)
else
table.cell(details, 0, 2, "Entry Quality",
text_color=color.gray, text_size=cellSize)
table.cell(details, 1, 2, "No Setup",
text_color=color.new(color.gray, 50), text_size=cellSize)
// === VOLATILITY REGIME ===
if enableVolatility
regimeColor = ltfRegime.isCompression ? color.new(color.blue, 20) :
ltfRegime.isExpansion ? color.new(color.orange, 20) :
color.new(color.gray, 50)
table.cell(details, 0, 3, "Volatility",
text_color=color.gray, text_size=cellSize)
table.cell(details, 1, 3, ltfRegime.regimeType,
text_color=color.white,
bgcolor=regimeColor,
text_size=cellSize,
text_halign=text.align_center)
// Regime details
regimeDetail = ltfRegime.isCompression ?
str.format("Breakout: {0}%", str.tostring(ltfRegime.breakoutProbability, "#")) :
ltfRegime.isExpansion ?
str.format("Score: {0}", str.tostring(ltfRegime.volatilityScore, "#")) :
str.format("P{0}", str.tostring(ltfRegime.atrPercentile, "#"))
table.cell(details, 0, 4, "Details",
text_color=color.gray, text_size=cellSize)
table.cell(details, 1, 4, regimeDetail,
text_color=color.white, text_size=cellSize)
// === RECOMMENDATION ===
recommendation = strongBullish ? "🟢 LONG SETUP" :
strongBearish ? "🔴 SHORT SETUP" :
alignmentScore < 50 ? "⚠️ NO ALIGNMENT" :
"⏳ WAIT"
recColor = strongBullish ? color.new(color.green, 20) :
strongBearish ? color.new(color.red, 20) :
color.new(color.gray, 50)
table.cell(details, 0, 5, "Signal",
text_color=color.gray, text_size=cellSize)
table.cell(details, 1, 5, recommendation,
text_color=color.white,
bgcolor=recColor,
text_size=cellSize,
text_halign=text.align_center)
// ============================================================================
// ALERTS
// ============================================================================
alertcondition(strongBullish and strongBullish[1] == false,
"Strong Bullish Alignment",
"MTF Alignment: Strong bullish setup detected")
alertcondition(strongBearish and strongBearish[1] == false,
"Strong Bearish Alignment",
"MTF Alignment: Strong bearish setup detected")
alertcondition(alignmentScore >= 100 and alignmentScore[1] < 100,
"Perfect Alignment",
"MTF Alignment: All timeframes aligned")
if enableVolatility
alertcondition(ltfRegime.isCompression and ltfRegime.breakoutProbability > 80,
"High Breakout Probability",
str.format("Volatility: {0}% breakout probability",
str.tostring(ltfRegime.breakoutProbability, "#")))
Show all 370 lines