# Bulkowski Double Bottom Pattern Indicator for ThinkorSwim

#### BenTen

Staff
VIP
This indicator was created for ThinkorSwim based on Bulkowski's Double Bottom Setup. You can learn more about the pattern, examples, and how to trade it here.

The Bulkowski Double Bottom indicator highlights a few things on your chart:
• First Pivot
• Pivot Low
• Double Bottom Price
• Breakout Price

### thinkScript Code

Code:
``````# Bulkowski Double Bottom Pattern
# TASC Aril 2019
# Nube 3.30.19
# v 0.02, unsuccessfully trying to mark the first pivot of the pattern

# INPUTS
input pivotLength = 4;
input maxDoubleBottomWidth = 24;
input tolerancePercentage = 1.5;
input ticksAboveDoubleBottomHigh = 1;

# VARIABLES
# Universal
def h = high;
def l = low;
def nan = Double.NaN;
def x = BarNumber();
def tick = TickSize();
# Study Specific
def lowPivotBar = if !GetMinValueOffset(l, pivotLength + 1)
and GetMinValueOffset(l, pivotLength + 1)[-pivotLength + 1] ==
pivotLength - 1
then x
else lowPivotBar[1];
def lowPivot = if x == lowPivotBar
then x
else nan;
def lowPivotPrice = if x == lowPivotBar
then l
else lowPivotPrice[1];
def priorLowPivotBar = if lowPivotBar != lowPivotBar[1]
then lowPivotBar[1]
else priorLowPivotBar[1];
def priorLowPivotPrice = if x == lowPivotBar
then GetValue(l,  lowPivotBar - priorLowPivotBar)
else priorLowPivotPrice[1];
def hh = if x crosses above lowPivotBar
then h
else if h > hh[1]
then h
else hh[1];
def highBetweenPivots = if x == lowPivotBar
then hh
else highBetweenPivots[1];
# Checking for pivot lows being within tolerancePercentage
def doubleBottom = if Between(lowPivotPrice,
priorLowPivotPrice * (1 - tolerancePercentage * .01),
priorLowPivotPrice * (1 + tolerancePercentage * .01))
and lowPivotBar - priorLowPivotBar <= maxDoubleBottomWidth
then Min(lowPivotPrice,priorLowPivotPrice)
else nan;
# invalidating pattern when price breaks below the doubleBottom price
def valid = if IsNaN(doubleBottom[1])
and !IsNaN(doubleBottom)
then 1
else if l crosses below doubleBottom
then 0
else valid[1];

# Plots
plot
PivotLow = x == lowPivotBar;
PivotLow.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
PivotLow.SetDefaultColor(Color.Red);

plot
DoubleBottomPrice = if valid then doubleBottom else nan;
DoubleBottomPrice.SetDefaultColor(Color.Red);
DoubleBottomPrice.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

plot
BreakoutPrice = if DoubleBottomPrice
then highBetweenPivots + ticksAboveDoubleBottomHigh * tick
else nan;
BreakoutPrice.SetDefaultColor(Color.Green);
BreakoutPrice.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

AddChartBubble(DoubleBottomPrice and IsNaN(DoubleBottomPrice[-1]), DoubleBottomPrice, DoubleBottomPrice+" Bottomm Price", Color.Red, 0);
AddChartBubble(BreakoutPrice and IsNaN(BreakoutPrice[-1]), BreakOutPrice, "Breakout Price"+ BreakOutPrice, Color.Green);

# f/  Bulkowski Double Bottom Pattern from April 2019 TASC this section still incorrect. Attempting to mark first pivot
def untilDB = fold i = -maxDoubleBottomWidth + 1 to 0
with u
while IsNaN(doubleBottom)
do u + GetValue(IsNaN(doubleBottom), i);

def firstPivot = !IsNaN(lowPivot) and
IsNaN(GetValue(doubleBottom, -untilDB)) and
Between(GetValue(doubleBottom, -untilDB -1),
l * (1 - tolerancePercentage * .01),
l * (1 + tolerancePercentage * .01));

AddChartBubble(firstPivot, l, "First Pivot", Color.Red, 0);``````

https://tos.mx/7678EI

Last edited:

#### CreativiTimothy

##### New member
Hey, I think it works very well, and I'm able to convert it into a scan filter like I can do with other studies, but the scan filter isn't working as intended for my purposes, and I need tips.

Intention: It detects a double bottom immediately and after about 30 minutes, it should no longer show up in the scan. For example, it bottoms at 1.45 once, then it bottoms 1.45 the second time 5 hours later. It shows up in my scan immediately when that happens, which is good. However, it remains in the scan even after 3 days after the double bottom has formed (two peak lows). I don't want to be trading a stock that has already went up a ton after 3 days after the double bottom formation. I want it to be removed from the scan after a 30 minute bar or (30 1 minute bars) because I like to buy the double bottom immediately with a tight stop loss for high reward/risk ratio, like buying at 5.01 at a bottom of 5, stop loss at 4.99.

Any tips on how to restrict the scan to only show immediate double bottom formations, not double bottoms that formed a long while ago like 3 days ago?

#### horserider

##### Well-known member
VIP
use within " x " days at the end of scan code

#### CreativiTimothy

##### New member
use within " x " days at the end of scan code
Hi I put within 1 bar at a few parts of the code, then several parts of the code, since putting it at the end didn't seem to work, but no luck. It still shows up the same number of results. For example, I modified the plot to this:

plot
DoubleBottomPrice = (if valid then 1 else nan) within 1 bar;

I

#### iamgshankar

##### New member
Friends,

Can someone please help me to use the above script to scan within the last few bars??

@BenTen I am not seeing the Break out price and other labels in my chart when i use the sharable link.. Am i missing something?

Thanks.

T

##### Active member
2019 Donor
VIP
There are errors in the label code.

H

#### hoojsn

##### New member
Hi Ben,
There is 2 Error Code:

#### BenTen

Staff
VIP
@hoojsn Thank you, fixed

C

#### Cleartarget

##### New member
VIP
Hey, I think it works very well, and I'm able to convert it into a scan filter like I can do with other studies, but the scan filter isn't working as intended for my purposes, and I need tips.

Intention: It detects a double bottom immediately and after about 30 minutes, it should no longer show up in the scan. For example, it bottoms at 1.45 once, then it bottoms 1.45 the second time 5 hours later. It shows up in my scan immediately when that happens, which is good. However, it remains in the scan even after 3 days after the double bottom has formed (two peak lows). I don't want to be trading a stock that has already went up a ton after 3 days after the double bottom formation. I want it to be removed from the scan after a 30 minute bar or (30 1 minute bars) because I like to buy the double bottom immediately with a tight stop loss for high reward/risk ratio, like buying at 5.01 at a bottom of 5, stop loss at 4.99.

Any tips on how to restrict the scan to only show immediate double bottom formations, not double bottoms that formed a long while ago like 3 days ago?
Hi can you share the Double bottom scan.
Thanks

#### CreativiTimothy

##### New member
Hi can you share the Double bottom scan.
Thanks
Sure. I basically just commented all the other plots out except the "DoubleBottomPrice" plot. That's the only plot you need for the scan (scans only allow one plot) that determines whether a double bottom exists in a stock or not.

Code:
``````# Bulkowski Double Bottom Pattern
# TASC Aril 2019
# Nube 3.30.19
# v 0.02, unsuccessfully trying to mark the first pivot of the pattern

# INPUTS
input pivotLength = 1;
input maxDoubleBottomWidth = 24;
input tolerancePercentage = 1.5;
input ticksAboveDoubleBottomHigh = 1;

# VARIABLES
## Universal
def h = high;
def l = low;
def nan = Double.NaN;
def x = BarNumber();
def tick = TickSize();
## Study Specific
def lowPivotBar = if !GetMinValueOffset(l, pivotLength + 1)
and GetMinValueOffset(l, pivotLength + 1)[-pivotLength + 1] ==
pivotLength - 1
then x
else lowPivotBar[1];
def lowPivot = if x == lowPivotBar
then x
else nan;
def lowPivotPrice = if x == lowPivotBar
then l
else lowPivotPrice[1];
def priorLowPivotBar = if lowPivotBar != lowPivotBar[1]
then lowPivotBar[1]
else priorLowPivotBar[1];
def priorLowPivotPrice = if x == lowPivotBar
then GetValue(l,  lowPivotBar - priorLowPivotBar)
else priorLowPivotPrice[1];
def hh = if x crosses above lowPivotBar
then h
else if h > hh[1]
then h
else hh[1];
def highBetweenPivots = if x == lowPivotBar
then hh
else highBetweenPivots[1];
### Checking for pivot lows being within tolerancePercentage
def doubleBottom = if Between(lowPivotPrice,
priorLowPivotPrice * (1 - tolerancePercentage * .01),
priorLowPivotPrice * (1 + tolerancePercentage * .01))
and lowPivotBar - priorLowPivotBar <= maxDoubleBottomWidth
then Min(lowPivotPrice,priorLowPivotPrice)
else nan;
### invalidating pattern when price breaks below the doubleBottom price
def valid = if IsNaN(doubleBottom[1])
and !IsNaN(doubleBottom)
then 1
else if l crosses below doubleBottom
then 0
else valid[1];

# Plots
#plot
#PivotLow = x == lowPivotBar;
#PivotLow.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
#PivotLow.SetDefaultColor(Color.Red);

plot
DoubleBottomPrice = if valid then doubleBottom else nan;
DoubleBottomPrice.SetDefaultColor(Color.Red);
DoubleBottomPrice.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

#plot
#BreakoutPrice = if DoubleBottomPrice
#                then highBetweenPivots + ticksAboveDoubleBottomHigh * tick
#                else nan;
#BreakoutPrice.SetDefaultColor(Color.Green);
#BreakoutPrice.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

DoubleBottomPrice, DoubleBottomPrice+"\nBottomm Price\n", Color.Red, 0);
#               BreakOutPrice, "Breakout Price\n"+ BreakOutPrice, Color.Green);

# f/  Bulkowski Double Bottom Pattern from April 2019 TASC

#### this section still incorrect. Attempting to mark first pivot
def untilDB = fold i = -maxDoubleBottomWidth + 1 to 0
with u
while IsNaN(doubleBottom)
do u + GetValue(IsNaN(doubleBottom), i);

def firstPivot = !IsNaN(lowPivot) and
IsNaN(GetValue(doubleBottom, -untilDB)) and
Between(GetValue(doubleBottom, -untilDB -1),
l * (1 - tolerancePercentage * .01),
l * (1 + tolerancePercentage * .01));

AddChartBubble(firstPivot, l, "First Pivot", Color.Red, 0);``````

C

#### Cleartarget

##### New member
VIP
Sure. I basically just commented all the other plots out except the "DoubleBottomPrice" plot. That's the only plot you need for the scan (scans only allow one plot) that determines whether a double bottom exists in a stock or not.

Code:
``````# Bulkowski Double Bottom Pattern
# TASC Aril 2019
# Nube 3.30.19
# v 0.02, unsuccessfully trying to mark the first pivot of the pattern

# INPUTS
input pivotLength = 1;
input maxDoubleBottomWidth = 24;
input tolerancePercentage = 1.5;
input ticksAboveDoubleBottomHigh = 1;

# VARIABLES
## Universal
def h = high;
def l = low;
def nan = Double.NaN;
def x = BarNumber();
def tick = TickSize();
## Study Specific
def lowPivotBar = if !GetMinValueOffset(l, pivotLength + 1)
and GetMinValueOffset(l, pivotLength + 1)[-pivotLength + 1] ==
pivotLength - 1
then x
else lowPivotBar[1];
def lowPivot = if x == lowPivotBar
then x
else nan;
def lowPivotPrice = if x == lowPivotBar
then l
else lowPivotPrice[1];
def priorLowPivotBar = if lowPivotBar != lowPivotBar[1]
then lowPivotBar[1]
else priorLowPivotBar[1];
def priorLowPivotPrice = if x == lowPivotBar
then GetValue(l,  lowPivotBar - priorLowPivotBar)
else priorLowPivotPrice[1];
def hh = if x crosses above lowPivotBar
then h
else if h > hh[1]
then h
else hh[1];
def highBetweenPivots = if x == lowPivotBar
then hh
else highBetweenPivots[1];
### Checking for pivot lows being within tolerancePercentage
def doubleBottom = if Between(lowPivotPrice,
priorLowPivotPrice * (1 - tolerancePercentage * .01),
priorLowPivotPrice * (1 + tolerancePercentage * .01))
and lowPivotBar - priorLowPivotBar <= maxDoubleBottomWidth
then Min(lowPivotPrice,priorLowPivotPrice)
else nan;
### invalidating pattern when price breaks below the doubleBottom price
def valid = if IsNaN(doubleBottom[1])
and !IsNaN(doubleBottom)
then 1
else if l crosses below doubleBottom
then 0
else valid[1];

# Plots
#plot
#PivotLow = x == lowPivotBar;
#PivotLow.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
#PivotLow.SetDefaultColor(Color.Red);

plot
DoubleBottomPrice = if valid then doubleBottom else nan;
DoubleBottomPrice.SetDefaultColor(Color.Red);
DoubleBottomPrice.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

#plot
#BreakoutPrice = if DoubleBottomPrice
#                then highBetweenPivots + ticksAboveDoubleBottomHigh * tick
#                else nan;
#BreakoutPrice.SetDefaultColor(Color.Green);
#BreakoutPrice.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

DoubleBottomPrice, DoubleBottomPrice+"\nBottomm Price\n", Color.Red, 0);
#               BreakOutPrice, "Breakout Price\n"+ BreakOutPrice, Color.Green);

# f/  Bulkowski Double Bottom Pattern from April 2019 TASC

#### this section still incorrect. Attempting to mark first pivot
def untilDB = fold i = -maxDoubleBottomWidth + 1 to 0
with u
while IsNaN(doubleBottom)
do u + GetValue(IsNaN(doubleBottom), i);

def firstPivot = !IsNaN(lowPivot) and
IsNaN(GetValue(doubleBottom, -untilDB)) and
Between(GetValue(doubleBottom, -untilDB -1),
l * (1 - tolerancePercentage * .01),
l * (1 + tolerancePercentage * .01));

AddChartBubble(firstPivot, l, "First Pivot", Color.Red, 0);``````
Great thank for the information and help.

R

#### Rambo

##### New member
VIP
How we do a scanner for double bottom ?

#### CLICKANDGRAB808

##### New member
looks great thanks

J

#### johnatasjmo

##### New member
Thanks, works well.