Search This Blog

Monday, August 18, 2025

TTM Squeeze Scan on Stock Charts

 Scanner for TTM squeeze, good daily liquidity, over $8.   Detailed explanation at the bottom. 

------------------------ 

[type is stock] and [sma(20,volume) > 2000000]
and [Upper BB(20,2) < Upper Kelt Chan(20,1.5,10)]
and [Lower BB(20,2) > Lower Kelt Chan(20,1.5,10)]
and [[group is SP500]
or [group is NASDAQ100]
or [group is SP400]
or [group is SP600]
or [group is SOX]
or [group is OSX]
or [group is XAU]
or [group is BTK]
or [group is DRG]
or [group is NWX]
or [group is XAL]
or [group is XBD]
or [group is XCI]
or [group is XNG]
or [group is XTC]
or [group is FinancialSector]
or [group is ConsumerStaplesSector]
or [group is CommunicationServicesSector]
or [group is EnergySector]
or [group is HealthCareSector]
or [group is IndustrialSector]
or [group is MaterialsSector]
or [group is RealEstateSector]
or [group is TechnologySector]
or [group is UtilitiesSector]
or [group is ETFNOUI]]
and [Close > 8.00]

if you want more charts, lower the minimum volume average.

--------------------------------- 

 Got it 👍 — you’re looking at a StockCharts Advanced Scan that uses both Bollinger Bands (BB) and the Keltner Channel (KC) together. This combo is usually used to detect “squeezes” — periods of very low volatility that often precede an expansion/breakout.

🔑 What Each Piece Means
1. [sma(20,volume) > 2000000]

Only stocks with 20-day average volume > 2 million.

Filters for liquidity so signals are tradeable.

2. Bollinger Bands (BB)

Upper BB(20,2): 20-day SMA of price + 2 standard deviations.

Lower BB(20,2): 20-day SMA of price – 2 standard deviations.

BB width expands and contracts based on volatility. Narrow BBs = compression, wide BBs = expansion.

3. Keltner Channel (KC)

Upper Kelt Chan(20,1.5,10): 20-day EMA of price + 1.5 × 10-day ATR (Average True Range).

Lower Kelt Chan(20,1.5,10): 20-day EMA – 1.5 × ATR.

KC is an ATR-based channel (range-based, not standard-deviation-based like BB).

KC bands are usually smoother and more stable than BB.

4. The Core Conditions
[Upper BB(20,2) < Upper Kelt Chan(20,1.5,10)]
and 
[Lower BB(20,2) > Lower Kelt Chan(20,1.5,10)]


This means:

The Bollinger Bands are fully inside the Keltner Channel.

Both the upper BB is below the upper KC, and the lower BB is above the lower KC.

✅ This condition defines the “squeeze setup.”

5. Group Filters

Limits scan to major indices, sectors, and ETFs (SP500, NASDAQ100, SOX, EnergySector, etc.).

Makes sure you’re only looking at widely traded stocks.

6. [Close > 8.00]

Excludes penny stocks / thinly traded equities.

Keeps scan focused on mid-price stocks or higher.

🧠 The Theory — Why This Matters

Bollinger Bands inside Keltner Channels = compressed volatility.

Market is in a tight range, volatility is low, “coiled spring” effect.

This condition is often used to anticipate a volatility breakout — either up or down.

Traders call this the “TTM Squeeze” setup (popularized by John Carter).

While in the squeeze: the market is quiet, traders wait.

Once BBs expand back outside the Keltner Channel, it signals the end of the squeeze and usually a sharp directional move.

📊 Trading Use

Scan finds stocks currently in a volatility squeeze.

Next step is to look for momentum confirmation (MACD, RSI, trend strength) to predict breakout direction.

Some traders buy straddles/strangles (options), others wait for the first directional close outside the BB.

✅ In short: This scan finds liquid, non-penny stocks in a volatility squeeze (BB inside KC).
It’s a watchlist generator for potential explosive moves once volatility returns.

 

Friday, August 15, 2025

Scanner for Backtesting a DownChannel Breakout

 # Scanner: Breakout + Backtest in Downtrend Channel (NASDAQ Composite)
# Scans NASDAQ index tickers (e.g. $COMP?) for breakout setups

input length = 60;
input stDevMult = 2.0;
input minDownSlope = -0.02;
input backtestWindow = 12;
input tol = 0.002;

def lr = Inertia(close, length);
def slope = lr - lr[1];
def resid = close - lr;
def sd = StDev(resid, length);
def upper = lr + stDevMult * sd;

def inDowntrend = slope < minDownSlope;
def breakout = inDowntrend[1] and close[1] <= upper[1] and close > upper;
def withinTol = AbsValue(low - upper) <= tol * upper;
def barsSinceBO = if breakout then 0 else if barsSinceBO[1] >= 1000 then 1000 else barsSinceBO[1] + 1;
def validBacktest = withinTol and barsSinceBO > 0 and barsSinceBO <= backtestWindow;

plot scan = validBacktest;
--------------------------

How to Use It in ThinkorSwim

Go to the Scan tab and create a Stock Hacker scan.

Set Symbol filter to tickers within the NASDAQ Composite.

You can use prebuilt sets like “All Tickers” or try custom filtering by exchange = NASDAQ.

Add the Custom Study filter and paste the above script.

Run the scan to highlight all tickers that recently broke out of a down-channel and are pulling back to retest.

You can also tailor the script—like adding minimum liquidity or focusing only on tech sectors.

Summary
Feature    Detail
Index    NASDAQ Composite (also NQ Computer index)
Scanner Purpose    Identify stocks with breakout + retest patterns within that index
How to Use    Paste into TOS Stock Hacker with NASDAQ filter; scan for valid setups
Why It Matters    Spot potential continuation setups across a wide universe, not just CRWV

Let me know if you'd like help adjusting the scanner (e.g., add volume filters, RSI thresholds, or limit to only AI/tech sectors)! 

Results After Backtest of a Downchannel

 Builds a downtrend channel from a linear regression + standard-deviation bands.

Flags when price breaks out above the upper band, then retests that band within a window.

Measures the forward return after N bars from the retest and computes:

number of setups,

hit rate (% with positive forward return),

average forward return.

Paste into Studies → Create:

# Downtrend Breakout->Backtest Stats (4h-friendly)
# by Rich's request

input len = 60;                 # channel lookback bars
input stDevMult = 2.0;          # channel width
input minDownSlope = -0.02;     # slope threshold per bar (negative means downtrend)
input backtestWindow = 12;      # bars allowed to retest after breakout
input tol = 0.002;              # 0.2% proximity tolerance to touch
input fwdBars = 12;             # measure return N bars after retest
input showMarkers = yes;

# --- Linear regression channel (mid +/− sd bands)
def lr = Inertia(close, len);
def slope = (lr - lr[1]);  # per-bar slope
def resid = close - lr;
def sd = StDev(resid, len);
def upper = lr + stDevMult * sd;
def lower = lr - stDevMult * sd;

# --- Define a "downtrend channel" regime
def inDowntrend = slope < minDownSlope;

# --- Breakout: close crosses above upper band while in downtrend regime
def breakout = inDowntrend[1] and close[1] <= upper[1] and close > upper;

# --- Backtest: after breakout, price tags the upper band (now support) within window
def withinTol = AbsValue(low - upper) <= tol * upper;
def backtestCandidate = withinTol;
def barsSinceBO = if breakout then 0 else if barsSinceBO[1] >= 1000 then 1000 else barsSinceBO[1] + 1;
def validBacktest = backtestCandidate and barsSinceBO > 0 and barsSinceBO <= backtestWindow;

# --- Forward return measured fwdBars after the valid backtest close
def ret = if validBacktest then (close[fwdBars] / close - 1) else Double.NaN;

# --- Accumulators
def nSetups = CompoundValue(1, nSetups[1] + (if validBacktest then 1 else 0), 0);
def sumRet  = CompoundValue(1, sumRet[1] + (if validBacktest then ret else 0), 0);
def posHits = CompoundValue(1, posHits[1] + (if validBacktest and ret > 0 then 1 else 0), 0);

def hitRate = if nSetups > 0 then posHits / nSetups else Double.NaN;
def avgRet  = if nSetups > 0 then sumRet / nSetups else Double.NaN;

# --- Visuals
plot UpperBand = upper; UpperBand.SetDefaultColor(Color.GRAY);
plot MidLine   = lr;    MidLine.SetDefaultColor(Color.DARK_GRAY);
plot LowerBand = lower; LowerBand.SetDefaultColor(Color.GRAY);

# Mark breakout and backtest
plot BO = showMarkers and breakout;
BO.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
BO.SetDefaultColor(Color.LIGHT_GREEN);

plot BT = showMarkers and validBacktest;
BT.SetPaintingStrategy(PaintingStrategy.POINTS);
BT.SetDefaultColor(Color.CYAN);
BT.SetLineWeight(3);

# Labels with live stats
AddLabel(yes, "Setups: " + nSetups, Color.WHITE);
AddLabel(nSetups > 0, "Hit Rate (" + fwdBars + " bars): " + AsPercent(hitRate),
         if hitRate >= 0.5 then Color.GREEN else Color.RED);
AddLabel(nSetups > 0, "Avg Ret (" + fwdBars + " bars): " + AsPercent(avgRet),
         if avgRet >= 0 then Color.GREEN else Color.RED);

How to use (for your 4-hour chart)

Keep your 4h / 180D view.

Start with defaults: len=60, stDevMult=2, backtestWindow=12, fwdBars=12, minDownSlope=-0.02.

You’ll see:

Green arrows at breakouts,

Cyan dots where the retest happened,

Live labels with # of setups, hit rate, average forward return measured fwdBars bars after the retest.

Tips

Want stricter downtrends? Make minDownSlope a larger negative (e.g., -0.05).

If you get too few events, widen tolerance (tol=0.003) or the retest window (backtestWindow=20).

For quicker confirmation stats, shorten fwdBars to 6–8; for swing confirmation, try 16–20.

Run this on CRWV first, then you can drop it on other tickers to see how reliable the pattern is across your universe. If you want, I can give you a scanner version that finds symbols currently completing the retest today.

Friday, August 8, 2025

The Ghosts of Bay View Inn, Petosky Michigan

 I'll fill in the story.   We stayed there, and there were 2 ghosts scampering across the floor of the room above us.   The caretaker claimed that the room was empty, they never rented that room.  And she said that the noise would stop soon enough. 

The next day I surmised, my hunch was that the ghosts died in a fire.    And in 1929 there was a fire. 

https://collections.petoskeymuseum.org/items/show/2648

TTM Squeeze Scan on Stock Charts

 Scanner for TTM squeeze , good daily liquidity, over $8.   Detailed explanation at the bottom.  ------------------------  [type is stock] a...