Loops#
Pine Script provides two loop structures: for and while. Since Pine Script executes bar by bar, loops are typically used to repeat calculations within a single bar — for example, finding the highest point over the past N bars, or batch-processing array elements.
Note: Loops increase computation time per bar. Using deeply nested loops on charts with many bars may cause script timeouts. It is recommended to use Pine Script’s built-in
ta.*functions first, as they are optimized for series calculations.
for Loop#
Basic Syntax#
for variable = startValue to endValue
// loop bodyThe for loop increments from the start value to the end value (inclusive), stepping by 1 each time:
//@version=6
indicator("for Loop Demo")
// Manually compute the sum of closing prices for the past 5 bars
var float total = 0.0
total := 0.0
for i = 0 to 4
total := total + close[i]
plot(total / 5, "5-Bar Average Price")by — Custom Step#
Use by to specify a custom increment (can be negative for counting down):
// Increment by 2
for i = 0 to 10 by 2
// i = 0, 2, 4, 6, 8, 10
// Count down: from 10 to 0
for i = 10 to 0 by -1
// i = 10, 9, 8, ..., 0for…in — Iterating Over Arrays#
for...in retrieves each element of an array one by one:
//@version=6
indicator("for-in Demo")
prices = array.from(close, close[1], close[2], close[3], close[4])
var float sum = 0.0
sum := 0.0
for price in prices
sum := sum + price
plot(sum / array.size(prices), "Average Price")If you also need the index alongside the value, use for [index, value] in array:
prices = array.from(10.0, 20.0, 30.0)
for [i, val] in prices
// i = 0, 1, 2
// val = 10.0, 20.0, 30.0
label.new(bar_index - i, val, str.tostring(val))while Loop#
while continues executing as long as its condition is true:
while condition
// loop bodyExample — find how many bars ago the close was last above the 20-period MA:
//@version=6
indicator("while Demo")
ma20 = ta.sma(close, 20)
// Walk back from the current bar to find the first bar with close above MA
barsAgo = 0
while close[barsAgo] <= ma20[barsAgo] and barsAgo < 50
barsAgo := barsAgo + 1
plot(barsAgo, "Bars since last close above MA")Note: A
whileloop must ensure its condition eventually becomesfalse, or it will cause an infinite loop and script timeout. It is recommended to add a maximum iteration limit (such asbarsAgo < 50above).
break — Exit the Loop Early#
break immediately terminates the loop, skipping all remaining iterations:
//@version=6
indicator("break Demo")
// Find how many bars ago the highest closing price occurred
highestBar = 0
for i = 1 to 50
if close[i] > close[highestBar]
highestBar := i
// Stop searching if there's a drop greater than 1%
if close[0] - close[i] > close[0] * 0.01
break
plot(highestBar, "Bars ago with highest close")continue — Skip the Current Iteration#
continue skips the current iteration and jumps to the next one:
//@version=6
indicator("continue Demo")
// Accumulate volume only for bullish bars (close > open)
var float bullVolume = 0.0
bullVolume := 0.0
for i = 0 to 9
if close[i] <= open[i]
continue // Skip bearish bars
bullVolume := bullVolume + volume[i]
plot(bullVolume, "Bullish volume (last 10 bars)")Practical Example: Manually Finding High/Low#
Although ta.highest and ta.lowest are already available, the following example demonstrates a full application of loops:
//@version=6
indicator("Loop High/Low Finder", overlay=true)
lookback = input.int(20, "Lookback Bars", minval=1)
// Use a for loop to find the highest and lowest closing prices
var float myHighest = na
var float myLowest = na
myHighest := close
myLowest := close
for i = 1 to lookback - 1
if close[i] > myHighest
myHighest := close[i]
if close[i] < myLowest
myLowest := close[i]
plot(myHighest, "Highest Close", color=color.green)
plot(myLowest, "Lowest Close", color=color.red)