CODESCRIPT

Drawing lines

A calculation you never see is a calculation you cannot trust. plot turns a value into a line bar by bar, hline pins a fixed level, and fill shades the space between two lines. This page walks you through all three.

You have written an indicator and it produces numbers. A number that never reaches the screen is a number you cannot check. Drawing it is the quickest way to inspect your own math. That makes the drawing functions a debugging tool, not decoration.

Drawing a value with plot

plot takes one number per bar and joins them end to end into an unbroken line. It is the tool for anything that runs continuously: a moving average, momentum, volume, position direction.

CODESCRIPT
// 20 barlik basit ortalama her barda yeniden hesaplanir
ortalama = sma(close, 20)
plot(ortalama)

A single line tracking the 20-bar average appears on the price panel. With no title or color given, the defaults apply.

NOTE

plot returns nothing; it only draws. So you cannot assign its result to anything. Compute into a variable first and draw afterwards — it reads better, and the same value stays available elsewhere in the script.

plot(series, title?, color?, pane?, style?, linewidth?, linestyle?, offset?, display?)

Returns nothing; draws the series onto the chart.

series
series
The series to draw. It must be numeric; passing text raises an error.
title
text
Optional. The line's name, which is what shows up in the chart legend.
color
color
Optional. A hex color code such as "#26a69a".
pane
text
Optional. Which panel the line goes to. Every line sharing a name lands in the same panel. Leave it out and the panel is picked from the value range.
style
text
Optional. How the value is drawn: line, stepline, histogram, columns, area, circles, cross. Defaults to line.
linewidth
number
Optional. Thickness, from 1 to 4.
linestyle
text
Optional. Dash pattern: solid, dashed or dotted.
offset
number
Optional. Shifts the line N bars right or left. Only the drawing moves; the calculation stays put.

Giving a title and a color

The second argument is the title, the third is the color. The moment you put two lines in one panel you need both: an unnamed line is unidentifiable in the legend, and two lines in the same color blur together.

CODESCRIPT
hizli = ema(close, 12)
yavas = ema(close, 26)
// ikinci arguman baslik, ucuncu arguman renk
plot(hizli, "EMA 12", "#26a69a")
plot(yavas, "EMA 26", "#ef5350")

A green EMA 12 and a red EMA 26 on the price panel, each listed under its own name in the legend.

TIP

Colors are hex: #rrggbb. Two extra characters set transparency, so #2962ff22 is a faint blue. If you would rather work in channels, rgb(38, 166, 154) gets you the same result.

Placing a line in a lower panel

Not every series belongs next to price. RSI travels between 0 and 100 while price is measured in thousands. Put them in one panel and the candles collapse into a thin strip. The fix is the fourth argument: you give the series a panel name.

CODESCRIPT
// RSI 0 ile 100 arasinda gezer, fiyatla ayni panoya sigmaz
plot(rsi(close, 14), "RSI 14", "#7e57c2", "rsi")
// ayni pano adini veren her cizgi ayni alt panoda toplanir
plot(sma(rsi(close, 14), 9), "RSI ortalamasi", "#ff9800", "rsi")

A panel named "rsi" opens below the price panel. RSI and its own 9-bar average are drawn together there, leaving the candles untouched.

CAUTION

Leave the panel name out and one is chosen for you. That usually works, but it is a guess: a series whose range happens to sit near price ends up on the price panel. Name the panel yourself when you want to be sure.

Changing how the line is drawn

plot does not have to produce a smooth line. Volume reads more honestly as bars, and a higher-timeframe value looks truer as a stepped line. The fifth argument sets the shape, the sixth the thickness, the seventh the dash pattern.

CODESCRIPT
// hacmi cubuk olarak ciz, ortalamasini kesikli cizgiyle ustune koy
plot(volume, "Hacim", "#78909c", "hacim", "histogram")
plot(sma(volume, 20), "Hacim ortalamasi", "#ff9800", "hacim", "line", 2, "dashed")

The "hacim" panel shows grey volume bars with a 2-pixel orange dashed average running across them. Bars that overshoot the average stand out at a glance.

A fixed level with hline

Some levels never move. The 70 and 30 thresholds on RSI, a target price you have in mind, a round number. You do not need plot for these; plot expects a fresh value each bar, and you only have one number. hline exists for exactly this.

hline(price, title?, color?, style?, width?, display?)

Returns nothing; draws a horizontal level spanning the chart.

price
number
The level the line sits at. A single constant number.
title
text
Optional. A name for the level.
color
color
Optional. The line color.
style
text
Optional. solid, dashed or dotted. Defaults to dashed.
width
number
Optional. Thickness in pixels. Defaults to 1.
CODESCRIPT
plot(rsi(close, 14), "RSI 14", "#7e57c2", "rsi")
// bu esikler bar bar degismez, sabit seviye olarak durur
hline(70, "Asiri alim", "#ef5350")
hline(50, "Orta", "#90a4ae", "dotted")
hline(30, "Asiri satim", "#26a69a")

Three horizontal levels in the RSI panel: a red dashed line at 70, a grey dotted one at 50, a green dashed one at 30. The RSI line now has something to be read against.

CAUTION

Do not hand hline an indicator series. Write sma(close, 50) and nothing breaks, but nothing works either: only the last bar's value is taken and the line freezes there. Use plot for an average that moves. This is the single most common beginner trap.

Shading between two lines with fill

Often the gap between two lines says more than the lines do. A widening band means volatility is picking up; a narrowing one means things are calming down. Shade that gap and you see it in a single glance.

fill(a, b, color)

Returns nothing; shades the area between a and b.

a
series
One edge of the band. A series, a constant number, or an hline().
b
series
The other edge of the band.
color
color
Optional. The fill color. Give it a transparent code so the candles underneath stay readable.
CODESCRIPT
bant = bb(close, 20, 2)
plot(bant.upper, "Ust bant", "#2962ff")
plot(bant.lower, "Alt bant", "#2962ff")
// sondaki 22 saydamliktir, mumlar dolgunun altinda gorunur kalir
fill(bant.upper, bant.lower, "#2962ff22")

Two blue band lines on the price panel with a translucent blue body between them. The body swells as volatility rises and pinches in when things go quiet.

The edges can be fixed levels too. Pass hline() calls straight into fill and the region between them gets shaded. This is how you mark the neutral zone between overbought and oversold.

CODESCRIPT
plot(rsi(close, 14), "RSI 14", "#7e57c2", "rsi")
// iki sabit seviye arasindaki notr bolgeyi boya
fill(hline(30), hline(70), "#7e57c222")

The area between 30 and 70 in the RSI panel fills with translucent purple. The moment the line leaves that band, it catches your eye.

TIP

fill does not draw the edges, only the space between them. If you want the boundaries visible, draw them separately with plot or hline. And keep the color transparent — a solid fill hides the candles beneath it.

When plot is not enough

plot is for a value that runs continuously. When you do not have a number on every bar, or you want separate marks rather than a line, you switch tools. The list below points you to the right one.

  • To mark only the bars where a signal fires, use plotshape; it drops a triangle, circle or flag.
  • When a single character is enough, plotchar gives a cleaner mark.
  • To show direction and strength at once, plotarrow draws an arrow that grows with the value.
  • To attach free text at a specific price, reach for label.
  • For a slanted line between two points use trendline; plot cannot do it, because it ties one value to every bar.
  • To frame a region with a rectangle, box is the fit.
  • To color a whole bar's background use bgcolor; fill only shades between two series, never the backdrop.
  • For a summary pinned in a corner, infoTable writes your rows there.

You can still bend plot into a marker. The line breaks on na bars, so if iff only produces a value on signal bars the rest stay empty. When you want the same thing as a discrete shape, plotshape looks tidier.

CODESCRIPT
// yalnizca kesisim barlarinda deger uret, digerleri na kalsin
sinyal = crossover(close, sma(close, 20))
plot(iff(sinyal, low, na), "Kesisim noktasi", "#26a69a", "price", "circles")
// ayni sinyali ayrik bir bicimle isaretlemek istersen
plotshape(sinyal, "Kesisim", "triangleup", "belowbar", "#26a69a")

Green dots at the low on up-cross bars, with green triangles under those same bars. Nothing at all is drawn on the na bars.

NOTE

The line breaking on na bars is a feature, not a flaw: it shows you which bars the calculation was not ready for. sma(close, 200), for instance, stays empty over the first 199 bars. When you see a gap, check that first.

Common mistakes

  • Handing plot a piece of text. The series must be numeric, and text stops the script with a clear error.
  • Drawing a series on a completely different scale from price onto the price panel. The candles get crushed. Name the panel.
  • Trying to draw a moving average with hline. The line freezes at the last bar's value and misleads you.
  • Calling fill without ever drawing the edges. The band shows up, but its boundaries stay vague.
  • Leaving the fill color solid. The candles disappear underneath it.
  • Piling fifteen lines into one panel. The chart turns to noise and none of them can be read.
TIP

To line a series up against an earlier stretch of the chart, use the offset argument. It slides the drawing N bars either way and leaves the calculation alone. Never take an entry off a shifted line — what you are looking at is an older value.