Price data and series
Every script runs over bars. Once you know which prices a bar carries, and why those prices are called a series, the rest falls into place.
Each candle on the chart is one bar. A bar sums up a slice of time with four prices. Your script walks those bars left to right, running your whole code once on every one.
The prices inside a bar
Five basic series are waiting on every bar. Writing the name is enough; there is nothing to declare.
- open — the first price the bar traded at.
- high — the highest price seen during the bar, the tip of the upper wick.
- low — the lowest price, the bottom of the lower wick.
- close — the last price of the bar. Most rules are built on it.
- volume — how much changed hands during the bar.
// bir barin govdesi: kapanis eksi acilis govde = close - open // barin tam araligi: en yuksek eksi en dusuk aralik = high - low plot(govde, "govde", "#2962ff", "olcu") plot(aralik, "aralik", "#ff9800", "olcu")
Two lines in the lower olcu panel: the blue one is the signed body size (positive on up bars, negative on down bars), the orange one is the full bar range including wicks.
close is the source you will reach for most often. In most indicator calls it is the first argument you see: sma(close, 20).
A series, or a single number?
A series is a column holding a separate value for each bar. A plain number stays the same on all of them. Getting this straight early spares you a lot of confusion later.
Compare a series with a number and you get a series back: one true or false per bar. Conditions are series as well, which is why one can hold on one bar and fail on the next.
// sma bir SERI dondurur: her barda ayri bir deger ortalama = sma(close, 20) // esik tek bir SAYIdir: butun barlarda ayni kalir esik = 70 // seriyi sayiyla karsilastirinca sonuc yine seridir asiri = rsi(close, 14) > esik plot(ortalama, "SMA20", "#2962ff") plotshape(asiri, style="circle", location="abovebar", color="#ef5350")
A blue SMA20 line on the price panel, plus a red circle above every bar where RSI runs past 70.
plot draws numeric series only. Hand it a single number and you get a flat line; for a fixed level, hline is the better tool.
Derived price sources
The close on its own can be noisy, and a single wick tip is enough to upset a rule. Three ready-made series average the bar's prices for you.
- hl2 — (high + low) / 2, the mid price of the bar.
- hlc3 — (high + low + close) / 3, the typical price, which also weighs the close.
- ohlc4 — (open + high + low + close) / 4, the smoothest source, weighting all four prices alike.
// ayni uzunluk, uc farkli kaynak plot(sma(close, 20), "close", "#787b86") plot(sma(hl2, 20), "hl2", "#2962ff") plot(sma(ohlc4, 20), "ohlc4", "#26a69a")
Three averages running close together on the price panel. The grey one wobbles most, the green one is the calmest.
Derived sources cut noise at the cost of a slower reaction. Breakout rules usually want close, while channels and envelopes sit better on hl2.
Reading an earlier bar
Most rules compare now against a moment ago. There are two ways to reach a series' past value, and both give the same answer.
- close[1] — the number in brackets says how many bars to step back. close[0] is the bar you are on.
- prev(close, 1) — the function form of the same thing. It reads better when the offset itself is computed.
// koseli parantez: sayi kac bar geriye gidilecegini soyler oncekiKapanis = close[1] // ayni degeri prev de verir ayniDeger = prev(close, 1) // ikisi her barda esit oldugu icin fark hep sifirdir plot(oncekiKapanis - ayniDeger, "fark", "#787b86", "fark") // ust uste iki yukselen kapanis plotshape(close > close[1] and close[1] > close[2], style="triangleup", location="belowbar", color="#26a69a")
A flat line pinned at zero in the lower fark panel, proof that the two forms agree. On the price panel, green triangles under each bar that closes higher twice in a row.
prev(source, n=1)
A series carrying the value from n bars back.
change(source, n=1)
The difference between the series now and n bars back.
The further back you look, the longer your script takes to warm up. With close[3] there is nothing to read on the first three bars, so the result stays na there.
Series carry gaps too
A series does not have to hold a number on every bar. Where a value is missing there is na instead, and na entering a calculation turns the result to na as well. Nothing errors out here, the rule simply falls silent, so you use nz to fill the gap.
// ilk 19 barda pencere dolmaz: sma na tasir ortalama = sma(close, 20) // na yerine 0 koy; cizgi bosluk yerine sifirdan baslar plot(nz(ortalama, 0), "ortalama", "#2962ff") // hacim eksik gelirse 0 say, sonra ortalamasiyla kiyasla yogun = nz(volume, 0) > sma(volume, 20) * 2 plotshape(yogun, style="circle", location="bottom", color="#ff9800")
Instead of leaving a gap, the average line starts at zero for the first nineteen bars and then settles onto price. Orange circles appear at the bottom of the panel on bars where volume runs past twice its average.
Writing nz(volume, 0) keeps the rule alive on bars where volume comes in empty. The full story of missing values has its own topic; what matters here is simply that a series can carry gaps.
Time-of-bar series
Every bar also has a time identity: the hour, the day, the month it formed in. You read these as separate series, all worked out in the exchange timezone the symbol belongs to.
- hour — the bar's hour, from 0 to 23.
- minute — the bar's minute, from 0 to 59.
- dayofweek — the day of the week, Sunday 1 through Saturday 7. Named constants such as dayofweek.monday work too.
- dayofmonth — the day within the month.
- month and year — the month (1-12) and the year.
- weekofyear — which week of the year it is.
You will mostly use them as filters: holding trades inside certain hours, skipping the first minutes of a session, resetting a counter when a new month starts.
// barin saati 0 ile 23 arasinda bir sayidir sabahSaati = hour >= 8 and hour < 12 // haftanin gunu: Pazar 1, Cumartesi 7 haftaSonu = dayofweek == 1 or dayofweek == 7 plotshape(sabahSaati, style="circle", location="bottom", color="#2962ff") plotshape(haftaSonu, style="square", location="top", color="#787b86")
Blue circles under the bars between 08:00 and 12:00, grey squares above the bars that fall on a weekend.
// bu barin ayi onceki bardan farkliysa ayin ilk bari demektir yeniAy = month != month[1] // gecenin ilk saatlerinde giris yapma sakinSaat = hour < 6 enterLong(crossover(close, sma(close, 20)) and not sakinSaat) exit(crossunder(close, sma(close, 20))) plotshape(yeniAy, style="flag", location="top", color="#ff9800")
An orange flag at the top of the panel on the first bar of each month. A buy opens only when the close crosses above the 20-bar average after 06:00; the position closes on the downward cross.
Crypto bars arrive on UTC, and since trading never pauses, weekends produce bars as well. Confirm which timezone you are in before writing an hour filter; one written for the wrong zone quietly screens out the wrong bars.
What else a bar knows about itself
Beyond the clock there are a few more facts to read. They come with dot notation and usually serve to narrow a rule.
- barstate.islast — is this the last bar. barstate.isconfirmed — has the bar closed.
- timeframe.isdaily, timeframe.isintraday — which timeframe the chart is on. timeframe.period gives its text form.
- syminfo.ticker — the symbol's code. syminfo.mintick — the smallest price step.
- session.ismarket — whether the bar falls inside the regular session.
// grafik gunluk mu, gun-ici mi gunluk = timeframe.isdaily plot(iff(gunluk, 1, 0), "gunluk mu", "#787b86", "bilgi") // son bara bir elmas birak plotshape(barstate.islast, style="diamond", location="top", color="#2962ff")
A flat line in the lower bilgi panel: 1 on a daily chart, 0 on any other timeframe. A blue diamond above the last bar on the right edge.
iff(condition, ifTrue, ifFalse)
A series that picks one of the two values on each bar.
Where beginners trip
- Mistaking a series for a number. ortalama = sma(close, 20) does not produce one value but one per bar, and reading it as a single number makes the rule behave oddly.
- Forgetting the opening bars. Until its window fills an indicator carries na, so the rule quietly does nothing there. Guard it with nz where it matters.
- Hunting for a difference between close[1] and prev(close, 1). They return the same value; choosing between them is a matter of readability.
- Reaching for a derived source without need. A breakout rule built on ohlc4 reacts late, because the wick tip dissolves into the average.
- Writing an hour filter against the wrong timezone. It raises no error, it just screens out the wrong bars, which quietly skews a backtest.
- Treating a condition as final before the bar closes. Values can still move on a forming bar, so pair the rule with barstate.isconfirmed when certainty matters.