In this post, we are going to take a look at pine script’s for loop
, how to use it and go over some useful examples. If you are new to programming or pine script in general than this will (hopefully) provide a gentle introduction.
The For Loop
Before we start talking about how to use For loops, we should first have a basic understanding of what they are. For Loops are common to almost every modern programming language. They allow you to perform repetitive tasks without needing to repeat line after line of code. I simple terms, they repeat the same lines of code over and over again. This not only saves time but it also makes your code easier to read whilst at the same time, reduces your chance of making an error or bug. Whilst the syntax and terminology of loops might seem a bit intimidating at first. They are quite simple to understand once you get past the technical jargon.
The Syntax
Now we have a concept of what a For loop is supposed to do, the next logical step would be to take a look at the syntax. I.e. how should we actually write a for loop? Let’s take a look at the official example from the Tradingview Wiki and break it down line by line.
1 2 3 4 5 6 7 8 9 10 |
var_declarationX = for counter = from_num to to_num [by step_num] var_decl0 var_decl1 … continue … break … var_declN return_expression |
The example, whilst very informative is written in quite a technical way. Sure, it is easy to understand if you have a background in programming but for the novice who is primarily interested in the market, and just dabbling in programming, it can tough to understand. So without further ado, here is the breakdown.
var_declarationX =
This is the first part of the first line. It just a simple variable like any other you are used to working with. The key thing here is that a value is returned from the loop after the loop is completed. In pine script, a loop can return a value at the end just like a function (a tutorial on pine script functions is here) and that value is stored in var_declarationX.
for counter = from_num to to_num
This is where the main magic happens. for
, =
and to
are the key bits you need to remember. The rest you are free to change. For example, for i = 0 to 10
is also a valid declaration. This is basically saying, loop from number 0 to number 10. counter
is just another variable name that holds the loop number we are on. So for example, infor i = 0 to 10
, i
will = 0 on the first loop, 1 on the second loop 2, on the third loop and so on. This is important as i
allows us to access different data on each loop through the code.
from_num
and to_num
can be variables that we declared before the loop or actual numbers as shown in the for i = 0 to 10
example. So if you have a variable called x
that has a value 10, you can write the same loop as for i = 0 to x
.
Simple example:
1 2 3 4 5 6 7 8 |
//@version=3 study("For Loop tutorial - Example 1") y = 0 for i = 0 to 10 y := y + i plot(y) |
Running the code above will return a straight line on the chart with a value of 55. Why? Because we are looping through adding i
to y
on each run of the loop. As discussed above, the value of i
changes every loop. So:
0 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = 55
On the chart:
[by step_num]
by step_num
is useful when you only want to use certain values in a range. For example, if you only want to get the close value every 2 bars, you can use a step number of two. Let’s add a step number to the example above and see what happens.
1 2 3 4 5 6 7 8 |
//@version=3 study("For Loop tutorial - Example 2") y = 0 for i = 0 to 10 by 2 y := y + i plot(y) |
Running the new example above will result in a straight line showing 30 because:
0 + 2 + 4 + 6 + 8 + 10 = 30
You can see that the loop is now assigning i
values in steps of 2.
Indentation
Now we are passed the first line, it is worth looking at indentation. Indentation is the number of white spaces between the start of the line and the text. Notice how that lines following the first line are all indented by 4 spaces? This is not an accident. Indenting by 4 spaces informs the pine script interpreter that the line is part of the loop and not part of the main script. Therefore, any logic that is part of the loop MUST be indented by 4 spaces.
It is important to stress the importance of 4 spaces again (or multiple of 4 e.g 8, 12,16) because any other number or multiple will result in an error. This is because other indentation levels (e.g 2 whitespaces) are reserved for line wrapping/continuation. For more on that topic see here: Tradingview: Line Wrapping.
Running the code above with 2 whitespaces will result in the following error:
'Add to Chart operation failed, reason: line 5: mismatched input 'y' expecting 'end of line without line continuation'
And if you ask me, that is not a user-friendly error message!
var_decl0 and var_decl1
This is part of the official example is just to tell you that you can declare variables within the loop. It is worth pointing out that these variables must be returned if you want to use them outside of the loop.
For example, running:
1 2 3 4 5 6 7 8 9 10 |
//@version=3 study("For Loop tutorial - Example 3") y = 0 for i = 0 to 10 by 2 z = 10 y := y + i plot(y) plot(z, color=green) |
Will result in the following error:
Add to Chart operation failed, reason: line 10: Undeclared identifier z
However, if you return z at the end of the loop you can access it like so
1 2 3 4 5 6 7 8 9 10 11 |
//@version=3 study("For Loop tutorial - Example 3") y = 0 z = for i = 0 to 10 by 2 z = 10 y := y + i z plot(y) plot(z, color=green) |
continue
The continue
keyword can be used to skip parts of the for loop code if certain conditions are met. When the condition is met all code following the continue
keyword is NOT executed. In the example below, we have added a check to see if z
equals 10
. Because it does, it means that the rest of the loop is skipped every time.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//@version=3 study("For Loop tutorial - Example 4") y = 0 z = for i = 0 to 10 by 2 z = 10 if z == 10 continue y := y + i z plot(y) plot(z, color=green) |
Plotting this on the chart you will see y
always has the value of 0
and z
has the value na
because z
is never returned.
A more practical example of whencontinue
can be useful, is to sum the volume only on down days. If there is an up day, continue
(skip it).
1 2 3 4 5 6 7 8 9 10 11 |
//@version=3 study("For Loop tutorial - Example 5") total_volume = volume - volume for i = 0 to 10 if close[i] >= open[i] continue total_volume := total_volume + volume[i] plot(total_volume, style=columns, color=red) |
This will result in a chart that looks something like this:
break
break
is another special keyword for pine script loops. It stops the loop when a condition is met. So instead of skipping lines of the loop, using break
skips the rest of the loops.
For example, you might want to loop through the past 10 bars of data but stop as soon as you find a certain value. So to continue with the theme of the example above, we can count the number of consecutive up days and then break
the loop as soon as you find a down day.
1 2 3 4 5 6 7 8 9 10 |
//@version=3 study("For Loop tutorial - Example 6") y = 0 for i = 0 to 10 if close[i] <= open[i] break y := y + 1 plot(y, style=line, color=green, linewidth=3) |
That will result in a chart which looks something similar to this:
Other things to note
Before we conclude this part and move onto a full code example, there are another couple of things to point out that could leave you scratching your head if not mentioned.
The first, which may not be obvious, is that 0
is one loop. So if you want to do twenty loops, you need to go from 0 to 19
or 1 to 20
and not 0 to 20
.
The second involves variables. In the examples above, when we add a value to y
, it has already been declared. Therefore,. when you need to assign a new value, you must use :=
instead of just =
. The reason for this is better suited to another post but if you want to look into it more now, search for the topic “Mutable Variables“.
Full Code Example
Now we understand the different parts of a For Loop, let’s move onto a practical example. In the code below we are going to use a for loop to perform some basic technical analysis. It will iterate (loop over) open and close data in order to provide the percentage of how many bars closed up vs down within a given lookback period. We can then use this to get a rolling picture of sentiment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
//@version=3 study("For Loop Example - Up / Down Bars Counter", precision=2) lbp = input(defval=20, title="Lookback Period", minval=1) // Declare the upcount, downcount and no change variables up = 0 dn = 0 nc = 0 // Run through historical data for i = 0 to lbp -1 if open[i] < close[i] up := up + 1 if open[i] > close[i] dn := dn + 1 if open[i] == close[i] nc := nc + 1 // Convert the counts to percentages up_perc = (up / lbp) * 100 dn_perc = (dn / lbp) * 100 nc_perc = (nc / lbp) * 100 // Plotting plot(up_perc, title="% Up Bars", color=green, linewidth=3) plot(dn_perc, title="% Down Bars", color=red, linewidth=3) plot(nc_perc, title="% No Change Bars", color=black, linewidth=3) // Fib based Horizontal lines h1 = hline(0, linestyle=solid, linewidth=2) h2 = hline(23.6, linestyle=dashed, linewidth=2) h3 = hline(38.2, linestyle=dashed, linewidth=2) h4 = hline(50, linestyle=dashed, linewidth=2) h5 = hline(61.8, linestyle=dashed, linewidth=2) h6 = hline(100, linestyle=solid, linewidth=2) // Fills to add a bit of visual polish fill(h1,h2, color=red, transp=90) fill(h5,h6, color=green, transp=90) |
On the charts
Ideas to extend the code:
After becoming comfortable with this code example, you can extend it to provide even more data insights. For example, you could further investigate:
- How much price changed in total during the lookback period. Did we have periods where more than 50% of the candles were green but price actually dropped?
- What percentage of total volume was allocated to up days vs down days? Have there been any instances where there has been more volume on down days but the price moved up over the lookback period?
These are just two ideas to spark your imagination. I believe extending the code with a clear question in mind will really help cement the ideas and concepts in this post.
Is there a way of running a loop on the current bar been formed?
I would like per example an alarm to go off only if the current 1 minute bar have passed 45 seconds.
Thanks from an old Power Basic coder. Your explanations are very instructive. Certainly, way less opaque than most of the Tradingview Wiki.
If only it could be possible to step through the execution of the code and watch the variables in real time.
One can dream….
Hi Paul,
Thank you for your kind words! You are most welcome.
How do you get the length of a series in Pine so you can do a for loop from 1 to the length of the series?
+1, I’m looking for similar functionality
Hi Greg, Mike
The built-in variable
n
should do it. That returns the current bar number.Every series in pinescript has a value for every bar whether it is
na
or something you calculate.Note: I have never tried looping through the complete series. As such, your mileage may vary!
Good luck.
I found many times the loop does not work well (not as expected). For example, when use the loop counter in valuewhen(cond, sourceData, occurrence or loop counter here) as an argument, it is usually not working well. Or to be more specific, it actually only works for the first time in the loop. I tried this in both main program having a loop to call a function, and in a function with a loop inside which the valuewhen() is called. As a result, I sometime have to right many repeated lines to replace the loop, but that works, losing all flexibility though.
I don’t what is the problem? Maybe it is because of the way using variables, especially for those mutated variables? For example, if you have defined a variable x, then next time you want to change it, you have to use x:= something. But in loop, you don’t do this way, right?
I would appreciate if some one can tell me what is the solution.
Hello Gentleman,
I’ve got an array in pinescript and wanna remove some of its elements
and plot them.
The array in my program is a[n] for n = 0,1,2,3,4, ….
I wanna create another array like b[n] = a[3*n] , this action is called decimation
in signal processing. The b[n] would be :
b[0] = a[0]
b[1] = a[3]
b[2] = a[6]
etc….
This means some samples in between are being drawn out and thrown away.
Would appreciate if you could help me with writing such code.
With best regards
Hi! Thanks for this article. I have a question: how could I create a loop that counts the peaks of an RSI line while the RSI remains above a level of 50? I created a stackoverflow question to illustrate: https://stackoverflow.com/questions/64435007/counting-number-of-rsi-peaks-while-rsi-level-50
Perhaps you could speak to this, it highlights a decent use case, ie “do this while this remains true”…
Thanks!! =)