It seems as though there is a fair bit of confusion regarding the new thinkScript looping capability implemented with the fold function. At first glance, the syntax is a bit unusual but dig a little deeper and there is a classic for loop hiding there – albeit with some constraints. Here’s the syntax taken directly from thinkorswim’s own Resource Center:
def <result> = fold <index> = <start> to <end> with <variable> [ = <init> ] do <expression>;
So, first and foremost, the fold function is used to define the value for a named variable. Hence, the end result of any fold iteration is saved into an immutable variable once the loop is complete. That variable can be either a non-self-referencing variable using the def statement or can refer to prior values of itself when used with the rec statement. The key point here is that you cannot operate on other variables or do anything within the loop. Your loop’s sole function will be to return a value into a variable. This alone heavily constrains what you can do with fold. In the sample code above result will contain the final computed value.
Let’s dive a little deeper into the beast, shall we. Every loop has an index over which it iterates. If you ever programmed in BASIC, you probably coded something like the following
for i = 1 to 100 print i next i
which result in the numbers 1 to 100 printing to the screen for your immense enjoyment. OK, so I’m dating myself here, but yes I began coding BASIC on my Apple II in the early 80′s and wrote such to impress my less computer savvy classmates. Back to the task at hand. The i variable in this syntax is the index over which this loop iterates or counts. There will be 100 iterations of the loop until the program completes. The functionality in the fold function is identical with the index variable being iterated from the value of start to end in the above sample code.
To recap, we have a variable result to store the final value of the calculation, and we have a loop which will iterate its index variable from start to end which is mathematically start-end times.
Now on to the calculation itself. Internal within the structure of the fold loop is another variable incidentally called variable within the sample code above. This is were the interim value of the loop calculation is held while the loop is iterating. At the conclusion of the loop, the final value of variable is then transferred to result. Beginning to get the idea? The value of variable may be initialized to something using the = init syntax. If you omit this optional code, the value of variable will simply start at 0.
The final piece of the puzzle is the calculation code itself. This is the do expression portion of the code. Within the expression you can perform any one-line thinkScript calculation using the index variable or other variables/numeric values from elsewhere in your thinkScript code. That is, the code you create here should have the syntax of whatever lies on the right side of an equals sign in the classic thinkScript variable definition. Each time through the loop, the expression will be evaluated and the result will be placed into variable awaiting the next iteration. So, if my expression were variable*index then you would be successively multiplying the value of variable by index each iteration through the loop. This might look like this in a BASIC pseudocode example:
for index = 1 to 10 variable = variable*index next index
Well, that’s all for today. Next time we’ll go through some examples to bring the picture into complete focus. Happy thinkScripting and best of luck in your trading. -Eric





Pingback: VSA for ThinkorSwim - Page 11 - Big Mike's Day Trading Forum
Though the syntax definition shows a “def” statement, note that all the examples use “plot” statements, and you can use “rec” statements as well. In fact in a rec you can use the rec variable in the fold expression. It’s worth mentioning that the “fold loop” happens on each and every bar. So the factorial example at the resource center yields n! (3,628,800) for each and every bar. Try this out for some interesting results. You’ll have to hide the bigCount plot to see nFactorial and hide that to see smlCount. Note that you can’t hit a target exactly from within a fold in a rec statement if you’re trying to control a runaway calculation.
declare lower;
input length = 10;
rec bigCount = compoundValue( 1, fold idx = 1 to length with a = 0 do a + bigCount[1], 1 );
plot BC = bigCount;
rec smlCount = compoundValue( 1, fold idx2 = 1 to length with b = 0 do if smlCount[1] >= 1000 and b >= 1000 then 1000 else b + smlCount[1], 1 );
plot SC = smlCount;
plot nFactorial = fold idx3 = 1 to length with n = 1 do n * idx3;
Thanks for the addition Rich.
-Eric
I am trying to create a study using the fold function. The study looks at the current bar and examines the highest rate of change achieved over x-number of days [forward]. The study examines the high() rather than the close() of each successive bar. Ideally the study will allow me to assume whether it is reasonable to expect a certain rate of change in x-number of days by looking at the history of rates achieved over the specified number of days.
It works for some cases but not for all (in fact, very few). The troubling part, however, is that it DOES work sometime. Please examine my study and share with me what I might be missing about the fold functionality.
A point about the study:
[Since data for future bars use negative indexes, (and assuming the fold function does not increment backward (e.g., from -1 to -5)), I had to start with the bar farthest out from my current bar and work backward (e.g., -5 to -1 step 1).
I initially had an exit condition: "...while getDay()[BarsOut] HROC then 100 * (high[index] / close – 1)else HROC;
plot zeroline = 0;
HAR.DefineColor(“Positive”, Color.GREEN);
HAR.DefineColor(“Negative”, Color.RED);
HAR.AssignValueColor(if HAR >= 0 then Har.Color(“Positive”) else HAR.Color(“Negative”));
zeroline.AssignValueColor(color.red);
Thanks,
Roy
Here it is AGAIN:
I initially had an exit condition: “…while getDay()[BarsOut] HROC then 100 * (high[index] / close – 1)else HROC;
plot zeroline = 0;
HAR.DefineColor(“Positive”, Color.GREEN);
HAR.DefineColor(“Negative”, Color.RED);
HAR.AssignValueColor(if HAR >= 0 then Har.Color(“Positive”) else HAR.Color(“Negative”));
zeroline.AssignValueColor(color.red);
declare lower;
input length = 10;
Def BarsOut = -length;
plot HAR = fold index = BarsOut + 1 to -1 with HROC = 100 * (high[BarsOut] / close – 1) do if 100 * (high[index] / close – 1) > HROC then 100 * (high[index] / close – 1)else HROC;
plot zeroline = 0;
HAR.DefineColor(“Positive”, Color.GREEN);
HAR.DefineColor(“Negative”, Color.RED);
HAR.AssignValueColor(if HAR >= 0 then Har.Color(“Positive”) else HAR.Color(“Negative”));
zeroline.AssignValueColor(color.red);
I think the general problem is with folding over future bars. Though the syntax may compile in the editor without errors, I don’t think it was intended to work in that manner. In order for this to work properly, your chart would need to recalculate prior bars with each new bar. TOS removed this kind of functionality when the “declare fullrange” command was deprecated.
Thanks for your prompt reply. If you attempted the study, did you see where it properly calculated the highest rate over the period for some bars? Is it possible within thinkscript functionality to track compilation or calculation errors ?
Thanks,
Roy