TTM Squeeze Format, Scan, Watchlist, Label For ThinkOrSwim

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

Hoping I am in the correct thread...

Is there a simple way to paint an arrow on the chart when:
  • Previous candle was in a squeeze
  • Current candle the squeeze has "fired" (dot turned green)
  • Current candle histogram has turned to that light blue color
I could add other conditions later, of course, but just those 3 things would be immensely helpful.
 
@C4men - Here are your 3 conditions, an arrow will plot on the chart when the conditions are true.

Code:
def S = reference TTM_Squeeze().SqueezeAlert;
def H = reference TTM_Squeeze().Histogram;

plot Arrow = !S[1] and S and H > 0 and H > H[1];
     Arrow.SetPaintingStrategy(PaintingStrategy.Boolean_Arrow_Up);
     Arrow.SetLineWeight(3);
     Arrow.SetDefaultColor(color.cyan);
 
Thank you @Pensar very much. I'm going to go play around with this.

I.. have... a... plan... lol

In the code above, does the [1] represent 1 bar ago?
 
@Sagar Breakout bull simply writes when the squeeze is has broken out and the histogram is anything above 0. You'll notice on alot of these squeeze charts that you cant even see a blue bar sometimes and that is likely why you're getting faked out. Try the new code below where I included a Move_Threshold. That number will set that not only is the histogram above 0=bull, but its above 50 (by default) to indicate a bigger/stronger move starting. You'll have to play around quite a bit for what kind of threshold level you have. It will have to be much higher for expensive stocks, etc.


@wtf_dude wondering how I can scan for advanced squeeze alert (breakout bull) ONLY if above ATR? Thanks in advance.

Added ATRplus for the two options that indicate the move is bigger than the ATR.
@Sagar these options might work better for you as well


For the scan, though, I would want candidates that have printed only one dark blue or one yellow bar on the daily. It would go on my watchlist for confirmation of a second bar print the following day. I would very much appreciate any help with this scan. Thank you!

@DDW What you want is already built in, I just changed the name to make it a bit more clear. What you want are the two options that are labeled either bulltrendreversal or beartrendreversal. It's exactly what you want. You can also try the next step up, which is if you want the trend to reverse, but also the volatility contracts into a squeeze consolidation (likely to be very rare). Those are labeled Squeeze_Changetobull or Squeeze_Changetobear

Everybody please note that in the previous version the ATR length and Bollinger length were equal, with no option to change. Now I've included an input for the ATR length in case you don't want them to be equal (they still are by default)

Code:
# Advanced Squeeze Scanner v2.0
# Momentum Squeeze basis coding by Moebius, based on John Carter
# Scanner by WTF_Dude. Mods on 9.9.20
# Added Squeeze Label with directional color
# Label is green when momentum is ascending, red when descending

declare lower;

input length = 20; #hint length: Length for average calculation
input price = close;
input SDmult = 2.0;
input ATR_mult = 1.5;
input ATR_length = 14;
input Move_Threshold = 50;


   def K = (Highest(High, length) + Lowest(low, length)) /
               2 + ExpAverage(close, length);
  def Momo = Inertia(price - K / 2, length);

def SD = StDev(close, length);
def Avg = Average(close, length);
def ATR = Average(TrueRange(high, close, low), ATR_length);
def SDup = Avg + (SdMult * Sd);
def ATRup = Avg + (Atr_Mult * ATR);

def Squeeze = SDup < ATRup;
      
def zero = if IsNaN(close) or !IsNaN(Squeeze) then Double.NaN else 0;

def momobullup = Momo > Momo[1] and Momo > Move_Threshold;
def momobulldown = Momo > 0 and Momo < Momo[1];
def momobeardown =  Momo > Momo[1] and Momo >(-Move_Threshold);
def momobearup = Momo < 0 and Momo > Momo[1];

def change = absvalue(close - close[1]);

# Squeeze breaks out in EITHER direction
Plot Breakout = squeeze[1] is true and squeeze is false;

# Breakout of squeeze to the upside
plot BreakoutBull = squeeze[1] is true and squeeze is false and momobullup;
# Breakout of squeeze to the downside
plot BreakoutBear = squeeze[1] is true and squeeze is false and momobulldown;

# Breakout of squeeze to the upside with move larger than ATR
plot BreakoutBullATRplus = squeeze[1] is true and squeeze is false and momobullup  and change>ATR;
# Breakout of squeeze to the downside with move larger than ATR
plot BreakoutBearATRplus = squeeze[1] is true and squeeze is false and momobulldown and change>ATR;

# Bull trend reverses and turns down while the color changes to dark blue
Plot BullTrendReversal = momobulldown is true and momobulldown[1] is false;
# Bear trend reverses and turns up while the color changes to yellow
Plot BearTrendReversal= momobearup is true and momobearup[1] is false;

# Zero line turns red and becomes a squeeze
plot EnteringSqueeze = Squeeze[1] is false and Squeeze is true;

FYI, I don't use squeezes. This indicator was started as an exercise when I first started coding and as such I haven't done any kind of "backtesting" really. If you find any issues, let me know what they are and we'll see what we need to do to get it working like you want.
 
Last edited:
Hoping someone can help me with a scan. I am looking to use a conservative strategy for my IRA account in which I would be selling credit spreads when an active squeeze breakout is starting to lose momentum on a daily chart. This would occur when histogram turns from light blue to dark blue or turns red to yellow. This is the ideal time for a credit spread, IV is still high and the probability that the move has slowed down for the time being is high. I would place the credit spread when the second dark blue or second yellow bar has printed on the daily chart. This would confirm the change in momentum. For the scan, though, I would want candidates that have printed only one dark blue or one yellow bar on the daily. It would go on my watchlist for confirmation of a second bar print the following day. I would very much appreciate any help with this scan. Thank you!
 
Use this in a column in your watch list:

def squeeze = if(reference BollingerBands().”upperband” – KeltnerChannels().”Upper_Band”)<0 then 1 else 0;
def insqueeze = if squeeze then insqueeze[1] + 1 else 0;
def fired = if !squeeze then fired[1]+1 else 0;
def direction = if (fired == 1 , if( TTM_Squeeze() > TTM_Squeeze()[1] , 1 , 0 ), direction[1]);
plot result = if insqueeze > 0 then insqueeze else if fired >0 and fired <8 then fired else 0;
AddLabel(yes, Concat(if insqueeze>0 then “Squeeze: ” else if fired >0 and fired <8 then Concat(“FIRED: “, if direction then ” ” else ” “) else “”, result), if insqueeze>0 then color.white else color.black);
AssignBackgroundColor( if insqueeze>0 then color.red else if fired>0 and fired <8 then color.green else color.black);
 
@Moose Thank you!

Average squeeze breakout tends to last 8-10 bars so the additional info of number of bars printed is great!
 
Last edited:
Hi @wtf_dude , thank you so much for sharing this. I've been trying out numerous different setting combos to get what I want, but not having luck. What are the settings you'd suggest if I'm looking for stocks that were on a red dot(s), and are now two cyan bars into a switch to green dots, and the price action is unusual for the stock (e.g., usually, within a bar, price goes +/-0.2%, but within these two most recent cyan bars, price moved up +0.6%)? I'm basically looking for the start of a strong breakout. TIA!
 
Hi @wtf_dude , thank you so much for sharing this. I've been trying out numerous different setting combos to get what I want, but not having luck. What are the settings you'd suggest if I'm looking for stocks that were on a red dot(s), and are now two cyan bars into a switch to green dots, and the price action is unusual for the stock (e.g., usually, within a bar, price goes +/-0.2%, but within these two most recent cyan bars, price moved up +0.6%)? I'm basically looking for the start of a strong breakout. TIA!
alright, since printing confirmation bars is a little bit tricky to do by default I had to do a recode. This is just for bull breakouts, but you can add how many extra bars ago you want the squeeze breakout to have happened . You can also change the percent threshold you want the change to be between now and however many bars ago you chose. I also made it so there must have been at least 3 periods/days of squeeze to count (right now there are crap tons of squeeze "breakouts" that were only in a squeeze for one day.

PLEASE REMEMBER: take this code and save it as a study on the CHART tab. Then on the SCAN tab, you will then load it up as a condition >> add study >>custom and select whatever name you saved it as on charts. All the default settings are the ones you requested, so just load it up, leave the inputs as is, select the middle box as "is true" and leave "within bars" as 1


Code:
# Advanced Squeeze Bull Breakout v1.0
# WTF_Dude on 9.10.20

input length = 20; #hint length: Length for average calculation
input price = close;
input SDmult = 2.0;
input ATR_mult = 1.5;
input ATR_length = 20;
input Extra_bars= 1;
input percent_move = .06;


   def K = (Highest(High, length) + Lowest(low, length)) /
               2 + ExpAverage(close, length);
  def Momo = Inertia(price - K / 2, length);

def SD = StDev(close, length);
def Avg = Average(close, length);
def ATR = Average(TrueRange(high, close, low), ATR_length);
def SDup = Avg + (SdMult * Sd);
def ATRup = Avg + (Atr_Mult * ATR);

def Squeeze = SDup < ATRup;
    
def zero = if IsNaN(close) or !IsNaN(Squeeze) then Double.NaN else 0;

def momobullup = Momo > Momo[1]  and momo>0;

def change =(close - close[Extra_bars]);
def PercentChg = 100 * (price / price[Extra_bars] - 1);

# Squeeze breakout to the upside 2 bars ago with move greater than percent_move
plot BreakoutBull = squeeze[Extra_bars+1] is true and squeeze[Extra_bars+2] is true  and squeeze[Extra_bars+3] is true and squeeze [Extra_bars] is false and squeeze is false and momobullup and percentchg>= percent_move;
 
Last edited:
Use this in a column in your watch list:

def squeeze = if(reference BollingerBands().”upperband” – KeltnerChannels().”Upper_Band”)<0 then 1 else 0;
def insqueeze = if squeeze then insqueeze[1] + 1 else 0;
def fired = if !squeeze then fired[1]+1 else 0;
def direction = if (fired == 1 , if( TTM_Squeeze() > TTM_Squeeze()[1] , 1 , 0 ), direction[1]);
plot result = if insqueeze > 0 then insqueeze else if fired >0 and fired <8 then fired else 0;
AddLabel(yes, Concat(if insqueeze>0 then “Squeeze: ” else if fired >0 and fired <8 then Concat(“FIRED: “, if direction then ” ” else ” “) else “”, result), if insqueeze>0 then color.white else color.black);
AssignBackgroundColor( if insqueeze>0 then color.red else if fired>0 and fired <8 then color.green else color.black);
How do we make this count on a different time metric?
 
How do we make this count on a different time metric?
Once you have the study loaded as one of the filters, the right side of the row will have a square box with D in it (day is default) click on the box and you can change the time frame. BE SURE to check or uncheck the EXT box if you want the extended hours included with the scan or your results will look like a bunch of false signals.
 
Last edited:
alright, since printing confirmation bars is a little bit tricky to do by default I had to do a recode. This is just for bull breakouts, but you can add how many extra bars ago you want the squeeze breakout to have happened . You can also change the percent threshold you want the change to be between now and however many bars ago you chose. I also made it so there must have been at least 3 periods/days of squeeze to count (right now there are crap tons of squeeze "breakouts" that were only in a squeeze for one day.

PLEASE REMEMBER: take this code and save it as a study on the CHART tab. Then on the SCAN tab, you will then load it up as a condition >> add study >>custom and select whatever name you saved it as on charts. All the default settings are the ones you requested, so just load it up, leave the inputs as is, select the middle box as "is true" and leave "within bars" as 1


Code:
# Advanced Squeeze Bull Breakout v1.0
# WTF_Dude on 9.10.20

input length = 20; #hint length: Length for average calculation
input price = close;
input SDmult = 2.0;
input ATR_mult = 1.5;
input ATR_length = 20;
input Extra_bars= 1;
input percent_move = .06;


   def K = (Highest(High, length) + Lowest(low, length)) /
               2 + ExpAverage(close, length);
  def Momo = Inertia(price - K / 2, length);

def SD = StDev(close, length);
def Avg = Average(close, length);
def ATR = Average(TrueRange(high, close, low), ATR_length);
def SDup = Avg + (SdMult * Sd);
def ATRup = Avg + (Atr_Mult * ATR);

def Squeeze = SDup < ATRup;
   
def zero = if IsNaN(close) or !IsNaN(Squeeze) then Double.NaN else 0;

def momobullup = Momo > Momo[1]  and momo>0;

def change =(close - close[Extra_bars]);
def PercentChg = 100 * (price / price[Extra_bars] - 1);

# Squeeze breakout to the upside 2 bars ago with move greater than percent_move
plot BreakoutBull = squeeze[Extra_bars+1] is true and squeeze[Extra_bars+2] is true  and squeeze[Extra_bars+3] is true and squeeze [Extra_bars] is false and squeeze is false and momobullup and percentchg>= percent_move;

@wtf_dude do you happen to have a Bear version of this scanner? Still going through the other scanners to see what the major differences are and what sort of results are generated. Thanks.
 
@wtf_dude do you happen to have a Bear version of this scanner? Still going through the other scanners to see what the major differences are and what sort of results are generated. Thanks.
This should work. Not much firing atm from what I can tell

Code:
# Advanced Squeeze Bear Scan
# WTF_Dude 9.15.20

input length = 20; #hint length: Length for average calculation
input price = close;
input SDmult = 2.0; #standard deviations
input ATR_mult = 1.5; #average true range multiplier
input ATR_length = 20; # length used for calculating ATR
input Extra_bars= 1; #extra bars allows you to select how many extra bars needed to confirm the breakout
input percent_move = .06; #how big of a percent move to confirm the breakout


   def K = (Highest(High, length) + Lowest(low, length)) /
               2 + ExpAverage(close, length);
  def Momo = Inertia(price - K / 2, length);

def SD = StDev(close, length);
def Avg = Average(close, length);
def ATR = Average(TrueRange(high, close, low), ATR_length);
def SDup = Avg + (SdMult * Sd);
def ATRup = Avg + (Atr_Mult * ATR);

def Squeeze = SDup < ATRup;
        
def zero = if IsNaN(close) or !IsNaN(Squeeze) then Double.NaN else 0;

def momobulldown = Momo < Momo[1] and momo<0;

def change = (close - close[Extra_bars]);
def PercentChg = absvalue(100 * (price / price[Extra_bars] - 1));

# Squeeze breakout to the upside 2 bars ago with move greater than percent_move
plot BreakoutBear = squeeze[Extra_bars+1] is true and squeeze[Extra_bars+2] is true  and squeeze[Extra_bars+3] is true and squeeze [Extra_bars] is false and squeeze is false and momobulldown and percentchg>= percent_move;
 
@wtf_dude Thanks for the scanner...Yeah I actually went through the whole thread here and tested the results from EVERY scanner condition you made thus far individually...I agree that not much results with the last two scanners...The best results that I personally found was from the scanner from your post #4.

I actually was using the different conditions of that scanner as filters for the Slim Ribbon scanner @diazlaz made here:

https://usethinkscript.com/threads/slim-ribbon-indicator-for-thinkorswim.245/page-3#post-21700

Your Squeeze Scanner with the combination of the Slim Ribbon scanner on a DAILY timeframe actually filtered out and generated some great results. Would it be possible for you to combine ALL BULL/BEAR conditions from scanner in your post #4 to scan either BULLISH or BEARISH scans?

With my limited skill set I don't feel confident in doing this but perhaps you can set the scanner to scan for multiple BULLISH or BEARISH conditions at once...IF so that would be awesome! But would you be able to make a scan using the #comment out method instead of the wizard...? Its less confusing at least to me...Here is what I tried to do...by changing plot to def but I can't figure out how to plot "both" or "and" conditions since you have 3 different conditions for each BULL/BEAR. If this is not too much work try this out with the SLIM Ribbon scanner I linked to...with the following plot options at the end of the script:

def both = bullish or bearish;
def both = neutral or bullish;
def both = neutral or bearish;


#plot results = bullish; #bullish scan
#plot results = bearish; #bearish scan
plot results = both; #include both bullish and bearish or neutral

#plot resultsChanged = bullish and bullish[0] != bullish[1]; # instant bullish change scan
#plot resultsChanged = bearish and bearish[0] != bearish[1]; #instant bearish change scan


I like to scan the SLIM Ribbon with both neutral or bullish or neutral and bearish conditions...

Code:
# AdvancedSqueezeScanner

# Momentum Squeeze open coding by Moebius, based on John Carter

# Scan by WTF_Dude

# Added Squeeze Label with directional color

# Label is green when momentum is ascending, red when descending

declare lower;

input length = 20; #hint length: Length for average calculation

input price = close;

input SDmult = 2.0;

input ATRmult = 1.5;

def K = (Highest(High, length) + Lowest(low, length)) /

2 + ExpAverage(close, length);

def Momo = Inertia(price - K / 2, length);

def SD = StDev(close, length);

def Avg = Average(close, length);

def ATR = Average(TrueRange(high, close, low), length);

def SDup = Avg + (SdMult * Sd);

def ATRup = Avg + (AtrMult * ATR);

def Squeeze = SDup < ATRup;

def zero = if IsNaN(close) or !IsNaN(Squeeze) then Double.NaN else 0;

def momobullup = Momo > Momo[1] and Momo > 0;

def momobulldown = Momo > 0 and Momo < Momo[1];

def momobeardown = Momo > Momo[1] and Momo > 0;

def momobearup = Momo < 0 and Momo > Momo[1];

def BullTrendReversal = momobulldown is true and momobulldown[1] is false;

def BearTrendReversal = momobearup is true and momobearup[1] is false;

#Plot BreakoutEitherDirection = squeeze[1] is true and squeeze is false;

#plot BreakoutBull = squeeze[1] is true and squeeze is false and momobullup;

#plot BreakoutBear = squeeze[1] is true and squeeze is false and momobulldown;

#Plot BullTrendReversal = momobulldown is true and momobulldown[1] is false;

#Plot BearTrendReversal = momobearup is true and momobearup[1] is false;

plot Squeeze_ChangetoBull = BearTrendReversal and squeeze is true;

#plot Squeeze_ChangetoBear = BullTrendReversal and squeeze is true;

#End Code)
 
Last edited:
@wtf_dude Thanks for the scanner...Yeah I actually went through the whole thread here and tested the results from EVERY scanner condition you made thus far individually...I agree that not much results with the last two scanners...The best results that I personally found was from the scanner from your post #4.

I actually was using the different conditions of that scanner as filters for the Slim Ribbon scanner @diazlaz made here:

https://usethinkscript.com/threads/slim-ribbon-indicator-for-thinkorswim.245/page-3#post-21700

Your Squeeze Scanner with the combination of the Slim Ribbon scanner on a DAILY timeframe actually filtered out and generated some great results. Would it be possible for you to combine ALL BULL/BEAR conditions from scanner in your post #4 to scan either BULLISH or BEARISH scans?

With my limited skill set I don't feel confident in doing this but perhaps you can set the scanner to scan for multiple BULLISH or BEARISH conditions at once...IF so that would be awesome! But would you be able to make a scan using the #comment out method instead of the wizard...? Its less confusing at least to me...Here is what I tried to do...by changing plot to def but I can't figure out how to plot "both" or "and" conditions since you have 3 different conditions for each BULL/BEAR. If this is not too much work try this out with the SLIM Ribbon scanner I linked to...with the following plot options at the end of the script:

def both = bullish or bearish;
def both = neutral or bullish;
def both = neutral or bearish;


#plot results = bullish; #bullish scan
#plot results = bearish; #bearish scan
plot results = both; #include both bullish and bearish or neutral

#plot resultsChanged = bullish and bullish[0] != bullish[1]; # instant bullish change scan
#plot resultsChanged = bearish and bearish[0] != bearish[1]; #instant bearish change scan


I like to scan the SLIM Ribbon with both neutral or bullish or neutral and bearish conditions...

Code:
# AdvancedSqueezeScanner

# Momentum Squeeze open coding by Moebius, based on John Carter

# Scan by WTF_Dude

# Added Squeeze Label with directional color

# Label is green when momentum is ascending, red when descending

declare lower;

input length = 20; #hint length: Length for average calculation

input price = close;

input SDmult = 2.0;

input ATRmult = 1.5;

def K = (Highest(High, length) + Lowest(low, length)) /

2 + ExpAverage(close, length);

def Momo = Inertia(price - K / 2, length);

def SD = StDev(close, length);

def Avg = Average(close, length);

def ATR = Average(TrueRange(high, close, low), length);

def SDup = Avg + (SdMult * Sd);

def ATRup = Avg + (AtrMult * ATR);

def Squeeze = SDup < ATRup;

def zero = if IsNaN(close) or !IsNaN(Squeeze) then Double.NaN else 0;

def momobullup = Momo > Momo[1] and Momo > 0;

def momobulldown = Momo > 0 and Momo < Momo[1];

def momobeardown = Momo > Momo[1] and Momo > 0;

def momobearup = Momo < 0 and Momo > Momo[1];

def BullTrendReversal = momobulldown is true and momobulldown[1] is false;

def BearTrendReversal = momobearup is true and momobearup[1] is false;

#Plot BreakoutEitherDirection = squeeze[1] is true and squeeze is false;

#plot BreakoutBull = squeeze[1] is true and squeeze is false and momobullup;

#plot BreakoutBear = squeeze[1] is true and squeeze is false and momobulldown;

#Plot BullTrendReversal = momobulldown is true and momobulldown[1] is false;

#Plot BearTrendReversal = momobearup is true and momobearup[1] is false;

plot Squeeze_ChangetoBull = BearTrendReversal and squeeze is true;

#plot Squeeze_ChangetoBear = BullTrendReversal and squeeze is true;

#End Code)
Not sure why you would need the code changed to add the SLM as a filter? You just have them loaded as 2 different studies on the same scan page and it will use both. Save that scan and you're good to go. What am I missing?

Also, the reason for using the study saved to chart vs just copy/pasting coding is because its ridiculous to go in and change the hard coding of a study just to change your variables It's too easy to jack up the code vs just changing whatever variable you want and never risking an error or screwing up the results.

Its not complicated, it just takes a few more seconds to set up in the beginning.

1. Go to the charts tab. Click the Studies and strategies Icon. Click create. Copy and paste the code and create a name for the scan

2. Go to the scan page. Click Add filter. Select study. On the dropdown menu, select Custom.

3. You likely wont need the ADXcrossover that comes preloaded so delete that condition.

4. Click Add Condition. Select Study. Select the scan name you just saved.

5. For the middle column just click "is true". Leave "within bars" the same. Save. Click Ok

6. Now select "Add filter" again and load up your SLM filter or coding.

7. Click the 3 bars on the top right and select "Save scan query". Youre all set and now you have the scan saved as an auto updating watchlist.

That may sound like alot of work, but now when you load up that scan query you can just edit the number settings and never even touch the code. When you're trying to work quickly during market hours it will save alot more of your time having all this done ahead of time
 

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
382 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