How to build a scan for Bollinger Volatility Breakout Method

The ARC

New member
I am trying to build a scanner to scan all optionable assets that match Bollinger volatility breakout method per the textbook.

General concept is that when Bollinger bandwidth contracts, the squeeze(low volatility) becomes a precursor for a breakout. Textbook recommends a lookback of 180 periods.

What I am trying to build is periods of low volatility (say bandwidth <10% in more than 30 time period) followed by increasing bandwidth suggesting a breakout. Can anyone assist with a script?

I tried to build something where BollingerBandwidth("squeeze length" = 50)."Bandwidth" from 1 bars ago is less than or equal to BollingerBandwidth("squeeze length" = 50)."Squeeze" from 1 bars ago but not exactly sure if its giving me anything more than assets going in a squeeze rather than assets that were in a squeeze and just breaking out.

In the example below, the rectangle shows the squeeze with bandwidth almost flatline then the breakdown. A scanner than checks for the flatline and the breakout/breakdown will be very helpful.

40dN7lx.png
 
Solution
I am trying to build a scanner to scan all optionable assets that match Bollinger volatility breakout method per the textbook.

General concept is that when Bollinger bandwidth contracts, the squeeze(low volatility) becomes a precursor for a breakout. Textbook recommends a lookback of 180 periods.

What I am trying to build is periods of low volatility (say bandwidth <10% in more than 30 time period) followed by increasing bandwidth suggesting a breakout. Can anyone assist with a script?

I tried to build something where BollingerBandwidth("squeeze length" = 50)."Bandwidth" from 1 bars ago is less than or equal to BollingerBandwidth("squeeze length" = 50)."Squeeze" from 1 bars ago but not exactly sure if its giving me anything more...
I am trying to build a scanner to scan all optionable assets that match Bollinger volatility breakout method per the textbook.

General concept is that when Bollinger bandwidth contracts, the squeeze(low volatility) becomes a precursor for a breakout. Textbook recommends a lookback of 180 periods.

What I am trying to build is periods of low volatility (say bandwidth <10% in more than 30 time period) followed by increasing bandwidth suggesting a breakout. Can anyone assist with a script?

I tried to build something where BollingerBandwidth("squeeze length" = 50)."Bandwidth" from 1 bars ago is less than or equal to BollingerBandwidth("squeeze length" = 50)."Squeeze" from 1 bars ago but not exactly sure if its giving me anything more than assets going in a squeeze rather than assets that were in a squeeze and just breaking out.

In the example below, the rectangle shows the squeeze with bandwidth almost flatline then the breakdown. A scanner than checks for the flatline and the breakout/breakdown will be very helpful.


this is a lower study, that uses BollingerBandwidth , bandwidth data
...1. look for bandwidth staying below the % min number (10), for x bars {30)
...2. followed by increasing bandwidth for x bars (3)
...3. draw a vertical green line, on the first bar of #2
...4. draw arrows when #3 happens, based on price movement.


i don't scan, so i don't make scans.
to make this a scan,
...change all plots to def and add # to plot parameter code lines
.then remove the # from this line, at the end of code
...# plot buy2 = buy;


Code:
# bband_sqz_out_01

#==============================

def na = double.nan;
def bn = barnumber();

#=================================
# BollingerBandwidth
# TD Ameritrade IP Company, Inc. (c) 2008-2021
declare lower;
input averageType = AverageType.SIMPLE;
def price = close;
def displace = 0;
input length = 20;
input Num_Dev_Dn = -2.0;
input Num_Dev_Up = 2.0;
input BulgeLength = 150;
input SqueezeLength = 150;

def upperBand = BollingerBands(price, displace, length, Num_Dev_Dn, Num_Dev_Up, averageType).UpperBand;
def lowerBand = BollingerBands(price, displace, length, Num_Dev_Dn, Num_Dev_Up, averageType).LowerBand;
def midLine = BollingerBands(price, displace, length, Num_Dev_Dn, Num_Dev_Up, averageType).MidLine;

plot Bandwidth = (upperBand - lowerBand) / midLine * 100;
Bandwidth.SetDefaultColor(GetColor(1));

input show_bulge_squeeze_lines = no;
plot Bulge = if show_bulge_squeeze_lines then Highest(Bandwidth, BulgeLength) else na;
Bulge.SetDefaultColor(GetColor(8));
Bulge.SetStyle(Curve.SHORT_DASH);
plot Squeeze = if show_bulge_squeeze_lines then Lowest(Bandwidth, SqueezeLength) else na;
Squeeze.SetDefaultColor(GetColor(8));
Squeeze.SetStyle(Curve.SHORT_DASH);
#==================================
#def bbb = BollingerBandwidth().Bandwidth;
def bbb = Bandwidth;
#---------------------------------

# draw a reference line
plot z0 = 0;
z0.setdefaultcolor(color.gray);

# a % number, that bandwidth has to stay under, to be considered in a squeeze
input squeeze_max_percent = 10;
def sqzper = squeeze_max_percent;

# qty of consecutive bars, to define a squeeze
input squeeze_min_bars = 30;
def sqzb = squeeze_min_bars;

# qty of bars after a squeeze, of increasing bandwidth, to define a breakout
input post_sqz_rising_bars = 3;
def sqzrise = post_sqz_rising_bars;

# qty of bars in series +1
def series_bars = (sqzb + sqzrise + 1);

input show_labels = yes;
addlabel(show_labels, "a yellow line, when bandwidth is < " + squeeze_max_percent + "%.", color.yellow);
addlabel(show_labels, "a white dot, in a squeeze. after " + squeeze_min_bars + " bars are < " + squeeze_max_percent + "%." , color.white);
addlabel(show_labels, "a green dot, after " + post_sqz_rising_bars + " rising bars, after a squeeze" , color.green);

#---------------------------------------------------------

# draw a line at the percent level , when bandwidth is < squeeze_max_percent
def sqzbar = (bbb < sqzper);
input show_sqz_bars = yes;
def v2 = sqzper;
plot z2 = if ( show_sqz_bars and sqzbar ) then v2 else na;
z2.SetDefaultColor(Color.yellow);
z2.hidebubble();

# ----------------------------------------------------------

# draw points under the min percent line,  after the squeeze_min_bars have passed

# set a var to 1 if a squeeze, the past x bars (30) were < the % min (10)
def sqz = if Sum( sqzbar, squeeze_min_bars) ==  squeeze_min_bars then 1 else 0;

def v3 = (sqzper * 0.8);
input show_sqzs = yes;
plot z3 = if ( show_sqzs and sqz ) then v3 else na;
z3.SetPaintingStrategy(PaintingStrategy.POINTS);
z3.SetDefaultColor(Color.white);
#z3.setlineweight(2);
z3.hidebubble();

# ----------------------------------------------------------

# check for 3 rising bars after a sqz
# put a comparison in a sum, to look for x increasing bars
def incr = bbb > bbb[1];

# find just the 1st sqz_out in a series
# if a sqz 3+1 bars ago, then did it rise for 3 bars in a row?
def after_sqz = if (sqz[sqzrise + 1] and ( Sum(incr, sqzrise) == sqzrise ) ) then 1 else 0;

def v4 = (sqzper * 0.6);
input show_sqz_rise = yes;
plot z4 = if ( show_sqz_rise and after_sqz ) then v4 else na;
z4.SetPaintingStrategy(PaintingStrategy.POINTS);
z4.SetDefaultColor(Color.green);
#z4.setlineweight(2);
z4.hidebubble();

# draw vertical line, 1st bar there is a sqz of 30 bars then a rise of 3 bars
def t = ( !after_sqz[1] and after_sqz );

#addverticalline( t, sqzb + " BAR SQUEEZE, " +  post_sqz_rising_bars + " RISING BARS" , color.green);
addverticalline( t, "-" , color.green);

# ----------------------------------------------------------

# smooth out price movements with an average
def pr = Average( close, 3);
def prup = ( pr > pr[1] );
def prdwn = ( pr < pr[1] );

# prup , prdwn , are avgs
def buy = (t and prup);
def sell = (t and prdwn);

plot buyx = if buy then sqzper else na;
buyx.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
buyx.SetDefaultColor(Color.green);
buyx.setlineweight(2);
buyx.hidebubble();

plot sellx = if sell then sqzper else na;
sellx.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
sellx.SetDefaultColor(Color.red);
sellx.setlineweight(2);
sellx.hidebubble();

# ---------------------------------------------
# to make this a scan,
#   change all plots to def and add # to plot parameter lines
# the enable this line
#   plot buy2 = buy;

# ----------------------------------------------------------
# test stuff
#input test5_after_sqz = no;
#addchartbubble(test5_after_sqz, 0, after_sqz, color.cyan, yes);
#addchartbubble(t, (sqzper * 0.4), bn, color.cyan, no);
#


yqfbSzn.jpg
 
Solution

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

this is a lower study, that uses BollingerBandwidth , bandwidth data
...1. look for bandwidth staying below the % min number (10), for x bars {30)
...2. followed by increasing bandwidth for x bars (3)
...3. draw a vertical green line, on the first bar of #2
...4. draw arrows when #3 happens, based on price movement.


i don't scan, so i don't make scans.
to make this a scan,
...change all plots to def and add # to plot parameter code lines
.then remove the # from this line, at the end of code
...# plot buy2 = buy;


Code:
# bband_sqz_out_01

#==============================

def na = double.nan;
def bn = barnumber();

#=================================
# BollingerBandwidth
# TD Ameritrade IP Company, Inc. (c) 2008-2021
declare lower;
input averageType = AverageType.SIMPLE;
def price = close;
def displace = 0;
input length = 20;
input Num_Dev_Dn = -2.0;
input Num_Dev_Up = 2.0;
input BulgeLength = 150;
input SqueezeLength = 150;

def upperBand = BollingerBands(price, displace, length, Num_Dev_Dn, Num_Dev_Up, averageType).UpperBand;
def lowerBand = BollingerBands(price, displace, length, Num_Dev_Dn, Num_Dev_Up, averageType).LowerBand;
def midLine = BollingerBands(price, displace, length, Num_Dev_Dn, Num_Dev_Up, averageType).MidLine;

plot Bandwidth = (upperBand - lowerBand) / midLine * 100;
Bandwidth.SetDefaultColor(GetColor(1));

input show_bulge_squeeze_lines = no;
plot Bulge = if show_bulge_squeeze_lines then Highest(Bandwidth, BulgeLength) else na;
Bulge.SetDefaultColor(GetColor(8));
Bulge.SetStyle(Curve.SHORT_DASH);
plot Squeeze = if show_bulge_squeeze_lines then Lowest(Bandwidth, SqueezeLength) else na;
Squeeze.SetDefaultColor(GetColor(8));
Squeeze.SetStyle(Curve.SHORT_DASH);
#==================================
#def bbb = BollingerBandwidth().Bandwidth;
def bbb = Bandwidth;
#---------------------------------

# draw a reference line
plot z0 = 0;
z0.setdefaultcolor(color.gray);

# a % number, that bandwidth has to stay under, to be considered in a squeeze
input squeeze_max_percent = 10;
def sqzper = squeeze_max_percent;

# qty of consecutive bars, to define a squeeze
input squeeze_min_bars = 30;
def sqzb = squeeze_min_bars;

# qty of bars after a squeeze, of increasing bandwidth, to define a breakout
input post_sqz_rising_bars = 3;
def sqzrise = post_sqz_rising_bars;

# qty of bars in series +1
def series_bars = (sqzb + sqzrise + 1);

input show_labels = yes;
addlabel(show_labels, "a yellow line, when bandwidth is < " + squeeze_max_percent + "%.", color.yellow);
addlabel(show_labels, "a white dot, in a squeeze. after " + squeeze_min_bars + " bars are < " + squeeze_max_percent + "%." , color.white);
addlabel(show_labels, "a green dot, after " + post_sqz_rising_bars + " rising bars, after a squeeze" , color.green);

#---------------------------------------------------------

# draw a line at the percent level , when bandwidth is < squeeze_max_percent
def sqzbar = (bbb < sqzper);
input show_sqz_bars = yes;
def v2 = sqzper;
plot z2 = if ( show_sqz_bars and sqzbar ) then v2 else na;
z2.SetDefaultColor(Color.yellow);
z2.hidebubble();

# ----------------------------------------------------------

# draw points under the min percent line,  after the squeeze_min_bars have passed

# set a var to 1 if a squeeze, the past x bars (30) were < the % min (10)
def sqz = if Sum( sqzbar, squeeze_min_bars) ==  squeeze_min_bars then 1 else 0;

def v3 = (sqzper * 0.8);
input show_sqzs = yes;
plot z3 = if ( show_sqzs and sqz ) then v3 else na;
z3.SetPaintingStrategy(PaintingStrategy.POINTS);
z3.SetDefaultColor(Color.white);
#z3.setlineweight(2);
z3.hidebubble();

# ----------------------------------------------------------

# check for 3 rising bars after a sqz
# put a comparison in a sum, to look for x increasing bars
def incr = bbb > bbb[1];

# find just the 1st sqz_out in a series
# if a sqz 3+1 bars ago, then did it rise for 3 bars in a row?
def after_sqz = if (sqz[sqzrise + 1] and ( Sum(incr, sqzrise) == sqzrise ) ) then 1 else 0;

def v4 = (sqzper * 0.6);
input show_sqz_rise = yes;
plot z4 = if ( show_sqz_rise and after_sqz ) then v4 else na;
z4.SetPaintingStrategy(PaintingStrategy.POINTS);
z4.SetDefaultColor(Color.green);
#z4.setlineweight(2);
z4.hidebubble();

# draw vertical line, 1st bar there is a sqz of 30 bars then a rise of 3 bars
def t = ( !after_sqz[1] and after_sqz );

#addverticalline( t, sqzb + " BAR SQUEEZE, " +  post_sqz_rising_bars + " RISING BARS" , color.green);
addverticalline( t, "-" , color.green);

# ----------------------------------------------------------

# smooth out price movements with an average
def pr = Average( close, 3);
def prup = ( pr > pr[1] );
def prdwn = ( pr < pr[1] );

# prup , prdwn , are avgs
def buy = (t and prup);
def sell = (t and prdwn);

plot buyx = if buy then sqzper else na;
buyx.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
buyx.SetDefaultColor(Color.green);
buyx.setlineweight(2);
buyx.hidebubble();

plot sellx = if sell then sqzper else na;
sellx.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
sellx.SetDefaultColor(Color.red);
sellx.setlineweight(2);
sellx.hidebubble();

# ---------------------------------------------
# to make this a scan,
#   change all plots to def and add # to plot parameter lines
# the enable this line
#   plot buy2 = buy;

# ----------------------------------------------------------
# test stuff
#input test5_after_sqz = no;
#addchartbubble(test5_after_sqz, 0, after_sqz, color.cyan, yes);
#addchartbubble(t, (sqzper * 0.4), bn, color.cyan, no);
#


yqfbSzn.jpg
Thank you very much. This worked very well when added as study on chart.
Your instructions to change this to scan were very simple and helped with no coding experience.
I changed plots to def and I think I commented out parameter lines but the scan didn't always show tickers that broke out!
Can you take a quick look to see I commented out right lines?
# bband_sqz_out_01

#==============================

def na = double.nan;
def bn = barnumber();

#=================================
# BollingerBandwidth
# TD Ameritrade IP Company, Inc. (c) 2008-2021
declare lower;
input averageType = AverageType.SIMPLE;
def price = close;
def displace = 0;
input length = 20;
input Num_Dev_Dn = -2.0;
input Num_Dev_Up = 2.0;
input BulgeLength = 150;
input SqueezeLength = 150;

def upperBand = BollingerBands(price, displace, length, Num_Dev_Dn, Num_Dev_Up, averageType).UpperBand;
def lowerBand = BollingerBands(price, displace, length, Num_Dev_Dn, Num_Dev_Up, averageType).LowerBand;
def midLine = BollingerBands(price, displace, length, Num_Dev_Dn, Num_Dev_Up, averageType).MidLine;

plot Bandwidth = (upperBand - lowerBand) / midLine * 100;
Bandwidth.SetDefaultColor(GetColor(1));

input show_bulge_squeeze_lines = no;
plot Bulge = if show_bulge_squeeze_lines then Highest(Bandwidth, BulgeLength) else na;
Bulge.SetDefaultColor(GetColor(8));
Bulge.SetStyle(Curve.SHORT_DASH);
plot Squeeze = if show_bulge_squeeze_lines then Lowest(Bandwidth, SqueezeLength) else na;
Squeeze.SetDefaultColor(GetColor(8));
Squeeze.SetStyle(Curve.SHORT_DASH);
#==================================
#def bbb = BollingerBandwidth().Bandwidth;
def bbb = Bandwidth;
#---------------------------------

# draw a reference line
Def z0 = 0; #replace def with plot to see this on chart as a study
#z0.setdefaultcolor(color.gray);

# a % number, that bandwidth has to stay under, to be considered in a squeeze
input squeeze_max_percent = 10;
def sqzper = squeeze_max_percent;

# qty of consecutive bars, to define a squeeze
input squeeze_min_bars = 30;
def sqzb = squeeze_min_bars;

# qty of bars after a squeeze, of increasing bandwidth, to define a breakout
input post_sqz_rising_bars = 3;
def sqzrise = post_sqz_rising_bars;

# qty of bars in series +1
def series_bars = (sqzb + sqzrise + 1);

input show_labels = yes;
addlabel(show_labels, "a yellow line, when bandwidth is < " + squeeze_max_percent + "%.", color.yellow);
addlabel(show_labels, "a white dot, in a squeeze. after " + squeeze_min_bars + " bars are < " + squeeze_max_percent + "%." , color.white);
addlabel(show_labels, "a green dot, after " + post_sqz_rising_bars + " rising bars, after a squeeze" , color.green);

#---------------------------------------------------------

# draw a line at the percent level , when bandwidth is < squeeze_max_percent
def sqzbar = (bbb < sqzper);
input show_sqz_bars = yes;
def v2 = sqzper;
def z2 = if ( show_sqz_bars and sqzbar ) then v2 else na; #replace def with plot to see this on chart as a study
#z2.SetDefaultColor(Color.yellow);
#z2.hidebubble();

# ----------------------------------------------------------

# draw points under the min percent line, after the squeeze_min_bars have passed

# set a var to 1 if a squeeze, the past x bars (30) were < the % min (10)
def sqz = if Sum( sqzbar, squeeze_min_bars) == squeeze_min_bars then 1 else 0;

def v3 = (sqzper * 0.8);
input show_sqzs = yes;
def z3 = if ( show_sqzs and sqz ) then v3 else na; #replace def with plot to see this on chart as a study
# z3.SetPaintingStrategy(PaintingStrategy.POINTS);
#z3.SetDefaultColor(Color.white);
#z3.setlineweight(2);
#z3.hidebubble();

# ----------------------------------------------------------

# check for 3 rising bars after a sqz
# put a comparison in a sum, to look for x increasing bars
def incr = bbb > bbb[1];

# find just the 1st sqz_out in a series
# if a sqz 3+1 bars ago, then did it rise for 3 bars in a row?
def after_sqz = if (sqz[sqzrise + 1] and ( Sum(incr, sqzrise) == sqzrise ) ) then 1 else 0;

def v4 = (sqzper * 0.6);
input show_sqz_rise = yes;
def z4 = if ( show_sqz_rise and after_sqz ) then v4 else na; #replace def with plot to see this on chart as a study
#z4.SetPaintingStrategy(PaintingStrategy.POINTS);
#z4.SetDefaultColor(Color.green);
#z4.setlineweight(2);
#z4.hidebubble();

# draw vertical line, 1st bar there is a sqz of 30 bars then a rise of 3 bars
def t = ( !after_sqz[1] and after_sqz );

#addverticalline( t, sqzb + " BAR SQUEEZE, " + post_sqz_rising_bars + " RISING BARS" , color.green);
addverticalline( t, "-" , color.green);

# ----------------------------------------------------------

# smooth out price movements with an average
def pr = Average( close, 3);
def prup = ( pr > pr[1] );
def prdwn = ( pr < pr[1] );

# prup , prdwn , are avgs
def buy = (t and prup);
def sell = (t and prdwn);

def buyx = if buy then sqzper else na; #replace def with plot to see this on chart as a study
#buyx.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
#buyx.SetDefaultColor(Color.green);
#buyx.setlineweight(2);
#buyx.hidebubble();

def sellx = if sell then sqzper else na; #replace def with plot to see this on chart as a study
#sellx.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
#sellx.SetDefaultColor(Color.red);
#sellx.setlineweight(2);
#sellx.hidebubble();

# ---------------------------------------------
# to make this a scan,
# change all plots to def and add # to plot parameter lines
# the enable this line
plot buy2 = buy;

# ----------------------------------------------------------
# test stuff
#input test5_after_sqz = no;
#addchartbubble(test5_after_sqz, 0, after_sqz, color.cyan, yes);
#addchartbubble(t, (sqzper * 0.4), bn, color.cyan, no);
#
 
I am trying to build a scanner to scan all optionable assets that match Bollinger volatility breakout method per the textbook.

General concept is that when Bollinger bandwidth contracts, the squeeze(low volatility) becomes a precursor for a breakout. Textbook recommends a lookback of 180 periods.

What I am trying to build is periods of low volatility (say bandwidth <10% in more than 30 time period) followed by increasing bandwidth suggesting a breakout. Can anyone assist with a script?

I tried to build something where BollingerBandwidth("squeeze length" = 50)."Bandwidth" from 1 bars ago is less than or equal to BollingerBandwidth("squeeze length" = 50)."Squeeze" from 1 bars ago but not exactly sure if its giving me anything more than assets going in a squeeze rather than assets that were in a squeeze and just breaking out.

In the example below, the rectangle shows the squeeze with bandwidth almost flatline then the breakdown. A scanner than checks for the flatline and the breakout/breakdown will be very helpful.

40dN7lx.png
All you need is a Momentum 12 period which is already think or swim to tell you the direction of the breakout in that squeeze area.
 
All you need is a Momentum 12 period which is already think or swim to tell you the direction of the breakout in that squeeze area.
I am looking at the Momentum 12 which is a lower indicator... TY for sharing it. I have dragged it into the price/candle window and am wondering- does anyone know if there is there a way to render it as a cloud- green above price action and red below price action?
 

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
402 Online
Create Post

Similar threads

Similar threads

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

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?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top