Pine Script Visuals

Fill Between Plots in Pine Script v5 and v6

The built-in function is fill(), not plotfill() or plot.fill(). Pass two IDs returned by plot(), or two IDs returned by hline(); a plot ID and an hline ID cannot be mixed. For a moving series and a fixed baseline, use plot() for both. Fills between either pair can use dynamic colors. If your boundaries are line.new() objects, use linefill.new() instead.

Open the Visual Pine Editor

Replace plotfill with fill()

Searching for plotfill in Pine Script v5 usually leads to the fill() API. The example stores two moving-average plot IDs and passes them to fill(). Passing the moving-average values themselves would be a type error. Each code block on this page is a separate complete indicator; paste one at a time into Pine Editor.

Complete v5 example: fill between two moving averagespinescript
//@version=5
indicator("MA Spread Fill", overlay=true)

fast = ta.sma(close, 9)
slow = ta.sma(close, 21)
fastPlot = plot(fast, "Fast SMA", color=color.teal)
slowPlot = plot(slow, "Slow SMA", color=color.orange)
fill(fastPlot, slowPlot, color=color.new(color.blue, 85), title="MA spread")

Plot IDs, hline IDs, and a fixed baseline

hline() has a fixed price and an input color: the line itself cannot change color on each bar. That restriction does not apply to fill(h1, h2, color=...), whose fill color can be a series. In this RSI example, the band between 30 and 70 changes color with RSI. A separate plot(50) supplies the matching plot ID needed to shade RSI against its midpoint. display.none hides that baseline plot without removing its fill anchor.

Boundary pairFunctionConstraint
Two plot IDsfill()Series or fixed values; dynamic fill color supported
Two hline IDsfill()Fixed levels; dynamic fill color supported
One plot and one hlineNo matching fill() overloadReplace the hline with a plot at the same level
Two line IDslinefill.new()Drawings with endpoints; the fill follows those lines
Complete v6 example: dynamic hline fill and RSI-to-midpoint fillpinescript
//@version=6
indicator("RSI Fill Boundaries", overlay=false)

rsi = ta.rsi(close, 14)
upper = hline(70, "Upper level", color=color.gray)
lower = hline(30, "Lower level", color=color.gray)
zoneColor = rsi >= 50 ? color.new(color.teal, 94) : color.new(color.red, 94)
fill(upper, lower, color=zoneColor, title="Fixed-level zone")

rsiPlot = plot(rsi, "RSI", color=color.blue, linewidth=2)
midPlot = plot(50, "Midpoint anchor", display=display.none)
polarityColor = rsi >= 50 ? color.new(color.teal, 75) : color.new(color.red, 75)
fill(rsiPlot, midPlot, color=polarityColor, title="RSI polarity")

Dynamic colors and transparency

A conditional color can switch a cloud between two hues. color.from_gradient() can instead map a numeric value to a color on each bar. The EMA example uses spread divided by ATR, then maps values from -2 to +2 to red through teal; values outside that interval use the endpoint colors. This changes the color over time. It is different from a vertical gradient within a single bar, which uses the separate fill() overload with top_value, bottom_value, top_color, and bottom_color.

  • Transparency 0 is fully opaque; 100 is fully transparent. Intermediate values can be fractional.
  • Use color=na to suppress a fill on selected bars without moving fill() into an if block.
  • These colors describe the chosen formula. They do not establish trend strength or predict a breakout.
Complete v6 example: a color gradient across bars with bounded transparencypinescript
//@version=6
indicator("EMA Gradient Fill", overlay=true)

fastLength = input.int(10, "Fast EMA length", minval=1)
slowLength = input.int(30, "Slow EMA length", minval=1)
transparency = input.int(80, "Fill transparency", minval=0, maxval=100)
showFill = input.bool(true, "Show fill")
fast = ta.ema(close, fastLength)
slow = ta.ema(close, slowLength)
atr = ta.atr(14)
normalizedSpread = not na(atr) and atr > 0 ? (fast - slow) / atr : na
baseColor = color.from_gradient(normalizedSpread, -2, 2, color.maroon, color.teal)
fillColor = showFill ? color.new(baseColor, transparency) : na
fastPlot = plot(fast, "Fast EMA", color=color.teal)
slowPlot = plot(slow, "Slow EMA", color=color.orange)
fill(fastPlot, slowPlot, color=fillColor, title="EMA spread gradient")

Missing values and global scope

fillgaps controls whether shading continues over chart bars where a boundary series is na. It does not create bars for weekends, holidays, or closed sessions. To leave visible breaks, use fillgaps=false and plot.style_linebr for the boundary lines. The example deliberately omits five bars in every twenty so you can compare the fill behavior by changing fillgaps=false to fillgaps=true in the code. This parameter requires a const bool, so it cannot be connected to an input toggle. Show fill changes only the color; the fill() call stays in global scope.

Complete v6 example: deliberate na gaps and conditional visibilitypinescript
//@version=6
indicator("Fill Gaps Example", overlay=true)

showFill = input.bool(true, "Show fill")
basis = ta.sma(close, 20)
width = ta.atr(14)
hasValue = bar_index % 20 < 15
upper = hasValue ? basis + width : na
lower = hasValue ? basis - width : na
upperPlot = plot(upper, "Upper", color=color.blue, style=plot.style_linebr)
lowerPlot = plot(lower, "Lower", color=color.blue, style=plot.style_linebr)
fillColor = showFill ? color.new(color.blue, 85) : na
fill(upperPlot, lowerPlot, color=fillColor, fillgaps=false, title="Channel")

Use linefill for line.new() drawings

A line.new() object has endpoints and can be updated inside a conditional block. fill() cannot use its line ID. linefill.new() connects two such objects, and moving either boundary updates the filled region. The following example maintains two horizontal drawings for the latest 20-bar high and low. It updates the same two line objects and one fill rather than creating new drawings on every bar.

Complete v6 example: a rolling range drawn with lines and linefillpinescript
//@version=6
indicator("Line Object Range Fill", overlay=true, max_lines_count=2)

upper = ta.highest(high, 20)
lower = ta.lowest(low, 20)
var line topLine = line.new(na, na, na, na, color=color.teal)
var line bottomLine = line.new(na, na, na, na, color=color.teal)
var linefill rangeFill = linefill.new(topLine, bottomLine, color.new(color.teal, 85))

if barstate.islast and bar_index >= 19
    line.set_xy1(topLine, bar_index - 19, upper)
    line.set_xy2(topLine, bar_index, upper)
    line.set_xy1(bottomLine, bar_index - 19, lower)
    line.set_xy2(bottomLine, bar_index, lower)
    linefill.set_color(rangeFill, color.new(color.teal, 85))

Common fill errors and what to change

Identify whether the problem is the function name, the boundary type, the scope, or the data. Changing colors will not fix incompatible IDs, and enabling fillgaps will not repair an invalid calculation. After compilation, inspect the chart while changing each input; a syntax check cannot establish that the shaded area matches your intended rule.

SymptomCauseCorrection
plotfill or plot.fill is not foundIncorrect built-in nameUse fill() with IDs from plot() or hline()
Numeric series rejected as a boundaryPassed a calculation instead of its plot IDAssign the plot() return value to a variable
Plot/hline type mismatchMixed boundary typesUse plot() for both the series and fixed baseline
Cannot use fill in local scopeCall placed in an if, loop, or function bodyKeep fill() global and make its color conditional
Cloud crosses missing valuesFill continues across na barsSet fillgaps=false and use linebr for broken boundary lines
Fill is invisibleColor is na or fully transparent, boundaries coincide, or data is unavailableCheck transparency, boundary values, and indicator warm-up
Where Pineify fits

Visual Pine Script Editor

Build indicators visually, then inspect the generated Pine Script and its channel-fill settings in TradingView.

Also useful: Pine Script AI Coding Agent. Ask the coding agent to draft or revise a fill indicator from your boundary and color rules, then review its code and chart output.

Open the Visual Pine Editor

Frequently asked questions

These examples explain chart shading. They are not tested trading strategies or investment recommendations. Check the plotted values and behavior in TradingView before using a fill as part of a trading rule.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.