Separately, for anyone who came here looking for, actually, how to create a variable that retains its value - meaning the value doesn't change across bars because you don't want it to - here are 3 methods...
Use a recursive variable, as follows:
Method 1: if statement
# declare variable without initializing
def myVar;
# set up `if` condition for which variable should be set
if ( BarNumber() == 1 ) {
# set the value you want when the condition is met
# in this case, the variable is set to the close value at bar 1
myVar = close;
}
# thinkScript always requires an `else`
else {
# now, here, if you want the variable to change, enter the desired value,
# or, if you want it to always stay the same, then...
myVar = myVar[1];
}
Method 2: if expression
# same as above, really, but more compact; use parens as desired for clarity
def myVar = if BarNumber() == 1 then close else myVar[1];
Method 3: CompoundValue()
Note: Generally, CompoundValue()
works the same as the above examples, so one would not need to use it; however, it sometimes must be used. See below the code for more detail.
def myVar = CompoundValue(1,
if BarNumber() == 2 then close[1] else myVar[1],
0);
plot test = myVar;
Some CompoundValue()
Details
First, parameters, as the descriptions in the docs can be confusing:
The first parameter is the length
. It represents the bar number after which CompoundValue()
will utilize the expression in the 2nd parameter.
1 is the minimum (and default) value accepted for this argument.
The 2nd parameter is "visible data"
. The value here must be an expression, usually a calculation (though I used an if
expression for this example).
This is the data manipulation CompoundValue()
will use once the BarNumber()
value is past the length. Eg, for this example, since I had a 1 in the first parameter, the if
expression won't take effect until thinkScript is processing the 2nd bar. At bars 0 and 1, the 3rd parameter value will come into play.
Note that I used an offset for close
in the expression. Since I had to put a minimum of 1 in the length
argument, thinkScript would be at bar 2 before it started using the expression. Thus, I had to indicate the close value for the prior bar (close[1]
) was really what I wanted.
The 3rd parameter, "historical data"
, is the value that will be used for the bar number before and including the length (bar number) value in the 1st parameter.
For this example, I put 0, but I also could've used Double.NaN
. It wouldn't matter in my case because I didn't care about setting any values prior to the calculation point.
The CompoundValue()
docs give a Fibonacci example that now is easy to understand. It also shows why one might want to set a value for prior bars:
def x = CompoundValue(2, x[1] + x[2], 1);
plot FibonacciNumbers = x;
length
= 2, so the 2nd argument's calculation won't take place until the 3rd bar comes around.
"visible data"
= x[1] + x[2]
, the calculation that will take place for every bar after the 2nd bar (ie, from the 3rd bar forward).
"historical data"
= 1, so that for bars 1 and 2, the constant value 1 will be used in place of the calculation in the 2nd parameter. That works for a Fibonacci calculation!
As for reasons why one would use CompoundValue()
instead of the first two methods above, the main one is that CompoundValue
is required when plotting items with multiple lengths or "offsets". In short, thinkScript will change all plotted offsets to equal the largest offset. CompoundValue
, unlike other plotted variables, keeps its stated offset values.
For details, see the thinkScript tutorial's Chapter 12. Past/Future Offset and Prefetch, as well as my answer to the SO question Understanding & Converting ThinkScripts CompoundValue Function