Appearance
Control flow
How do you branch and loop in a script that already runs once per bar? if and switch choose what runs on this bar. for and while repeat work inside this one bar, so a loop never steps from bar to bar: the script itself does that, running from the first bar to the last.
pine
//@version=6
indicator("Closes above the average")
float avg = ta.sma(close, 20) // on every bar, outside any branch
int above = 0
for i = 0 to 9 // 10 passes, all on this bar
if close[i] > avg
above += 1
color shade = if above >= 7 // an if as a value
color.green
else if above <= 3
color.red
else
color.gray
plot(above, "Last 10 closes above", shade, style = plot.style_columns)Choosing with if
if runs the indented block under it on the bars where its condition is true. else if adds another condition, tried only when the ones before it were false, and else runs when none was true. A condition that reads na is false, so the else way runs.
A block runs only on the bars its condition picks, and that changes what a ta.* call inside it sees: it misses the other bars. The example above computes avg before the loop and the if for that reason. See State in functions and branches.
Choosing among many with switch
switch picks one arm. With a value after it, it runs the first arm whose value equals it. Without one, it runs the first arm whose condition is true. An arm with nothing before its => is the default, which runs when no other does.
pine
//@version=6
indicator("Average of your choice", overlay = true)
kind = input.string("EMA", "Average", options = ["SMA", "EMA", "WMA"])
float sma = ta.sma(close, 20) // all three run on every bar
float ema = ta.ema(close, 20)
float wma = ta.wma(close, 20)
float avg = switch kind
"SMA" => sma
"EMA" => ema
=> wma // the default arm
plot(avg, "Average")A branch as a value
if and switch can give a value, as shade and avg do above. The value is the last expression of the branch or arm that ran. Where none ran, an if with no else or a switch with no default gives na, and false when the value is a bool.
Write the if or switch on the same line as the =, with its branches indented below. A loop can't give a value this way here, though TradingView's can: x = for i = 1 to 3 is a syntax error. Assign a variable inside the loop instead, and the script runs on both. See Pine compatibility.
Counting with for
for i = from to end runs its block once for each i from from to end, both included. When end is below from, it counts down. by sets the step: for i = 0 to 10 by 2 gives 0, 2, 4, 6, 8 and 10.
Each part of the header is read at its own time, as on TradingView:
| Part | When it's read |
|---|---|
end | Again before every pass. A body that moves the end changes how many passes run, and an end that turns na stops the loop. |
from, by | Once, as the loop starts. The direction, up or down, is fixed then too. |
| A fraction | for i = 0 to 2.5 runs 0, 1 and 2. A float step compares within 1e-10, so 0.0 to 0.3 by 0.1 runs four passes, the last at 0.3. |
Keep by positive. TradingView stops a script whose step is 0 or less. This engine runs a negative step by its size, toward end, and runs no pass for a step of 0.
The counter belongs to the loop. A counter named like a variable outside the loop is a second variable, and the outer one keeps its value: see Variables.
Walking a collection with for…in
for x in a runs once for each element of an array, in order. for [i, x] in a gives each index with its element. A map gives each key and value with for [k, v] in m, in the order the keys were first put. A matrix gives each row, as an array, with for row in m.
pine
//@version=6
indicator("Sum of the last five ranges")
array<float> ranges = array.new<float>()
for i = 0 to 4
ranges.push(high[i] - low[i])
float total = 0
for r in ranges // each element in turn
total += r
plot(total, "Total range")Looping on a condition with while
while cond tests its condition before each pass and runs the block while it's true. In both kinds of loop, break leaves the loop at once and continue skips to the next pass.
pine
//@version=6
indicator("Bars back to a close as high")
int back = 1
while back < 500 and close[back] < close // stops at one as high
back += 1
plot(back, "Bars back")How long a loop may run
Every engine stops a loop after 100,000 passes, without an error or a warning, and the script goes on with what the loop did so far. TradingView limits loops by the time they take instead, so a loop that runs long fails there in a way it doesn't here. Give a loop that needs more passes another shape, such as work spread over bars with var. See Limits.
Traps
- A
ta.*call inside anif, a ternary or a loop. In a branch it sees only the bars that ran it, and the Script Editor warns (TradingView's CW10003). In a loop every pass shares one state, and the editor warns too. Call it outside and use its value inside. See State in functions and branches. x = for ...orx = while .... A syntax error here, though TradingView allows it. Assign inside the loop.- A counter named like an outer variable. The outer variable never changes.
- Changing
endin the body. The loop reads it again before each pass, so the pass count changes. - A loop past 100,000 passes. It stops there without a word.
See also
- Keywords reference:
if,switch,forandwhilein a few lines each - State in functions and branches: what a branch does to
ta.* - Variables: scope inside blocks
- Collections: the arrays, maps and matrices that
for…inwalks - Errors and debugging: the limits a run works within