This indicator classifies market state into bull, bear, or neutral regimes using three moving averages and ATR-based stop bands plotted directly on the price chart.
//@version=6
// ============================================================================
// MA Regime Bands [WavesUnchained]
// Version: 1.0.3
// Author: WavesUnchained
// Build: 2026-06-30 00:00:00
// ============================================================================
// Regime overlay using multi-MA alignment with ATR-based stop bands and normalized trend strength.
//
// Features:
// ✓ Three configurable MAs (SMA, EMA, DEMA, TEMA, JMA) — default 21 / 55 / 89
// ✓ Regime classification — Bull, Bear, Neutral based on MA alignment
// ✓ ATR-based stop bands rendered as overlay
// ✓ ATR-normalized trend-strength gate (Off / By MA Type / Auto)
//
// ============================================================================
indicator("MA Regime Bands [WavesUnchained]", overlay=true, max_labels_count=200)
// ============================================================================
// MODULES:
// - inputs.pine
// - core.pine
// - visualization.pine
// ============================================================================
// NOTE: Modules are combined by the build system.
// ============================================================================
// INLINE MODULES (Combined at build time)
// ============================================================================
// ============================================================================
// MODULE: inputs
// ============================================================================
// ─────────────────────────────────────────────────────────────────────────────
// Inputs
// ─────────────────────────────────────────────────────────────────────────────
grpMA = "Moving Averages"
maType = input.string("DEMA", "MA Type", options=["SMA","EMA","DEMA","TEMA","JMA"], group=grpMA)
len1 = input.int(21, "MA 1 Length", group=grpMA, minval=1)
len2 = input.int(55, "MA 2 Length", group=grpMA, minval=1)
len3 = input.int(89, "MA 3 Length", group=grpMA, minval=1)
showMAs = input.bool(false, "Show MAs", group=grpMA)
showAMA = input.bool(false, "Show Average MA", group=grpMA)
grpATR = "ATR Stop Zones"
atrLen = input.int(20, "ATR Length", group=grpATR, minval=1)
mult = input.float(2.0, "ATR Stop Loss Multiplier", group=grpATR, minval=0.1, step=0.1)
showZones = input.bool(true, "Show Stop Zones", group=grpATR)
grpStrength = "Trend Strength"
strengthMode = input.string("By MA Type", "Strength Normalization", options=["Off","By MA Type","Auto"], group=grpStrength)
baseMinStrength = input.float(0.6, "Base Min Strength (spread / ATR)", step=0.05, group=grpStrength)
autoLookback = input.int(200, "Auto Normalize Lookback", group=grpStrength, minval=50)
grpUI = "UI"
showLabels = input.bool(true, "Show Regime Labels", group=grpUI)
labelSize = input.string("tiny", "Label Size", options=["tiny","small","normal"], group=grpUI)
showBg = input.bool(true, "Show Regime Background", group=grpUI)
// label size map
_ls = labelSize == "small" ? size.small : labelSize == "normal" ? size.normal : size.tiny
// ============================================================================
// MODULE: core
// ============================================================================
// ─────────────────────────────────────────────────────────────────────────────
// MA function
// ─────────────────────────────────────────────────────────────────────────────
f_jma(_src, _len, _phase, _power) =>
var float jma = na
var float e0 = na
var float e1 = na
var float e2 = na
_pr = _phase < -100 ? 0.5 : _phase > 100 ? 2.5 : _phase / 100.0 + 1.5
_beta = 0.45 * (_len - 1) / (0.45 * (_len - 1) + 2)
_alpha = math.pow(_beta, _power)
e0 := (1 - _alpha) * _src + _alpha * nz(e0[1], _src)
e1 := (_src - e0) * (1 - _beta) + _beta * nz(e1[1], 0)
e2 := (e0 + _pr * e1 - nz(jma[1], _src)) * math.pow(1 - _alpha, 2) + math.pow(_alpha, 2) * nz(e2[1], 0)
jma := nz(jma[1], _src) + e2
jma
f_ma(_src, _len) =>
switch maType
"SMA" => ta.sma(_src, _len)
"EMA" => ta.ema(_src, _len)
"DEMA" =>
ema1 = ta.ema(_src, _len)
2.0 * ema1 - ta.ema(ema1, _len)
"TEMA" =>
ema1 = ta.ema(_src, _len)
ema2 = ta.ema(ema1, _len)
3.0 * ema1 - 3.0 * ema2 + ta.ema(ema2, _len)
"JMA" => f_jma(_src, _len, 0, 2)
=> ta.ema(_src, _len)
// Strength factor by MA type (simple normalization)
f_strengthFactor() =>
switch maType
"SMA" => 1.00
"EMA" => 1.00
"DEMA" => 1.05 // slightly stricter
"TEMA" => 0.80 // smoother -> allow smaller spread
"JMA" => 0.85 // smoother -> allow smaller spread
=> 1.00
// ─────────────────────────────────────────────────────────────────────────────
// Core calc
// ─────────────────────────────────────────────────────────────────────────────
ma1 = f_ma(close, len1)
ma2 = f_ma(close, len2)
ma3 = f_ma(close, len3)
ama = (ma1 + ma2 + ma3) / 3.0
atr = ta.atr(atrLen)
slDist = atr * mult
highestMA = math.max(ma1, math.max(ma2, ma3))
lowestMA = math.min(ma1, math.min(ma2, ma3))
// Trend strength = MA spread normalized by ATR
spreadATR = atr > 0 ? (highestMA - lowestMA) / atr : 0.0
minStrengthByType = baseMinStrength * f_strengthFactor()
// Auto normalization: compare current AMA "step" to its long-run average
amaStep = atr > 0 ? ta.rma(math.abs(ama - ama[1]), atrLen) / atr : 0.0
amaStepRef = ta.sma(amaStep, autoLookback)
autoFactor = (amaStepRef > 0) ? (amaStep / amaStepRef) : 1.0
minStrengthAuto = baseMinStrength * autoFactor
minStrength = strengthMode == "Off" ? baseMinStrength : strengthMode == "By MA Type" ? minStrengthByType : minStrengthAuto
strongTrend = spreadATR >= minStrength
// Regimes (confirmed close + strength gate + MA alignment)
bullRaw = barstate.isconfirmed and close >= ma1 and close >= ma2 and close >= ma3 and ma1 >= ma2 and ma2 >= ma3
bearRaw = barstate.isconfirmed and close <= ma1 and close <= ma2 and close <= ma3 and ma1 <= ma2 and ma2 <= ma3
bull = bullRaw and strongTrend
bear = bearRaw and strongTrend
neutral = barstate.isconfirmed and not bull and not bear
bullFlip = bull and not bull[1]
bearFlip = bear and not bear[1]
exitFlip = (neutral and not neutral[1]) or ((bull[1] and not bull) and not bear) or ((bear[1] and not bear) and not bull)
// ─────────────────────────────────────────────────────────────────────────────
// Persisted levels (overlay zones)
// ─────────────────────────────────────────────────────────────────────────────
var float longEntry = na
var float longSL = na
var float shortEntry = na
var float shortSL = na
if bullFlip
longEntry := highestMA
longSL := highestMA - slDist
shortEntry := na
shortSL := na
if bearFlip
shortEntry := lowestMA
shortSL := lowestMA + slDist
longEntry := na
longSL := na
if exitFlip
longEntry := na
longSL := na
shortEntry := na
shortSL := na
// ============================================================================
// MODULE: visualization
// ============================================================================
// ─────────────────────────────────────────────────────────────────────────────
// Plots
// ─────────────────────────────────────────────────────────────────────────────
trendCol = bull ? color.new(color.lime, 0) : bear ? color.new(color.fuchsia, 0) : color.new(color.gray, 0)
plot(showMAs ? ma1 : na, "MA 1", color=color.new(trendCol, 60))
plot(showMAs ? ma2 : na, "MA 2", color=color.new(trendCol, 60))
plot(showMAs ? ma3 : na, "MA 3", color=color.new(trendCol, 60))
plot(showAMA ? ama : na, "Average MA",
color=bull ? color.new(color.blue, 0) : bear ? color.new(color.red, 0) : color.new(color.gray, 0),
linewidth=2)
pLongSL = plot(bull ? longSL : na, "Long SL", color=color.new(color.gray, 0), style=plot.style_linebr)
pLongEntry = plot(bull ? longEntry : na, "Long Entry", color=color.new(color.white, 0), style=plot.style_linebr)
pShortSL = plot(bear ? shortSL : na, "Short SL", color=color.new(color.gray, 0), style=plot.style_linebr)
pShortEntry = plot(bear ? shortEntry : na, "Short Entry", color=color.new(color.white, 0), style=plot.style_linebr)
fill(pLongSL, pLongEntry, title="Long Stop Zone", color=showZones and bull ? color.new(color.red, 75) : na)
fill(pShortEntry, pShortSL, title="Short Stop Zone", color=showZones and bear ? color.new(color.yellow, 75) : na)
bgcolor(showBg and bull ? color.new(color.green, 93) : showBg and bear ? color.new(color.purple, 93) : na, title="Regime BG")
// ─────────────────────────────────────────────────────────────────────────────
// Labels
// ─────────────────────────────────────────────────────────────────────────────
if showLabels and bullFlip
label.new(bar_index, high, "BULL", style=label.style_label_up, textcolor=color.white, color=color.new(color.green, 0), size=_ls)
if showLabels and bearFlip
label.new(bar_index, low, "BEAR", style=label.style_label_down, textcolor=color.white, color=color.new(color.red, 0), size=_ls)
if showLabels and exitFlip
label.new(bar_index, close, "NEUTRAL", style=label.style_label_left, textcolor=color.white, color=color.new(color.gray, 40), size=_ls)
// ─────────────────────────────────────────────────────────────────────────────
// Alerts
// ─────────────────────────────────────────────────────────────────────────────
bool alertsOnBarClose = input.bool(true, "Alerts only on bar close (confirmed)", group="Alerts")
bool alertOk = not alertsOnBarClose or barstate.isconfirmed
alertcondition(alertOk and (bullFlip), "Bull Regime", "MRB · Bull Regime · {{ticker}} {{interval}}")
alertcondition(alertOk and (bearFlip), "Bear Regime", "MRB · Bear Regime · {{ticker}} {{interval}}")
alertcondition(alertOk and (exitFlip), "Neutral/Transition", "MRB · Neutral/Transition · {{ticker}} {{interval}}")
Overview
MA Regime Bands [WavesUnchained] evaluates alignment across customizable MA types (SMA, EMA, DEMA, TEMA, or JMA) and filters trend strength using an ATR spread threshold. The script displays stop zones, regime labels, and background highlighting, with optional plots for the individual moving averages and an average baseline.
Three-MA alignment regime classification
Multiple MA types including DEMA, TEMA, and JMA
ATR-based stop bands and zones
Normalized trend strength filter
Configurable regime labels and background coloring
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
MA Type
string
DEMA
maType
MA 1 Length
int
21
len1
MA 2 Length
int
55
len2
MA 3 Length
int
89
len3
Show MAs
bool
false
showMAs
Show Average MA
bool
false
showAMA
ATR Length
int
20
atrLen
ATR Stop Loss Multiplier
float
2.0
mult
Show Stop Zones
bool
true
showZones
Strength Normalization
string
By MA Type
strengthMode
Base Min Strength (spread / ATR)
float
0.6
baseMinStrength
Auto Normalize Lookback
int
200
autoLookback
Show all 16 settings
Setting
Type
Default
Variable
Show Regime Labels
bool
true
showLabels
Label Size
string
tiny
labelSize
Show Regime Background
bool
true
showBg
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.
This indicator plots standard Bollinger Bands and three configurable moving averages directly on the price chart. Users can toggle the Bollinger Bands, adjust their length and multiplier, and choose between exponential or simple moving averages for fast, slow,
This indicator plots four customizable moving averages directly on the main price chart using default lengths of 3, 8, 21, and 50 periods. It fills the space between adjacent averages in green or maroon depending on trend alignment. Additionally, it computes B
This indicator plots three exponential moving averages and ATR volatility envelopes on the price chart. It compares the fast and slow EMAs to shade a trend ribbon and marks confirmed upward and downward crossovers with triangle labels. Settings change the thre
This indicator modifies standard Bollinger Bands to measure directional trend force based on line alignment. It calculates a simple moving average basis along with upper and lower volatility bands. When all three lines move upward or downward simultaneously, i
This indicator overlays trend-following Supertrend bands on the price chart using Average True Range calculations. It plots trailing stop lines, highlights active trend directions, and prints buy or sell shape labels when price closes across band thresholds. I
This indicator calculates Kaufman's Adaptive Moving Average (KAMA) on a chosen price source and determines trend direction based on the slope across a configurable lookback window. Signals can be filtered by short-term volatility expansion using ATR comparison