Guides

Pine Script v6 for beginners: the concepts that make everything click

A beginner-friendly tour of Pine Script v6 — how scripts run bar by bar, series and history, inputs, plots, strategies and what changed from v5 — with working examples.

Pine Script is TradingView's language for indicators and strategies. It's small, purpose-built and forgiving in many ways — but it runs differently from most programming languages, and that difference trips up almost every beginner. Once you understand how a script executes, the rest is mostly vocabulary.

This guide covers the concepts you need to read, tweak and debug Pine Script v6 code, whether you write it yourself or generate it.

Three kinds of scripts

Every script starts with a version annotation and a declaration:

  • indicator() — calculates and draws things: lines, shapes, backgrounds, tables, alerts.
  • strategy() — everything an indicator can do, plus simulated orders that appear in the Strategy Tester.
  • library() — reusable functions for other scripts to import.

The first line, //@version=6, tells the compiler which version of the language to use. Without it, or with an older number, the same code can behave differently or fail to compile.

The execution model: one bar at a time

Your script runs once on every bar of the chart, from the oldest to the newest, and then again on every price update of the live bar. Each run sees only the data up to that bar.

So when you write close, you don't get "the closing price" as a single number — you get the close of whichever bar the script is processing. Values that change from bar to bar are called series.

To look back in time, use the history-referencing operator []:

  • close[1] — the previous bar's close
  • high[5] — the high from five bars ago

On the live bar, close is the latest price and keeps changing until the bar closes, so logic that depends on it can flicker on and off in real time. If you only want to act on completed bars, check barstate.isconfirmed.

Variables and var

A normal declaration runs again on every bar:

count = 0
count := count + 1   // always 1: reset to 0 on each bar

The var keyword initialises a variable once and keeps its value across bars:

var int count = 0
count += 1           // counts bars

Note the two operators: = declares a variable, while := (or += and friends) reassigns one.

Your first indicator

//@version=6
indicator("RSI with zones")

len = input.int(14, "RSI length", minval = 2)
src = input.source(close, "Source")
upper = input.int(70, "Overbought")
lower = input.int(30, "Oversold")

r = ta.rsi(src, len)

plot(r, "RSI", color = color.purple, linewidth = 2)
hline(upper, "Overbought", color = color.gray)
hline(lower, "Oversold", color = color.gray)
bgcolor(r > upper ? color.new(color.red, 85) : r < lower ? color.new(color.green, 85) : na)

What's going on:

  • input.*() functions create settings the user can change in the indicator's settings dialog.
  • ta.rsi() comes from the ta namespace of built-in technical analysis functions: ta.ema, ta.sma, ta.atr, ta.crossover, ta.highest and many more.
  • plot() draws a series, hline() draws a fixed horizontal level, and bgcolor() tints the background.
  • color.new(color.red, 85) is red at 85% transparency.
  • The ? : ternary operator picks a value based on a condition; na means "no value", so no tint.

Because the declaration doesn't set overlay = true, the indicator appears in its own pane below the price chart.

Your first strategy

//@version=6
strategy("Trend pullback", overlay = true, initial_capital = 10000,
  default_qty_type = strategy.percent_of_equity, default_qty_value = 10,
  commission_type = strategy.commission.percent, commission_value = 0.05)

trend = ta.ema(close, 200)
r = ta.rsi(close, 14)
atr = ta.atr(14)

longSignal = close > trend and ta.crossover(r, 40)

var float stopPrice = na
var float targetPrice = na

if longSignal and strategy.position_size == 0
    stopPrice := close - 2 * atr
    targetPrice := close + 3 * atr
    strategy.entry("Long", strategy.long)

strategy.exit("Exit", "Long", stop = stopPrice, limit = targetPrice)
plot(trend, "EMA 200", color = color.gray)

Key points:

  • strategy.entry() opens a position; strategy.exit() attaches a stop and a target to it.
  • Orders placed on a bar normally fill at the next bar's open in the backtest.
  • The stop and target are stored with var at entry time, so they don't drift as ATR changes.
  • Commission is set in the declaration — leaving costs out is one of the backtesting mistakes that inflate results.
  • ta.crossover() is called on every bar, outside the if block. Functions that depend on history should run on every bar so their internal values stay consistent.
  • The long strategy() call wraps across lines. Continuation lines are indented by a number of spaces that isn't a multiple of four, so the compiler doesn't mistake them for a new block.

What changed in v6

If you're reading older v5 code, these v6 changes matter most:

ChangeWhat it means
No implicit numeric-to-bool castingif volume no longer compiles; write if volume > 0 or use bool()
Booleans can't be naA bool is always true or false, and na() no longer accepts bools
Lazy and / orThe right-hand side is only evaluated when needed — don't hide required calculations there
Dynamic requests by defaultrequest.security() can be called inside loops and conditional blocks
when parameter removedWrap strategy.entry() and similar calls in an if block instead

The Pine Editor can convert a v5 script to v6 from its menu. Review the result, particularly around boolean logic.

Reading compiler errors

Errors appear in the console under the editor with a line number. The common ones are typos (Undeclared identifier), indentation inside if blocks (local blocks use four spaces or a tab), and calling a function with the wrong argument type. Fix the first error first — later ones are often caused by it.

Next steps

Once your script compiles, add it to a TradingView chart, then change one input at a time and watch the effect. When you're ready to turn an idea into code, read how to describe a trading strategy to AI.

Try it with Edgoro

Describe an indicator or strategy in plain English and Edgoro writes it in Pine Script v6, ready to paste. Ask it to explain any line you don't understand or to change the logic, and every version is saved in your library. Start free.

Trading involves substantial risk of loss. Learning to code a strategy doesn't make it profitable; test before you trade.

Build it with Edgoro

Describe your strategy in plain English and get a TradingView indicator in Pine Script v6 or a MetaTrader 5 Expert Advisor in minutes. Three generations are free.

Start free