Reversal Trap Probability Bands [BigBeluga] for ThinkOrSwim

chewie76

Well-known member
VIP
VIP Enthusiast
The Reversal Trap Probability Bands is an advanced technical indicator created by BigBeluga to identify and trade fakeout traps around market extremes. Traditional envelope or band indicators often fail because traders blindly enter breakouts that quickly reverse into whipsaw losses. In order to provide a solution to this problem, this indicator combines volatility-based envelope channels with a dynamic probability tracking engine, measuring historical RSI buckets to calculate real-time win probabilities for reversal traps.

The indicator aims to visualize institutional exhaustion and subsequent mean-reversion expansions. Candle colors, bubbles, and cloud coloring are all optional in the settings.

Original code: https://www.tradingview.com/script/fcmOq240-Reversal-Trap-Probability-Bands-BigBeluga/

This example is a four-hour chart of /NQ.
1785900597869.png


Code:
# Reversal_Trap_Probability_Bands [BigBeluga]
# Original Pine Script by BigBeluga
# https://www.tradingview.com/script/fcmOq240-Reversal-Trap-Probability-Bands-BigBeluga/
# Conversion and modification by Chewie 8/4/2026

declare upper;

# ═══════════════════════════════════════════════════════════
# INPUTS
# ═══════════════════════════════════════════════════════════

input color_candles = yes;
input TrapBubble    = yes;
input WinBubble     = yes;
input cloud         = yes;
input envelope_len  = 55;        # Envelope Smoothness
input multiplier    = 4.0;       # Envelope Width
input XMult         = 5.5;       # Exttreme band width
input trap_window   = 10;        # Trap Window (Candles)
input signal_gap    = 10;        # Minimum Bars Between Signals
input stop_mult     = 1.0;       # Original Stop is 0.5   ATR Stop Multiplier

DefineGlobalColor("Bearish",  CreateColor(236, 51, 51));
DefineGlobalColor("Bullish",  CreateColor(18, 175, 159));
DefineGlobalColor("MidLine",  CreateColor(120, 123, 134));

# ═══════════════════════════════════════════════════════════
# CORE CALCULATIONS
# ═══════════════════════════════════════════════════════════

def basis      = ExpAverage(close, envelope_len);
def vola       = Average(TrueRange(high, close, low), envelope_len);   # ATR(envelope_len)
def rsi        = RSI(Length = 20);

def upper_band = basis + (multiplier * vola);
def lower_band = basis - (multiplier * vola);
def Xupper_band = basis + (XMult * vola);
def Xlower_band = basis - (XMult * vola);
def atr        = Average(TrueRange(high, close, low), 100) * stop_mult;

# ═══════════════════════════════════════════════════════════
# TRAP COUNTER STATES
# ═══════════════════════════════════════════════════════════

def close_above_count = if high > upper_band
                        then close_above_count[1] + 1
                        else 0;

def close_below_count = if low < lower_band
                        then close_below_count[1] + 1
                        else 0;

# ═══════════════════════════════════════════════════════════
# RAW TRAP DETECTION
# Bear trap: price poked above upper band then closed back inside
# Bull trap: price poked below lower band then closed back inside
# ═══════════════════════════════════════════════════════════

# Bear trap — close drops back below upper_band after a poke above
def raw_bear_trap =
    if close < upper_band and
       ((high > upper_band and close[1] < upper_band and close_above_count[1] <= trap_window) or
        (close[1] > upper_band and close_above_count[1] <= trap_window))
    then 1
    else 0;

# Bull trap — close recovers back above lower_band after a poke below
def raw_bull_trap =
    if close > lower_band and
       ((low < lower_band and close[1] > lower_band and close_below_count[1] <= trap_window) or
        (close[1] < lower_band and close_below_count[1] <= trap_window))
    then 1
    else 0;

# ═══════════════════════════════════════════════════════════
# COOLDOWN / SIGNAL GAP
# Only fire a signal if at least signal_gap bars have passed since the last one
# ═══════════════════════════════════════════════════════════

def any_raw_signal = if raw_bull_trap or raw_bear_trap then 1 else 0;

# Track bars since the last fired signal
def bars_since_signal =
    if any_raw_signal and bars_since_signal[1] >= signal_gap
    then 0
    else if bars_since_signal[1] < signal_gap
    then bars_since_signal[1] + 1
    else bars_since_signal[1] + 1;

def can_fire = bars_since_signal[1] >= signal_gap;
def bull_trap = raw_bull_trap and can_fire;
def bear_trap = raw_bear_trap and can_fire;

# Reset the cooldown counter whenever a signal fires
def cooldown =
    if bull_trap or bear_trap
    then 0
    else if cooldown[1] < signal_gap
    then cooldown[1] + 1
    else cooldown[1] + 1;

# Refined with the cooldown counter (single-source-of-truth approach)
def bull_signal = raw_bull_trap and cooldown[1] >= signal_gap;
def bear_signal = raw_bear_trap and cooldown[1] >= signal_gap;

# ═══════════════════════════════════════════════════════════
# STOP & TARGET LEVELS — held active until resolved
# Bull: target = basis, stop = lowest(low,2) - atr
# Bear: target = basis, stop = highest(high,2) + atr
# ═══════════════════════════════════════════════════════════

# ── Bull trade tracking ──────────────────────────────────

def bull_target_stored =
    CompoundValue(1,
        if bull_signal
        then basis
        else bull_target_stored[1],
        basis);

def bull_stop_stored =
    CompoundValue(1,
        if bull_signal
        then Lowest(low, 2) - atr
        else bull_stop_stored[1],
        Lowest(low, 2) - atr);

def bull_active =
    CompoundValue(1,
        if bull_signal and bull_active[1] == 0
        then 1
        else if bull_active[1] == 1 and
                (high >= bull_target_stored[1] or low < bull_stop_stored[1])
        then 0
        else bull_active[1],
        0);

def bull_target_level = if bull_active then bull_target_stored else Double.NaN;
def bull_stop_level   = if bull_active then bull_stop_stored   else Double.NaN;

# ── Bear trade tracking ──────────────────────────────────
def bear_target_stored =
    CompoundValue(1,
        if bear_signal
        then basis
        else bear_target_stored[1],
        basis);

def bear_stop_stored =
    CompoundValue(1,
        if bear_signal
        then Highest(high, 2) + atr
        else bear_stop_stored[1],
        Highest(high, 2) + atr);

def bear_active =
    CompoundValue(1,
        if bear_signal and bear_active[1] == 0
        then 1
        else if bear_active[1] == 1 and
                (low <= bear_target_stored[1] or high > bear_stop_stored[1])
        then 0
        else bear_active[1],
        0);

def bear_target_level = if bear_active then bear_target_stored else Double.NaN;
def bear_stop_level   = if bear_active then bear_stop_stored   else Double.NaN;

# ── Win/Loss detection for chart bubbles ────────────────
def bull_win  = bull_active[1] == 1 and high >= bull_target_stored[1];
def bull_loss = bull_active[1] == 1 and low  <  bull_stop_stored[1];
def bear_win  = bear_active[1] == 1 and low  <= bear_target_stored[1];
def bear_loss = bear_active[1] == 1 and high >  bear_stop_stored[1];

# ═══════════════════════════════════════════════════════════
# PLOTS — Envelope Bands
# ═══════════════════════════════════════════════════════════

plot UpperBand = upper_band;
UpperBand.SetDefaultColor(GlobalColor("Bearish"));
UpperBand.SetLineWeight(3);

plot LowerBand = lower_band;
LowerBand.SetDefaultColor(GlobalColor("Bullish"));
LowerBand.SetLineWeight(3);

plot XUpperBand = Xupper_band;
plot XLowerBand = Xlower_band;
XupperBand.setdefaultColor(color.gray);
XLowerband.setdefaultColor(color.gray);

plot BasisLine = basis;
BasisLine.SetDefaultColor(GlobalColor("MidLine"));
#BasisLine.SetStyle(Curve.SHORT_DASH);
BasisLine.SetLineWeight(1);

plot Bull = if bull_signal then low - ATR(60) / 2 else Double.NaN;

Bull.SetPaintingStrategy(PaintingStrategy.arrow_up);
Bull.SetDefaultColor(Color.cyan);
Bull.SetLineWeight(3);

plot Bear = if bear_signal then high + ATR(60) / 2 else Double.NaN;

Bear.SetPaintingStrategy(PaintingStrategy.arrow_down);
Bear.SetDefaultColor(Color.magenta);
Bear.SetLineWeight(3);

# Gradient fills (upper zone = bearish, lower zone = bullish)
AddCloud(if cloud then UpperBand else Double.NaN, BasisLine, CreateColor(236, 51, 51), CreateColor(236, 51, 51));
AddCloud(if cloud then BasisLine else Double.NaN, LowerBand, CreateColor(18, 175, 159), CreateColor(18, 175, 159));
AddCloud(if cloud then UpperBand else Double.NaN, XUpperband, color.gray, color.gray);
AddCloud(if cloud then XLowerband else Double.NaN, LowerBand, color.gray, color.gray);

# ═══════════════════════════════════════════════════════════
# PLOTS — Active Stop & Target Dashed Lines
# ═══════════════════════════════════════════════════════════

plot BullTarget = bull_target_level;
BullTarget.SetDefaultColor(GlobalColor("Bullish"));
#BullTarget.SetStyle(Curve.SHORT_DASH);
BullTarget.SetLineWeight(2);

plot BullStop = bull_stop_level;
BullStop.SetDefaultColor(GlobalColor("Bearish"));
#BullStop.SetStyle(Curve.SHORT_DASH);
BullStop.SetLineWeight(2);

plot BearTarget = bear_target_level;
BearTarget.SetDefaultColor(GlobalColor("Bullish"));
#BearTarget.SetStyle(Curve.SHORT_DASH);
BearTarget.SetLineWeight(2);

plot BearStop = bear_stop_level;
BearStop.SetDefaultColor(GlobalColor("Bearish"));
#BearStop.SetStyle(Curve.SHORT_DASH);
BearStop.SetLineWeight(2);

# ═══════════════════════════════════════════════════════════
# SIGNAL LABELS
# ═══════════════════════════════════════════════════════════

# Bull Trap signal bubble (below bar)
AddChartBubble(trapbubble and
    bull_signal,
    low - atr,
    "TRAP UP\nRSI: " + Round(rsi, 0),
    GlobalColor("Bullish"),
    no   # below price
);

# Bear Trap signal bubble (above bar)
AddChartBubble(trapbubble and
    bear_signal,
    high + atr,
    "TRAP DOWN\nRSI: " + Round(rsi, 0),
    GlobalColor("Bearish"),
    yes  # above price
);

# Win confirmation bubbles
AddChartBubble(winbubble and bull_win,  high, "Y", GlobalColor("Bullish"), yes);
AddChartBubble(winbubble and bear_win,  low,  "Y", GlobalColor("Bearish"), no);

AssignPriceColor(
    if !color_candles
    then Color.CURRENT
    else if close > upper_band
    then Color.MAGENTA
    else if close < lower_band
    then Color.green
    else if close > basis
    then GlobalColor("Bearish")
    else GlobalColor("Bullish")
);
 
Last edited:

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

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

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