Indicator · Pine Script v6 · On the chart

Adaptive Fair Value Cloud [WavesUnchained]

by casoon

Adaptive Fair Value Cloud calculates a volatility-adaptive fair value channel around a selectable centerline, such as KAMA, EMA, linear regression, or VWMA.

View on GitHub

GitHub stars9on the repository
Pine versionv6current
Lines of code276
Settings19inputs
LicenceMIT
Last updateyesterday27 Oct 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

276 lines of Pine Script v6 from archive/indicators/adaptive_fair_value_cloud/adaptive_fair_value_cloud.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

adaptive_fair_value_cloud.pine
//@version=6
// ============================================================================
// Adaptive Fair Value Cloud [WavesUnchained]
// Version: 1.1
// Author: WavesUnchained
// Build: 2026-07-04 00:00:00
// ============================================================================
// Volatility-adaptive fair value channel around a configurable centerline.
//
// Features:
//   ✓ Selectable Centerline (EMA, KAMA, Regression, VWMA)
//   ✓ ATR + Mean-Deviation Blended Band Width
//   ✓ Regime-Adaptive Width Multiplier (Compression / Expansion / Range / Trend)
//   ✓ Trend Sensors (Slope, ADX, Efficiency Ratio, R²)
//   ✓ Cloud Break and Fair Value Reclaim/Reject Signals
//   ✓ Watch Layer: Regime-Acceleration, Squeeze-Release, Divergence-at-Edge
//   ✓ Regime Dashboard
//
// ============================================================================

indicator("Adaptive Fair Value Cloud [WavesUnchained]", shorttitle="AFVC", overlay=true, max_labels_count=300)

//------------------------------------------------------------------------------
// Inputs
//------------------------------------------------------------------------------
basisMode = input.string("KAMA", "Centerline", options=["EMA", "KAMA", "Regression", "VWMA"])
basisLen  = input.int(50, "Basis Length", minval=5)

atrLen    = input.int(14, "ATR Length", minval=1)
devLen    = input.int(50, "Deviation Length", minval=5)
pctLen    = input.int(100, "Volatility Percentile Length", minval=20)

baseMult  = input.float(1.8, "Base Width Multiplier", step=0.1)
minMult   = input.float(0.8, "Min Multiplier", step=0.1)
maxMult   = input.float(3.5, "Max Multiplier", step=0.1)

erLen     = input.int(20, "Efficiency Length", minval=5)
adxLen    = input.int(14, "ADX Length", minval=5)
r2Len     = input.int(50, "Regression Quality Length", minval=10)

showSignals = input.bool(true, "Show Signals")
showDashboard = input.bool(true, "Show Dashboard")

g_watch = "Predictive / Watch Signals"
showWatchSignals = input.bool(true, "Show Watch Signals (leading, unconfirmed)", group=g_watch)
rsiLen           = input.int(14, "Divergence RSI Length", minval=2, group=g_watch)
divPivLen        = input.int(5, "Divergence Pivot Confirmation", minval=2, group=g_watch)
buildAccelThresh = input.float(0.08, "Regime Build Acceleration Threshold", step=0.01, group=g_watch)
squeezeTolerance = input.float(1.15, "Squeeze Width Tolerance", step=0.05, group=g_watch)

g_alert = "Alerts"
alertsOnBarClose = input.bool(true, "Alerts only on bar close (confirmed)", group=g_alert)

//------------------------------------------------------------------------------
// Helper
//------------------------------------------------------------------------------
f_clamp(x, lo, hi) =>
    math.max(lo, math.min(hi, x))

f_kama(src, len, fastLen, slowLen) =>
    change = math.abs(src - src[len])
    volatility = ta.sma(math.abs(src - src[1]), len) * len
    er = volatility != 0.0 ? change / volatility : 0.0
    fastSC = 2.0 / (fastLen + 1.0)
    slowSC = 2.0 / (slowLen + 1.0)
    sc = math.pow(er * (fastSC - slowSC) + slowSC, 2)
    var float kama = na
    kama := na(kama[1]) ? src : kama[1] + sc * (src - kama[1])
    kama

//------------------------------------------------------------------------------
// Centerline
//------------------------------------------------------------------------------
emaBasis = ta.ema(close, basisLen)
kamaBasis = f_kama(close, basisLen, 2, 30)
regBasis = ta.linreg(close, basisLen, 0)
vwmaBasis = ta.vwma(close, basisLen)

basis = switch basisMode
    "EMA"        => emaBasis
    "KAMA"       => kamaBasis
    "Regression" => regBasis
    => vwmaBasis

//------------------------------------------------------------------------------
// Volatility / Width
//------------------------------------------------------------------------------
atr = ta.atr(atrLen)
meanAbsDev = ta.sma(math.abs(close - basis), devLen)
rawWidth = atr * 0.65 + meanAbsDev * 0.35

atrPct = ta.percentile_nearest_rank(atr, pctLen, 80)
atrLow = ta.percentile_nearest_rank(atr, pctLen, 20)

volScore = atrPct != atrLow ? f_clamp((atr - atrLow) / (atrPct - atrLow), 0.0, 1.0) : 0.5

//------------------------------------------------------------------------------
// Regime Sensors
//------------------------------------------------------------------------------
directionMove = math.abs(close - close[erLen])
noiseMove = ta.sma(math.abs(close - close[1]), erLen) * erLen
efficiency = noiseMove != 0.0 ? directionMove / noiseMove : 0.0

[plusDI, minusDI, adx] = ta.dmi(adxLen, adxLen)

corr = ta.correlation(close, bar_index, r2Len)
r2 = math.pow(nz(corr), 2)

regNow = ta.linreg(close, basisLen, 0)
regPrev = ta.linreg(close, basisLen, 1)
slope = atr != 0.0 ? (regNow - regPrev) / atr : 0.0

hh = ta.highest(high, erLen)
ll = ta.lowest(low, erLen)
chopRange = hh - ll
chop = chopRange != 0.0 ? 100.0 * math.log10(ta.sma(ta.tr(true), erLen) * erLen / chopRange) / math.log10(erLen) : 50.0

trendUp = slope > 0 and adx > 18 and efficiency > 0.25 and r2 > 0.25
trendDown = slope < 0 and adx > 18 and efficiency > 0.25 and r2 > 0.25
compression = volScore < 0.35 and chop > 55
expansion = volScore > 0.65 and efficiency > 0.35
rangeMode = chop > 60 and adx < 20

//------------------------------------------------------------------------------
// Adaptive Multiplier
//------------------------------------------------------------------------------
regimeBoost = compression ? 0.75 : expansion ? 1.35 : rangeMode ? 1.05 : trendUp or trendDown ? 1.20 : 1.0

qualityBoost = 1.0 + r2 * 0.35 + efficiency * 0.25
dynamicMult = f_clamp(baseMult * regimeBoost * qualityBoost, minMult, maxMult)

upper = basis + rawWidth * dynamicMult
lower = basis - rawWidth * dynamicMult
midUpper = basis + rawWidth * dynamicMult * 0.5
midLower = basis - rawWidth * dynamicMult * 0.5

//------------------------------------------------------------------------------
// Color Logic
//------------------------------------------------------------------------------
regimeBase = compression ? color.gray : rangeMode ? color.silver : trendUp ? #00c853 : trendDown ? #d50000 : #2962ff

cloudColor = color.new(regimeBase, 88)
coreColor  = color.new(regimeBase, 94)
innerLineColor = color.new(regimeBase, 65)
edgeColor  = trendUp or trendDown ? color.new(regimeBase, 25) : color.new(color.gray, 45)

//------------------------------------------------------------------------------
// Plots
//------------------------------------------------------------------------------
pUpper = plot(upper, "Upper Edge", color=edgeColor, linewidth=1)
pLower = plot(lower, "Lower Edge", color=edgeColor, linewidth=1)
pBasis = plot(basis, "Fair Value", color=color.new(#37474f, 0), linewidth=2)

pMidUpper = plot(midUpper, "Inner Upper", color=innerLineColor, linewidth=1)
pMidLower = plot(midLower, "Inner Lower", color=innerLineColor, linewidth=1)

fill(pUpper, pLower, color=cloudColor, title="Adaptive Cloud")
fill(pMidUpper, pMidLower, color=coreColor, title="Fair Value Core")

//------------------------------------------------------------------------------
// Signals
//------------------------------------------------------------------------------
bullBreak = showSignals and ta.crossover(close, upper) and (trendUp or expansion)
bearBreak = showSignals and ta.crossunder(close, lower) and (trendDown or expansion)

bullReclaim = showSignals and ta.crossover(close, basis) and trendUp and close > lower
bearReject = showSignals and ta.crossunder(close, basis) and trendDown and close < upper

plotshape(bullBreak, title="Bullish Cloud Break", style=shape.triangleup, location=location.belowbar, size=size.tiny, color=#00c853, text="Break", textcolor=#00c853)
plotshape(bearBreak, title="Bearish Cloud Break", style=shape.triangledown, location=location.abovebar, size=size.tiny, color=#d50000, text="Break", textcolor=#d50000)

plotshape(bullReclaim, title="Bullish Reclaim", style=shape.circle, location=location.belowbar, size=size.tiny, color=color.new(#00c853, 0))
plotshape(bearReject, title="Bearish Reject", style=shape.circle, location=location.abovebar, size=size.tiny, color=color.new(#d50000, 0))

//------------------------------------------------------------------------------
// Watch / Predictive Layer
// Leading, unconfirmed early-warning signals — anticipate a regime shift or
// volatility release before the confirmed Trigger above fires. None of these
// predict direction with certainty; they flag a rising probability of a move.
//------------------------------------------------------------------------------

// --- A: Regime acceleration — efficiency/R² rising before the trend gate trips
erAccel = efficiency - efficiency[3]
r2Accel = r2 - r2[3]
regimeBuilding = not trendUp and not trendDown and erAccel > buildAccelThresh and r2Accel > buildAccelThresh and adx > 12
buildingUp   = showWatchSignals and regimeBuilding and slope > 0
buildingDown = showWatchSignals and regimeBuilding and slope < 0

// --- B: Squeeze release — band width was near a multi-bar low and is now widening
bandWidth = upper - lower
widthLowN = ta.lowest(bandWidth, pctLen)
squeezeActive     = bandWidth <= widthLowN * squeezeTolerance
squeezeReleasing  = showWatchSignals and squeezeActive[2] and ta.rising(bandWidth, 2)

// --- C: Divergence at cloud edge — price extreme not confirmed by RSI at the band
rsi = ta.rsi(close, rsiLen)

plPiv = ta.pivotlow(low, divPivLen, divPivLen)
phPiv = ta.pivothigh(high, divPivLen, divPivLen)
plBar = not na(plPiv)
phBar = not na(phPiv)

lastPL    = ta.valuewhen(plBar, plPiv, 0)
prevPL    = ta.valuewhen(plBar, plPiv, 1)
lastPLRsi = ta.valuewhen(plBar, rsi[divPivLen], 0)
prevPLRsi = ta.valuewhen(plBar, rsi[divPivLen], 1)

lastPH    = ta.valuewhen(phBar, phPiv, 0)
prevPH    = ta.valuewhen(phBar, phPiv, 1)
lastPHRsi = ta.valuewhen(phBar, rsi[divPivLen], 0)
prevPHRsi = ta.valuewhen(phBar, rsi[divPivLen], 1)

bullDivAtEdge = showWatchSignals and plBar and lastPL < prevPL and lastPLRsi > prevPLRsi and lastPL <= lower[divPivLen] * 1.01
bearDivAtEdge = showWatchSignals and phBar and lastPH > prevPH and lastPHRsi < prevPHRsi and lastPH >= upper[divPivLen] * 0.99

watchColor = color.new(#ff6f00, 0)

plotshape(buildingUp,   title="Watch: Trend Building Up",   style=shape.triangleup,   location=location.belowbar, size=size.tiny, color=watchColor, text="Build")
plotshape(buildingDown, title="Watch: Trend Building Down", style=shape.triangledown, location=location.abovebar, size=size.tiny, color=watchColor, text="Build")

plotshape(squeezeReleasing, title="Watch: Squeeze Releasing", style=shape.square, location=location.belowbar, size=size.tiny, color=watchColor, text="Sqz")

plotshape(bullDivAtEdge, title="Watch: Bullish Divergence", style=shape.xcross, location=location.belowbar, size=size.tiny, color=watchColor, text="Div")
plotshape(bearDivAtEdge, title="Watch: Bearish Divergence", style=shape.xcross, location=location.abovebar, size=size.tiny, color=watchColor, text="Div")

//------------------------------------------------------------------------------
// Dashboard
//------------------------------------------------------------------------------
regimeText = compression ? "COMPRESSION" : expansion ? "EXPANSION" : rangeMode ? "RANGE" : trendUp ? "TREND UP" : trendDown ? "TREND DOWN" : "NEUTRAL"

biasText = trendUp ? "Bullish" : trendDown ? "Bearish" : "Neutral"

color tc = color.new(color.gray, 20)
color hd = color.new(color.gray, 90)

watchText = buildingUp ? "Build ↑" : buildingDown ? "Build ↓" : squeezeReleasing ? "Squeeze" : bullDivAtEdge ? "Div ↑" : bearDivAtEdge ? "Div ↓" : "—"
watchColorDash = watchText == "—" ? tc : watchColor

var table dash = table.new(position.top_right, 2, 7,
     bgcolor=color.new(color.white, 5),
     border_color=color.new(color.gray, 60),
     border_width=1,
     frame_color=color.new(color.gray, 40),
     frame_width=1)

if showDashboard and barstate.islast
    table.cell(dash, 0, 0, "Regime", text_color=tc, bgcolor=hd, text_size=size.small)
    table.cell(dash, 1, 0, regimeText, text_color=tc, bgcolor=hd, text_size=size.small)
    table.cell(dash, 0, 1, "Bias", text_color=tc, text_size=size.small)
    table.cell(dash, 1, 1, biasText, text_color=trendUp ? #00c853 : trendDown ? #d50000 : tc, text_size=size.small)
    table.cell(dash, 0, 2, "ADX", text_color=tc, text_size=size.small)
    table.cell(dash, 1, 2, str.tostring(adx, "#.0"), text_color=tc, text_size=size.small)
    table.cell(dash, 0, 3, "Efficiency", text_color=tc, text_size=size.small)
    table.cell(dash, 1, 3, str.tostring(efficiency * 100, "#.0") + "%", text_color=tc, text_size=size.small)
    table.cell(dash, 0, 4, "R²", text_color=tc, text_size=size.small)
    table.cell(dash, 1, 4, str.tostring(r2 * 100, "#.0") + "%", text_color=tc, text_size=size.small)
    table.cell(dash, 0, 5, "Width Mult", text_color=tc, text_size=size.small)
    table.cell(dash, 1, 5, str.tostring(dynamicMult, "#.00"), text_color=tc, text_size=size.small)
    table.cell(dash, 0, 6, "Watch", text_color=tc, text_size=size.small)
    table.cell(dash, 1, 6, watchText, text_color=watchColorDash, text_size=size.small)

//------------------------------------------------------------------------------
// Alerts
//------------------------------------------------------------------------------
alertOk = not alertsOnBarClose or barstate.isconfirmed

alertcondition(alertOk and bullBreak, "Bullish Cloud Break", "AFVC · BREAK LONG · {{ticker}} {{interval}}")
alertcondition(alertOk and bearBreak, "Bearish Cloud Break", "AFVC · BREAK SHORT · {{ticker}} {{interval}}")
alertcondition(alertOk and compression, "Compression Regime", "AFVC · REGIME COMPRESSION · {{ticker}} {{interval}}")
alertcondition(alertOk and expansion, "Expansion Regime", "AFVC · REGIME EXPANSION · {{ticker}} {{interval}}")

alertcondition(alertOk and buildingUp, "Watch: Trend Building Up", "AFVC · WATCH BUILD UP · {{ticker}} {{interval}}")
alertcondition(alertOk and buildingDown, "Watch: Trend Building Down", "AFVC · WATCH BUILD DOWN · {{ticker}} {{interval}}")
alertcondition(alertOk and squeezeReleasing, "Watch: Squeeze Releasing", "AFVC · WATCH SQUEEZE · {{ticker}} {{interval}}")
alertcondition(alertOk and bullDivAtEdge, "Watch: Bullish Divergence", "AFVC · WATCH DIV UP · {{ticker}} {{interval}}")
alertcondition(alertOk and bearDivAtEdge, "Watch: Bearish Divergence", "AFVC · WATCH DIV DOWN · {{ticker}} {{interval}}")

Overview

Adaptive Fair Value Cloud [WavesUnchained] blends ATR and mean deviation with volatility percentiles and trend sensors, including ADX, Efficiency Ratio, and linear regression R-squared, to dynamically adjust cloud width. The indicator plots signals for cloud breakouts, fair value reclaims, rejections, squeezes, and RSI divergences directly on the main price chart, complemented by an optional on-screen regime dashboard.

Details

Published by

casoon on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Volatility & bands, Trend, Divergence, Screeners & dashboards

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-scriptpinescripttechnical-analysistrading-indicatorstrading-strategiestradingview

Settings

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

SettingTypeDefaultVariable
CenterlinestringKAMAbasisMode
Basis Lengthint50basisLen
ATR Lengthint14atrLen
Deviation Lengthint50devLen
Volatility Percentile Lengthint100pctLen
Base Width Multiplierfloat1.8baseMult
Min Multiplierfloat0.8minMult
Max Multiplierfloat3.5maxMult
Efficiency Lengthint20erLen
ADX Lengthint14adxLen
Regression Quality Lengthint50r2Len
Show SignalsbooltrueshowSignals
Show all 19 settings
SettingTypeDefaultVariable
Show DashboardbooltrueshowDashboard
Show Watch Signals (leading, unconfirmed)booltrueshowWatchSignals
Divergence RSI Lengthint14rsiLen
Divergence Pivot Confirmationint5divPivLen
Regime Build Acceleration Thresholdfloat0.08buildAccelThresh
Squeeze Width Tolerancefloat1.15squeezeTolerance
Alerts only on bar close (confirmed)booltruealertsOnBarClose
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

92 stars

This indicator classifies the market into gamma regime types (negative gamma trend, positive gamma mean-reversion, or transition) by calculating a composite score based on daily ATR ratios, session VWAP crossover frequencies, and opening range displacement. It

Indicator v5 Volatility & bandsTrend
Updated 8 weeks ago · Custom licence GitHub repository of Moon Dev GEX Regime & Trap
46 stars

This indicator uses a Hidden Markov Model (HMM) framework combined with an adaptive dual moving average engine and Directional Movement Index (DMI) features to identify market regimes (bullish, bearish, or ranging/chop). It calculates regime probabilities on e

Indicator v5 AI / machine learningTrend
Updated 7 weeks ago · None stated GitHub repository of HMM Enhanced: Regime Probability
43 stars

This indicator calculates standardized trend strength and historical volatility to estimate position sizes. It computes the differences between three user-defined EMAs standardized by price using MACD logic, while historical volatility is derived from the stan

Indicator v5 TrendVolatility & bands
Updated 1 year ago · None stated GitHub repository of Trend Strength & Volatility v2

This overlay indicator plots a SuperTrend-style band on the price chart using ATR length, a selectable source, and a base factor. Optional settings enable an adaptive factor driven by rate of change, a volatility filter, K-means clustering, and an LSTM layer w

Indicator v6 TrendVolatility & bands
Updated 4 months ago · MIT GitHub repository of ML SuperTrend (Ultimate) - Auto-Optimized AI with LSTM

Trend Compass 15m

by chris-c-thomas
14 stars

Trend Compass 15m is an intraday trend analysis overlay designed for 15-minute charts. It calculates a triple exponential moving average ribbon, higher-timeframe reference EMAs from 1H, 4H, and Daily periods, RSI and MACD divergences, On-Balance Volume trends,

Indicator v6 TrendMoving averages Repaints
Updated 6 months ago · MIT GitHub repository of Trend Compass 15m

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