Pine Script Tutorial for Beginners: Hello World, Pine Editor Setup & First Chart Script
Pine Script is TradingView's built-in scripting language, purpose-built for creating custom technical indicators, strategies, and libraries directly on live charts. This step-by-step tutorial walks through opening the Pine Editor, understanding the minimal required structure of a Pine Script, writing a verified Hello World script, and applying it to a chart — all grounded in Pine Script v6 syntax and TradingView's documented behavior.
1. What Is Pine Script? A Technical Overview
Pine Script is a domain-specific language (DSL) compiled and executed on TradingView's servers. It operates on a bar-by-bar execution model: the script is called once per historical bar and once per real-time tick, processing data as a time series. Key engine characteristics include:
- Strongly typed with implicit typing: Pine is strongly typed, but the compiler infers types in most cases. Variables carry series qualifiers such as
series floatorseries int, reflecting that each variable holds a sequence of values across bars rather than a single scalar. - Execution model: Scripts execute sequentially from the oldest bar to the most recent, then re-execute on each new tick.
- Drawing object limits: TradingView enforces limits on drawing objects (lines, labels, boxes, tables). In practice, creating objects unconditionally on every bar will quickly exhaust these limits; consult TradingView's official documentation for current per-type limits.
2. Opening the Pine Editor
The Pine Editor is embedded directly in the TradingView platform. Follow these steps to access it:
- Log in to TradingView and open any chart.
- At the bottom of the screen, click the "Pine Editor" tab
- The editor panel opens with a default template. Click "New" to start a blank script.
- After writing code, click "Add to chart" (or "Save & Add to chart") to compile and apply the script.
Insert a screenshot here showing the TradingView interface with the Pine Editor tab highlighted at the bottom of the screen, and the "Add to chart" button visible in the editor toolbar.
3. Anatomy of a Pine Script: Required Structure
A valid Pine Script requires at minimum two declarations: the version directive and the script type declaration. Everything else — plots, calculations, inputs — is optional depending on the script's purpose. Note that library() scripts and some strategy() configurations may produce no visual output on the chart by design.
| Component | Required? | Example | Purpose |
|---|---|---|---|
| Version Directive | Yes | //@version=6 |
Declares the Pine Script version for the compiler |
| Script Type Declaration | Yes | indicator("My Script") |
Defines the script as an indicator, strategy, or library |
| Calculations & Logic | No | sma20 = ta.sma(close, 20) |
User-defined computations on price series |
| Visual Output | No | plot(close) |
Renders data visually on the chart pane |
The mathematical relationship between bars and series values can be expressed as:
$$\text{series}[i] = f(\text{bar}_i), \quad i \in \{0, 1, 2, \ldots, N-1\}$$
where $N$ is the total number of bars loaded, and $f$ is the user-defined computation applied at each bar index $i$.
4. Your First Script: Hello World in Pine Script v6
The canonical "Hello World" in Pine Script renders a label on the most recent bar displaying the text "Hello, World!". Because labels are drawing objects subject to TradingView's per-script limits, the script must guard against creating a new label on every bar — the correct pattern is to create the label only on the last bar using barstate.islast.
🔽 [Click to expand] View Full Pine Script Code — Hello World v6
//@version=6
// ─────────────────────────────────────────────────────────────
// Script Type: indicator
// Title : Hello World — Pine Script v6 Tutorial
// Description: Renders a 'Hello, World!' label on the last bar
// and plots the closing price as a baseline.
// ─────────────────────────────────────────────────────────────
indicator(
title = "Hello World — Pine Script v6", // Name shown on chart
shorttitle = "HW", // Abbreviated name in legend
overlay = true // Draw on the main price chart
)
// ── Section 1: Plot the closing price ────────────────────────
// plot() renders a continuous line on the chart.
// 'close' is a built-in series float representing the bar's closing price.
plot(
series = close, // The data series to plot
title = "Close Price", // Label shown in the Data Window
color = color.blue, // Line color
linewidth = 1 // Line thickness in pixels
)
// ── Section 2: Hello World label on the last bar ─────────────
// barstate.islast is true only on the most recently confirmed bar.
// Guarding label creation with this condition ensures we create
// at most one label, staying well within TradingView's drawing
// object limits for labels.
if barstate.islast
label.new(
x = bar_index, // x-position: current bar index (series int — valid for x)
y = high, // y-position: current bar's high price
text = "Hello, World! 👋", // Display text
style = label.style_label_down, // Label shape pointing downward
color = color.new(color.green, 20), // Background color with 20% transparency
textcolor = color.white, // Text color
size = size.normal // Text size
)
4.1 Code Walkthrough
//@version=6— Instructs the compiler to use Pine Script version 6 semantics. This must be the first non-comment line.indicator(..., overlay = true)— Declares this as an indicator script overlaid on the main price pane. Withoutoverlay = true, the script renders in a separate sub-pane.plot(close, ...)— Plots the built-incloseseries (type:series float) as a continuous line.if barstate.islast— Conditional guard ensuringlabel.new()is called only once, on the final bar. Callinglabel.new()unconditionally on every bar creates a new label object each bar and in practice quickly exhausts TradingView's drawing object limits for labels.bar_index— A built-inseries intrepresenting the zero-based index of the current bar. It is a valid argument for thexparameter oflabel.new().
5. Common Beginner Errors and Fixes
The following table documents the most frequently encountered errors when writing a first Pine Script, along with their root causes and verified fixes.
| Error / Symptom | Root Cause | Fix |
|---|---|---|
Could not determine the referencing length |
Using a dynamic (series) value as a history reference offset, e.g., close[n] where n is a series int |
Use a simple int (literal or input.int()) as the offset, or restructure with array |
| Script compiles but no label appears | label.new() called on every bar without a guard; drawing object limit reached and older labels are recycled or dropped |
Wrap label.new() in if barstate.islast or manage labels with an array and explicit deletion |
Indentation error |
Mixing tabs and spaces within the same block; Pine Script requires consistent indentation using spaces only | Use spaces only (do not mix tabs and spaces); configure your editor to insert spaces on Tab key press |
table.new() called on every bar causes drawing limit issues |
table.new() creates a new table object on each bar execution, quickly exceeding TradingView's drawing object limits for tables |
Declare the table with var so it is created only once: var myTable = table.new(...) |
Version directive missing |
The //@version=6 line is absent or placed after code |
Place //@version=6 as the very first line of the script |
6. Execution Flow: Bar-by-Bar Processing
Understanding Pine Script's execution model is essential for writing correct scripts. The diagram below illustrates how the engine processes bars sequentially and how barstate flags change across the timeline.
7. Extending the Hello World: Adding a Simple Moving Average
Once the basic structure is confirmed, a natural extension is to overlay a Simple Moving Average (SMA). The SMA over $n$ periods is defined as:
$$\text{SMA}_n(i) = \frac{1}{n} \sum_{k=0}^{n-1} \text{close}[i-k]$$
In Pine Script v6, this is computed with the built-in ta.sma() function:
🔽 [Click to expand] View Full Pine Script Code — Hello World + SMA Extension
//@version=6
// ─────────────────────────────────────────────────────────────
// Script Type: indicator
// Title : Hello World + SMA — Pine Script v6 Tutorial
// Description: Extends the Hello World script with a user-
// configurable Simple Moving Average overlay.
// ─────────────────────────────────────────────────────────────
indicator(
title = "Hello World + SMA — Pine Script v6",
shorttitle = "HW+SMA",
overlay = true // Overlay on the main price pane
)
// ── Section 1: User Input ─────────────────────────────────────
// input.int() creates an interactive integer input in the
// script's Settings panel. 'minval' enforces a minimum of 1.
int smaPeriod = input.int(
defval = 20, // Default period
title = "SMA Period", // Label in Settings panel
minval = 1 // Minimum allowed value
)
// ── Section 2: SMA Calculation ───────────────────────────────
// ta.sma() computes the Simple Moving Average of a series.
// Result type: series float
float smaValue = ta.sma(close, smaPeriod)
// ── Section 3: Plot Close and SMA ────────────────────────────
plot(
series = close,
title = "Close",
color = color.new(color.blue, 60), // Semi-transparent blue
linewidth = 1
)
plot(
series = smaValue,
title = "SMA",
color = color.orange,
linewidth = 2
)
// ── Section 4: Hello World label on last bar ─────────────────
// var keyword: the label variable is declared once and persists.
// We delete and recreate it on the last bar to keep exactly one
// label object alive at all times.
var label helloLabel = na
if barstate.islast
// Delete the previous label instance if it exists
label.delete(helloLabel)
// Create a fresh label at the current last bar
helloLabel := label.new(
x = bar_index,
y = high,
text = "Hello, World! 👋\nSMA(" + str.tostring(smaPeriod) + ") = " + str.tostring(math.round(smaValue, 2)),
style = label.style_label_down,
color = color.new(color.green, 20),
textcolor = color.white,
size = size.normal
)
7.1 Key Additions Explained
input.int()— Exposes a configurable integer parameter in the script's Settings panel, allowing users to change the SMA period without editing code.ta.sma(close, smaPeriod)— Computes the rolling SMA. Returnsnafor the firstsmaPeriod - 1bars where insufficient history exists.var label helloLabel = na— Thevarkeyword initializes the variable only on bar 0 and retains its value across bars, enabling the delete-and-recreate pattern that keeps exactly one label object alive.str.tostring(math.round(smaValue, 2))— Converts the rounded float SMA value to a string for display in the label text.
8. Pine Script Type System: A Practical Reference
Pine Script is strongly typed with implicit typing. The compiler infers types automatically in most assignments, but understanding the type qualifiers helps diagnose errors. The most important qualifier is series, which indicates the variable holds a distinct value for each bar.
| Type Qualifier | Description | Example |
|---|---|---|
const |
Value known at compile time; never changes | const float PI = 3.14159 |
simple |
Single value determined on bar 0; constant across all bars | simple int len = input.int(20) |
series |
A distinct value per bar; the default qualifier for most built-ins | series float c = close |
series int |
Integer series; e.g., bar_index is a built-in series int |
bar_index (valid as x in label.new()) |
9. Conclusion
This tutorial established the foundational workflow for Pine Script development on TradingView. The core takeaways are:
- ✅ Minimum required structure: A valid Pine Script needs only the version directive (
//@version=6) and a script type declaration (indicator(),strategy(), orlibrary()). Visual output is optional and context-dependent. - ✅ Drawing object discipline: Functions like
label.new()andtable.new()create persistent drawing objects. Calling them unconditionally on every bar in practice quickly exhausts TradingView's per-type drawing limits. Usebarstate.islastguards or thevar+ delete pattern. - ✅ Series execution model: Pine executes bar-by-bar from oldest to newest. Every built-in price variable (
close,high, etc.) is aseries float, and understanding this qualifier is key to avoiding type-related compiler errors.
Ideas for Script Advancement
- Multi-timeframe (MTF) data: Extend the SMA script to fetch the same SMA from a higher timeframe using
request.security(), and compare it to the current timeframe's SMA to build a basic trend-alignment filter. - Alert integration: Add
alertcondition()to trigger TradingView alerts when the close price crosses the SMA, transforming the visual indicator into an actionable notification system.
Comments
Post a Comment