thinkScript BarNumber() Function Usage and Examples

markos

Well-known member
VIP
Trying to learn BarNumber() function in thinkscript? Take a look at some of the notes below—credit to the folks over at the ThinkScript Lounge.

BarNumber Usage

First you must remember that thinkscript runs your script once for each and every bar on your chart, regardless of the aggregation period. So for instance, for daily charts I usually run a 9m D (9 month daily) with 5 expansion bars. TOS counts around 195 bars for this chart, the number varies slightly based on the mix of months on the chart. Typically you'll want to suspend a study's calculation for data in the expansion bars.

So looking at the two subject lines the first is simple enough we create a variable, barNum, that contains the number assigned each individual bar on the chart, 1 thru N. This is done because we want to use barNum in several places in the script without incurring the processing expense of calling the barNumber() function each time.

Code:
``````******************************************************
def barNum = if(barNumber() * (close > 0)<=barnumber(),barnumber(),double.nan);
************************************************************

# define period to plot
declare lower;
input candlestart = 28;
input candlestop = 14;

# Test if the barnumber has a closing value, if there is, the barnumber is good
# If there is no close value, the candle has not formed yet,

def barNum = if(barNumber() * (close > 0)<=barnumber(),barnumber(),double.nan);
def numBars = HighestAll(barNum);

plot barsWanted = if(  (numBars - barNum >= candlestop)
AND (numBars - barNum < candlestart),
high, double.NaN);
barsWanted.SetLineWeight(3);
barsWanted.SetPaintingStrategy(curve.POINTS);

*************** Plot barnumber **********************
def barNumber = barNumber();
#def barCount = HighestAll(if(IsNaN(price), 0, barNumber));
plot bn = barNumber;
bn.setPaintingStrategy(PaintingStrategy.VALUES_BELOW);
If the strategy is omitted a straight line is plotted. With the strategy included
the number of each bar is printed instead of the plot.
##################################``````

BarNumber() will never be 0

Simplify, simplify, simplify. Here's what is going is going wrong. Labels show the current value of a variable.

Code:
``````def FormingBar = !IsNaN(open) and IsNaN(open [-1] ) ;  # This is 1 if true and 0 is false.
def FormingBarNumber = if barnumber() == [1 or 0] then barNumber() else double.nan ; # BarNumber() will never be 0 and in order for it to be 1 you would need a chart with only 1 bar on the screen.``````

But more importantly those aren't doing anything at all in the script, why have them? What are you trying to do?

Barnumber() and bn - a function and a variable are different things

Also remember when using both Barnumber() and bn that a function and a variable are different things. Here is something that should show that difference

Code:
``````declare lower;

def random = Random();

plot
"Function/Function" = Random() / Random();
plot
"Variable/Variable" = random / random;
"Variable/Variable".SetStyle(Curve.Points);``````

9-21-19 17:22 JohnnyQs_IRA: If anyone is interested.. I put together a little Education Script to assist myself in understanding the Script Function and some general line drawing logic. It is included below..

Code:
``````## Education: The Script Function Exercise #1 JQ
## OneNote Name:Edu_Script_Ex1_JQ

#Mobius:  Scripts must end in a plot as their output. That plot can then be referenced as a global variable.
The objective of ALL ThinkScript is to plot something on a chart. ThinkScript is a chart painting program.

# Drawing a line from Point_A with and without a Script{} sub-routine
# Mobius
# Data Needed: Bar at Condition (bC), Value at Condition (vC), Length of Line (LL)

# User Inputs
input n = 20;             #hint n: Length for calculations.
input SdMulti = 2.0;      #hint SdMulti: Multiplier for St Dev.
input AtrMulti = 1.5;     #hint AtrMulti: Multiplier for ATR.

# Chart Data
def o = open;
def h = high;
def l = low;
def c = close;
def bar = BarNumber();

# Internal Script Reference
script LinePlot
{
input LL = 0; #Line Length
input vC = close; #Value at Condition
input bC = 0; #Bar at Condition
plot line = if HighestAll(bC) - LL <= bC
and bC == highestAll(bC)
then vC
else Double.NaN;
}
#                if the highest bar meeting the condition - LineLength is less than Bar at Condition
#                  and bC == highest bar meeting the condition
#                then value at condition
#                else double.nan

#> End Script (JQ)

#> BarNumber Plot
plot barNumBelow = bar;
barNumBelow.setpaintingStrategy(paintingStrategy.VALUES_BELOW);

# Variables for example
# Example: First bar of mean value in a squeeze
def Avg = Average(c, n); # c = close    n = length
def SD = StDev(c, n); # c = close  n = length
def ATR = Average(TrueRange(h, c, l), n);  # h = high   c = close   l = low   n = length
plot upperSD = Avg + (SdMulti * SD);
upperSD.setdefaultcolor(color.BLUE);
upperSD.setlineweight(2);
#    addchartbubble(1, lowestall(low), "SD\n" + upperSD, color.white, no);
plot upperATR = Avg + (AtrMulti * ATR);
upperATR.setdefaultcolor(color.plum);
#    addchartbubble(1, lowestall(low), "ATR\n" + upperATR, color.white, no);
upperATR.setlineweight(2);
addlabel(1," Condition: upperSD crosses below upperATR ", Color.violet);

# Variables for plotting line segment
# bC is the Bar at Condition input to the Script
def bC = if upperSD crosses below upperATR
then bar
else bC[1];  # barnumber where the condition is met
#!        assigns bC an initial value of n/a
#!        bC retains its bC[1] value until the condition is met
#!        if upperSD crosses below upperATR bC takes the current barnumber as its value
#!        bC retains that barnumber until the condition is met again if ever
#>    addchartbubble(1, lowestall(low), "bC\n" + bC, color.white, no);

# vC is the Value at Condition input to the Script
def vC = if upperSD crosses below upperATR
then Round(Avg / TickSize(), 0) * TickSize()
else vC[1];   # value (y-axis) where the condition is met
#!        assigns vC an initial value of n/a
#!        vC retains its vC[1] value until the condition is met
#!        if upperSD crosses below upperATR vC takes the current Avg rounded to the nearest tick as its value
#!        vC retains that value until the condition is met again if ever
#>    addchartbubble(1, lowestall(low), "vC\n" + vC, color.white, no);

# LL is then LineLength input to the sctipt
def LL = if bar != bC
then bar - bC
else if bar == bC
then Double.NaN
else LL[1];  #  Line Length
input Display_LL_Debug = {default "Hide", "Display"};
addchartbubble(Display_LL_Debug, lowestall(low), "bar\n" + bar, color.white, no);
addchartbubble(Display_LL_Debug, lowestall(low), "bC\n" + bC, color.white, no);
addchartbubble(Display_LL_Debug, lowestall(low), "bar\n!=bC\n" + (bar != bC), color.white, no);
addchartbubble(Display_LL_Debug, lowestall(low), "bar\n-bC\n" + (bar - bC), color.white, no);
addchartbubble(Display_LL_Debug, lowestall(low), "bar\n==bC\n" + (bar == bC), color.white, no);
addchartbubble(Display_LL_Debug, lowestall(low), "LL\n" + LL, color.white, no);
addchartbubble(Display_LL_Debug, lowestall(low), "LL[1]\n" + LL[1], color.white, no);

# Plots
# Method without Script{} for plotting just one line
plot Squeeze_Pivot_1 = if HighestAll(bC) - LL <= bC
and bC == highestAll(bC)
then vC
else Double.NaN;
Squeeze_Pivot_1.SetStyle(Curve.Points);
Squeeze_Pivot_1.setDefaultColor(color.orange);
Squeeze_Pivot_1.setLineWeight(5);
input Display_SP1_Debug = { default "Hide", "Display"};
addchartbubble(Display_SP1_Debug, lowestall(low), "HAbC\n" + highestall(bC), color.white, no);
addchartbubble(Display_SP1_Debug, lowestall(low), "LL\n" + LL, color.white, no);
addchartbubble(Display_SP1_Debug, lowestall(low), "HAbC\n-LL\n" + (highestall(bC) - ll), color.white, no);
addchartbubble(Display_SP1_Debug, lowestall(low), "bC\n" + bC, color.white, no);
addchartbubble(Display_SP1_Debug, lowestall(low), "bC==\nHAbC\n" + (bC == highestall(bC)), color.white, no);
# Method with Script{} for plotting multiple lines with different conditions
#Note: Since there's only one plot statement in the Script() a plot extension name is not needed.

plot Squeeze_Pivot_2 = LinePlot(vC = vC, LL = LL, bC = bC);
Squeeze_Pivot_2.setDefaultColor(color.cyan);
Squeeze_Pivot_2.SetLineWeight(3);

# End of Code``````

Last edited by a moderator:

paramay

New member
Greetings,

Has anyone had any success plotting a numeric value to a defined/specified date?

Each Friday, I generate a report and I would like that value (0 to 100) to be displayed on the plot. I suppose the value could be assigned to the open of that date. I have been informed by the kind folks here that I cannot tie to an external data set, so I am comfortable inputting a new value each week.

I do not have the foggiest just yet how to make that work. Has anyone on the forum had any success with this strange request?

tomsk

Well-known member
VIP
@paramay @BenTen Sure you can plot whatever value you wish so long as you can identify a bar number to do so against. Here is a simple example. Let's say you want to plot the value 280 on January 3, 2020 forward in time. This snippet does it. Load this on a daily aggregation of AAPL

Code:
``````# Plot Specific Date
# tomsk
# 1.21.2020

input date = 20200103;
input myLevel = 280;

def bar = if getYYYYMMDD() == date then barNumber() else Double.NaN;
plot data = if barNumber() >= HighestAll(bar) then myLevel else Double.NaN;
# End Plot Specific Date``````

tomsk

Well-known member
VIP
@BenTen ThinkScript is like a painting program. Important thing is to identify bars, then pretty much you can do whatever you want.

@paramay Over time all those levels are going to be a real challenge to manage. You might be better served to use a spreadsheet of some kind. That said if you really want to achieve this sort of thing by Thinkscript, you literally have to manage dates, barNumbers as well as input levels. Suggest you rethink about this a bit and maybe have a different approach

paramay

New member
@tomsk Thank you for the assistance with this. It does appear to be a lot of work. Generating the code and managing the dates I have a handle on (My report only maintains 1 year, and 6 months of visible data, anything more is shaved off). I'm certain I could generate a template from my data-set/spreadsheet, filling in the dynamic variables.

Thinking about the 40+ /futures contracts of data that I generate a report for, I can foresee, with this approach, could be a lengthy Study (or more like 40!).

I do have a wonderful report that I look at and have cultivated over the last several months, and I thought, "Man, this would be nice to have these levels right on the charts since it is a part of my strategy.

I'm not yet ready to give up on it. I am open to different approaches. Even if I was managing less data (dates, barNumbers, input levels), say 2 months worth - it would be beneficial to have that on a chart. I do like the idea of having this juxtaposed to candles and other indicators (minimal I mind you - I run a clean ship), as I find myself manually drawing things on the many charts everyday for reference. This could potentially save me 10's of hours a week of fiddling and managing my charts.

The data I am looking for, from what I can tell, is available on other platforms, just not TS yet - I wish it was.

"Nothing ventured, nothing gained" - Thanks for the help thus far, as I yet do not know much about the limitations/capabilities of thinkScript.

I was able to get some assistance with some simple code that does what I need it to do.

My report takes about 30 seconds to update, and the indicator another 30 seconds. I use a spreadsheet based off my report spreadsheet to generate the code. The code itself is a bit lengthy, nothing epic, but it delivers what I need while only adding a second or two to the load. I can absolutely live with this.

The folks at thinkScript lounge assisted and in it's simplest form looks like this:

Code:
``````plot line6MonthRTY = if GetSymbol() == "/RTY:XCME" OR  GetSymbol() == "/M2K:XCME" then
if GetYYYYMMDD() >     20200121    then    0.00    else
if GetYYYYMMDD() >     20200114    then    2.81    else
if GetYYYYMMDD() >     20200107    then    5.72    else
if GetYYYYMMDD() >     20191231    then    0.28    else
if GetYYYYMMDD() >     20190730    then    94.92    else    94.92
else double.nan;``````

Thanks for all the assistance. If anyone wants to know more, please ask.

Max911

Member
Hi, How can I use function BarNumber() on a moving average, so every time I need to change period, I don't have to enter the numbers of bars from that period.

def MA = ExpAverage(close, BarNumber());

but I get "Only constants expected here: BarNumber() CL constant function parameter 'length'

How can I fix that? Thanks

JP782

Active member
Saw this post by happenstance and am curious if anyone of you with knowledge on bar numbers etc could help out with the MTF standard deviation study that is 98% completed, working very well, but has 1 slight problem - the lengths must be input manually which means you have to run a bar count script to be able to accurately set up the MTF, and then update it manually later in day for each stock youre watching.

Is there a way to implement bar count in conjunction with aggregation( ex: DAY, or FOUR_HOURS) with the study??

MerryDay

Staff member
Staff
VIP
Hi, How can I use function BarNumber() on a moving average, so every time I need to change period, I don't have to enter the numbers of bars from that period.

def MA = ExpAverage(close, BarNumber());

but I get "Only constants expected here: BarNumber() CL constant function parameter 'length'

How can I fix that? Thanks
Only constants allowed.

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
• Exclusive indicators
• Proven strategies & setups
• Private Discord community
• Exclusive members-only content
• 1 full year of unlimited support

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?