Basic Syntax

Every programming language has grammar rules, just like every spoken language. In English, you put the subject before the verb. In Pine Script, you put the version declaration before everything else. This lesson teaches you the structural rules so that TradingView can understand what you write.

The Structure of a Pine Script

Think of a Pine Script like a recipe. A recipe has a predictable structure: a title, a list of ingredients, and step-by-step instructions. Pine Script follows a similar pattern:

  1. Version declaration - which edition of the language you're using
  2. Script type declaration - what kind of script this is (indicator, strategy, or library)
  3. Inputs (optional) - settings the user can adjust without editing code
  4. Calculations - your trading logic and math
  5. Outputs - what gets displayed on the chart

Every script you write will follow this order. Let's examine each part.

Version Declaration

Every Pine Script file must start with a version declaration on the very first line. Here's what it looks like:

Pine Script
//@version=5

This isn't optional. If you omit it, TradingView will either reject your script or assume an older version, which may cause functions to behave differently than you expect.

Why does the version matter?

Pine Script has evolved significantly over the years. Functions that existed in v3 may have different names or parameters in v5. For example, the study() function from v4 was renamed to indicator() in v5. If you copy code from an old forum post or blog and it starts with //@version=3, you can't just change it to v5 - you'll likely need to update function names and syntax too.

💡Always use version 5

Unless you're maintaining someone else's old script, there's no reason to use anything other than v5. It has the most features, the best error messages, and is the only version that receives updates.

Script Types

After the version declaration, you must tell TradingView what kind of script you're writing. There are three types, and choosing the right one matters because it determines what your script can do.

Indicators

An indicator performs calculations and displays visual output on the chart. It cannot place trades. Use an indicator when you want to visualize something - a moving average, an oscillator, support/resistance levels, colored candles, or any other visual analysis tool.

Let's create a simple indicator that shows whether today's trading volume is above or below its 20-day average. This is useful because unusually high volume often signals important price moves.

Pine Script
//@version=5
indicator("Volume vs Average", overlay=false)

avgVolume = ta.sma(volume, 20)
plot(volume, color=color.gray, style=plot.style_columns, title="Volume")
plot(avgVolume, color=color.orange, linewidth=2, title="20-bar Avg")

Here's what this script does. The first plot() draws the raw volume as gray columns. The second plot() draws the 20-bar average volume as an orange line on top. When the gray columns tower above the orange line, volume is unusually high. We set overlay=false because volume values (millions of shares) are on a completely different scale than price, so they need their own panel.

Strategies

A strategy can do everything an indicator can, plus it can simulate trades. It has access to functions like strategy.entry() and strategy.close() that let you define buy and sell rules. TradingView then backtests those rules against historical data and gives you a performance report.

Use a strategy when you want to test whether a trading idea is actually profitable. Here's a minimal example that buys when a fast moving average crosses above a slow one:

Pine Script
//@version=5
strategy("MA Crossover", overlay=true)

fast = ta.sma(close, 10)
slow = ta.sma(close, 30)

if ta.crossover(fast, slow)
    strategy.entry("Buy", strategy.long)

if ta.crossunder(fast, slow)
    strategy.close("Buy")

plot(fast, color=color.green)
plot(slow, color=color.red)

This script calculates two moving averages. When the fast (10-period) crosses above the slow (30-period), it enters a long position. When the fast crosses below, it exits. After adding this to a chart, you can click the "Strategy Tester" tab to see how it would have performed historically - including net profit, number of trades, and maximum drawdown.

The key difference from an indicator: the strategy() declaration unlocks the strategy.* family of functions. If you try to use strategy.entry() inside an indicator() script, you'll get a compiler error.

Libraries

A library is a collection of reusable functions that other scripts can import. You won't need libraries as a beginner, but it's good to know they exist. If you find yourself copying the same helper function into multiple scripts, that's a sign you should put it in a library instead.

Pine Script
//@version=5
library("MyHelpers")

export isHighVolume(int lookback) =>
    volume > ta.sma(volume, lookback)

This library exports a single function called isHighVolume() that other scripts can call. We'll revisit libraries in a later lesson; for now, focus on indicators and strategies.

⚠️Indicator vs Strategy - pick the right one

A common mistake is building an indicator when you actually want to backtest, or building a strategy when you just want a visual overlay. Ask yourself: "Do I need to simulate trades?" If yes, use strategy(). If no, use indicator(). You cannot switch between them by just changing the declaration - each type has exclusive functions that the other type cannot access.

Comments

Comments are notes you write in your code that Pine Script completely ignores. They exist solely for humans - including future you, who will look at this code in three months and wonder what it does.

Single-line comments

Anything after // on a line is a comment:

Pine Script
// This entire line is a comment
smaValue = ta.sma(close, 20)  // This part is a comment too

Multi-line comments

For longer notes, use /* */ to wrap multiple lines:

Pine Script
/*
  This strategy uses a dual moving average crossover system.
  Fast MA: 10 periods
  Slow MA: 30 periods
  Entry: fast crosses above slow
  Exit: fast crosses below slow
*/

Good comments vs bad comments

Not all comments are helpful. A bad comment restates what the code already says. A good comment explains why you made a choice or what the broader goal is. Compare these:

Pine Script
// Bad comments - they just repeat the code
sma20 = ta.sma(close, 20)  // Calculate 20-period SMA
isAbove = close > sma20     // Check if close is above SMA

// Good comments - they explain intent and reasoning
// Using 20 periods because it represents roughly one trading month
sma20 = ta.sma(close, 20)
// Signal that price has reclaimed the trend - potential entry zone
isAbove = close > sma20

The bad comments would make a reader think "I can see that." The good comments make a reader think "Ah, that's why they chose 20, and that's what this condition means for the trading logic."

💡When to comment

Comment the why, not the what. If a line of code is self-explanatory, it doesn't need a comment. If you made a deliberate choice (why this period length, why this threshold, why this specific condition), that deserves a comment.

Naming Conventions

Pine Script doesn't enforce a naming style, but following conventions makes your code much easier to read - especially when scripts grow longer.

Variables - use camelCase

Start with a lowercase letter, and capitalize the first letter of each subsequent word. No spaces, no underscores.

Pine Script
// Clear, descriptive camelCase names
fastLength = 10
slowLength = 30
fastMovingAvg = ta.sma(close, fastLength)
slowMovingAvg = ta.sma(close, slowLength)
isBullishCross = ta.crossover(fastMovingAvg, slowMovingAvg)

Compare that to this version, which is technically valid but much harder to read:

Pine Script
// Vague, abbreviated names - avoid this
a = 10
b = 30
x = ta.sma(close, a)
y = ta.sma(close, b)
z = ta.crossover(x, y)

Both scripts compile and produce identical results. But when you come back to the second version next week, you'll have no idea what a, b, x, y, and z represent. The few extra keystrokes for descriptive names save you real debugging time later.

Indentation and Whitespace

Pine Script uses indentation to define code blocks (similar to Python). When you write an if statement or a function, the body must be indented by exactly 4 spaces or 1 tab. Mixing tabs and spaces in the same script can cause confusing errors.

Here's a properly indented conditional block. We're checking whether the current bar's close is higher than the previous bar's close, and if so, plotting a green color. Otherwise, we plot red.

Pine Script
//@version=5
indicator("Color by Direction", overlay=false)

if close > close[1]
    label.new(bar_index, close, "Up")
else
    label.new(bar_index, close, "Down")

plot(close, color = close > close[1] ? color.green : color.red)

Notice that the lines inside if and else are indented. If you removed the indentation, Pine Script would not know which lines belong to the conditional block, and you'd get a compiler error.

Putting It All Together

Let's write a complete, well-structured script that combines everything from this lesson. The goal is to create an indicator that plots a Simple Moving Average and changes its color based on whether price is above or below it. This is a practical tool: a rising SMA with price above it suggests an uptrend; price below a falling SMA suggests a downtrend.

Pine Script
//@version=5
indicator("Trend SMA", overlay=true)

// --- Inputs ---
// Let the user customize the SMA length without editing code
length = input.int(20, title="SMA Length", minval=1)

// --- Calculation ---
// Calculate the SMA of closing prices over the user-defined period
smaValue = ta.sma(close, length)

// Determine if price is currently above or below the SMA
isAboveSma = close > smaValue

// Determine if the SMA itself is rising or falling
smaRising = smaValue > smaValue[1]

// --- Output ---
// Color the SMA line based on trend direction:
//   Green = price above SMA and SMA is rising (strong uptrend)
//   Red   = price below SMA and SMA is falling (strong downtrend)
//   Gray  = mixed signals
trendColor = isAboveSma and smaRising ? color.green :
     not isAboveSma and not smaRising ? color.red :
     color.gray

plot(smaValue, color=trendColor, linewidth=2, title="SMA")

After adding this to your chart, you'll see a colored moving average line. Green means both price and the SMA agree that the trend is up. Red means both agree the trend is down. Gray means they disagree - price might be above a falling SMA, or below a rising one - which often signals a transition.

Line-by-line breakdown of key concepts

input.int(20, ...) - This creates a user-adjustable setting. Instead of hardcoding the SMA length as 20, we let the user change it from the indicator's settings panel. input.int means the input must be an integer. The minval=1 prevents nonsensical values like 0 or negative numbers.

smaValue[1] - The [1] operator accesses the previous bar's value. So smaValue[1] is what the SMA was on the bar before the current one. By comparing smaValue to smaValue[1], we determine whether the SMA is rising or falling. We'll explore this operator in depth in the next lesson.

The ternary operator ? : - This is a compact way to write conditional logic inline. The pattern is condition ? valueIfTrue : valueIfFalse. We chained two of them together to handle three cases (green, red, gray). Don't worry if this syntax feels dense - you'll get used to it quickly, and we'll cover it in the control flow lesson.

Try It Yourself

Now it's your turn. Here are three modifications to try. Each one reinforces a concept from this lesson.

Exercise 1: Change the script type. Take the Trend SMA script above and change indicator(...) to strategy(...). What error do you get? Why? (Hint: strategies require different parameters.) Change it back when you're done.

Exercise 2: Add a second plot. Below the existing plot() line, add a second SMA with a different length - say, 50 periods. Plot it in a different color. You now have a dual moving average system.

Exercise 3: Improve the comments. Look at the Trend SMA script and add a comment block at the top (using /* */) that describes what the indicator does, how it determines trend direction, and when a trader might use it. Practice writing comments that explain why, not what.

Common Mistakes and How to Fix Them

Forgetting the version declaration

Pine Script
// This will cause an error or unexpected behavior
indicator("My Script")
plot(close)

What goes wrong: TradingView may either reject the script entirely or default to an older version where function names and behaviors differ. Fix: Always start with //@version=5 on line 1.

Using indicator-only features in a strategy (or vice versa)

Pine Script
//@version=5
indicator("My Indicator")
strategy.entry("Buy", strategy.long)  // Error!

What goes wrong: The compiler will tell you that strategy.entry is not available in indicator scripts. Fix: If you need to place trades, use strategy() instead of indicator(). If you only need visuals, remove the strategy.* calls.

Incorrect indentation

Pine Script
//@version=5
indicator("Bad Indent")

if close > open
label.new(bar_index, high, "Up")  // Error - not indented!

What goes wrong: Pine Script expects the line after if to be indented. Without indentation, it doesn't know what code belongs inside the if block. Fix: Indent the body of if, else, for, and function definitions by 4 spaces or 1 tab.

Misspelling built-in functions

Pine Script
smaValue = ta.SMA(close, 20)  // Error - wrong capitalization

What goes wrong: Pine Script is case-sensitive. ta.SMA is not the same as ta.sma. Fix: Use all lowercase for built-in function names. The Pine Editor's autocomplete can help - start typing ta.s and it will suggest ta.sma.

⚠️Case sensitivity matters

Pine Script is fully case-sensitive. Close is not the same as close. Color.Blue is not the same as color.blue. If you get a "Could not find function or variable" error, check your capitalization first.

Next Steps

You now understand the structural rules that govern every Pine Script program. You know how to declare the version and script type, write useful comments, name variables clearly, and avoid the most common syntax errors. In the next lesson, we'll explore variables and data types - how Pine Script stores and works with numbers, text, booleans, and colors.