Script Name: HTF Supply & Demand with Multi-Timeframe Trend Analyzer
Type: Institutional Supply/Demand + Trend Confluence Strategy
Author: Quantitative Technical Analysis
Platform: ThinkScript (ThinkorSwim)
for your consideration:Thank You
Strategy Overview
This institutional-grade script combines higher timeframe supply/demand zones, session-based opening ranges, and multi-timeframe trend alignment to identify high-probability trading opportunities. The unique "reactivity" feature filters only those HTF levels that have been tested multiple times, eliminating stale or irrelevant zones. This creates a dynamic, adaptive supply/demand framework suitable for professional discretionary and semi-systematic traders.
Entry Logic
Long Entry (Demand Zone Bounce)
Exit Logic
Take Profit Targets
Stop Loss Placement
Trailing Exit (After TP1 Hit)
Best Time Frames
Session-Specific Optimization
Additional Professional Notes
Parameter Recommendations by Market
Risk Management
Summary Table
Type: Institutional Supply/Demand + Trend Confluence Strategy
Author: Quantitative Technical Analysis
Platform: ThinkScript (ThinkorSwim)
for your consideration:Thank You
Strategy Overview
This institutional-grade script combines higher timeframe supply/demand zones, session-based opening ranges, and multi-timeframe trend alignment to identify high-probability trading opportunities. The unique "reactivity" feature filters only those HTF levels that have been tested multiple times, eliminating stale or irrelevant zones. This creates a dynamic, adaptive supply/demand framework suitable for professional discretionary and semi-systematic traders.
Entry Logic
Long Entry (Demand Zone Bounce)
- Primary Condition: Price approaches HTF_SUP (higher timeframe swing low)
- Reactivity Filter: lowTouches >= minTouches (level is "active" – tested minimum 2 times within proximity)
- Trend Confluence (Minimum 2 of 3 bullish):
- 15m: smaFast15 > smaSlow15
- 1H: smaFast60 > smaSlow60
- 4H: smaFast240 > smaSlow240
- Session Context (Optional Enhancer): Price within 15-minute opening range of RTH, Globex, or London session
- Execution: Limit order resting reactTicks (default 2) above HTF_SUP, or market on bullish reversal candle (hammer, engulfing) after touch confirmation
- Primary Condition: Price approaches HTF_RES (higher timeframe swing high)
- Reactivity Filter: highTouches >= minTouches (level is "active" – tested minimum 2 times within proximity)
- Trend Confluence (Minimum 2 of 3 bearish):
- 15m: smaFast15 < smaSlow15
- 1H: smaFast60 < smaSlow60
- 4H: smaFast240 < smaSlow240
- Session Context (Optional Enhancer): Price within 15-minute opening range of any major session
- Execution: Limit order resting reactTicks below HTF_RES, or market on bearish reversal candle after touch confirmation
- HTF PRESSURE label shows resistance active AND support active simultaneously (chopping zone)
- Trend alignment shows "MIXED" (conflicting timeframes)
- Level touches >= minTouches but price has already broken through level by >2× reactTicks
Exit Logic
Take Profit Targets
| Target | Level | Partial Exit |
|---|---|---|
| TP1 | Opposite HTF level (HTF_SUP for short, HTF_RES for long) | 50% position |
| TP2 | Next session opening range extreme (e.g., RTHH for long) | 30% position |
| TP3 | Trailing with 15m trend flip | 20% position |
| Position | Stop Level | Distance |
|---|---|---|
| Long | HTF_SUP - (2× reactTicks × tickSize) | ~4 ticks below demand |
| Short | HTF_RES + (2× reactTicks × tickSize) | ~4 ticks above resistance |
- Long: Trail stop 1 tick below each new 15m swing low while t15Bull = yes
- Short: Trail stop 1 tick above each new 15m swing high while t15Bear = yes
- Exit all remaining positions 30 minutes before major news (NFP, FOMC, CPI)
- Friday: Exit 1 hour before market close to avoid weekend gap
- If price closes beyond HTF level by > reactTicks × 3 on 15m timeframe → immediately exit
Best Time Frames
| Preference | Time Frame | Use Case | Expected Trades/Week |
|---|---|---|---|
| Primary | 15-minute (15m) | Day trading with HTF context – optimal for reactivity detection | 5–12 |
| Secondary | 1-hour (1H) | Swing trading intraday; smoother levels, fewer false touches | 3–6 |
| Tertiary | 5-minute (5m) | Aggressive entries aligned with 15m/1H/4H trend (requires higher minTouches = 3) | 10–20 |
| Avoid | Below 5-minutes | Microstructure noise; level integrity degrades | – |
| Session | Best Time Frame | Notes |
|---|---|---|
| London Open (0300 GMT) | 15m | Highest volatility; use London opening range (LNH/LNL) |
| RTH Open (0930 EST) | 5m or 15m | Use RTHH/RTHL for breakout confirmation |
| Globex (1800 EST) | 1H | Lower volume; wider stops recommended |
Additional Professional Notes
Parameter Recommendations by Market
| Market | swingLookback | reactTicks | minTouches | Fast/Slow Lengths |
|---|---|---|---|---|
| ES, NQ (Futures) | 10 | 2 | 2 | 20, 50 |
| EURUSD, GBPUSD | 8 | 3 | 2 | 20, 50 |
| Equities (AAPL, NVDA) | 12 | 4 | 3 | 20, 50 |
| Crypto (BTC, ETH) | 14 | 5 | 3 | 25, 55 |
- Maximum 2 concurrent positions
- Daily loss limit: 2× average winning trade
- Risk per trade: 0.5%–1% of account equity
- Volume spike on level touch increases probability
- Divergence (RSI/MACD) at HTF_SUP or HTF_RES → add to position size
- Does not auto-execute trades (discretionary script)
- Reactivity logic resets on each new HTF pivot – levels older than swingLookback × 2 bars may become stale
- Best used on liquid, high-ATR instruments
Summary Table
| Aspect | Specification |
|---|---|
| Strategy Type | Supply/Demand + Trend Confluence |
| Primary Entry | HTF pivot with reactivity + MTF trend alignment |
| Primary Exit | Opposite HTF level or trend flip |
| Best Time Frames | 15m (primary), 1H (secondary) |
| Key Filters | minTouches = 2, reactTicks = 2 |
| Markets | Futures, Forex, Large-cap Equities |
Code:
# HTF Supply Demand with Multi-Timeframe Trend Analyzer
# Combines Opening Range levels, Prior Day levels, HTF Swing Pivots with Reactivity,
# and Multi-Timeframe Trend Alignment (15m, 1H, 4H)
#
# Version: 1.0
# Author: ?
declare upper;
# ============================================================
# INPUTS
# ============================================================
input showPrevDay = yes;
input showRTH = yes;
input showGlobex = yes;
input showLondon = yes;
input showPDO = yes;
input rthStart = 0930;
input globexStart = 1800;
input londonStart = 0300;
input orMinutes = 15;
input htfAggregation = AggregationPeriod.HOUR;
input swingLookback = 10;
input reactTicks = 2;
input minTouches = 2;
input fastLength = 20;
input slowLength = 50;
# ============================================================
# COLORS
# ============================================================
DefineGlobalColor("RTH", Color.CYAN);
DefineGlobalColor("GX", Color.MAGENTA);
DefineGlobalColor("LN", Color.YELLOW);
DefineGlobalColor("PD", Color.GRAY);
DefineGlobalColor("RES", Color.RED);
DefineGlobalColor("SUP", Color.GREEN);
DefineGlobalColor("REACT", Color.ORANGE);
# ============================================================
# TIME BASE (SESSION WINDOWS)
# ============================================================
def hhmm = SecondsFromTime(0000) / 60;
def hour = Floor(hhmm / 60);
def minute = hhmm - hour * 60;
def timeHHMM = hour * 100 + minute;
def inRTH = timeHHMM >= rthStart and timeHHMM < rthStart + orMinutes;
def inGX = timeHHMM >= globexStart and timeHHMM < globexStart + orMinutes;
def inLN = timeHHMM >= londonStart and timeHHMM < londonStart + orMinutes;
def newDay = GetYYYYMMDD() != GetYYYYMMDD()[1];
# ============================================================
# PRIOR DAY LEVELS
# ============================================================
def pdHigh = high(period = AggregationPeriod.DAY)[1];
def pdLow = low(period = AggregationPeriod.DAY)[1];
def pdClose = close(period = AggregationPeriod.DAY)[1];
def pdOpen = open(period = AggregationPeriod.DAY)[1];
plot PDH = if showPrevDay then pdHigh else Double.NaN;
plot PDL = if showPrevDay then pdLow else Double.NaN;
plot PDC = if showPrevDay then pdClose else Double.NaN;
plot PDO = if showPDO then pdOpen else Double.NaN;
PDH.SetDefaultColor(GlobalColor("PD"));
PDL.SetDefaultColor(GlobalColor("PD"));
PDC.SetDefaultColor(GlobalColor("PD"));
PDO.SetDefaultColor(GlobalColor("PD"));
PDH.SetStyle(Curve.LONG_DASH);
PDL.SetStyle(Curve.LONG_DASH);
PDC.SetStyle(Curve.SHORT_DASH);
PDO.SetStyle(Curve.SHORT_DASH);
# ============================================================
# OPENING RANGE TRACKING (SESSION STRUCTURE)
# ============================================================
rec rthHigh = if newDay then Double.NaN
else if inRTH then Max(high, rthHigh[1])
else rthHigh[1];
rec rthLow = if newDay then Double.NaN
else if inRTH then Min(low, rthLow[1])
else rthLow[1];
rec gxHigh = if newDay then Double.NaN
else if inGX then Max(high, gxHigh[1])
else gxHigh[1];
rec gxLow = if newDay then Double.NaN
else if inGX then Min(low, gxLow[1])
else gxLow[1];
rec lnHigh = if newDay then Double.NaN
else if inLN then Max(high, lnHigh[1])
else lnHigh[1];
rec lnLow = if newDay then Double.NaN
else if inLN then Min(low, lnLow[1])
else lnLow[1];
plot RTHH = if showRTH then rthHigh else Double.NaN;
plot RTHL = if showRTH then rthLow else Double.NaN;
plot GXH = if showGlobex then gxHigh else Double.NaN;
plot GXL = if showGlobex then gxLow else Double.NaN;
plot LNH = if showLondon then lnHigh else Double.NaN;
plot LNL = if showLondon then lnLow else Double.NaN;
RTHH.SetDefaultColor(GlobalColor("RTH"));
RTHL.SetDefaultColor(GlobalColor("RTH"));
GXH.SetDefaultColor(GlobalColor("GX"));
GXL.SetDefaultColor(GlobalColor("GX"));
LNH.SetDefaultColor(GlobalColor("LN"));
LNL.SetDefaultColor(GlobalColor("LN"));
# Set opening range levels to dashed
RTHH.SetStyle(Curve.LONG_DASH);
RTHL.SetStyle(Curve.LONG_DASH);
GXH.SetStyle(Curve.LONG_DASH);
GXL.SetStyle(Curve.LONG_DASH);
LNH.SetStyle(Curve.LONG_DASH);
LNL.SetStyle(Curve.LONG_DASH);
# ============================================================
# HTF PINE-STYLE PIVOT ENGINE
# ============================================================
def htfHigh = high(period = htfAggregation);
def htfLow = low(period = htfAggregation);
def pivotHigh =
htfHigh[swingLookback] == Highest(htfHigh, swingLookback * 2 + 1);
def pivotLow =
htfLow[swingLookback] == Lowest(htfLow, swingLookback * 2 + 1);
rec lastSwingHigh =
if pivotHigh then htfHigh[swingLookback]
else lastSwingHigh[1];
rec lastSwingLow =
if pivotLow then htfLow[swingLookback]
else lastSwingLow[1];
# ============================================================
# REACTIVITY (PINE-STYLE VALUEWHEN BEHAVIOR)
# ============================================================
def tick = TickSize();
def proximity = reactTicks * tick;
def touchHigh =
!IsNaN(lastSwingHigh) and
(AbsValue(high - lastSwingHigh) <= proximity or AbsValue(low - lastSwingHigh) <= proximity);
def touchLow =
!IsNaN(lastSwingLow) and
(AbsValue(high - lastSwingLow) <= proximity or AbsValue(low - lastSwingLow) <= proximity);
rec highTouches =
if pivotHigh then 0
else if touchHigh then highTouches[1] + 1
else highTouches[1];
rec lowTouches =
if pivotLow then 0
else if touchLow then lowTouches[1] + 1
else lowTouches[1];
# ============================================================
# HTF LEVEL PLOTS (FINAL OUTPUT)
# ============================================================
plot HTF_RES = lastSwingHigh;
plot HTF_SUP = lastSwingLow;
HTF_RES.SetDefaultColor(GlobalColor("RES"));
HTF_SUP.SetDefaultColor(GlobalColor("SUP"));
HTF_RES.SetLineWeight(2);
HTF_SUP.SetLineWeight(2);
# Set HTF levels to dashed
HTF_RES.SetStyle(Curve.LONG_DASH);
HTF_SUP.SetStyle(Curve.LONG_DASH);
# ============================================================
# REACTIVITY LEVELS (ACTIVE ONLY)
# ============================================================
plot ReactHigh = if highTouches >= minTouches then lastSwingHigh else Double.NaN;
plot ReactLow = if lowTouches >= minTouches then lastSwingLow else Double.NaN;
ReactHigh.SetDefaultColor(GlobalColor("REACT"));
ReactLow.SetDefaultColor(GlobalColor("REACT"));
ReactHigh.SetStyle(Curve.SHORT_DASH);
ReactLow.SetStyle(Curve.SHORT_DASH);
ReactHigh.SetLineWeight(2);
ReactLow.SetLineWeight(2);
# ============================================================
# TREND ENGINE (MULTI-TIMEFRAME)
# ============================================================
def smaFast15 = Average(close(period = AggregationPeriod.FIFTEEN_MIN), fastLength);
def smaSlow15 = Average(close(period = AggregationPeriod.FIFTEEN_MIN), slowLength);
def smaFast60 = Average(close(period = AggregationPeriod.HOUR), fastLength);
def smaSlow60 = Average(close(period = AggregationPeriod.HOUR), slowLength);
def smaFast240 = Average(close(period = AggregationPeriod.FOUR_HOURS), fastLength);
def smaSlow240 = Average(close(period = AggregationPeriod.FOUR_HOURS), slowLength);
def t15Bull = smaFast15 > smaSlow15;
def t60Bull = smaFast60 > smaSlow60;
def t240Bull = smaFast240 > smaSlow240;
def t15Bear = smaFast15 < smaSlow15;
def t60Bear = smaFast60 < smaSlow60;
def t240Bear = smaFast240 < smaSlow240;
# ============================================================
# LABELS (MATCH PINE OUTPUT STYLE)
# ============================================================
AddLabel(yes,
"HTF RES: " +
(if IsNaN(lastSwingHigh) then "NA" else AsText(Round(lastSwingHigh, 2))) +
" | T: " + highTouches +
(if highTouches >= minTouches then " ACTIVE" else ""),
if highTouches >= minTouches then Color.RED else Color.DARK_GRAY
);
AddLabel(yes,
"HTF SUP: " +
(if IsNaN(lastSwingLow) then "NA" else AsText(Round(lastSwingLow, 2))) +
" | T: " + lowTouches +
(if lowTouches >= minTouches then " ACTIVE" else ""),
if lowTouches >= minTouches then Color.GREEN else Color.DARK_GRAY
);
# ============================================================
# TREND ALIGNMENT LABEL
# ============================================================
AddLabel(yes,
"ALIGN: " +
(if t15Bull and t60Bull and t240Bull then "STRONG BULL"
else if t15Bear and t60Bear and t240Bear then "STRONG BEAR"
else "MIXED"),
if t15Bull and t60Bull and t240Bull then Color.GREEN
else if t15Bear and t60Bear and t240Bear then Color.RED
else Color.GRAY
);
# ============================================================
# INDIVIDUAL TIMEFRAME LABELS
# ============================================================
AddLabel(yes,
"15m: " + (if t15Bull then "BULL" else if t15Bear then "BEAR" else "NEUTRAL"),
if t15Bull then Color.GREEN else if t15Bear then Color.RED else Color.GRAY
);
AddLabel(yes,
"1H: " + (if t60Bull then "BULL" else if t60Bear then "BEAR" else "NEUTRAL"),
if t60Bull then Color.GREEN else if t60Bear then Color.RED else Color.GRAY
);
AddLabel(yes,
"4H: " + (if t240Bull then "BULL" else if t240Bear then "BEAR" else "NEUTRAL"),
if t240Bull then Color.GREEN else if t240Bear then Color.RED else Color.GRAY
);
# ============================================================
# HTF PRESSURE LABEL
# ============================================================
def pressure =
(if (highTouches >= minTouches) then 1 else 0) -
(if (lowTouches >= minTouches) then 1 else 0);
AddLabel(yes,
"HTF PRESSURE: " +
(if pressure > 0 then "BEARISH RESISTANCE"
else if pressure < 0 then "BULLISH SUPPORT"
else "BALANCED"),
if pressure > 0 then Color.RED
else if pressure < 0 then Color.GREEN
else Color.GRAY
);
Last edited by a moderator: