Consecutive Bar Count Indicator for ThinkorSwim

korygill

korygill

Active member
VIP
Like roulette in Vegas, the longer the ball keeps landing on Red, the more likely it is to land on Black the next turn, right? Well, in roulette, the odds are the same each turn, but perhaps in the stock market, all trends change at some point. [side note on roulette]

This is also an example of how to count things in thinkscript. If you are new to thinkscript, remember that your code runs on each bar and calculates everything based on that bar and any forward or backward looking values (like close[1] being the close 1 bar in the past). You can also reference the values of your own variables!

CompoundValue is a powerful function, and one you can use to in a couple ways. One way is counting things. That is what I will show here. Search other articles and the documentation for other usages like how to carry a previous value/condition forward until it changes.

For this example, we will count the number of consecutive up and down bars (based on close) on a chart. This image should give you a clear idea of what we're doing. Perhaps this technique can be applied to other studies and strategies.



Code for ConsecutiveBarCount

Code:
#
# ConsecutiveBarCount
#
# Study to indicate count consecutive up/down bars.
#
# Author: Kory Gill, @korygill
#
# VERSION HISTORY (sortable date and time (your local time is fine), and your initials
# 20190709-1200-KG    - created
# ...
# ...
#
# Comment out unnecessary portions to preserve TOS memory and enhance speed
#

declare lower;
declare once_per_bar;

#
# Common variables. Using variables reduces calls to TOS iData server.
#

# iData Definitions
#def vHigh = high;
#def initHigh =  CompoundValue(1, high, high);  # creates an initialized variable for high
#def vLow = low;
#def initLow = CompoundValue(1, low, low);
#def vOpen = open;
#def initOpen = CompoundValue(1, open, open);
def vClose = close;
#def initClose = CompoundValue(1, close, close);
#def vVolume = volume;
#def initVolume = CompoundValue(1, volume, volume);
def nan = Double.NaN;

# Bar Time & Date
#def bn = BarNumber();
#def currentBar = HighestAll(if !IsNaN(vHigh) then bn else nan);
#def Today = GetDay() ==GetLastDay();
#def time = GetTime();
#def GlobeX = GetTime() < RegularTradingStart(GetYYYYMMDD());
#def globeX_v2 = if time crosses below RegularTradingEnd(GetYYYYMMDD()) then bn else GlobeX[1];
#def RTS  = RegularTradingStart(GetYYYYMMDD());
#def RTE  = RegularTradingEnd(GetYYYYMMDD());
#def RTH = GetTime() > RegularTradingStart(GetYYYYMMDD());
#def RTH_v2 = if time crosses above RegularTradingStart(GetYYYYMMDD()) then bn else RTH[1];

# Bars that start and end the sessions
#def rthStartBar    = CompoundValue(1,
#                         if   !IsNaN(vClose)
#                         &&   time crosses above RegularTradingStart(GetYYYYMMDD())
#                         then bn
#                         else rthStartBar[1], 0);
#def rthEndBar      = CompoundValue(1,
#                         if   !IsNaN(vClose)
#                         &&   time crosses above RegularTradingEnd(GetYYYYMMDD())
#                         then bn
#                         else rthEndBar[1], 1);
#def globexStartBar = CompoundValue(1,
#                         if   !IsNaN(vClose)
#                         &&   time crosses below RegularTradingEnd(GetYYYYMMDD())
#                         then bn
#                         else globexStartBar[1], 1);
#def rthSession = if bn crosses above rthStartBar #+ barsExtendedBeyondSession
#                    then 1
#                    else if   bn crosses above rthEndBar #+ barsExtendedBeyondSession
#                         then 0
#                    else rthSession[1];

def zeroLine = 0;
plot pZeroLine = zeroLine;
pZeroLine.SetDefaultColor(Color.WHITE);
def upLine = 5;
plot pUpLine = upLine;
pUpLine.SetDefaultColor(Color.GREEN);
def downLine = -5;
plot pDownLine = downLine;
pDownLine.SetDefaultColor(Color.RED);

def barUp = vClose > vClose[1];
def barDown = vClose < vClose[1];

def barUpCount = CompoundValue(1, if barUp then barUpCount[1] + 1 else 0, 0);
plot pBarUpCount = if barUpCount > 0 then barUpCount else nan;
pBarUpCount.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
pBarUpCount.AssignValueColor(Color.GREEN);

def barDownCount = CompoundValue(1, if barDown then barDownCount[1] - 1 else 0, 0);
plot pBarDownCount = if barDownCount < 0 then barDownCount else nan;
pBarDownCount.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
pBarDownCount.AssignValueColor(Color.RED);

AddLabel(yes, "Consecutive Bar Count", Color.GRAY);
The secret sauce
def barUpCount = CompoundValue(1, if barUp then barUpCount[1] + 1 else 0, 0);

This statement says...
if the current bar is up
then set barUpCount to the "barUpCount of the previous bar" plus 1
else set barUpCount to zero

For now, don't worry about the first "1," and the last ",0" parts. You will just about always keep those like that and just change the middle part...

So the first UP bar we see is 1. If the next bar is also UP, then we take the previous barUpCount (1) and add 1 to it for 2. If we get a third UP bar, then we take the previous barUpCount (2) and add 1 to it for 3. Once you get this (and don't worry if it takes you a while; I struggled for a bit at first too), you will get an aha moment and this will become a great tool in your thinkscript arsenal.

Shareable link to the image and code
http://tos.mx/eY58Fy
 
Last edited:
markos

markos

Well-known member
VIP
Hey Kory, that is a very nice little touch that you put in; placing a version history at the top of the script. Quite professional.
 
korygill

korygill

Active member
VIP
Hey Kory, that is a very nice little touch that you put in; placing a version history at the top of the script. Quite professional.
Thanks. I get paid to code for a living, and I try to use best practices everywhere. I saw other scripts that have a version scheme that did not sort well. It should be real easy to see if your version is newer/older than something else you are looking at. Also I am experimenting/exploring the right amount of boilerplate at the top. I expect many scripts here get modified by everyone a little. Want to encourage sharing/extending and attribution.
 
I

imnobody

Member
Sorry if this has been answered perhaps it'll make this easier if so, but I'm just looking for a simple study that counts candles. it has to keep a running total so if we've had 4 red candles it'll say 4 red candles then 5 and flip upon green, etc.

wow awesome thanks a lot

here's the label i was trying to make i just plugged in the data from this

Code:
AddLabel(yes, " BarCount: " +(" "+(Round(barDownCount + barUpCount, 1))), if barUpCount > 1 then color.upTICK else if barDownCount <= 0 then color.downtick else Color.gray);
 
Last edited by a moderator:
D

DeusMecanicus

New member
I like this one on the daily/weekly chart. I added this code in for a quick assessment of price difference since last down bar.
Code:
def close_diffpositive = if barUp then close - close[1] else 0;
def totalpositive = compoundvalue ( 1,if barupcount then close_diffpositive + totalpositive[1] else 0,0);
def close_diffnegative = if barDown then (close[1] - close) * -1 else 0;
def totalnegative = CompoundValue(1, if bardowncount then close_diffnegative + totalnegative[1] else 0, 0);
AddChartBubble(1, pBarUpCount,totalpositive, Color.GREEN);
AddChartBubble(1, pBarDownCount, totalnegative, Color.RED);
 
G

GimmickFace

New member
I know this should be basic, but I'm not getting the correct results. If I wanted to scan for stocks closing down 8 straight days in a row, is the below code wrong? If so, what should it be? Thanks for any help

sum (close < Average(close,5), 8) >= 8
 
E

ext99k

New member
Thank you @korygill for taking the time to do this and everyone else for adding their modifications, I think it is great and everyone appreciates it.

I wanted to offer a suggestion that will make reading this a lot easier:

With Labels, can you please add the % of time the consecutive events occur? For example, there would be a label "1: 60%" if the number of consecutive up events were 60%, and another would be "-1: 65%" if the number of consecutive down days was 65% of the time... this would be repeated for all of the consecutive events (2, 3, etc. for both up and down days/candles) -- this would make summarizing data a lot more efficient.

Or instead of labels, if possible, we can place these just to the right of where the indicator's title is shown (beside the other data point squares), that would save space!

I am not sure if this is possible to create, because I'm not a programmer, but I think that will be a lot more powerful! If someone is capable of adding this to the script, that would be awesome and thanks a lot in advance! Thanks!
 
Last edited:
korygill

korygill

Active member
VIP
There might be a way to get various counts using fold or compoundvalue, but I chose to just carry some variables forward and solve that way.

Now you can use a "percent" mode on another lower study to see the percent of time a given count is achieved. This is based on visible data, so the longer the chart, the better the accuracy.

Chart:


Code:

Code:
#
# ConsecutiveBarCount
#
# Study to indicate count consecutive up/down bars.
#
# Author: Kory Gill, @korygill
#
# VERSION HISTORY (sortable date and time (your local time is fine), and your initials
# 20190709-1200-KG    - created
# 20200218-1200-KG    - added a percent mode to show percent of time a given count is achieved
# ...
#
# Comment out unnecessary portions to preserve TOS memory and enhance speed
#

declare lower;
declare once_per_bar;

input mode = {default histogram, percent};
input hideBarsBefore = 20;

#
# Common variables. Using variables reduces calls to TOS iData server.
#
def vClose = close;
def nan = Double.NaN;
def bn = BarNumber();

#
# Logic for histogram mode
#
def zeroLine = 0;
plot pZeroLine = if mode == mode.histogram then zeroLine else nan;
pZeroLine.SetDefaultColor(Color.WHITE);
def upLine = 5;
plot pUpLine = if mode == mode.histogram then upLine else nan;
pUpLine.SetDefaultColor(Color.GREEN);
def downLine = -5;
plot pDownLine = if mode == mode.histogram then downLine else nan;
pDownLine.SetDefaultColor(Color.RED);

def barUp = vClose > vClose[1];
def barDown = vClose < vClose[1];

def barUpCount = CompoundValue(1, if barUp then barUpCount[1] + 1 else 0, 0);
plot pBarUpCount = if mode == mode.histogram and barUpCount > 0 then barUpCount else nan;
pBarUpCount.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
pBarUpCount.AssignValueColor(Color.GREEN);

def barDownCount = CompoundValue(1, if barDown then barDownCount[1] - 1 else 0, 0);
plot pBarDownCount = if mode == mode.histogram and barDownCount < 0 then barDownCount else nan;
pBarDownCount.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
pBarDownCount.AssignValueColor(Color.RED);

AddLabel(yes, "Consecutive Bar Count", Color.GRAY);

#
# Logic for percent mode
#
def p1;
def p2;
def p3;
def p4;
def p5;
def p6;
def n1;
def n2;
def n3;
def n4;
def n5;
def n6;

if (bn == 1) then
{
    p1 = 0;
    p2 = 0;
    p3 = 0;
    p4 = 0;
    p5 = 0;
    p6 = 0;
    n1 = 0;
    n2 = 0;
    n3 = 0;
    n4 = 0;
    n5 = 0;
    n6 = 0;
}
else
{
    if (barUp and barUpCount == 1) then {p1 = p1[1] + 1;} else {p1 = p1[1];}
    if (barUp and barUpCount == 2) then {p2 = p2[1] + 1;} else {p2 = p2[1];}
    if (barUp and barUpCount == 3) then {p3 = p3[1] + 1;} else {p3 = p3[1];}
    if (barUp and barUpCount == 4) then {p4 = p4[1] + 1;} else {p4 = p4[1];}
    if (barUp and barUpCount == 5) then {p5 = p5[1] + 1;} else {p5 = p5[1];}
    if (barUp and barUpCount == 6) then {p6 = p6[1] + 1;} else {p6 = p6[1];}
    if (barDown and barDownCount == -1) then {n1 = n1[1] + 1;} else {n1 = n1[1];}
    if (barDown and barDownCount == -2) then {n2 = n2[1] + 1;} else {n2 = n2[1];}
    if (barDown and barDownCount == -3) then {n3 = n3[1] + 1;} else {n3 = n3[1];}
    if (barDown and barDownCount == -4) then {n4 = n4[1] + 1;} else {n4 = n4[1];}
    if (barDown and barDownCount == -5) then {n5 = n5[1] + 1;} else {n5 = n5[1];}
    if (barDown and barDownCount == -6) then {n6 = n6[1] + 1;} else {n6 = n6[1];}
}

# used for debugging/development
#AddChartBubble(mode == mode.histogram and barUp and barUpCount == 4, barUpCount, p4);
#AddChartBubble(mode == mode.histogram and barUp and barUpCount == 5, barUpCount, p5);

plot ppX =
    if bn > hideBarsBefore and mode == mode.percent and barUp and barUpCount == 1 then p1/(bn-1)*100
    else if bn > hideBarsBefore and mode == mode.percent and barUp and barUpCount == 2 then p2/(bn-1)*100
    else if bn > hideBarsBefore and mode == mode.percent and barUp and barUpCount == 3 then p3/(bn-1)*100
    else if bn > hideBarsBefore and mode == mode.percent and barUp and barUpCount == 4 then p4/(bn-1)*100
    else if bn > hideBarsBefore and mode == mode.percent and barUp and barUpCount == 5 then p5/(bn-1)*100
    else if bn > hideBarsBefore and mode == mode.percent and barUp and barUpCount == 6 then p6/(bn-1)*100
    else if bn > hideBarsBefore and mode == mode.percent and barDown and barDownCount == -1 then n1/(bn-1)*100
    else if bn > hideBarsBefore and mode == mode.percent and barDown and barDownCount == -2 then n2/(bn-1)*100
    else if bn > hideBarsBefore and mode == mode.percent and barDown and barDownCount == -3 then n3/(bn-1)*100
    else if bn > hideBarsBefore and mode == mode.percent and barDown and barDownCount == -4 then n4/(bn-1)*100
    else if bn > hideBarsBefore and mode == mode.percent and barDown and barDownCount == -5 then n5/(bn-1)*100
    else if bn > hideBarsBefore and mode == mode.percent and barDown and barDownCount == -6 then n6/(bn-1)*100
    else nan;
ppX.AssignValueColor(
    if ppX > 20 then color.Gray
    else if ppX > 10 then Color.Yellow
    else if ppx > 5 then Color.Green
    else Color.Magenta);
ppX.SetPaintingStrategy(PaintingStrategy.SQUARES);

plot ppx30 = if mode == mode.percent then 30 else nan;
ppx30.SetDefaultColor(Color.Gray);
plot ppx20 = if mode == mode.percent then 20 else nan;
ppx20.SetDefaultColor(Color.Yellow);
plot ppx10 = if mode == mode.percent then 10 else nan;
ppx10.SetDefaultColor(Color.Green);
plot ppx5 = if mode == mode.percent then 5 else nan;
ppx5.SetDefaultColor(Color.Magenta);
Here is a link to the shared study:
ConsecutiveBarCount_20200218_1200

Enjoy,
Kory Gill, @korygill
 
E

ext99k

New member
@korygill thanks so much for the code. Can you please explain it a bit for us non-programmers... if I wanted to see the % of two consecutive up days, where would I find that % on the indicator? And does this segregate % two consecutive up days, and % two consecutive down days, or are both up and down days counted the same when the two days/candles are consecutive? Thanks.
 
korygill

korygill

Active member
VIP
Each count is treated as it's own. +1 is a distinct calculation then -1, etc. For the 1yr of CRM, -1 is like 26.9% of all the bars visible. +1 is 27.2. Hover over the rightmost bars and see the value in the study on the title bar for the lower study. There are 5 bars that are +6 for 2.2% of all the bars from the start of the chart to that point in time.
 
E

ext99k

New member
Thanks for clearing that up, and finally, the "30", "20", "10", "5" what do those mean inside the title bar? Thanks
 
D

daredevilxv5

New member
def close_diffpositive = if barUp then close - close[1] else 0; def totalpositive = compoundvalue ( 1,if barupcount then close_diffpositive + totalpositive[1] else 0,0); def close_diffnegative = if barDown then (close[1] - close) * -1 else 0; def totalnegative = CompoundValue(1, if bardowncount then close_diffnegative + totalnegative[1] else 0, 0); AddChartBubble(1, pBarUpCount,totalpositive, Color.GREEN); AddChartBubble(1, pBarDownCount, totalnegative, Color.RED); where would I add this ? does not work itself , sorry new guy. 😅 @DeusMecanicus
 
D

DeusMecanicus

New member
def close_diffpositive = if barUp then close - close[1] else 0; def totalpositive = compoundvalue ( 1,if barupcount then close_diffpositive + totalpositive[1] else 0,0); def close_diffnegative = if barDown then (close[1] - close) * -1 else 0; def totalnegative = CompoundValue(1, if bardowncount then close_diffnegative + totalnegative[1] else 0, 0); AddChartBubble(1, pBarUpCount,totalpositive, Color.GREEN); AddChartBubble(1, pBarDownCount, totalnegative, Color.RED); where would I add this ? does not work itself , sorry new guy. 😅 @DeusMecanicus
Just add it to the bottom of the code in the original post by korygill. It just needs to be after the def barup/bardown and def barupcount/bardowncount since those are referenced in my post.
 
J

joshua74133

New member
Thanks. I get paid to code for a living, and I try to use best practices everywhere. I saw other scripts that have a version scheme that did not sort well. It should be real easy to see if your version is newer/older than something else you are looking at. Also I am experimenting/exploring the right amount of boilerplate at the top. I expect many scripts here get modified by everyone a little. Want to encourage sharing/extending and attribution.
Is there a way to code a scanner that counts the number of times a stock makes a new high after market open?
 
E

ext99k

New member
Is it possible to modify this code to show the number of consecutive days the stock opened higher, lower than the previous close, the same way the % frequency was added for the # up/down days with the squares (in the most recent update to the code)? Thanks!
 
Last edited:
korygill

korygill

Active member
VIP
@ext99k i think you can do this by changing
def barUp = vClose > vClose[1];
def barDown = vClose < vClose[1];
to
def barUp = vOpen > vClose[1];
def barDown = vOpen < vClose[1];
and using the study on a 1 day chart.

give it a shot, and if it does not work, i can look at the study in the evening when i am free.
 
E

ext99k

New member
@korygill Thanks for your help, but it gets an error "No such variable: vOpen -- thanks!
 

Top