Pine Script for Beginners
Write Your First Strategy in 30 Minutes
Pine Script is TradingView's proprietary programming language, used by tens of millions of traders worldwide to write strategies. The upside of learning it: you write, edit, and backtest directly inside TradingView — no servers required. Pair it with webhooks and you can route signals straight to an exchange for automated execution.
The goal of this article: take someone who has never written code, and in 30 minutes get them to a point where they can read and modify Pine strategies and understand the difference between an indicator and a strategy.
1. Before you start: what you need
- A TradingView account (the free plan lets you write code, but firing webhooks requires a paid plan)
- Basic chart navigation skills
- Understanding of candlesticks and open / high / low / close
- No programming background required
2. Your first Pine script: print the current close
Open any chart on TradingView → click the Pine Editor tab at the bottom → click New → select Blank Indicator. Paste this in:
//@version=5
indicator("My First Pine", overlay=true)
plot(close, color=color.blue)Click Save in the top right, then Add to chart.
You'll see a blue line that overlaps the closing price of every candle exactly (because close is the closing price). Congratulations — that's your first Pine script.
What each line means
//@version=5: tells TradingView to use v5 (the latest version)indicator(...): declares this as an indicator (overlay=true draws it on top of the candles; false draws it in a separate pane below)plot(close, ...): plots the close series
3. Add some logic: compute RSI
Pine ships with hundreds of built-in technical indicator functions under ta.*. Modify the script above to look like this:
//@version=5
indicator("RSI Display", overlay=false)
length = input.int(14, "RSI Period")
rsi = ta.rsi(close, length)
plot(rsi, color=color.purple)
hline(70, "Overbought", color=color.red)
hline(30, "Oversold", color=color.green)We change overlay to false because RSI is a 0–100 oscillator — drawing it on top of the candles would squash it into a single line.
New things: input and hline
input.int(14, "RSI Period"): adds an integer input field to the indicator's settings panel so users can change 14 to any value without editing the codehline(70, ...): draws a horizontal line marking the overbought/oversold thresholds
4. Indicator vs strategy — what's the difference
The first line of a Pine script can declare one of two things:
| Type | Purpose | Backtest | Alert |
|---|---|---|---|
indicator() | Draw lines, fire signals | No | Yes — alert() |
strategy() | Full buy/sell strategy + automatic backtest | Yes | Yes — strategy.entry() + alert_message |
Either works for automated trading, but strategy() has one extra benefit: TradingView automatically runs the backtest for you and shows historical PnL, win rate, and max drawdown.
5. Writing a complete, backtestable strategy
Below is an RSI mean-reversion strategy — buy oversold, sell overbought. You can paste it straight into TradingView and backtest:
//@version=5
strategy("RSI Reversal Strategy v1", overlay=true,
initial_capital=10000, default_qty_type=strategy.percent_of_equity,
default_qty_value=100)
// === Parameters ===
length = input.int(14, "RSI Period")
oversold = input.int(30, "Oversold Value")
overbought = input.int(70, "Overbought Value")
// === Indicator calculation ===
rsi = ta.rsi(close, length)
// === Entry condition ===
longCondition = ta.crossover(rsi, oversold)
shortCondition = ta.crossunder(rsi, overbought)
// === Entry order ===
if (longCondition)
strategy.entry("Long", strategy.long)
if (shortCondition)
strategy.entry("Short", strategy.short)
// === Visual aid ===
plot(rsi, "RSI", color=color.purple, display=display.pane)
hline(overbought, "Overbought", color=color.red)
hline(oversold, "Oversold", color=color.green)Paste it into the Pine Editor → Save → Add to chart. A "Strategy Tester" tab appears at the bottom, showing Net Profit, win rate, drawdown, and other backtest stats.
1. Does the full period match the most recent 30% of the period?
2. Does it work across different coins and timeframes?
3. Is the max drawdown survivable?
Only after passing all three should you consider going live, and run a forward-test (live observation period) for at least 14 days first.
6. How to make a strategy fire alerts to a webhook
Two approaches:
Method A: strategy.entry with alert_message
if (longCondition)
strategy.entry("Long", strategy.long,
alert_message='{"action":"buy","symbol":"{{ticker}}"}')
if (shortCondition)
strategy.entry("Short", strategy.short,
alert_message='{"action":"sell","symbol":"{{ticker}}"}')When creating the alert, fill the Message field with {{strategy.order.alert_message}}. Pine substitutes the message you set in the entry into the webhook payload.
Method B: the alert() function (good for indicators)
if (longCondition)
alert('{"action":"buy","symbol":"' + syminfo.ticker + '"}',
alert.freq_once_per_bar_close)7. Pine syntax cheat sheet
Historical values
close // current bar close
close[1] // 1 bar back close
close[5] // 5 bars back close
high[2] // 2 bars back highConditions / crossovers
ta.crossover(a, b) // a crosses b from below
ta.crossunder(a, b) // a crosses b from above
// Equivalent
a > b and a[1] <= b[1] // crossover
a < b and a[1] >= b[1] // crossunderCommon indicators
ta.sma(close, 20) // SMA
ta.ema(close, 20) // EMA
ta.rsi(close, 14) // RSI
ta.atr(14) // ATR (volatility)
ta.macd(close, 12, 26, 9) // returns [macd, signal, hist]
ta.highest(high, 20) // 20-bar high
ta.lowest(low, 20) // 20-bar lowDrawing
plot(close) // Line
plotshape(longCondition, location=location.belowbar, color=color.green)
plotchar(shortCondition, char="↓", location=location.abovebar, color=color.red)
bgcolor(rsi > 70 ? color.new(color.red, 90) : na)8. Common mistakes
Using = instead of := to reassign a value
In Pine, variables are declared with =, but reassigning a value requires :=. Get this wrong and the compiler throws an error.
Flipping the condition direction
ta.crossover(rsi, 30) means RSI crossed up from below 30 (an oversold bounce signal), not "broke below 30". Beginners frequently get this backwards.
Confusing Once Per Bar with Once Per Bar Close
Once Per Bar fires the instant the condition becomes true, which means the signal can disappear again before the bar closes — false signals. Once Per Bar Close waits for the bar to finish, which is safer. For automated trading, strongly prefer the latter.
Look-ahead bias (peeking at future data)
Accidentally using data that wouldn't have been available at the time of decision — for example, a request.security call without lookahead=barmerge.lookahead_off. This is the single biggest reason a backtest prints 100% profit while live trading loses 50%.
Get started
Wire your strategy to a TradingView webhook and auto-execute on Binance / OKX / Bybit and 4 more.
Start free trial9. What to learn next
- Community library: TradingView has a massive community sharing Pine scripts. Click "Indicators" at the bottom-left of any chart and search the concept you want to learn
- Official docs: Pine Script v5 Reference
- Multi-timeframe: how to use
request.security() - Arrays and objects: the advanced data structures introduced in v5
- Functions: extracting repeated logic into reusable functions for readability
10. Strategy ready — want to auto-trade it?
Set up an alert on your Pine strategy → TVSBot receives the webhook → orders go straight to the exchange. Full walkthrough: