Traders Dynamic Index (TDI) Indicator for ThinkorSwim

I added a trend up/down column to the watch list.
Not sure this makes much sense, but it helps me with the general stock direction. It's simply based on the BB midline going either up or down.

Code bit needs to be added the end of master code on page #1

Code:
# I used just 5 to see trend changes faster
input length = 5;

def BBmid = Average(BBmidline[1], length);

AddLabel(yes, if BBmidline > bbMid then "Up" else "Down", if BBmidline > bbMid then Color.GREEN else Color.RED);


1716287892036.png
 

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

My fave indicator and go to. I did decide to update it, add color changing bands and. THE BEST: midline dots that indicate when the fast line has overblown the BBs AND is above 75 or below 25. They act as a high probability entry or reversal area.

tdi rsi bbs.PNG


http://tos.mx/!2i1u9sqw

Code:
# ════════════════════════════════════════════════════════════════════════════════════
# LS Traders Dynamic Index — Redesigned Edition
# Stateful color system: every line reports its own state at a glance
# v10 — Overblow signal as persistent dots on 50-line (shows extreme duration)
# ════════════════════════════════════════════════════════════════════════════════════
#
# COLOR LANGUAGE
#   bright green : RSI above upper BB         (extreme bullish blowout)
#   olive        : RSI > 70 inside bands      (normal overbought)
#   bright red   : RSI below lower BB         (extreme bearish blowout)
#   orange       : RSI < 30 inside bands      (normal oversold)
#   gray         : neutral / mid-range
#
# ════════════════════════════════════════════════════════════════════════════════════

declare lower;

# ════════════════════════════════════════════════════════
# INPUTS — RSI
# ════════════════════════════════════════════════════════
input averageType = {default SMA, EMA};
input Period      = 13;
input sm1         = 2;     # Fast smoother (divergence)
input sm2         = 7;     # Slow smoother (50-line bias)

# ════════════════════════════════════════════════════════
# INPUTS — Bollinger Bands of Raw RSI
# ════════════════════════════════════════════════════════
input BBlength = 34;
input BBsdMult = 1.62;

# ════════════════════════════════════════════════════════
# INPUTS — Divergence
# ════════════════════════════════════════════════════════
input divergenceLength = 14;
input divergenceType   = {default regular, reverse};

# ════════════════════════════════════════════════════════
# INPUTS — Display Toggles
# ════════════════════════════════════════════════════════
input showSqueeze     = yes;   # Plum cloud, BB width < 16
input showPreSqueeze  = yes;   # Yellow cloud, BB width 15-20
input showCrossArrows = yes;   # Cyan cross-against-bias arrows
input showVerticals   = yes;   # Vertical lines on BB cross events
input showOverblowDots = yes;  # Persistent dots on 50-line during BB-breach extremes
input overblowOB_level = 75;   # Red dots: RSI >= this AND > uBB
input overblowOS_level = 25;   # Green dots: RSI <= this AND < lBB

# ════════════════════════════════════════════════════════
# GLOBAL COLORS
# ════════════════════════════════════════════════════════
DefineGlobalColor("Plum",          CreateColor(221, 160, 221));
DefineGlobalColor("BlowoutUp",     CreateColor(0, 255, 0));
DefineGlobalColor("BlowoutDown",   CreateColor(255, 30, 30));
DefineGlobalColor("Overbought",    CreateColor(65, 90, 75));    # olive
DefineGlobalColor("Oversold",      CreateColor(40, 80, 80));    # orange
DefineGlobalColor("FastNeutral",   CreateColor(130, 200, 130));  # dim green
DefineGlobalColor("SlowNeutral",   CreateColor(200, 140, 60));   # dim orange
DefineGlobalColor("ChopBlue",      CreateColor(0, 150, 200));
DefineGlobalColor("MidUp",         CreateColor(50, 220, 100));
DefineGlobalColor("MidDown",       CreateColor(220, 60, 60));

# ════════════════════════════════════════════════════════
# CORE CALCULATIONS
# ════════════════════════════════════════════════════════
def RegRSI = reference RSI(Period);

def smRSI1 = if averageType == averageType.SMA
             then Average(RegRSI, sm1)
             else ExpAverage(RegRSI, sm1);

def smRSI2 = if averageType == averageType.SMA
             then Average(RegRSI, sm2)
             else ExpAverage(RegRSI, sm2);

def BBmid = Average(RegRSI, BBlength);
def SDBB  = StDev(RegRSI, BBlength);
def uBB   = BBmid + BBsdMult * SDBB;
def lBB   = BBmid - BBsdMult * SDBB;

# ════════════════════════════════════════════════════════
# STATE ENGINE — drives all coloring
#   1 = blowout up  (RSI > uBB)
#   2 = overbought  (RSI > 70 inside bands)
#  -1 = blowout dn  (RSI < lBB)
#  -2 = oversold    (RSI < 30 inside bands)
#   0 = neutral
# ════════════════════════════════════════════════════════
def state =
    if      RegRSI > uBB then  1
    else if RegRSI > 70  then  2
    else if RegRSI < lBB then -1
    else if RegRSI < 30  then -2
    else                       0;

# ════════════════════════════════════════════════════════
# PLOTS — RSI LINES (state-colored)
# Fast line uses bright variants, slow line uses dimmer variants
# so they remain visually distinct at all times
# ════════════════════════════════════════════════════════

plot RSI1 = smRSI1;
RSI1.SetLineWeight(2);
RSI1.SetStyle(Curve.FIRM);
RSI1.HideBubble();
RSI1.HideTitle();
RSI1.AssignValueColor(
    if      state ==  1 then GlobalColor("BlowoutUp")
    else if state ==  2 then GlobalColor("Overbought")
    else if state == -1 then GlobalColor("BlowoutDown")
    else if state == -2 then GlobalColor("Oversold")
    else                     GlobalColor("FastNeutral")
);

plot RSI2 = smRSI2;
RSI2.SetLineWeight(3);
RSI2.SetStyle(Curve.FIRM);
RSI2.HideBubble();
RSI2.HideTitle();
RSI2.AssignValueColor(
    if      state ==  1 then GlobalColor("BlowoutUp")
    else if state ==  2 then GlobalColor("Overbought")
    else if state == -1 then GlobalColor("BlowoutDown")
    else if state == -2 then GlobalColor("Oversold")
    else                     GlobalColor("SlowNeutral")
);

# ════════════════════════════════════════════════════════
# PLOTS — BB MIDLINE (momentum-state colored)
# Bright lime when RSI rising and above mid (real strength)
# Bright red when RSI falling and below mid (real weakness)
# Dim variants when slope and side disagree (transition)
# ════════════════════════════════════════════════════════
plot BBmidline = BBmid;
BBmidline.SetLineWeight(3);
BBmidline.SetStyle(Curve.FIRM);
BBmidline.HideBubble();
BBmidline.HideTitle();
BBmidline.AssignValueColor(
    if      RegRSI > BBmid and BBmid >= BBmid[1] then GlobalColor("MidUp")
    else if RegRSI < BBmid and BBmid <= BBmid[1] then GlobalColor("MidDown")
    else if BBmid >= BBmid[1]                     then Color.DARK_GREEN
    else                                              Color.DARK_RED
);

# ════════════════════════════════════════════════════════
# PLOTS — BB UPPER/LOWER BANDS
# Brighten when RSI is breaching them, dim otherwise
# ════════════════════════════════════════════════════════
plot uBBline = uBB;
uBBline.SetStyle(Curve.LONG_DASH);
uBBline.SetLineWeight(2);
uBBline.HideBubble();
uBBline.HideTitle();
uBBline.AssignValueColor(
    if state == 1 then GlobalColor("BlowoutUp") else GlobalColor("Plum")
);

plot lBBline = lBB;
lBBline.SetStyle(Curve.LONG_DASH);
lBBline.SetLineWeight(2);
lBBline.HideBubble();
lBBline.HideTitle();
lBBline.AssignValueColor(
    if state == -1 then GlobalColor("BlowoutDown") else GlobalColor("Plum")
);

# ════════════════════════════════════════════════════════
# PLOTS — STATIC GRID
# ════════════════════════════════════════════════════════
plot OB = 68;
OB.SetStyle(Curve.SHORT_DASH);
OB.SetDefaultColor(CreateColor(80, 30, 30));
OB.SetLineWeight(1);
OB.HideTitle();

plot OS = 32;
OS.SetStyle(Curve.SHORT_DASH);
OS.SetDefaultColor(CreateColor(30, 80, 30));
OS.SetLineWeight(1);
OS.HideTitle();

# ════════════════════════════════════════════════════════
# 50 LINE — Chopband-style
# Orange in dead zone (40-60), trade-blue when committed
# Slope-aware: rises greenish, falls reddish at extremes
# ════════════════════════════════════════════════════════
plot ML = 50;
ML.SetStyle(Curve.LONG_DASH);
ML.SetLineWeight(2);
ML.HideTitle();
ML.AssignValueColor(
    if      smRSI2 >= 40 and smRSI2 <= 60 then Color.ORANGE
    else if smRSI2 > 60                    then GlobalColor("ChopBlue")
    else                                        GlobalColor("ChopBlue")
);

# ════════════════════════════════════════════════════════
# CLOUD — RSI2 vs BB midline (bias zone)
# ════════════════════════════════════════════════════════
AddCloud(smRSI2, BBmid,
    CreateColor(0, 100, 50), CreateColor(100, 20, 20)
);

# ════════════════════════════════════════════════════════
# ARROWS — BB cross events (raw RSI)
# ════════════════════════════════════════════════════════
plot ArrowUp = if RegRSI crosses above lBB then lBB else Double.NaN;
ArrowUp.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
ArrowUp.SetLineWeight(4);
ArrowUp.SetDefaultColor(Color.WHITE);
ArrowUp.HideTitle();
ArrowUp.HideBubble();

plot ArrowDN = if RegRSI crosses below uBB then uBB else Double.NaN;
ArrowDN.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
ArrowDN.SetLineWeight(4);
ArrowDN.SetDefaultColor(Color.LIGHT_GRAY);
ArrowDN.HideTitle();
ArrowDN.HideBubble();

# ════════════════════════════════════════════════════════
# ARROWS — RSI cross against BB-midline bias
# ════════════════════════════════════════════════════════
plot ArrowUpST =
    if showCrossArrows and RegRSI crosses above smRSI2 and smRSI2 < BBmid
    then smRSI2 else Double.NaN;
ArrowUpST.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
ArrowUpST.SetLineWeight(3);
ArrowUpST.SetDefaultColor(Color.CYAN);
ArrowUpST.HideTitle();
ArrowUpST.HideBubble();

plot ArrowDNST =
    if showCrossArrows and RegRSI crosses below smRSI2 and smRSI2 > BBmid
    then smRSI2 else Double.NaN;
ArrowDNST.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
ArrowDNST.SetLineWeight(3);
ArrowDNST.SetDefaultColor(Color.CYAN);
ArrowDNST.HideTitle();
ArrowDNST.HideBubble();

# ════════════════════════════════════════════════════════
# OVERBLOW DOTS — Persistent dots on 50-line during extremes
# Red dots while raw RSI > upper BB AND >= overbought threshold
# Green dots while raw RSI < lower BB AND <= oversold threshold
# Dots persist for the full duration of the extreme — cluster size
# is a visual read on how long the overblow has held.
# ════════════════════════════════════════════════════════
def buyOverblow  = RegRSI < lBB and RegRSI <= overblowOS_level;
def sellOverblow = RegRSI > uBB and RegRSI >= overblowOB_level;

plot OverblowBuyDot  = if showOverblowDots and buyOverblow  then 50 else Double.NaN;
OverblowBuyDot.SetPaintingStrategy(PaintingStrategy.LINE_VS_POINTS);
OverblowBuyDot.SetLineWeight(5);
OverblowBuyDot.SetDefaultColor(CreateColor(50, 255, 100));
OverblowBuyDot.HideTitle();
OverblowBuyDot.HideBubble();

plot OverblowSellDot = if showOverblowDots and sellOverblow then 50 else Double.NaN;
OverblowSellDot.SetPaintingStrategy(PaintingStrategy.LINE_VS_POINTS);
OverblowSellDot.SetLineWeight(5);
OverblowSellDot.SetDefaultColor(CreateColor(255, 50, 50));
OverblowSellDot.HideTitle();
OverblowSellDot.HideBubble();

# ════════════════════════════════════════════════════════
# VERTICAL LINES — BB cross events on smRSI1
# ════════════════════════════════════════════════════════
AddVerticalLine(
    showVerticals and smRSI1 > lBB and smRSI1[1] <= lBB,
    "↑", Color.GREEN, Curve.FIRM
);

AddVerticalLine(
    showVerticals and smRSI1 < uBB and smRSI1[1] >= uBB,
    "↓", Color.RED, Curve.FIRM
);

# ════════════════════════════════════════════════════════
# DIVERGENCE ENGINE — RSI1 (fast) vs Price
#   regular : Price HH + RSI LH = bear | Price LL + RSI HL = bull
#   reverse : Price LH + RSI HH = bear | Price HL + RSI LL = bull (hidden)
# Logic preserved verbatim from v6
# ════════════════════════════════════════════════════════
def K = smRSI1;

def pivotTop    = K[1] == Highest(K, divergenceLength + 1) and K[1] > K[2];
def pivotBottom = K[1] == Lowest(K,  divergenceLength + 1) and K[1] < K[2];

# ─── Bearish: track last pivot high ───
def hiBars;
def hiInd;
def hiPrice;
if pivotTop {
    hiBars  = 1;
    hiInd   = K[1];
    hiPrice = Max(high[2], Max(high[1], high[0]));
} else {
    hiBars  = hiBars[1] + 1;
    hiInd   = hiInd[1];
    hiPrice = hiPrice[1];
}

def xDownBars;
def xDowns;
if K < K[1] and K[1] >= K[2] {
    xDownBars = 1;
    xDowns    = xDowns[1] + 1;
} else {
    xDownBars = xDownBars[1] + 1;
    xDowns    = if pivotTop[1] then 0 else xDowns[1];
}

def bearCond;
switch (divergenceType) {
case regular:
    bearCond =
        K < K[1] and
        high[1] == Highest(high, divergenceLength + 1) and
        hiBars[1] > xDownBars[1] and
        xDowns == 1 and
        hiPrice[1] < high[1] and
        hiInd[1] > K[1];
case reverse:
    bearCond =
        K < K[1] and
        hiPrice[1] > high[1] and
        hiInd[1] < K[1];
}

plot bearishd = if bearCond then K[1] else Double.NaN;
bearishd.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
bearishd.SetDefaultColor(Color.MAGENTA);
bearishd.SetLineWeight(3);
bearishd.HideTitle();
bearishd.HideBubble();

# Bearish trendline
def countBear  = if bearCond[-1] then countBear[1] + 1 else countBear[1];
def recentBear = countBear == HighestAll(countBear);
def secHigh    = HighestAll(if bearCond[-1] and recentBear then K else Double.NaN);
def FH_bar     = HighestAll(if recentBear and bearCond[-1] and K == secHigh
                            then GetValue(BarNumber(), hiBars) else Double.NaN);

plot bearTrendline =
    if recentBear and bearCond[-1] and K == secHigh then Max(K[1], K[0])
    else if FH_bar == BarNumber()                   then K
    else                                                  Double.NaN;
bearTrendline.EnableApproximation();
bearTrendline.SetDefaultColor(Color.MAGENTA);
bearTrendline.SetLineWeight(2);
bearTrendline.SetStyle(Curve.SHORT_DASH);
bearTrendline.HideBubble();
bearTrendline.HideTitle();

# ─── Bullish: track last pivot low ───
def loBars;
def loInd;
def loPrice;
if pivotBottom {
    loBars  = 1;
    loInd   = K[1];
    loPrice = Min(low[2], Min(low[1], low[0]));
} else {
    loBars  = loBars[1] + 1;
    loInd   = loInd[1];
    loPrice = loPrice[1];
}

def xUpBars;
def xUps;
if K > K[1] and K[1] <= K[2] {
    xUpBars = 1;
    xUps    = xUps[1] + 1;
} else {
    xUpBars = xUpBars[1] + 1;
    xUps    = if pivotBottom[1] then 0 else xUps[1];
}

def bullCond;
switch (divergenceType) {
case regular:
    bullCond =
        K > K[1] and
        low[1] == Lowest(low, divergenceLength + 1) and
        loBars[1] > xUpBars[1] and
        xUps == 1 and
        loPrice[1] > low[1] and
        loInd[1] < K[1];
case reverse:
    bullCond =
        K > K[1] and
        loPrice[1] < low[1] and
        loInd[1] > K[1];
}

plot bullishd = if bullCond then K[1] else Double.NaN;
bullishd.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
bullishd.SetDefaultColor(Color.YELLOW);
bullishd.SetLineWeight(3);
bullishd.HideTitle();
bullishd.HideBubble();

# Bullish trendline
def countBull  = if bullCond[-1] then countBull[1] + 1 else countBull[1];
def recentBull = countBull == HighestAll(countBull);
def secLow     = HighestAll(if bullCond[-1] and recentBull then K else Double.NaN);
def FL_bar     = HighestAll(if recentBull and bullCond[-1] and K == secLow
                            then GetValue(BarNumber(), loBars) else Double.NaN);

plot bullTrendline =
    if recentBull and bullCond[-1] and K == secLow then Min(K[1], K[0])
    else if FL_bar == BarNumber()                  then K[0]
    else                                                 Double.NaN;
bullTrendline.EnableApproximation();
bullTrendline.SetDefaultColor(Color.YELLOW);
bullTrendline.SetLineWeight(2);
bullTrendline.SetStyle(Curve.SHORT_DASH);
bullTrendline.HideBubble();
bullTrendline.HideTitle();

# ════════════════════════════════════════════════════════
# SQUEEZE & PRE-SQUEEZE CLOUDS
# ════════════════════════════════════════════════════════
def bbWidth      = uBB - lBB;
def bbSqueeze    = bbWidth < 16;
def bbPreSqueeze = bbWidth >= 15 and bbWidth < 20;

AddCloud(
    if showSqueeze and bbSqueeze then uBB else Double.NaN,
    if showSqueeze and bbSqueeze then lBB else Double.NaN,
    GlobalColor("Plum"), GlobalColor("Plum")
);

AddCloud(
    if showPreSqueeze and bbPreSqueeze then uBB else Double.NaN,
    if showPreSqueeze and bbPreSqueeze then lBB else Double.NaN,
    Color.YELLOW, Color.YELLOW
);

# ════════════════════════════════════════════════════════
# MOMENTUM DISTANCES (defs only — for scans/strategy use)
# ════════════════════════════════════════════════════════
def distToBB_Lower    = smRSI2 - smRSI1;
def distToBB_Lower_3P = smRSI2[3] - smRSI1[3];
def distToBB_Lower_1P = smRSI2[1] - smRSI1[1];
def distToBB_Upper    = smRSI1 - smRSI2;
def distToBB_Upper_3P = smRSI1[3] - smRSI2[3];
def distToBB_Upper_1P = smRSI1[1] - smRSI2[1];
def pctChange3Lower   = (distToBB_Lower - distToBB_Lower_3P) / distToBB_Lower_3P * 100;
def pctChange1Lower   = (distToBB_Lower - distToBB_Lower_1P) / distToBB_Lower_1P * 100;
def pctChange3Upper   = (distToBB_Upper - distToBB_Upper_3P) / distToBB_Upper_3P * 100;
def pctChange1Upper   = (distToBB_Upper - distToBB_Upper_1P) / distToBB_Upper_1P * 100;

# === END ===
 
Last edited:

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

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