Using BarsPerYear in Highest() Lowest()

excessivechaos

New member
Hello, can anyone tell me why this code does not work?

Code:
def currentDate = GetYYYYMMDD();
def yearBack = currentDate - 10000;
def barsPerYear = fold i = 0 to 253 with count = -1 while currentDate[i] >= yearBack do count + 1;

def lowestSpread = Lowest(spread, barsPerYear);
def highestSpread = Highest(spread, barsPerYear);

When I try to use the barsPerYear variable as the length parameter of the Lowest() and Highest() functions I get the following error:
Only constants expected here: barsPerYear CL constant function parameter 'length' at 48:23
Only constants expected here: barsPerYear CL constant function parameter 'length' at 48:23

If I create an input parameter to allow the user to enter the number of bars in a year. I can use that variable in the Highest() and Lowest() functions. I have also tried other methods for determining the number of bars in a year and that fails as well.

BTW, I don't think it matters much what the variable spread is in case you are wondering. I can put any value here, such as 1 and it will still error.

What I'm trying to do here is determine how many bars make up a year of data, which will change depending on the aggregation period. Right now I have the user set the agg period as input, but I wanted to code the dynamically. This is helpful when there isn't a years worth of data (new stocks) and the indicator fails because it's trying to do a calc based on having 252 bars. I just don't understand why this doesn't work. But the following code works fine:

Code:
input AggregationPeriod = {default Daily, Weekly, Monthly, Annual};

def ap;
switch (AggregationPeriod) {
case Daily:
    ap = 252;
case Weekly:
    ap = 52;
case Monthly:
    ap = 12;
case Annual:
    ap = 1;
}

def lowestSpread = Lowest(spread, ap);
def highestSpread = Highest(spread, ap);
 
Last edited:

excessivechaos

New member
your not going to be able to count any bars that dont exist on the chart
Once you reference the date for a bar before the first bar, the date returned is 19691231. So that would cause the counting to stop and I would have the number of bars available to me. This calc works, If I pull up a chart with only 50 bars, the barsPerYear variable is 49 (I'm not counting the current bar).

Counting the number of bars in a year, or the number of bars available to me on the chart is already solved. I just can't understand why I can't use this variable in the Highest() and Lowest() functions. Perhaps I can remake the functions...if anyone has an idea about that...
 

XeoNoX

Well-known member
VIP
with only part of the code, its hard to tell where its going wrong, you will have to post more of a complete code.
sounds like you may be trying to reference the bar as time when the time will only be increments of the aggregation and visa versa. In other words your constant may possibly not be a constant and your trying to go from fraction of time into a bar that doesnt see time lower than the charted aggregation . or maybe your going from variable to a constant and then referencing it as a variable or visa versa. this is just my guess, you will have to post the complete code or its just a guessing game.
 
Last edited:

excessivechaos

New member
with only part of the code, its hard to tell where its going wrong, you will have to post more of a complete code.
sounds like you may be trying to reference the bar as time when the time will only be increments of the aggregation and visa versa. In other words your constant may possibly not be a constant and your trying to go from fraction of time into a bar that doesnt see time lower than the charted aggregation . or maybe your going from variable to a constant and then referencing it as a variable or visa versa. this is just my guess, you will have to post the complete code or its just a guessing game.
Ok, here is the complete code. Note, this currently works because I am using the variable "ap" as the length parameter for the Highest() and Lowest() functions. I am taking user input for "AggregationPeriod" and doing a switch to set the "ap" variable to a certain value. This fails if there is less data than 1 year. So I would like to use the "barsPerYear" variable as the length parameter, but I get the errors noted above. Note, the "barPerYear" variable works fine when used to calculate HV.

Code:
declare lower;
declare hide_on_intraday;


input length = 20; #the rolling avg for historical volatility calc
input basis = {default Annual, Monthly, Weekly, Daily};
# Using barsPerYear calc below doesn't work in the functions needed to calculate
# Spread rank for some reason, so user will need to set the Aggregation Period manually
# until I can figure out why Highest and Lowest do not like barsPerYear as input
input AggregationPeriod = {default Daily, Weekly, Monthly, Annual};
input SpreadRankSignalHigh = 50;
input SpreadRankSignalLow = -50;
input ShowSpreadLine = no;
input ShowSpRankLine = yes;

def currentDate = GetYYYYMMDD();
def yearBack = currentDate - 10000;
def barsPerYear = fold i = 0 to 300 with count = -1 while currentDate[i] >= yearBack do count + 1;

def ap;
switch (AggregationPeriod) {
case Daily:
    ap = 252;
case Weekly:
    ap = 52;
case Monthly:
    ap = 12;
case Annual:
    ap = 1;
}

def basisCoeff;
switch (basis) {
case Annual:
    basisCoeff = 1;
case Monthly:
    basisCoeff = 12;
case Weekly:
    basisCoeff = 52;
case Daily:
    basisCoeff = 252;
}

def clLog = Log(close / close[1]);

def ImpVol = imp_volatility() * 100.0;
def HV = (StDev(clLog, length) * Sqrt(barsPerYear / basisCoeff * length / (length - 1)) * 100.0);

#Spread between Implied and Historical Volatility
def spread = ImpVol - HV;
AddLabel(yes, "Spread: " + spread, Color.VIOLET);

#Calculate Spread Rank - Where we are in the range of spread values
def lowestSpread = Lowest(spread, ap);
def highestSpread = Highest(spread, ap);
def spreadRank =
    if spread >= 0
    then Round(spread / highestSpread * 100.0, 0)
    else Round(spread / -lowestSpread * 100.0, 0);
AddLabel(yes, "SpRank: " + spreadRank,
        if spreadRank >  SpreadRankSignalHigh or spreadRank <  SpreadRankSignalLow
            then Color.GREEN
            else Color.RED
        );

plot ImpVolLine = ImpVol;
ImpVolLine.SetDefaultColor(Color.MAGENTA);
plot HistVolLine = HV ;
HistVolLine.SetDefaultColor(Color.CYAN);
plot SpreadLine = spread;
SpreadLine.SetDefaultColor(Color.WHITE);
SpreadLine.SetHiding(!ShowSpreadLine);
plot spRankLine = spreadRank;
spRankLine.AssignValueColor(
        if spreadRank > SpreadRankSignalHigh or spreadRank < SpreadRankSignalLow
            then Color.GREEN
            else Color.RED
        );
spRankLine.SetLineWeight(2);
spRankLine.SetHiding(!ShowSpRankLine);
plot posFifty = SpreadRankSignalHigh;
posFifty.SetDefaultColor(Color.Gray);
PosFifty.SetStyle(Curve.Medium_DASH);
plot negFifty = SpreadRankSignalLow;
negFifty.SetDefaultColor(Color.Gray);
negFifty.SetStyle(Curve.Medium_DASH);
 

XeoNoX

Well-known member
VIP
you can do something like this for the timeframes you will be using, i supposes most common are 1 ,5,15,30,1hr,2hr,4hr
so that would be 7 lines of code. you just have to figure out the number of bars there would be. Keep in mind TOS does have limit on how far it can count back.
# if the current charted period is 5 minutes then use 424433 else 0
Code:
def five= if GetAggregationPeriod() == AggregationPeriod.FIVE_MIN  then 42424333 else 0;
# if the current charted period is 10 minutes then use 824433 else 0
Code:
def ten= if GetAggregationPeriod() == AggregationPeriod.ten_MIN  then 82424333 else 0;

#since only of time period will return a positive number you can use the code below to define bars per year
Code:
def barsPerYear = five + ten+ fifteen + thirty + hour + hour2 + hour4;


thats not the actual coding but that would be the formulated code in theory.

https://tlc.thinkorswim.com/center/reference/thinkScript/Functions/Others/GetAggregationPeriod
https://tlc.thinkorswim.com/center/reference/thinkScript/Constants/AggregationPeriod
 
Last edited:

excessivechaos

New member
you can do something like this for the timeframes you will be using, i supposes most common are 1 ,5,15,30,1hr,2hr,4hr
so that would be 7 lines of code. you just have to figure out the number of bars there would be. Keep in mind TOS does have limit on how far it can count back.
I actually did try a method similar to this, but the issue I have is that I am still setting the bars per year statically, which is a problem if there is less than 1 year of data. Let's say I'm using a daily agg period and the stock IPO 3 months ago. If I set bars per year to 252 it breaks the indicator when I try to use it on new stocks.

Btw, I should have mentioned this, but I am not using this for intraday.
 

XeoNoX

Well-known member
VIP
thats correct because i assume there are less than 252 bars available on chart, you cant grab data from something that doesnt exist. you will get NAN error or "not a number" because it doesnt know whats there since it doesnt exisit.
 

sep23

New member
I'm trying to plot a moving average that resets on the start of the session. I get the start of the day, say 0930, then reset a variable to 0 then begin incrementing that variable by 1 for each bar that completes. These are intraday candle charts on usually a 15 min timeframe.

The code looks like this.

Code:
def BoDLenCtr = if firstBarOfDay then 0 else bodlenCtr + 1;
plot ADRatioMA = if showma then movingAverage(averageType.SIMPLE, ADRatio, BoDLenCtr) else double.nan;

When I do this I get the following error: "Only constants expected here: barsPerYear CL constant function parameter "

This is similar to the question posed here, but didn't find this to be helpful.

I can't see that this is very hard to do but since I'm getting used to thinkscript I need some guidance. Thanks.
 

SleepyZ

Active member
I'm trying to plot a moving average that resets on the start of the session. I get the start of the day, say 0930, then reset a variable to 0 then begin incrementing that variable by 1 for each bar that completes. These are intraday candle charts on usually a 15 min timeframe.

The code looks like this.

Code:
def BoDLenCtr = if firstBarOfDay then 0 else bodlenCtr + 1;
plot ADRatioMA = if showma then movingAverage(averageType.SIMPLE, ADRatio, BoDLenCtr) else double.nan;

When I do this I get the following error: "Only constants expected here: barsPerYear CL constant function parameter "

This is similar to the question posed here, but didn't find this to be helpful.

I can't see that this is very hard to do but since I'm getting used to thinkscript I need some guidance. Thanks.

See if this helps
Code:
# Example Moving Average
# Sleepyz

input var     = close;

def length    = if SecondsFromTime(0930) == 0
                then 0
                else length[1] + 1;

plot MA       = if length == 0 then Double.NaN
                else (fold x = 0 to length
                      with y = 0
                      do y + GetValue(var, x)) / length ;
Capture.jpg
 

halcyonguy

Member
VIP
Hello, can anyone tell me why this code does not work?

Code:
def currentDate = GetYYYYMMDD();
def yearBack = currentDate - 10000;
def barsPerYear = fold i = 0 to 253 with count = -1 while currentDate[i] >= yearBack do count + 1;

def lowestSpread = Lowest(spread, barsPerYear);
def highestSpread = Highest(spread, barsPerYear);

When I try to use the barsPerYear variable as the length parameter of the Lowest() and Highest() functions I get the following error:
Only constants expected here: barsPerYear CL constant function parameter 'length' at 48:23
Only constants expected here: barsPerYear CL constant function parameter 'length' at 48:23

If I create an input parameter to allow the user to enter the number of bars in a year. I can use that variable in the Highest() and Lowest() functions. I have also tried other methods for determining the number of bars in a year and that fails as well.

BTW, I don't think it matters much what the variable spread is in case you are wondering. I can put any value here, such as 1 and it will still error.

What I'm trying to do here is determine how many bars make up a year of data, which will change depending on the aggregation period. Right now I have the user set the agg period as input, but I wanted to code the dynamically. This is helpful when there isn't a years worth of data (new stocks) and the indicator fails because it's trying to do a calc based on having 252 bars. I just don't understand why this doesn't work. But the following code works fine:

Code:
input AggregationPeriod = {default Daily, Weekly, Monthly, Annual};

def ap;
switch (AggregationPeriod) {
case Daily:
    ap = 252;
case Weekly:
    ap = 52;
case Monthly:
    ap = 12;
case Annual:
    ap = 1;
}

def lowestSpread = Lowest(spread, ap);
def highestSpread = Highest(spread, ap);

what i have seen is that bar offsets and function lengths, don't like variables that don't originate from a constant.
the values from the fold function are created from a formula and are different from each other.
the values in your 2nd example with switch, originate as constants.
 

Similar threads

Top