Indicator · Pine Script v6 · Own pane

WaveTrend Advanced Smoothing [WavesUnchained]

by casoon

WaveTrend Advanced Smoothing is a separate-pane momentum oscillator built on the classic WaveTrend algorithm with eight selectable smoothing techniques, including SuperSmoother, T3, KAMA, and JMA.

View on GitHub

GitHub stars9on the repository
Pine versionv6current
Lines of code316
Settings27inputs
LicenceMIT
Last update3 days ago27 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

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

wavetrend_advanced_smoothing.pine
//@version=6
// ============================================================================
// WaveTrend Advanced Smoothing [WavesUnchained]
// Version: 1.1.2
// Author: WavesUnchained
// Build: 2026-10-02 00:00:00
// ============================================================================
// WaveTrend oscillator with pluggable smoothing kernels and rich visualization.
//
// Features:
//   ✓ 8 smoothing kernels: EMA, SMA, RMA, WMA, SuperSmoother, T3, KAMA, JMA
//   ✓ Three scale modes: Classic, Clamp ±100, Adaptive ±100
//   ✓ Gradient line color (bull ↔ bear based on oscillator level)
//   ✓ Gradient shadow fills between WT and zero line
//   ✓ 4-state color-coded histogram (momentum direction + strength)
//   ✓ Optional fill between WT main and signal lines
//   ✓ OB/OS zone background fills
//   ✓ Extreme cross signal markers + subtle dots for all crosses
//   ✓ Sentiment Bar — live ±100 OB/OS extremity score + mini bar
//   ✓ Alert conditions for all cross events
//
// ============================================================================

indicator("WaveTrend Advanced Smoothing [WavesUnchained]", "WT·AS", format=format.price, precision=2, overlay=false, max_labels_count=500)

// ─────────────────────────────────────────────────────────────────────────────
// INPUTS
// ─────────────────────────────────────────────────────────────────────────────

g_wt = "1 · WaveTrend"
src        = input.source(hlc3, "Source",         group=g_wt)
channelLen = input.int(10,    "Channel Length",    minval=1,           group=g_wt)
averageLen = input.int(21,    "Average Length",    minval=1,           group=g_wt)
signalLen  = input.int(4,     "Signal Length",     minval=1,           group=g_wt)

g_smooth = "2 · Smoothing"
smoothType = input.string("EMA", "Type",
     options=["EMA", "SMA", "RMA", "WMA", "SuperSmoother", "T3", "KAMA", "JMA Approx"],
     group=g_smooth)
jmaPhase = input.int(50,    "  JMA Phase", minval=-100, maxval=100,             group=g_smooth)
jmaPower = input.float(2.0, "  JMA Power", minval=1.0, maxval=4.0, step=0.25,  group=g_smooth)

g_scale = "3 · Scale"
scaleMode     = input.string("Classic", "Mode",
     options=["Classic", "Clamp ±100", "Adaptive ±100"], group=g_scale,
     tooltip="Classic: raw oscillator values. Clamp ±100: hard clips to ±100. Adaptive ±100: rescales to ±100 based on recent range.")
scaleLookback = input.int(200, "Adaptive Lookback", minval=20, group=g_scale,
     tooltip="Lookback used for Adaptive ±100 normalization.")

g_levels = "4 · Levels"
ob1 = input.float( 60,  "Overbought 1",  group=g_levels)
ob2 = input.float( 100, "Overbought 2",  group=g_levels)
os1 = input.float(-60,  "Oversold 1",    group=g_levels)
os2 = input.float(-100, "Oversold 2",    group=g_levels)

g_col = "5 · Colors"
colBull     = input.color(#00bcd4,                  "Bull",           group=g_col)
colBear     = input.color(#f06292,                  "Bear",           group=g_col)
colHistBull = input.color(#26a69a,                  "Histogram Bull", group=g_col)
colHistBear = input.color(#ef5350,                  "Histogram Bear", group=g_col)
colZoneOB   = input.color(color.new(#ef5350, 90),   "OB Zone Fill",   group=g_col)
colZoneOS   = input.color(color.new(#26a69a, 90),   "OS Zone Fill",   group=g_col)

g_disp = "6 · Display"
showShadow   = input.bool(true,  "Shadow Fill (WT vs Zero)",    group=g_disp)
showFill     = input.bool(true,  "Fill WT / Signal",            group=g_disp)
showZoneFill = input.bool(true,  "Fill OB / OS Zones",          group=g_disp)
showHist     = input.bool(true,  "Show Histogram",              group=g_disp)
showSignals  = input.bool(true,  "Show Extreme Signal Markers", group=g_disp)
showDots     = input.bool(true,  "Show Cross Dots",             group=g_disp)

g_score = "7 · Score"
showSentiment = input.bool(true, "Show Sentiment Bar", group=g_score,
     tooltip="Live label at the panel's right edge — how far WT sits inside its own OB/OS zone, signed ±100. Not a fixed Bullish/Bearish claim. Mirrors Williams VIX Fix Advanced's Sentiment Bar. No Signal Quality score here — this variant has no trend-context/stall layer for the quality weighting to draw on.")

// ─────────────────────────────────────────────────────────────────────────────
// SMOOTHING FUNCTIONS
// ─────────────────────────────────────────────────────────────────────────────

f_supersmoother(series float x, simple int len) =>
    float pi = math.pi
    float a1 = math.exp(-1.414 * pi / len)
    float b1 = 2.0 * a1 * math.cos(1.414 * pi / len)
    float c2 = b1
    float c3 = -(a1 * a1)
    float c1 = 1.0 - c2 - c3
    var float ss = na
    ss := c1 * (x + nz(x[1])) / 2.0 + c2 * nz(ss[1]) + c3 * nz(ss[2])
    ss

f_t3(series float x, simple int len) =>
    float b  = 0.7
    float e1 = ta.ema(x, len)
    float e2 = ta.ema(e1, len)
    float e3 = ta.ema(e2, len)
    float e4 = ta.ema(e3, len)
    float e5 = ta.ema(e4, len)
    float e6 = ta.ema(e5, len)
    float c1 = -(b * b * b)
    float c2 =  3.0 * b * b + 3.0 * b * b * b
    float c3 = -6.0 * b * b - 3.0 * b - 3.0 * b * b * b
    float c4 =  1.0 + 3.0 * b + b * b * b + 3.0 * b * b
    c1 * e6 + c2 * e5 + c3 * e4 + c4 * e3

f_kama(series float x, simple int len) =>
    float change    = math.abs(x - x[len])
    float vol       = math.sum(math.abs(x - x[1]), len)
    float er        = vol != 0.0 ? change / vol : 0.0
    float sc        = math.pow(er * (2.0 / 3.0 - 2.0 / 31.0) + 2.0 / 31.0, 2)
    var float kama  = na
    kama := nz(kama[1], x) + sc * (x - nz(kama[1], x))
    kama

f_jma(series float x, simple int len, simple int phase, simple float power) =>
    var float jma = na
    var float e0  = na
    var float e1  = na
    var float e2  = na
    float phaseRatio = phase < -100 ? 0.5 : phase > 100 ? 2.5 : phase / 100.0 + 1.5
    float beta       = 0.45 * (len - 1) / (0.45 * (len - 1) + 2.0)
    float alpha      = math.pow(beta, power)
    e0  := (1.0 - alpha) * x + alpha * nz(e0[1], x)
    e1  := (x - e0) * (1.0 - beta) + beta * nz(e1[1], 0.0)
    e2  := (e0 + phaseRatio * e1 - nz(jma[1], x)) * math.pow(1.0 - alpha, 2.0) + math.pow(alpha, 2.0) * nz(e2[1], 0.0)
    jma := nz(jma[1], x) + e2
    jma

f_smooth(series float x, simple int len, simple string mode) =>
    switch mode
        "SMA"           => ta.sma(x, len)
        "RMA"           => ta.rma(x, len)
        "WMA"           => ta.wma(x, len)
        "SuperSmoother" => f_supersmoother(x, len)
        "T3"            => f_t3(x, len)
        "KAMA"          => f_kama(x, len)
        "JMA Approx"    => f_jma(x, len, jmaPhase, jmaPower)
        =>                 ta.ema(x, len)

// ─────────────────────────────────────────────────────────────────────────────
// WAVETREND CORE
// ─────────────────────────────────────────────────────────────────────────────

esa    = f_smooth(src,                 channelLen, smoothType)
devRaw = f_smooth(math.abs(src - esa), channelLen, smoothType)
dev    = math.max(math.abs(devRaw), 1e-10)
ci     = (src - esa) / (0.015 * dev)
wt1Raw = f_smooth(ci,     averageLen, smoothType)
wt2Raw = f_smooth(wt1Raw, signalLen,  smoothType)

// ─────────────────────────────────────────────────────────────────────────────
// SCALE
// ─────────────────────────────────────────────────────────────────────────────

// Shared normalization factor — same denominator for both lines so their
// relationship (and therefore crossovers) stays proportional after scaling.
float scaleAbs = ta.highest(math.max(math.abs(wt1Raw), math.abs(wt2Raw)), scaleLookback)

f_scale(series float x, float sharedMax) =>
    if scaleMode == "Clamp ±100"
        math.max(math.min(x, 100.0), -100.0)
    else if scaleMode == "Adaptive ±100"
        sharedMax != 0.0 ? 100.0 * x / sharedMax : 0.0
    else
        x

wt1  = f_scale(wt1Raw, scaleAbs)
wt2  = f_scale(wt2Raw, scaleAbs)
hist = wt1 - wt2

// ─────────────────────────────────────────────────────────────────────────────
// SIGNALS
// ─────────────────────────────────────────────────────────────────────────────

// Signals on raw values — adaptive scaling must not create or destroy crossovers.
// Extreme thresholds also compare against raw values so OB/OS levels stay meaningful
// regardless of scale mode.
bullCross   = ta.crossover(wt1Raw,  wt2Raw)
bearCross   = ta.crossunder(wt1Raw, wt2Raw)
bullExtreme = bullCross and wt1Raw < os1
bearExtreme = bearCross and wt1Raw > ob1

// ─────────────────────────────────────────────────────────────────────────────
// SCORE — Sentiment Bar only (live extremity read). Computed on raw wt1Raw/ob1/
// os1, same convention as the signal logic above — scale-mode agnostic. No
// Signal Quality score: that weighting needs a trend-context line and a stall/
// absorption layer, neither of which exists in this variant.
// ─────────────────────────────────────────────────────────────────────────────

float sentBullPct  = ob1 != 0.0 ? math.max(0.0, wt1Raw) / ob1 * 100.0 : 0.0
float sentBearPct  = os1 != 0.0 ? math.max(0.0, -wt1Raw) / math.abs(os1) * 100.0 : 0.0
float sentScore    = math.max(-100.0, math.min(100.0, sentBullPct - sentBearPct))
float sentAbsScore = math.abs(sentScore)

// ─────────────────────────────────────────────────────────────────────────────
// DERIVED COLORS
// ─────────────────────────────────────────────────────────────────────────────

// Gradient: bull color at OS level, bear color at OB level
color lineCol1  = color.from_gradient(wt1, os1, ob1, colBull, colBear)
color lineCol2  = color.from_gradient(wt2, os1, ob1, color.new(colBull, 40), color.new(colBear, 40))

// 4-state histogram: rising/falling × positive/negative
bool histRising = hist >= hist[1]
color histColor = hist >= 0.0
     ? (histRising  ? colHistBull                     : color.new(colHistBull, 55))
     : (not histRising ? colHistBear                  : color.new(colHistBear, 55))

// ─────────────────────────────────────────────────────────────────────────────
// HLINES + ZONE FILLS
// ─────────────────────────────────────────────────────────────────────────────

hline(0, "Zero", color=color.new(color.gray, 60), linestyle=hline.style_dotted, linewidth=1)

hOB2 = hline(ob2, "OB 2", color=color.new(color.red, 45),    linestyle=hline.style_solid,  linewidth=1)
hOB1 = hline(ob1, "OB 1", color=color.new(color.red, 65),    linestyle=hline.style_dashed, linewidth=1)
hOS1 = hline(os1, "OS 1", color=color.new(#26a69a, 65),      linestyle=hline.style_dashed, linewidth=1)
hOS2 = hline(os2, "OS 2", color=color.new(#26a69a, 45),      linestyle=hline.style_solid,  linewidth=1)

fill(hOB1, hOB2, color=showZoneFill ? colZoneOB : na, title="OB Zone")
fill(hOS2, hOS1, color=showZoneFill ? colZoneOS : na, title="OS Zone")

// ─────────────────────────────────────────────────────────────────────────────
// PLOTS — Histogram (rendered first, behind lines)
// ─────────────────────────────────────────────────────────────────────────────

plot(showHist ? hist : na, "Histogram", style=plot.style_columns, color=histColor)

// ─────────────────────────────────────────────────────────────────────────────
// PLOTS — Main lines
// ─────────────────────────────────────────────────────────────────────────────

pZero = plot(0.0, display=display.none)
pWT2  = plot(wt2, "WT Signal", color=lineCol2, linewidth=1)
pWT1  = plot(wt1, "WT Main",   color=lineCol1, linewidth=2)

// Gradient shadow between WT1 and zero: bear tint above, bull tint below
fill(pWT1, pZero, ob1, 0.0, color.new(colBear, 78), color.new(colBear, 100),
     title="Bear Shadow", display=showShadow ? display.all : display.none)
fill(pWT1, pZero, 0.0, os1, color.new(colBull, 100), color.new(colBull, 78),
     title="Bull Shadow", display=showShadow ? display.all : display.none)

// Fill between WT main and signal
fill(pWT1, pWT2,
     color=showFill ? (wt1 >= wt2 ? color.new(colBull, 88) : color.new(colBear, 88)) : na,
     title="WT Fill")

// ─────────────────────────────────────────────────────────────────────────────
// SIGNAL MARKERS
// ─────────────────────────────────────────────────────────────────────────────

// Extreme crosses — triangle markers at pane edges
plotshape(showSignals and bullExtreme, "Bull Extreme",
     style=shape.triangleup, location=location.bottom,
     color=color.new(colHistBull, 0), size=size.small,
     text="WT↑", textcolor=color.new(colHistBull, 0))

plotshape(showSignals and bearExtreme, "Bear Extreme",
     style=shape.triangledown, location=location.top,
     color=color.new(colHistBear, 0), size=size.small,
     text="WT↓", textcolor=color.new(colHistBear, 0))

// Regular (non-extreme) crosses — small dots on the WT1 line
plotshape(showDots and bullCross and not bullExtreme ? wt1 : na, "Bull Cross",
     style=shape.circle, location=location.absolute,
     color=color.new(colBull, 15), size=size.tiny)

plotshape(showDots and bearCross and not bearExtreme ? wt1 : na, "Bear Cross",
     style=shape.circle, location=location.absolute,
     color=color.new(colBear, 15), size=size.tiny)

// ─────────────────────────────────────────────────────────────────────────────
// SCORE DISPLAY — Sentiment Bar, always-on read of current extremity
// ─────────────────────────────────────────────────────────────────────────────

f_scoreColor(score, absS) =>
    base = score > 0 ? colBear : colBull
    color result = na
    if absS < 15
        result := color.new(color.gray, 40)
    else if absS >= 80
        result := color.new(base, 10)
    else if absS >= 60
        result := color.new(base, 30)
    else if absS >= 40
        result := color.new(base, 50)
    else
        result := color.new(base, 70)
    result

int    scoreBarSegments = 8
int    scoreFilled      = int(math.round(sentAbsScore / 100.0 * scoreBarSegments))
string scoreBarStr      = str.repeat("■", scoreFilled) + str.repeat("·", scoreBarSegments - scoreFilled)
string scoreSignStr     = sentScore > 0 ? "+" : ""
string sentTxt          = scoreSignStr + str.tostring(sentScore, "#") + "  " + scoreBarStr
color  sentColor        = f_scoreColor(sentScore, sentAbsScore)

var label sentLabel = na
if showSentiment and barstate.islast
    label.delete(sentLabel)
    sentLabel := label.new(bar_index + 3, 0.0, sentTxt,
         xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left,
         color=sentColor, textcolor=color.white, size=size.normal,
         tooltip="How far WT sits inside its own OB/OS zone: 100×WT/Overbought1 when bullish, -100×WT/Oversold1 when bearish, clamped to ±100. |score| < 15 reads as balanced.")
else if not showSentiment and barstate.islast
    label.delete(sentLabel)

// ─────────────────────────────────────────────────────────────────────────────
// ALERTS
// ─────────────────────────────────────────────────────────────────────────────

bool alertsOnBarClose = input.bool(true, "Alerts only on bar close (confirmed)", group="8 · Alerts")
bool alertOk = not alertsOnBarClose or barstate.isconfirmed
alertcondition(alertOk and (bullExtreme), "Bull Extreme Cross", "WTAS · BULL CROSS OVERSOLD · {{ticker}} {{interval}}")
alertcondition(alertOk and (bearExtreme), "Bear Extreme Cross", "WTAS · BEAR CROSS OVERBOUGHT · {{ticker}} {{interval}}")
alertcondition(alertOk and (bullCross),   "WaveTrend Cross Up",   "WTAS · CROSS UP · {{ticker}} {{interval}}")
alertcondition(alertOk and (bearCross),   "WaveTrend Cross Down",  "WTAS · CROSS DOWN · {{ticker}} {{interval}}")

Overview

WaveTrend Advanced Smoothing [WavesUnchained] provides three normalization scale modes: Classic, Clamp, and Adaptive ±100. The indicator plots main and signal lines alongside a four-state directional histogram, crossing markers, overbought and oversold background zones, and a live sentiment display. Users can adjust channel lengths, signal periods, and threshold levels to fine-tune sensitivity across different trading instruments.

Details

Published by

casoon on GitHub

Draws

Separate pane below the chart

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
Sourcesourcehlc3src
Channel Lengthint10channelLen
Average Lengthint21averageLen
Signal Lengthint4signalLen
TypestringEMAsmoothType
JMA Phaseint50jmaPhase
JMA Powerfloat2.0jmaPower
ModestringClassicscaleMode
Adaptive Lookbackint200scaleLookback
Overbought 1float60ob1
Overbought 2float100ob2
Oversold 1float-60os1
Show all 27 settings
SettingTypeDefaultVariable
Oversold 2float-100os2
Bullcolor#00bcd4colBull
Bearcolor#f06292colBear
Histogram Bullcolor#26a69acolHistBull
Histogram Bearcolor#ef5350colHistBear
OB Zone Fillcolorcolor.new(#ef5350, 90)colZoneOB
OS Zone Fillcolorcolor.new(#26a69a, 90)colZoneOS
Shadow Fill (WT vs Zero)booltrueshowShadow
Fill WT / SignalbooltrueshowFill
Fill OB / OS ZonesbooltrueshowZoneFill
Show HistogrambooltrueshowHist
Show Extreme Signal MarkersbooltrueshowSignals
Show Cross DotsbooltrueshowDots
Show Sentiment BarbooltrueshowSentiment
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

947 stars

The Derivative Oscillator calculates a double-exponentially smoothed Relative Strength Index (RSI) and subtracts its Simple Moving Average (SMA) to form the main oscillator line. A secondary signal line is plotted using an SMA of the main oscillator values. Th

Indicator v4 Oscillators & momentumMoving averages
Updated 12 days ago · GPL-3.0 GitHub repository of Derivative Oscillator

Beep Boop

by magic8bot
409 stars

This indicator calculates a modified MACD oscillator and signal line alongside a trend EMA filter, plotting the output as a stylized column histogram in a separate pane. Instead of plotting true MACD distance, it quantifies positive and negative histogram mome

Indicator v4 Oscillators & momentumTrend
Updated 3 years ago · MIT GitHub repository of Beep Boop

MACD

by Alorse
330 stars

This indicator calculates and plots the standard Moving Average Convergence Divergence oscillator in a separate pane. It computes the difference between a fast and slow moving average, derives a signal line through smoothing, and plots a histogram representing

Indicator v4 Oscillators & momentumMoving averages
Updated 2 months ago · None stated GitHub repository of MACD
228 stars

Multi-Timeframe Analysis Suite calculates trend direction and momentum conditions across five user-selected timeframes using moving averages, RSI, and Stochastic oscillators. It evaluates moving average slope and oscillator levels to compute trend alignment, m

Indicator v6 Screeners & dashboardsTrend
Updated 3 months ago · None stated GitHub repository of Multi-Timeframe Analysis Suite

MACD-V

by harryguiacorn
220 stars

MACD-V is a volatility-normalized momentum indicator based on research by Alex Spiroglou. It calculates the standard MACD histogram and normalizes it by dividing by the Average True Range (ATR). Plotted in a separate pane as a colored histogram, it includes us

Indicator v5 Oscillators & momentumVolatility & bands
Updated 1 year ago · None stated GitHub repository of MACD-V

KamaFama

by Mastaaa1987
141 stars

KamaFama is an indicator that translates a Freqtrade trading strategy into Pine Script for visualization. It combines Kaufman Adaptive Moving Average (KAMA), MAMA/FAMA calculations derived via Hilbert Transform, Williams %R, and correlation trend filters to ev

Indicator v6 Moving averagesOscillators & momentum
Updated 6 weeks ago · MIT GitHub repository of KamaFama

More Oscillators & momentum scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

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

Compare brokers