Moving Average Channel: High–Low SMA and Pine Script | Pineify
The Moving Average Channel plots an SMA of highs and an SMA of lows, then colors bars by the close’s position relative to those lines. With equal lengths and matching valid observations, its width equals the SMA of each bar’s high-low range. The width is not fixed, and a bar color describes a comparison rather than a confirmed trend or trade.
Inspect the Pine ScriptEqual lengths give a useful width identity
The default call uses upper = SMA(high, 20) and lower = SMA(low, 20). On a complete common window, linearity gives upper − lower = SMA(high − low, 20). The midpoint equals SMA(HL2, 20).
Because high is at least low on each valid bar, the upper average is at least the lower average under these conditions. Neither fact implies that current price must stay inside: a current close can exceed an average of earlier highs without exceeding its own high.
Changing recent ranges changes width even when the length is unchanged. Increasing length does not necessarily widen the channel: it depends on which wider or narrower ranges enter the average. Different missing-data patterns or custom sources require a separate alignment check before using the identity.
Worked channel and color example
Use length 3 for this hypothetical calculation. The first three high/low pairs are 102/98, 104/100, and 106/102. Their averages are upper 104 and lower 100, giving width 4 and midpoint 102. If the third close is 105, it is above the upper average and the bar is lime.
Next, add high 110, low 100, close 103. The old 102/98 pair leaves the window. Upper becomes (104 + 106 + 110)/3 = 106.666667; lower becomes (100 + 102 + 100)/3 = 100.666667. Width rises from 4 to 6. Close 103 lies inside, so the bar is gray.
The same fixed length thus produces a wider channel. The gray bar also shows why returning below the upper line does not necessarily make a bar red: red requires a close strictly below the lower line.
A gap can behave differently from intrabar range. If every high-low range remains 4 while the whole price level gaps, the equal-length channel width stays 4. True range can still increase because it includes distances from the previous close. This channel width is not ATR.
Read the exact color branches
The code first tests close > upper and assigns lime. Otherwise it tests close < lower and assigns red. All other cases are gray. With valid ordered lines, equality at either boundary is gray; a close above upper can stay lime for many consecutive bars without a new crossover.
Before both default SMAs are available, the comparisons do not establish a valid channel state and the fallback color is gray. Gray therefore does not prove consolidation or low volatility. The code has no separate warmup marker.
The current high, low, and close can update intrabar, so both lines and bar colors can change. There is no barstate.isconfirmed gate. A closing confirmation must be implemented explicitly if that is the desired event policy; it still does not guarantee the next bar continues the move.
Unequal windows can reverse the line ordering
If the two lengths or sources differ, upper and lower are labels, not a mathematical ordering guarantee. For example, let three lows be 118, 108, 98 and the current high be 102. With upper length 1 and lower length 3, upper = 102 and lower = 108. A valid current close of 101 is below both and becomes red.
Overlapping inequalities can also occur with valid high-low data. Take three high/low pairs 142/138, 94/90, and 106/104, with current close 105. Upper length 2 gives (94 + 106)/2 = 100. Lower length 3 gives (138 + 90 + 104)/3 = 110.666667. Both close comparisons are true and the first branch wins: lime.
Before interpreting colors from asymmetric settings, inspect line ordering and choose whether to reject inverted states, reorder the boundaries, or retain explicit branch priority. Those alternatives change the model and should not be silently substituted.
Parameters and display offsets in this exact copy
The helper accepts source, length, and offset arguments for each side, but its body uses only sources and lengths. Both offsets are unused. The two plot calls also omit plot offset. Changing the offset arguments alone has no effect on this copied script.
The call fixes high/20/0 and low/20/0; there are no settings inputs. The line colors, fill, and bar coloring are present. There are no alerts, automatic orders, ATR stops, or performance calculations.
A plot offset, if deliberately added, moves a drawing horizontally; it does not change the underlying series used by a close-versus-channel test. It is not equivalent to waiting an extra bar for confirmation. A negative drawing offset can also display later-known values on earlier bars, so observation time must remain explicit.
Pineify’s Visual Editor configuration has source, length, offset, and styling fields for this indicator. The existence of those fields does not establish that an offset is applied in this standalone example. Compare generated plot calls and values before relying on a display setting.
Keep comparisons and trading hypotheses separate
This high-low SMA channel, a percentage envelope, a standard-deviation band, and an ATR channel use different width definitions. None is a universal replacement for the others. This page’s default width measures average high-low range, not a constant percentage of a centerline.
Choose whether a proposed rule means a new crossover, two successive closes outside, or a return inside. Also define current versus previous boundaries and the first executable order time. Adding ADX, volume, or an ATR distance is a separate hypothesis, not an established reduction in false signals.
Related references: live-bar and historical display behavior, plot offsets, and ATR’s gap-aware input.
Pine Script v6: implementation and limits
This unchanged calculation plots two fixed SMA 20 lines, a gold fill, and lime/red/gray bar colors. The offset arguments are retained in the helper signature but are not used. There are no inputs or trading orders.
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify
//@version=6
indicator(title="Moving Average Channel", overlay=true, max_labels_count=500)
p_ta_moving_average_channel(series float upperSrc, simple int upperLength, simple int upperOffset, series float lowerSrc, simple int lowerLength, simple int lowerOffset) =>
upper = ta.sma(upperSrc, upperLength)
lower = ta.sma(lowerSrc, lowerLength)
[upper, lower]
[p_ind_1_upper, p_ind_1_lower] = p_ta_moving_average_channel(high, 20, 0, low, 20, 0)
p_ind_1_upper_plot = plot(p_ind_1_upper, title="MAC - Upper", color=color.rgb(60, 120, 216, 0), linewidth=1)
p_ind_1_lower_plot = plot(p_ind_1_lower, title="MAC - Lower", color=color.rgb(245, 124, 0, 0), linewidth=1)
fill(p_ind_1_upper_plot, p_ind_1_lower_plot, title="MAC - Background", color=color.rgb(255, 217, 102, 90))
p_ind_1_color = close > p_ind_1_upper ? color.lime : close < p_ind_1_lower ? color.red : color.gray
barcolor(p_ind_1_color, title="MAC - Bar Color")
Specify a checkable adaptation in Pineify
Describe both source series and lengths, how inverted boundaries should be handled, and whether an event is a state or a new crossing. Ask the Pine Script AI Coding Agent to expose only the intended controls and implement any confirmation policy explicitly. Verify the worked values and generated plot offsets before testing a strategy.
Open Pine Script AI Coding AgentEducational indicator analysis. No measured trading performance is established here. Syntax validation does not prove formula equivalence, execution assumptions or profitability.