TradingView indicators

Moving average envelopes: percent bands and signals

A moving average envelope puts an upper and lower band a fixed percentage from an SMA or EMA. It measures distance from that average. It does not estimate volatility or prescribe a trade when price touches a band.

Upper = basis × (1 + percent / 100)
Lower = basis × (1 − percent / 100)

Basis $100, distance 2%: upper $102, lower $98, total width $4.

Copy the Pine Script v6 example

Educational examples only, not investment advice. No setting or signal here has a demonstrated return or success rate.

Parameters and units in TradingView

The TradingView ENV inputs include length, percentage, source and an Exponential switch. Match all four when comparing scripts.

Envelope parameter meanings and comparison checks
InputMeaningExample / check
LengthNumber of chart bars for the MA calculation20 on a daily chart uses daily observations; 20 on a 1-hour chart uses hourly observations.
PercentDistance on each side of the basisEnter 2 for 2%, not 0.02. The total width is 4% of a positive basis.
SourcePrice series averagedClose is the documented default. An average of high, low and close produces a different basis.
ExponentialEMA when enabled; SMA otherwiseThe percentage formula stays the same; the basis changes.

An SMA equally weights its last N observations. An EMA uses α = 2 / (N + 1) and retains older information through its previous value. See EMA calculation and initialization for the full distinction.

For an independent one-step example, let the prior 5-bar SMA and EMA both equal 100. If an old SMA observation of 100 leaves the window and a new close of 106 enters, the new SMA is 101.2. The EMA is 106 / 3 + 100 × 2 / 3 = 102. At 2%, the SMA bands are 103.224 and 99.176; the EMA bands are 104.04 and 99.96. These assume the stated prior EMA and window, not a claim that equal-length averages always match beforehand.

Use positive price bases for these conventional upper/lower labels. At zero the bands collapse; at a negative basis the labels reverse. The script suppresses event markers when its current or lookback basis is nonpositive.

Price scale and volatility are different inputs

A fixed percentage does not fix the dollar width. With a 2% distance, doubling the basis from $100 to $200 moves the bands from $102/$98 to $204/$196. The distance to one band doubles from $2 to $4; the total channel width doubles from $4 to $8.

Now hold the basis at 100. Two hypothetical five-close windows, [99, 100, 100, 100, 101] and [94, 98, 100, 102, 106], both average 100. A 2% SMA envelope is 98 to 102 in both cases, although their population standard deviations are about 0.63 and 4.00. The second window ends at 106, outside the envelope; the first ends at 101, inside. The dispersion changed without widening the percent bands.

How envelope width differs from adaptive bands
IndicatorDistance from basisWhat changes width?
MA envelopesBasis × percentage / 100Basis price or the selected percentage
Bollinger BandsStandard deviation × multiplierDispersion of the selected price series
Keltner ChannelsSelected range measure × multiplierRange or ATR, depending on settings

Those are differences in measurement, not evidence that one method wins more trades. A narrower band changes how often price crosses it; that frequency is not a profitability measure.

Two event rules to test separately

The following rules are authored test hypotheses, not TradingView recommendations. Both wait for the chart bar to close. The slope measure is 100 × (current basis / basis five bars ago − 1); 0.1 means 0.1%, not 10%.

B: upward breakout with a rising basis

Require slope above 0.1%, the previous close at or below its upper band, and the current close above its upper band. For a 2% envelope, previous basis 100 gives upper 102; previous close 101.5 is inside. Current basis 101 gives upper 103.02; current close 103.5 crosses above. If the basis five bars ago was 99, slope is about 2.02%, so B is true.

If only the high reaches 104 while the close is 102.9, B is false against the same 103.02 band. A confirmed B can still fail on the next bar: a close back inside does not undo the earlier event, but can invalidate a continuation trade under a separately defined exit rule.

R: lower-band reentry with a flat basis

Require absolute slope at most 0.1%, the previous close strictly below its lower band, and the current close back above its lower band but at or below its upper band. With previous and current basis 100, bands are 98 and 102. A previous close of 97 followed by 98.5 qualifies if the five-bar-ago basis is also 100. A current close of 97.8 does not.

If the current basis is 99 and the five-bar-ago basis is 100, slope is −1%, so R is false even if price reenters the envelope. This filter defines the example's meaning of flat; it does not prove a range will persist. A reentry can fail when a downtrend resumes.

Each comparison uses that bar's own band. A moving band can cross price, too. Keep the source, session, symbol and timeframe fixed when investigating why an event appeared.

Pine Script v6: bands and confirmed event markers

The script exposes MA type, length, source and percentage. B and R label the rules above; they are not orders. Alerts must be created separately in TradingView. Use the built-in ENV alongside it with identical inputs to compare basis and bands in the Data Window on closed bars.

Pine Script v6
//@version=6
indicator("Moving Average Envelopes: confirmed events", overlay=true)

length = input.int(20, "MA length (bars)", minval=1)
source = input.source(close, "MA source")
useEMA = input.bool(false, "Use EMA instead of SMA")
percent = input.float(2.0, "Envelope distance (%)", minval=0.01, maxval=99.0, step=0.1)
slopeBars = input.int(5, "Slope lookback (bars)", minval=1)
flatLimit = input.float(0.1, "Flat basis tolerance (%)", minval=0.0, step=0.05)

smaBasis = ta.sma(source, length)
emaBasis = ta.ema(source, length)
basis = useEMA ? emaBasis : smaBasis
upper = basis * (1 + percent / 100)
lower = basis * (1 - percent / 100)
valid = not na(basis[slopeBars]) and basis > 0 and basis[slopeBars] > 0
slopePct = valid ? 100 * (basis / basis[slopeBars] - 1) : na
crossUpper = ta.crossover(close, upper)
crossLower = ta.crossover(close, lower)
trendEvent = barstate.isconfirmed and valid and slopePct > flatLimit and crossUpper
reentryEvent = barstate.isconfirmed and valid and math.abs(slopePct) <= flatLimit and close[1] < lower[1] and crossLower and close <= upper

plot(basis, "Basis", color=color.blue)
u = plot(upper, "Upper envelope", color=color.orange)
l = plot(lower, "Lower envelope", color=color.orange)
fill(u, l, color=color.new(color.blue, 92))
plotshape(trendEvent, title="Upward breakout", style=shape.triangleup, location=location.belowbar, color=color.blue, size=size.tiny, text="B")
plotshape(reentryEvent, title="Lower-band reentry", style=shape.circle, location=location.belowbar, color=color.orange, size=size.tiny, text="R")
alertcondition(trendEvent, "Upward breakout", "Confirmed upward envelope breakout with rising basis")
alertcondition(reentryEvent, "Lower-band reentry", "Confirmed lower-band reentry with flat basis")

Copy Pine Script

Bands update with an open bar; markers require barstate.isconfirmed. This removes intrabar marker triggers on the chart timeframe. It does not protect against changed data feeds, revisions or modified inputs. Allow sufficient history for the selected average and slope lookback before comparing values.

Turn the rule into a testable strategy

Pineify's Pine Script AI Coding Agent can help modify the formula or convert a chosen event into strategy code. Specify entry timing, exits, position sizing and costs. Ask it to check syntax explicitly, then compare the result in TradingView. The indicator above does not contain that trading logic.

  1. Choose one hypothesis. Define whether the signal leads to an order on the next bar and what happens after a gap.
  2. Fix the symbol, timeframe, session and date window. Include commission and slippage in the strategy test.
  3. For a small illustrative parameter grid, compare lengths 15, 20 and 25 with distances 1.5%, 2% and 2.5%. Keep the MA type and event rule fixed: this produces nine combinations, not nine independent discoveries.
  4. For a compatible TradingView strategy, use Strategy Optimizer to compare input combinations. Review neighboring results, trade count and drawdown rather than selecting only the highest profit.
  5. Freeze the rule and settings before testing a separate time period. Repeatedly adjusting to that period turns it into another development sample.
Build an envelope rule with the AI Coding Agent

Generated code and historical results require review. Neither syntax validation nor parameter optimization establishes future returns.

Moving average envelope questions

Sources and scope

Official documentation checked October 17, 2026. The numerical windows and B/R rules on this page are constructed examples, not market observations or measured trading results.

Continue with EMA weighting, Bollinger Bands, or the TradingView indicator library.