Chapter 11. Referencing Secondary Aggregation

So far, we have learned many things about the bars on charts and values which can be calculated for them. But we never discussed the way they are formed (or, aggregated). In TOS Charts, three types of aggregation are available: time aggregation, tick aggregation, and range aggregation.

Time charts represent price action in terms of time: a new bar (or candlestick, line section, etc.) is plotted after completion of a certain time period (called aggregation period). For example, the 1y D bar chart plots the price action for one year, marking Open, High, Low, and Close prices on the daily basis.

Tick charts represent intraday price action in terms of quantity of trades: a new bar (or candlestick, line section, etc.) is plotted after completion of a certain number of trades (ticks). This aggregation type can be used on intraday charts with time interval not greater than five days. For example, the 2d 133t bar chart plots the price action for two days, defining Open, High, Low, and Close prices every time the number of trades becomes equal to 133.

Range charts represent price action in terms of price accumulation. Three modes of range aggregation are available in TOS Charts: Range Bars, Momentum Bars, and Renko Bars. However, these are not the subject of this chapter as we are going to discuss time aggregation in thinkScript® (information on range charts is available here).

All scripts we created before were the ones using aggregation period defined in chart settings. In order to access data of a different aggregation period in your code, specify the period parameter using the corresponding Aggregation Period constant. You can also use a pre-defined string value for this purpose: 1 min, 2 min, 3 min, 4 min, 5 min, 10 min, 15 min, 20 min, 30 min, 1 hour, 2 hours, 4 hours, Day, 2 Days, 3 Days, 4 Days, Week, Month, Opt Exp, or <current period>. Here is an example script:

plot dailyOpen = open(period = AggregationPeriod.DAY);

This script plots daily Open price for the current symbol.

plot weeklyClose = close("IBM", period = AggregationPeriod.WEEK);

This code plots weekly Close price for IBM. Interesting thing is that the IBM chart does not have to be opened to plot the Close price: it will be plotted on chart of any symbol you specified in chart settings. There is, however, a restriction in terms of time aggregation: secondary aggregation period cannot be less than the primary aggregation period defined by chart settings:

plot yesterdayHigh = High(period = AggregationPeriod.DAY)[1];

Designed to plot the High price reached on the previous day, this script will not work on weekly charts. Another restriction is that two different secondary aggregation periods cannot be used within a single variable:

plot Data = close(period = AggregationPeriod.MONTH) + close(period = AggregationPeriod.WEEK);

This script will not work on daily charts. In order to make it work, you need to break Data into two variables:

def a = close(period = AggregationPeriod.MONTH);
def b = close(period = AggregationPeriod.WEEK);
plot Data = a + b;

When referencing secondary aggregation with a variable, keep in mind that if this variable is used in an expression with any of the Fundamental or Date&Time functions with the primary aggregation period, the whole expression will use the latter, not the secondary one. E.g.,

def priClose = close; # primary context
def secClose = close(period = AggregationPeriod.DAY); # secondary context
def priContext = if GetYYYYMMDD() > 20130101 then secClose else secClose[1]; # primary context due to "GetYYYYMMDD()"

plot SecondaryAvg = Average(secClose , 12); # secondary context is kept
plot PrimaryAvg1 = Average((priClose + secClose) / 2 , 12); # primary context due to "priClose"
plot PrimaryAvg2 = Average(priContext , 12); # primary context

Here, SecondaryAvg is calculated with secondary aggregation period, but both PrimaryAvg1 and PrimaryAvg2 with primary aggregation period. Note also that some functions, e.g., BodyHeight use fundamental data implicitly, therefore, the same algorithm will be applied to expressions with them.

Expressions that use a variable referencing secondary aggregation and constant values will keep the secondary aggregation period:

def secClose10 = 10 + close(period = AggregationPeriod.DAY); # secondary context
plot SecondaryAvg = Average(secClose10 , 12); # secondary context is kept

The SecondaryAvg plot will be calculated as a 12 day SMA of the Close price plus 10.

By now, a lot of thinkScript® features have been explained to you. We are sure you will have absolutely no problems with reading this script:

declare lower;

input over_bought = 80;
input over_sold = 20;
input KPeriod = 10;
input DPeriod = 10;
input priceH = FundamentalType.HIGH;
input priceL = FundamentalType.LOW;
input priceC = FundamentalType.CLOSE;
input aggregationPeriod = AggregationPeriod.DAY;
input slowing_period = 3;
input smoothingType = {Default SMA, EMA};

def lowest_k = Lowest(Fundamental(priceL, period = aggregationPeriod), KPeriod);
def c1 = Fundamental(priceC, period = aggregationPeriod) - lowest_k;
def c2 = Highest(Fundamental(priceH, period = aggregationPeriod), KPeriod) - lowest_k;
def FastK = if c2 != 0 then c1 / c2 * 100 else 0;

plot FullK;
plot FullD;

switch(smoothingType) {
case SMA:
FullK = Average(FastK, slowing_period);
FullD = Average(FullK, DPeriod);
case EMA:
FullK = ExpAverage(FastK, slowing_period);
FullD = ExpAverage(FullK, DPeriod);

plot OverBought = over_bought;
plot OverSold = over_sold;

This script is based on the Stochastic Full study but price inputs were substituted by FundamentalType constant input, new AggregationPeriod constant input was added, and old price input references were replaced with Fundamental function calls. This approach can be used to rewrite predefined studies to add support of secondary aggregation period.