When referencing historical data (described in chapter 10), you should keep in mind a feature called past offset. Let's study the following example.
plot CloseOffset = close;
This example script will plot the Close price five bars prior to the current bar. This calculation mechanism is obvious for bars from the sixth through the last one, but how exactly this plot is going to be calculated for the first five bars?
Past offset is a number of additional bars from the past, necessary for calculating a study. In this very example, the past offset is equal to five; it means that the calculation will start with the sixth bar using price data obtained from the first five bars. However, if additional historical data is available for the chart you are currently using, it will be used for calculating the plot for the first five bars.
When scripting a study, you might need to use several different past offsets for expressions in your script. Let's analyze the following example:
def x = x + 1;
plot Average11 = Average(close, 11);
plot myline = x;
In this script, variable
x uses a past offset equal to 1, while function
Average uses a past offset equal to 10. In thinkScript®, the highest past offset overrides lower offsets in the same study, which means that all expressions in a single study will have the same (highest) past offset. In the example script, this offset is equal to 10 and is assigned to both expressions. This is why the myline plot will return 11 for the first bar, not 2 as one might have expected.
Note that past offset might affect calculation mechanism of some studies due to setting a single intialization point for all expressions. However, if for some reason you need an independent initialization point for an expression, you can use the
CompoundValue function that you are already familiar with:
def x = compoundValue(1, x+1, 1);
plot ATR = average(TrueRange(high, close, low), 10);
plot myline = x;
This would explicitly set the value for the
myline plot for the first bar, and all other values of this plot will be calculated corresponding to it.
Prefetch is a property characteristic of Exponential Moving Averages that consists in fetching historical data prior to beginning of time period. This property enables these functions to be range independent. Three thinkScript® functions use prefetch: ExpAverage, EMA2, and WildersAverage.
The number of bars needed for each of these to become range-independent can be calculated as follows:
- ExpAverage: 4*length bars
- Ema2: 8/α + 4 bars
- WildersAverage: 7*length bars
WildersAverage also uses a past offset which is equal to
(length – 1) bars; two others have a zero past offset.
There is a notable difference between the past offset and prefetch: when historical data is not available, functions that only use prefetch will have the first bar on chart as an initialization point, while functions using past offset will be initialized at a bar whose number is equal to the past offset value.
Unlike the two previously described features, future offset affects re-calculation of values for the most recent bars. When the future offset is equal to zero, e.g., in
plot data = close;
the only value that has to be re-calculated is that of the last bar on chart. However, if we specify a future offset in this expression using a negative index:
plot data = close [-1];
the study will wait for a new quote in order to calculate the value for the second latest bar. Basically, this script plots the close price of the next bar as soon as there is a quote for it.
Some functions use the future offset (and increase its value for the whole script) without waiting for the upcoming quotes. These functions produce values based on events, e.g., conference calls or earnings, scheduled for a future date. To see how it works, refer, for example, to the GetEventOffset function article.
Apart from its influence on recent values, future offset can be useful in a number of specific tasks. For example, it is widely employed to indicate the level of the last close price across several most recent bars:
input lineLength = 4;
def lastBar = !IsNaN(close) && IsNaN(close[-1]);
def lastClose = if lastBar then close else lastClose;
plot data = if IsNaN(close[-lineLength-1]) then lastClose[-lineLength] else Double.NaN;
This script records the last close price and plots it as a line across the last 4 bars, the number being customizable via the input parameter. In case you’re wondering what those
IsNaN and !
IsNaN are, refer to the Appendix D. Here, these constants are used for finding the last bar on chart. We strongly recommend that you use the “IsNaN + future offset” method for detection of the last bar, not the popular HighestAll method:
def isLastBar = BarNumber() == HighestAll(if !IsNaN(close) then BarNumber() else Double.NEGATIVE_INFINITY);
plot LastBarSignal = isLastBar;
The script above makes the study dependent on all bars of chart, which may result in productivity problems. Besides, the re-calculation mode will be set to once per bar instead of once per quote, which may also affect the output in an unwanted way. Should you need to fix the last bar in your script, use the future offset version:
def isLastBar = !IsNaN(close) and IsNaN(close[-1]);
plot LastBarSignal = isLastBar;
Three last chapters only covered time referencing: finding historical values, using secondary aggregation, or using additional bars from the past. However, there are several other things you might need to reference in your script; all of these will be explained in the next chapter.