//@version=6
// ============================================================================
// Vein Execution 15m [WavesUnchained]
// Version: 0.1.8
// Author: WavesUnchained
// Build: 2026-10-12
// ============================================================================
// Lean 15m execution/timing overlay that works WITH the 4H system.
// 4H = Context (where to look). 15m = Timing (when to act).
//
// Only activates when 4H has an interesting setup. Focuses on:
// ✓ Micro structure shifts (pivots, BOS, higher low / lower high)
// ✓ Liquidity sweeps (springs/upthrusts on 15m)
// ✓ Rejection candles + engulfing
// ✓ Follow-through / tempo validation
// ✓ Entry + invalidation signals
// ✓ Compact micro score (0-10)
//
// Data Contract:
// Price: REQUIRED chart symbol
// Volume: OPTIONAL real trade volume only — relVol degrades to neutral 1.0
// OI: NO
// Reference: NO
// Verdict: CFD-degraded
//
// ============================================================================
indicator("Vein: Execution 15m [WavesUnchained]", "Vein Exec", overlay=true, max_labels_count=200, max_lines_count=50)
// ============================================================================
// MODULE: inputs
// ============================================================================
var gHTF = "4H Context"
string htfTimeframe = input.timeframe("240", "HTF Timeframe", group=gHTF)
float activationThresh = input.float(2.0, "Min 4H Setup Score to Activate", minval=0.5, maxval=5.0, step=0.5, group=gHTF, tooltip="15m only works when 4H setup >= this value")
float zoneProximityATR = input.float(0.8, "Zone Proximity (ATR)", minval=0.2, maxval=3.0, step=0.1, group=gHTF, tooltip="Max distance to 4H zone for 'near zone' bonus")
var gMicro = "Micro Structure"
int microLeft = input.int(2, "Micro Pivot Left Bars", minval=1, maxval=5, group=gMicro)
int microRight = input.int(2, "Micro Pivot Right Bars", minval=1, maxval=5, group=gMicro)
int sweepLookback = input.int(10, "Sweep: Lookback Bars", minval=3, maxval=30, group=gMicro)
float sweepMinDepth = input.float(0.1, "Sweep: Min Depth (ATR)", minval=0.0, maxval=1.0, step=0.05, group=gMicro)
int sweepMaxBars = input.int(3, "Sweep: Max Bars to Reclaim", minval=1, maxval=8, group=gMicro)
var gCandle = "Candle Behaviour"
float rejWickThresh = input.float(0.45, "Rejection: Min Wick Ratio", minval=0.2, maxval=0.8, step=0.05, group=gCandle)
float engBodyRatio = input.float(0.6, "Engulfing: Min Body Ratio", minval=0.3, maxval=0.9, step=0.05, group=gCandle)
var gTempo = "Follow-Through"
int ftWindow = input.int(4, "Follow-Through Window (Bars)", minval=2, maxval=8, group=gTempo)
float ftMinMove = input.float(0.3, "Follow-Through Min Move (ATR)", minval=0.1, maxval=1.0, step=0.1, group=gTempo)
float entryScoreThresh = input.float(6.0, "Entry Min Micro Score", minval=1.0, maxval=10.0, step=0.5, group=gTempo, tooltip="Role-weighted micro score required to emit an entry (with a structure trigger). Behaviour/FT contribute weight rather than acting as a hard gate. Provisional default — not yet validated on data.")
var gDisplay = "Display"
string displayMode = input.string("Light", "Display Mode", options=["Light", "Debug"], group=gDisplay)
bool enableEntries = input.bool(false, "Enable Entry / Invalidation Signals", group=gDisplay,
tooltip="Default OFF: this module shows execution context/status. Turn on to emit entry and invalidation labels/alerts.")
bool showEntryLbl = input.bool(true, "Show Entry Labels", group=gDisplay)
bool showInvalLbl = input.bool(true, "Show Invalidation Labels", group=gDisplay)
bool showHTFLevels = input.bool(true, "Show 4H Reference Levels", group=gDisplay)
bool showTable = input.bool(true, "Show Status Table", group=gDisplay)
bool isDebug = displayMode == "Debug"
// ============================================================================
// MODULE: 4H context via request.security()
// ============================================================================
g_scores = "Vein Module Inputs"
htfTrendUp = input.source(close, "Vein Trend Up Source", group=g_scores,
tooltip="Connect to Trend module's bullish trend plot/source.")
htfTrendDown = input.source(close, "Vein Trend Down Source", group=g_scores,
tooltip="Connect to Trend module's bearish trend plot/source.")
htfBullSetup = input.source(close, "Vein Bull Setup Score Source", group=g_scores,
tooltip="Connect to Reversal/Structure module's bull score plot.")
htfBearSetup = input.source(close, "Vein Bear Setup Score Source", group=g_scores,
tooltip="Connect to Reversal/Structure module's bear score plot.")
// Unconnected input.source inputs default to the chart close. When both sources of a
// pair still read close, treat the pair as not connected: setup inactive, trend neutral.
bool setupSrcConnected = not (htfBullSetup == close and htfBearSetup == close)
bool trendSrcConnected = not (htfTrendUp == close and htfTrendDown == close)
float bullSetupSrc = setupSrcConnected ? htfBullSetup : na
float bearSetupSrc = setupSrcConnected ? htfBearSetup : na
float trendUpSrc = trendSrcConnected ? htfTrendUp : na
float trendDownSrc = trendSrcConnected ? htfTrendDown : na
// Reference levels pivots requested from HTF
htf_pivHi_raw = ta.pivothigh(high, 3, 3)
htf_pivLo_raw = ta.pivotlow(low, 3, 3)
htf_ema20_raw = ta.ema(close, 20)
htf_rsi_raw = ta.rsi(close, 14)
[htfPivHi, htfPivLo, htfEma20, htfRsi] = request.security(syminfo.tickerid, htfTimeframe, [htf_pivHi_raw, htf_pivLo_raw, htf_ema20_raw, htf_rsi_raw], lookahead=barmerge.lookahead_off)
// Persist last known 4H swing levels (pivots are sparse)
var float htfSwingHi = na
var float htfSwingLo = na
if not na(htfPivHi)
htfSwingHi := htfPivHi
if not na(htfPivLo)
htfSwingLo := htfPivLo
// ============================================================================
// MODULE: activation gate
// ============================================================================
bool htfHasBull = not na(bullSetupSrc) and bullSetupSrc >= activationThresh
bool htfHasBear = not na(bearSetupSrc) and bearSetupSrc >= activationThresh
bool isActive = htfHasBull or htfHasBear
// Bias: 1 = bull, -1 = bear, 0 = both/conflict
int bias = htfHasBull and not htfHasBear ? 1 : htfHasBear and not htfHasBull ? -1 : htfHasBull and htfHasBear ? 0 : 0
// ============================================================================
// MODULE: 15m base calculations
// ============================================================================
bool volumeIsReal = (ta.cum(nz(volume)) > 0 and syminfo.volumetype != "tick") and not na(volume)
float atr15m = ta.atr(14)
float ema9 = ta.ema(close, 9)
float avgVol = ta.sma(volume, 20)
float relVol = volumeIsReal and avgVol > 0 ? volume / avgVol : 1.0
float candleRange = high - low
float bodySize = math.abs(close - open)
float upperWick = candleRange > 0 ? (high - math.max(close, open)) / candleRange : 0.0
float lowerWick = candleRange > 0 ? (math.min(close, open) - low) / candleRange : 0.0
float bodyRatio = candleRange > 0 ? bodySize / candleRange : 0.0
bool isBullBar = close > open
bool isBearBar = close < open
// ============================================================================
// MODULE: micro pivots & BOS
// ============================================================================
float microPivHi = ta.pivothigh(high, microLeft, microRight)
float microPivLo = ta.pivotlow(low, microLeft, microRight)
// Persist last swing levels
var float lastMicroHi = na
var float lastMicroLo = na
var float prevMicroHi = na
var float prevMicroLo = na
if not na(microPivHi)
prevMicroHi := lastMicroHi
lastMicroHi := microPivHi
if not na(microPivLo)
prevMicroLo := lastMicroLo
lastMicroLo := microPivLo
// Micro BOS detection
bool microBullBOS = not na(lastMicroHi) and close > lastMicroHi and close[1] <= lastMicroHi
bool microBearBOS = not na(lastMicroLo) and close < lastMicroLo and close[1] >= lastMicroLo
// Structure shift detection
bool higherLow = not na(microPivLo) and not na(prevMicroLo) and microPivLo > prevMicroLo
bool lowerHigh = not na(microPivHi) and not na(prevMicroHi) and microPivHi < prevMicroHi
// ============================================================================
// MODULE: liquidity sweep detection
// ============================================================================
// Find recent swing low/high within lookback for sweep reference
var float sweepRefLo = na
var float sweepRefHi = na
// Use the last confirmed micro pivot as sweep reference
sweepRefLo := nz(lastMicroLo, sweepRefLo)
sweepRefHi := nz(lastMicroHi, sweepRefHi)
// Bull sweep: wick below reference low, close back above
bool sweepBullRaw = not na(sweepRefLo) and low < sweepRefLo and close > sweepRefLo
float sweepBullDepth = sweepBullRaw and atr15m > 0 ? (sweepRefLo - low) / atr15m : 0.0
bool sweepBull = sweepBullRaw and sweepBullDepth >= sweepMinDepth
// Bear sweep: wick above reference high, close back below
bool sweepBearRaw = not na(sweepRefHi) and high > sweepRefHi and close < sweepRefHi
float sweepBearDepth = sweepBearRaw and atr15m > 0 ? (high - sweepRefHi) / atr15m : 0.0
bool sweepBear = sweepBearRaw and sweepBearDepth >= sweepMinDepth
// Track sweep confirmation (holds on next bars)
var int sweepBullAge = 999
var int sweepBearAge = 999
var float sweepBullLevel = na
var float sweepBearLevel = na
if sweepBull
sweepBullAge := 0
sweepBullLevel := low
else
sweepBullAge += 1
if sweepBear
sweepBearAge := 0
sweepBearLevel := high
else
sweepBearAge += 1
bool sweepBullConfirmed = sweepBullAge >= 1 and sweepBullAge <= sweepMaxBars and close > nz(sweepRefLo)
bool sweepBearConfirmed = sweepBearAge >= 1 and sweepBearAge <= sweepMaxBars and close < nz(sweepRefHi)
// ============================================================================
// MODULE: rejection & candle patterns
// ============================================================================
// Bull rejection: long lower wick, small body, bias-aligned
bool bullRejection = lowerWick >= rejWickThresh and bodyRatio < 0.4 and (bias >= 0 or not isActive)
// Bear rejection: long upper wick, small body
bool bearRejection = upperWick >= rejWickThresh and bodyRatio < 0.4 and (bias <= 0 or not isActive)
// Engulfing
float prevBody = math.abs(close[1] - open[1])
bool bullEngulfing = isBullBar and close > open[1] and open < close[1] and bodySize > prevBody * engBodyRatio and bodySize > candleRange * 0.5
bool bearEngulfing = isBearBar and close < open[1] and open > close[1] and bodySize > prevBody * engBodyRatio and bodySize > candleRange * 0.5
// Range expansion after BOS
float avgRange = ta.sma(candleRange, 14)
bool rangeExpansion = candleRange > avgRange * 1.3 and relVol > 1.0
// ============================================================================
// MODULE: follow-through / tempo
// ============================================================================
// Track triggers for follow-through check
var int bullTriggerAge = 999
var float bullTriggerPrice = na
var int bearTriggerAge = 999
var float bearTriggerPrice = na
// A trigger fires on sweep or BOS in bias direction
bool newBullTrigger = isActive and (bias >= 0) and (sweepBull or microBullBOS)
bool newBearTrigger = isActive and (bias <= 0) and (sweepBear or microBearBOS)
if newBullTrigger
bullTriggerAge := 0
bullTriggerPrice := close
else
bullTriggerAge += 1
if newBearTrigger
bearTriggerAge := 0
bearTriggerPrice := close
else
bearTriggerAge += 1
// Follow-through: price moved in signal direction within window
bool bullFT = bullTriggerAge > 0 and bullTriggerAge <= ftWindow and not na(bullTriggerPrice) and atr15m > 0 and (close - bullTriggerPrice) / atr15m >= ftMinMove
bool bearFT = bearTriggerAge > 0 and bearTriggerAge <= ftWindow and not na(bearTriggerPrice) and atr15m > 0 and (bearTriggerPrice - close) / atr15m >= ftMinMove
// ============================================================================
// MODULE: micro score (0-10)
// ============================================================================
// Distance to the 4H swing levels — kept as a control/diagnosis reference for the
// dashboard only. Per the role ruleset, proximity to a (HTF) pivot does NOT feed the
// micro score; it is shown but never scored.
float distToHTFSup = not na(htfSwingLo) and atr15m > 0 ? math.abs(close - htfSwingLo) / atr15m : 999.0
float distToHTFRes = not na(htfSwingHi) and atr15m > 0 ? math.abs(close - htfSwingHi) / atr15m : 999.0
bool nearHTFZone = (bias >= 0 and distToHTFSup <= zoneProximityATR) or (bias <= 0 and distToHTFRes <= zoneProximityATR)
// This module has ONE score: the 15m timing evidence. The 4H setup is consumed as the
// activation/context evidence (single score path) — it is NOT re-built into a parallel
// internal setup score. microScore = Evidence(4H) + Structure + Behaviour + Tempo,
// each computed 0..1 within its role, then combined with role weights (total ≈ 0..10).
// --- Evidence role (0..1) — strength of the gating 4H setup ---
float activeSetup = bias == 1 ? nz(bullSetupSrc) : bias == -1 ? nz(bearSetupSrc) : math.max(nz(bullSetupSrc), nz(bearSetupSrc))
float evidenceRole = activationThresh > 0 ? math.min(activeSetup / (activationThresh * 2.0), 1.0) : 0.0
// --- Structure role (0..1) — 15m micro events ---
float structRaw = 0.0
if bias >= 0
structRaw += sweepBull ? 1.0 : 0.0
structRaw += sweepBullConfirmed ? 1.0 : 0.0
structRaw += microBullBOS ? 1.0 : 0.0
structRaw += higherLow ? 1.0 : 0.0
if bias <= 0
structRaw += sweepBear ? 1.0 : 0.0
structRaw += sweepBearConfirmed ? 1.0 : 0.0
structRaw += microBearBOS ? 1.0 : 0.0
structRaw += lowerHigh ? 1.0 : 0.0
if bias == 0
structRaw := structRaw / 2.0 // dampen during conflict
float structRole = math.min(structRaw / 4.0, 1.0)
// --- Behaviour role (0..1) — candle character ---
float behRaw = 0.0
if bias >= 0
behRaw += (bullRejection or bullEngulfing) ? 1.0 : 0.0
behRaw += (isBullBar and rangeExpansion) ? 1.0 : 0.0
if bias <= 0
behRaw += (bearRejection or bearEngulfing) ? 1.0 : 0.0
behRaw += (isBearBar and rangeExpansion) ? 1.0 : 0.0
if bias == 0
behRaw := behRaw / 2.0
float behRole = math.min(behRaw / 2.0, 1.0)
// --- Tempo role (0..1) — follow-through ---
float tempoRole = 0.0
if bias >= 0 and bullFT
tempoRole := 1.0
if bias <= 0 and bearFT
tempoRole := 1.0
// --- Role-weighted micro score (≈0..10): Evidence 3 · Structure 4 · Behaviour 2 · Tempo 1 ---
float microScore = isActive ? 3.0 * evidenceRole + 4.0 * structRole + 2.0 * behRole + 1.0 * tempoRole : 0.0
// Component scores retained on the original scales for the status table / data window.
float setupScore = 3.0 * evidenceRole
float structScore = 4.0 * structRole
float behScore = 2.0 * behRole
float tempoScore = 1.0 * tempoRole
// ============================================================================
// MODULE: status logic
// ============================================================================
bool hasStructureTrigger = (bias >= 0 and (sweepBull or sweepBullConfirmed or microBullBOS)) or (bias <= 0 and (sweepBear or sweepBearConfirmed or microBearBOS))
string microStatus = "QUIET"
if not isActive
microStatus := "QUIET"
else if microScore >= 7.0 and hasStructureTrigger
microStatus := "TRIGGER"
else if microScore >= 5.0 and hasStructureTrigger
microStatus := "SETUP"
else if microScore >= 3.0
microStatus := "WATCH"
else
microStatus := "QUIET"
// Effective direction for signals
int signalDir = bias == 1 ? 1 : bias == -1 ? -1 : (nz(bullSetupSrc) > nz(bearSetupSrc) ? 1 : -1)
// ============================================================================
// MODULE: entry & invalidation signals
// ============================================================================
// Entry conditions — evidence scoring, not a hard AND chain.
// Trigger = a 15m structure event firing in the bias direction (timing).
// Weight = the role-weighted micro score must clear entryScoreThresh.
// Behaviour/follow-through now contribute weight (via microScore) instead of acting
// as a separate mandatory gate, so a strong-structure entry is no longer vetoed by a
// single missing candle-character condition.
bool bullTrigger = signalDir == 1 and (sweepBull or sweepBullConfirmed or microBullBOS)
bool bearTrigger = signalDir == -1 and (sweepBear or sweepBearConfirmed or microBearBOS)
bool entryBull = enableEntries and isActive and bullTrigger and microScore >= entryScoreThresh
bool entryBear = enableEntries and isActive and bearTrigger and microScore >= entryScoreThresh
// Track active entries for invalidation
var bool bullEntryActive = false
var float bullEntryLevel = na
var float bullStopLevel = na
var int bullEntryBar = na
var bool bearEntryActive = false
var float bearEntryLevel = na
var float bearStopLevel = na
var int bearEntryBar = na
if entryBull and not entryBull[1]
bullEntryActive := true
bullEntryLevel := close
bullStopLevel := not na(sweepBullLevel) ? sweepBullLevel : nz(lastMicroLo)
bullEntryBar := bar_index
if entryBear and not entryBear[1]
bearEntryActive := true
bearEntryLevel := close
bearStopLevel := not na(sweepBearLevel) ? sweepBearLevel : nz(lastMicroHi)
bearEntryBar := bar_index
// Invalidation checks
bool bullInval = bullEntryActive and (close < nz(bullStopLevel) or microBearBOS)
bool bearInval = bearEntryActive and (close > nz(bearStopLevel) or microBullBOS)
if bullInval
bullEntryActive := false
if bearInval
bearEntryActive := false
// Also expire entries after extended time without follow-through
// (entry bar tracked directly — ta.valuewhen must not be called conditionally)
if bullEntryActive and not na(bullEntryBar) and bar_index - bullEntryBar > ftWindow * 3
bullEntryActive := false
if bearEntryActive and not na(bearEntryBar) and bar_index - bearEntryBar > ftWindow * 3
bearEntryActive := false
// ============================================================================
// MODULE: labels
// ============================================================================
// Entry labels
if showEntryLbl and entryBull and not entryBull[1]
label.new(bar_index, low, "ENTRY ▲", style=label.style_label_up, color=#00e676, textcolor=color.white, size=size.small)
if showEntryLbl and entryBear and not entryBear[1]
label.new(bar_index, high, "ENTRY ▼", style=label.style_label_down, color=#ff1744, textcolor=color.white, size=size.small)
// Invalidation labels
if showInvalLbl and bullInval and not bullInval[1]
label.new(bar_index, high, "INVAL ✗", style=label.style_label_down, color=#ff6d00, textcolor=color.white, size=size.tiny)
if showInvalLbl and bearInval and not bearInval[1]
label.new(bar_index, low, "INVAL ✗", style=label.style_label_up, color=#ff6d00, textcolor=color.white, size=size.tiny)
// Debug: sweep + BOS labels
if isDebug and sweepBull and bias >= 0 and isActive
label.new(bar_index, low, "SWP", style=label.style_label_up, color=color.new(#00e676, 50), textcolor=#00e676, size=size.tiny)
if isDebug and sweepBear and bias <= 0 and isActive
label.new(bar_index, high, "SWP", style=label.style_label_down, color=color.new(#ff1744, 50), textcolor=#ff1744, size=size.tiny)
if isDebug and microBullBOS and bias >= 0 and isActive
label.new(bar_index, low, "BOS↑", style=label.style_label_up, color=color.new(#00e676, 70), textcolor=#00e676, size=size.tiny)
if isDebug and microBearBOS and bias <= 0 and isActive
label.new(bar_index, high, "BOS↓", style=label.style_label_down, color=color.new(#ff1744, 70), textcolor=#ff1744, size=size.tiny)
// ============================================================================
// MODULE: 4H reference levels overlay
// ============================================================================
var line htfHiLine = na
var line htfLoLine = na
var line htfEma20Line = na
if showHTFLevels and barstate.islast
if not na(htfHiLine)
line.delete(htfHiLine)
if not na(htfLoLine)
line.delete(htfLoLine)
if not na(htfEma20Line)
line.delete(htfEma20Line)
if not na(htfSwingHi)
htfHiLine := line.new(bar_index - 50, htfSwingHi, bar_index + 5, htfSwingHi, color=color.new(#ff1744, 50), style=line.style_dashed, width=1)
if not na(htfSwingLo)
htfLoLine := line.new(bar_index - 50, htfSwingLo, bar_index + 5, htfSwingLo, color=color.new(#00e676, 50), style=line.style_dashed, width=1)
if not na(htfEma20)
htfEma20Line := line.new(bar_index - 50, htfEma20, bar_index + 5, htfEma20, color=color.new(#ffab00, 40), style=line.style_dotted, width=1)
// ============================================================================
// MODULE: background tint
// ============================================================================
color bgCol = microStatus == "TRIGGER" and signalDir == 1 ? color.new(#00e676, 92) : microStatus == "TRIGGER" and signalDir == -1 ? color.new(#ff1744, 92) : microStatus == "SETUP" ? color.new(#ffab00, 95) : na
bgcolor(bgCol)
// ============================================================================
// MODULE: status table
// ============================================================================
var table statusTbl = na
if showTable and barstate.islast
if na(statusTbl)
statusTbl := table.new(position.top_right, 2, 7, bgcolor=color.new(color.white, 100), border_color=color.new(color.gray, 80), border_width=0, frame_color=color.new(color.gray, 80), frame_width=0)
// Header
table.cell(statusTbl, 0, 0, "Vein Exec", text_color=chart.fg_color, text_size=size.normal)
color statusCol = microStatus == "TRIGGER" ? (signalDir == 1 ? #00e676 : #ff1744) : microStatus == "SETUP" ? #e65100 : microStatus == "WATCH" ? color.new(chart.fg_color, 30) : color.new(chart.fg_color, 60)
table.cell(statusTbl, 1, 0, microStatus, text_color=statusCol, text_size=size.normal, text_halign=text.align_right)
// 4H Context
string biasStr = bias == 1 ? "BULL" : bias == -1 ? "BEAR" : htfHasBull and htfHasBear ? "MIXED" : "QUIET"
color biasCol = bias == 1 ? #00e676 : bias == -1 ? #ff1744 : htfHasBull and htfHasBear ? #e65100 : color.new(chart.fg_color, 60)
table.cell(statusTbl, 0, 1, "4H Bias", text_color=color.new(chart.fg_color, 30), text_size=size.normal)
table.cell(statusTbl, 1, 1, biasStr + " " + str.tostring(math.max(nz(bullSetupSrc), nz(bearSetupSrc)), "#.0"), text_color=biasCol, text_size=size.normal, text_halign=text.align_right)
// Micro Score breakdown
table.cell(statusTbl, 0, 2, "Micro Score", text_color=color.new(chart.fg_color, 30), text_size=size.normal)
table.cell(statusTbl, 1, 2, str.tostring(microScore, "#.0") + " / 10", text_color=microScore >= 7 ? (signalDir == 1 ? #00e676 : #ff1744) : microScore >= 5 ? #e65100 : color.new(chart.fg_color, 60), text_size=size.normal, text_halign=text.align_right)
// Components
table.cell(statusTbl, 0, 3, "Set|Str|Beh|Tmp", text_color=color.new(chart.fg_color, 50), text_size=size.normal)
table.cell(statusTbl, 1, 3, str.tostring(setupScore, "#") + " | " + str.tostring(structScore, "#") + " | " + str.tostring(behScore, "#") + " | " + str.tostring(tempoScore, "#"), text_color=color.new(chart.fg_color, 30), text_size=size.normal, text_halign=text.align_right)
// Interpretation line
string interpStr = ""
if not isActive
if not setupSrcConnected
interpStr := "4H sources not connected"
else if nz(trendDownSrc) > 0 and nz(htfRsi) > 40
interpStr := "4H downtrend, no exhaustion — wait"
else if nz(trendUpSrc) > 0 and nz(htfRsi) < 60
interpStr := "4H uptrend, no overheating — wait"
else if nz(bullSetupSrc) > 0 or nz(bearSetupSrc) > 0
interpStr := "4H building (" + str.tostring(math.max(nz(bullSetupSrc), nz(bearSetupSrc)), "#.0") + ") — not yet active"
else
interpStr := "4H quiet — nothing to time"
else if microStatus == "TRIGGER"
interpStr := (signalDir == 1 ? "Bull" : "Bear") + " trigger: structure + behaviour confirmed"
else if microStatus == "SETUP"
interpStr := "Micro structure forming — waiting for confirmation"
else if microStatus == "WATCH"
interpStr := "4H active, 15m watching for structure shift"
else
interpStr := "Active but no micro signals yet"
color interpCol = microStatus == "TRIGGER" ? (signalDir == 1 ? #00e676 : #ff1744) : microStatus == "SETUP" ? #e65100 : color.new(chart.fg_color, 40)
table.cell(statusTbl, 0, 4, interpStr, text_color=interpCol, text_size=size.normal)
table.cell(statusTbl, 1, 4, "", text_size=size.normal)
// Entry status
string entryStr = bullEntryActive ? "BULL ENTRY active" : bearEntryActive ? "BEAR ENTRY active" : "—"
color entryCol = bullEntryActive ? #00e676 : bearEntryActive ? #ff1744 : color.new(chart.fg_color, 60)
table.cell(statusTbl, 0, 5, "Signal", text_color=color.new(chart.fg_color, 30), text_size=size.normal)
table.cell(statusTbl, 1, 5, entryStr, text_color=entryCol, text_size=size.normal, text_halign=text.align_right)
// 4H zone distance
float nearDist = bias >= 0 ? distToHTFSup : distToHTFRes
string distStr = nearDist < 999 ? str.tostring(nearDist, "#.1") + " ATR" : "—"
table.cell(statusTbl, 0, 6, "4H Zone", text_color=color.new(chart.fg_color, 30), text_size=size.normal)
table.cell(statusTbl, 1, 6, distStr, text_color=nearDist <= zoneProximityATR ? #00e676 : color.new(chart.fg_color, 30), text_size=size.normal, text_halign=text.align_right)
// ============================================================================
// MODULE: data window plots
// ============================================================================
plot(microScore, "Micro Score [dw]", display=display.data_window, color=color.new(color.gray, 100))
plot(setupScore, "Setup Score [dw]", display=display.data_window, color=color.new(color.gray, 100))
plot(structScore, "Structure Score [dw]", display=display.data_window, color=color.new(color.gray, 100))
plot(behScore, "Behaviour Score [dw]", display=display.data_window, color=color.new(color.gray, 100))
plot(tempoScore, "Tempo Score [dw]", display=display.data_window, color=color.new(color.gray, 100))
plot(nz(bullSetupSrc), "4H Bull Setup [dw]", display=display.data_window, color=color.new(color.gray, 100))
plot(nz(bearSetupSrc), "4H Bear Setup [dw]", display=display.data_window, color=color.new(color.gray, 100))
plot(bias, "Bias [dw]", display=display.data_window, color=color.new(color.gray, 100))
// ============================================================================
// MODULE: alerts
// ============================================================================
bool alertsOnBarClose = input.bool(true, "Alerts only on bar close (confirmed)", group="Alerts")
bool alertOk = not alertsOnBarClose or barstate.isconfirmed
alertcondition(alertOk and (microStatus == "TRIGGER" and signalDir == 1), "Bull Trigger", "VEIN-EXE · TRIGGER LONG · {{ticker}} {{interval}}")
alertcondition(alertOk and (microStatus == "TRIGGER" and signalDir == -1), "Bear Trigger", "VEIN-EXE · TRIGGER SHORT · {{ticker}} {{interval}}")
alertcondition(alertOk and (enableEntries and entryBull and not entryBull[1]), "Bull Entry", "VEIN-EXE · ENTRY LONG · {{ticker}} {{interval}}")
alertcondition(alertOk and (enableEntries and entryBear and not entryBear[1]), "Bear Entry", "VEIN-EXE · ENTRY SHORT · {{ticker}} {{interval}}")
alertcondition(alertOk and (enableEntries and bullInval and not bullInval[1]), "Bull Invalidation", "VEIN-EXE · INVALIDATION LONG · {{ticker}} {{interval}}")
alertcondition(alertOk and (enableEntries and bearInval and not bearInval[1]), "Bear Invalidation", "VEIN-EXE · INVALIDATION SHORT · {{ticker}} {{interval}}")
alertcondition(alertOk and (microStatus == "SETUP" and microStatus[1] != "SETUP"), "Micro Setup", "VEIN-EXE · MICRO SETUP · {{ticker}} {{interval}}")
Overview
Vein: Execution 15m [WavesUnchained] monitors lower-timeframe micro structure shifts, liquidity sweeps, rejection candles, engulfing patterns, and follow-through momentum. The script calculates a confluence micro score from 0 to 10, plotting optional entry and invalidation labels, 4-hour reference levels, and an execution status table on the main chart. Settings allow customization of higher-timeframe activation thresholds, micro pivot lookbacks, sweep parameters, and candle behavior criteria.
Micro structure shift and liquidity sweep detection
Candle behavior analysis with rejection wicks and engulfing patterns
Follow-through tempo validation and micro confluence scoring
Higher-timeframe reference levels and status dashboard table
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
HTF Timeframe
timeframe
240
htfTimeframe
Min 4H Setup Score to Activate
float
2.0
activationThresh
Zone Proximity (ATR)
float
0.8
zoneProximityATR
Micro Pivot Left Bars
int
2
microLeft
Micro Pivot Right Bars
int
2
microRight
Sweep: Lookback Bars
int
10
sweepLookback
Sweep: Min Depth (ATR)
float
0.1
sweepMinDepth
Sweep: Max Bars to Reclaim
int
3
sweepMaxBars
Rejection: Min Wick Ratio
float
0.45
rejWickThresh
Engulfing: Min Body Ratio
float
0.6
engBodyRatio
Follow-Through Window (Bars)
int
4
ftWindow
Follow-Through Min Move (ATR)
float
0.3
ftMinMove
Show all 24 settings
Setting
Type
Default
Variable
Entry Min Micro Score
float
6.0
entryScoreThresh
Display Mode
string
Light
displayMode
Enable Entry / Invalidation Signals
bool
false
enableEntries
Show Entry Labels
bool
true
showEntryLbl
Show Invalidation Labels
bool
true
showInvalLbl
Show 4H Reference Levels
bool
true
showHTFLevels
Show Status Table
bool
true
showTable
Vein Trend Up Source
source
close
htfTrendUp
Vein Trend Down Source
source
close
htfTrendDown
Vein Bull Setup Score Source
source
close
htfBullSetup
Vein Bear Setup Score Source
source
close
htfBearSetup
Alerts only on bar close (confirmed)
bool
true
alertsOnBarClose
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.
Apex Trend & Liquidity Master calculates a trend cloud using customizable moving averages expanded by a volatility multiplier directly on the main price chart. It identifies dynamic support and resistance liquidity zones from swing high and low pivots, extendi
This indicator analyzes market structure and identifies key swing highs, swing lows, and consolidation ranges across multiple timeframes. It automatically adapts swing lengths and consolidation thresholds according to chosen profiles for scalping, intraday, or
Smart Krypto Futures Daytrade Suite is an all-in-one technical indicator tailored for intraday cryptocurrency trading. It plots higher-timeframe supply and demand zones, Fair Value Gaps with optional mitigation filtering, session VWAP, dynamic moving averages,
This indicator plots Smart Money Concepts (SMC) elements directly on the price chart, including higher-timeframe structure breaks, order blocks, and fair value gaps (FVGs). It uses an inducement filter to validate market structure shifts alongside expected hig
This indicator detects equal highs and lows by comparing prices within user-defined left and right bars using a tolerance percentage. It plots horizontal lines on the price chart for equal highs in one color and lows in another. A screener allows input of mult
This Pine Script indicator plots a ZigZag on the price chart. It identifies reversal points when price moves more than a set percentage from the last pivot. The script calculates forecasts using zigzag data and labels detected geometric patterns including harm