Absolute Strength Index [ASI] (Zeiierman) For ThinkOrSwim

snoopydoopy

New member
VIP
General Overview from the About Script Page:
The Absolute Strength Index (ASI) is a next-generation oscillator designed to measure the strength and direction of price movements by leveraging percentile-based normalization of historical returns. Developed by Zeiierman, this indicator offers a highly visual and intuitive approach to identifying market conditions, trend strength, and divergence opportunities.

By dynamically scaling price returns into a bounded oscillator (-10 to +10), the ASI helps traders spot overbought/oversold conditions, trend reversals, and momentum changes with enhanced precision. It also incorporates advanced features like divergence detection and adaptive signal smoothing for versatile trading applications.

4NBK7z3.png

Here is the original Tradingview code:
https://www.tradingview.com/script/EFGQPt1E-Absolute-Strength-Index-ASI-Zeiierman/

For the new ThinkOrSwim code, you must scroll down to the next post
 
Last edited by a moderator:
Hi there! Long time reader first time poster.

I am in the Zeiierman discord and he just released this morning a new take on RSI called the Absolute Strength Index [ASI] Zeiierman on TradingView. It is not a paid indicator, he released it as open source on TradingView so I believe that it is ok for us to try and convert it as it is not commercial code (I have come across a couple threads where members have pointed out we can't convert commercial code).

I am going to try to convert it through ChatGPT / Claude but I have had a lot of issues in the past trying to convert more complex scripts from pine to thinkscript but I will post an update here if I have any luck with this one

@samer800 I have come across your name a lot in TV conversions, apologies if I am not supposed to tag you but would much appreciate if you could take a look! Thanks :)

You can find more information about the ASI here

General Overview from the About Script Page:
The Absolute Strength Index (ASI) is a next-generation oscillator designed to measure the strength and direction of price movements by leveraging percentile-based normalization of historical returns. Developed by Zeiierman, this indicator offers a highly visual and intuitive approach to identifying market conditions, trend strength, and divergence opportunities.

snapshot

By dynamically scaling price returns into a bounded oscillator (-10 to +10), the ASI helps traders spot overbought/oversold conditions, trend reversals, and momentum changes with enhanced precision. It also incorporates advanced features like divergence detection and adaptive signal smoothing for versatile trading applications.

TradingView code below:


Code:
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © Zeiierman {
//@version=6
indicator('Absolute Strength Index [ASI] (Zeiierman)', overlay = false, precision = 1)
//~~}

//~~ Tooltips {
string t1 = 'Returns Lookback: Sets the number of previous bars to consider when calculating returns. A higher value makes the oscillator smoother, reducing sensitivity to short-term price changes.'
string t2 = 'Top Percentile (Winners): Defines the percentile threshold for identifying top-performing returns. Determines the cutoff for considering returns as winners.'
string t3 = 'Bottom Percentile (Losers): Defines the percentile threshold for identifying bottom-performing returns. Determines the cutoff for considering returns as losers.'
string t4 = 'MA Type: Select the type of moving average to apply to the ASI. Options include:\n\n• None: No Moving Average.\n• SMA: Simple Moving Average.\n• EMA: Exponential Moving Average.\n• WMA: Weighted Moving Average.\n• RMA: Running Moving Average.\n• HMA: Hull Moving Average.'
string t5 = 'MA Length: Sets the length for the selected moving average type. A longer length results in a smoother moving average, while a shorter length makes it more responsive to recent changes.'
string t6 = 'Divergence: Enables or disables the divergence detection feature. When enabled, the indicator will plot bullish and bearish divergence signals based on ASI and price action.'
string t7 = 'Lookback: Sets the number of bars used to detect divergences. A larger lookback period makes divergence detection less sensitive, filtering out minor fluctuations, while a smaller period increases sensitivity to recent changes.'
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~  Enum Definition {
enum MA_Type
    SMA = "SMA"
    EMA = "EMA"
    WMA = "WMA"
    RMA = "RMA"
    HMA = "HMA"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Inputs {
returnLookback   = input.int(15, 'Returns Lookback', minval=3, group="Absolute Strength Index [ASI]", inline="", tooltip=t1)
topPercentile    = input.float(0.15, 'Top Percentile (Winners)', minval = 0.05, maxval = 0.3, step=0.01, group="Absolute Strength Index [ASI]", inline="", tooltip=t2)
bottomPercentile = input.float(0.15, 'Bottom Percentile (Losers)', minval = 0.05, maxval = 0.3, step=0.01, group="Absolute Strength Index [ASI]", inline="", tooltip=t3)

maTypeInput   = input.enum(MA_Type.SMA, title="Signal Line", group="Absolute Strength Index [ASI]", inline="", tooltip=t4)
maLengthInput = input.int(14, "Signal Length", group="Absolute Strength Index [ASI]", inline="", tooltip=t5)

asiColor   = input.color(color.blue, title="", group="Absolute Strength Index [ASI]", inline="ASI style")
maAsiColor = input.color(color.yellow, title="", group="Absolute Strength Index [ASI]", inline="ASI style")
fillColor  = input.color(#94def0, title="", group="Absolute Strength Index [ASI]", inline="ASI style")

obColor  = input.color(color.lime, title="", group="Absolute Strength Index [ASI]", inline="ASI style")
osColor  = input.color(color.red, title="", group="Absolute Strength Index [ASI]", inline="ASI style")

calculateDivergence = input.bool(false, title="Divergence", group="Divergence", inline="", tooltip=t6)
lookback            = input.int(20, title="lookback", minval=1, group="Divergence", inline="", tooltip=t7)
bearColor = input.color(color.red, title="", group="Divergence", inline="style")
bullColor = input.color(color.green, title="", group="Divergence", inline="style")
textColor = input.color(color.white, title="", group="Divergence", inline="style")
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~  Calculate Returns {
Returns = array.new_float()

for i = 1 to returnLookback
    if not na(close[i]) and not na(close[i + 1])
        ret = close[i] / close[i + 1] - 1
        Returns.push(ret)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~  Calculate ASI {
ASI  = 0.0
if Returns.size() > 0
    sortedReturns = Returns.copy()
    sortedReturns.sort(order.ascending)

    // Determine Thresholds for Winners and Losers
    thresholdWinnerIndex = math.ceil(sortedReturns.size() * (1 - topPercentile)) - 1
    thresholdLoserIndex  = math.ceil(sortedReturns.size() * bottomPercentile) - 1

    // Handle edge cases
    thresholdWinner = thresholdWinnerIndex >= 0 and thresholdWinnerIndex < sortedReturns.size() ? sortedReturns.get(thresholdWinnerIndex) : 0
    thresholdLoser  = thresholdLoserIndex >= 0 and thresholdLoserIndex < sortedReturns.size()  ? sortedReturns.get(thresholdLoserIndex)  : 0

    // Current Return based on the oldest close in the lookback
    currentReturn = close / close[returnLookback] - 1

    // Normalize Oscillator Value
    if not na(currentReturn) and (thresholdWinner - thresholdLoser) != 0
        ASI := (currentReturn - thresholdLoser) / (thresholdWinner - thresholdLoser) * 2 - 1
    else
        ASI := 0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~  Smoothing MA Calculation {
smoothingMA = 0.0
smoothingMA := switch maTypeInput
    MA_Type.SMA => ta.sma(ASI, maLengthInput)
    MA_Type.EMA => ta.ema(ASI, maLengthInput)
    MA_Type.WMA => ta.wma(ASI, maLengthInput)
    MA_Type.RMA => ta.rma(ASI, maLengthInput)
    MA_Type.HMA => ta.hma(ASI, maLengthInput)
    => na
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Divergence {
var float prevASILow    = na
var float prevPriceLow  = na
var float prevASIHigh   = na
var float prevPriceHigh = na

plFound = false
phFound = false

bullCond = false
bearCond = false

if calculateDivergence
    // --- Bullish Divergence Detection ---
    // Check if current ASI is the lowest in the lookback period
    isASILow = ASI == ta.lowest(ASI, lookback)
    plFound := isASILow
   
    if (isASILow)
        // Check if previous ASI low exists and current ASI low is higher
        if (not na(prevASILow) and ASI > prevASILow and low < prevPriceLow)
            bullCond := true
            // Update previous lows
            prevASILow := ASI
            prevPriceLow := low
        else
            // Initialize or reset previous lows
            prevASILow := ASI
            prevPriceLow := low
            bullCond := false
    else
        bullCond := false

    // --- Bearish Divergence Detection ---
    // Check if current ASI is the highest in the lookback period
    isASIHigh = ASI == ta.highest(ASI, lookback)
    phFound := isASIHigh
   
    if (isASIHigh)
        // Check if previous ASI high exists and current ASI high is lower
        if (not na(prevASIHigh) and ASI < prevASIHigh and high > prevPriceHigh)
            bearCond := true
            // Update previous highs
            prevASIHigh := ASI
            prevPriceHigh := high
        else
            // Initialize or reset previous highs
            prevASIHigh := ASI
            prevPriceHigh := high
            bearCond := false
    else
        bearCond := false
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~  Plot ASI {
ASIPlot      = plot(ASI, "ASI", color=asiColor)
ASIMAPlot    = plot(smoothingMA, "ASI-based MA", color=maAsiColor)
ASIUpperBand = hline(8, "ASI Upper Band", color=fillColor)
midline      = hline(0, "ASI Middle Band", color=color.new(fillColor, 50))
ASILowerBand = hline(-8, "ASI Lower Band", color=fillColor)
midLinePlot  = plot(0, color = na, editable = false, display = display.none)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Fill {
fill(ASIUpperBand, ASILowerBand, color=color.new(fillColor,90),title="ASI Background Fill")
fill(ASIPlot, midLinePlot, 8, 5, top_color = color.new(obColor, 0), bottom_color = color.new(obColor, 100),title = "Overbought Gradient Fill")
fill(ASIPlot, midLinePlot, -5,  -8,  top_color = color.new(osColor, 100), bottom_color = color.new(osColor, 0),title = "Oversold Gradient Fill")
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~  Plot Bullish Divergence {
plot(plFound?ASI:na, title="ASI Bullish Divergence", linewidth=2,color=(bullCond ? bullColor : na), display = display.pane)
plotshape(bullCond?ASI:na,  title="ASI Bullish Divergence Label",text="Bull",  style=shape.labelup,location=location.absolute,color=bullColor, textcolor=textColor)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~  Plot Bearish Divergence {
plot(phFound?ASI:na, title="ASI Bearish Divergence", linewidth=2, color=(bearCond?bearColor:na),display = display.pane)
plotshape(bearCond?ASI:na,title="ASI Bearish Divergence Label", text="Bear", style=shape.labeldown,location=location.absolute,color=bearColor,textcolor=textColor)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Divergence Alerts {
alertcondition(bullCond, title='Regular Bullish Divergence', message="Found a new Regular Bullish Divergence")
alertcondition(bearCond, title='Regular Bearish Divergence', message='Found a new Regular Bearish Divergence')
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
check below.

CSS:
#// Indicator for TOS
#// © Zeiierman {
#indicator('Absolute Strength Index [ASI] (Zeiierman)', overlay = false, precision = 1
#Hint returnLookback: Sets the number of previous bars to consider when calculating returns. A higher value makes the oscillator smoother, reducing sensitivity to short-term price changes.
#hint topPercentile: (Winners): Defines the percentile threshold for identifying top-performing returns. Determines the cutoff for considering returns as winners.
#Hint bottomPercentile: (Losers): Defines the percentile threshold for identifying bottom-performing returns. Determines the cutoff for considering returns as losers.
#Hint showDivergence: Enables or disables the divergence detection feature. When enabled, the indicator will plot bullish and bearish divergence signals based on ASI and price action.
#Hint DivergenceLookback: Sets the number of bars used to detect divergences. A larger lookback period makes divergence detection less sensitive, filtering out minor fluctuations, while a smaller period increases sensitivity to recent changes.

#- Converted by Sam4Cok@Samer800    - 01/2025
declare lower;

input colorBars = no;
input returnLookback   = 15;         # 'Returns Lookback'
input topPercentile    = 0.15;       # 'Top Percentile (Winners)'
input bottomPercentile = 0.15;       # 'Bottom Percentile (Losers)'
input smoothingMovAvg  = AverageType.SIMPLE;     # "Signal Line"
input smoothingLength = 14;                      # "Signal Length"
input showDivergence = no;           # "Divergence"
input DivergenceLookback = 20;       # "lookback"

def na = Double.NaN;
def last = IsNaN(close);
def lookback = Max(returnLookback, 3);
def top = Min(0.95, Max(topPercentile, 0.05));
def bot = Min(0.95, Max(bottomPercentile, 0.05));
def n = n[1] + 1;
def bar = if !last then n else bar[1];
def FinalBar = if !IsNaN(close) then HighestAll(bar) else FinalBar[1];
def startFold = (bar - FinalBar) + 1;
def endFold = (startFold + lookback);

#Rolling Rank
def returns = if !isNaN(close[1]) and close[2] then (close[1] / close[2]) else returns[1];
def rankLab = fold i = startFold to endFold with q = 1 do
              if isNaN(GetValue(close, i) / GetValue(close, i + 1)) then q else
              if returns > (GetValue(close, i) / GetValue(close, i + 1)) then q + 1 else q;
#// Handle edge cases
def thresholdWinnerIndex = Ceil(lookback * (1 - top));
def thresholdLoserIndex  = Ceil(lookback * bot);

def sortedWin = if rankLab == thresholdWinnerIndex then returns - 1 else sortedWin[1];
def sortedLos = if rankLab == thresholdLoserIndex  then returns - 1 else sortedLos[1];
def thresholdWinner = if thresholdWinnerIndex >= 0 and thresholdWinnerIndex < lookback then sortedWin else 0;
def thresholdLoser  = if thresholdLoserIndex >= 0  and thresholdLoserIndex  < lookback then sortedLos else 0;

#// Current Return based on the oldest close in the lookback
def currentReturn = close / close[lookback] - 1;
#// Normalize Oscillator Value
def ASI;
    if !isNaN(currentReturn) and (thresholdWinner - thresholdLoser) != 0 {
        ASI = (currentReturn - thresholdLoser) / (thresholdWinner - thresholdLoser) * 2 - 1;
    } else {
        ASI = 0;
    }
def smoothingMA = MovingAverage(smoothingMovAvg, ASI, smoothingLength);

plot asiLine  = if last then na else ASI;
plot smoothMa = if last then na else smoothingMA;
plot ASIUpperBand = if last then na else 8;  # "ASI Upper Band"
plot midline      = if last then na else 0;  # "ASI Middle Band"
plot ASILowerBand = if last then na else -8; # "ASI Lower Band"

smoothMa.SetLineWeight(1);
asiLine.SetDefaultColor(Color.CYAN);
smoothMa.SetDefaultColor(Color.ORANGE);
ASIUpperBand.SetPaintingStrategy(PaintingStrategy.DASHES);
midline.SetStyle(Curve.SHORT_DASH);
ASILowerBand.SetPaintingStrategy(PaintingStrategy.DASHES);
ASIUpperBand.SetDefaultColor(Color.GRAY);
midline.SetDefaultColor(Color.DARK_GRAY);
ASILowerBand.SetDefaultColor(Color.GRAY);

AddCloud(asiLine, 8, Color.GREEN, Color.CURRENT);
AddCloud(asiLine, 5, Color.GREEN, Color.CURRENT);
AddCloud(-5, asiLine, Color.RED, Color.CURRENT);
AddCloud(-8, asiLine, Color.RED, Color.CURRENT);

#-- bar color
AssignPriceColor(if !colorBars then Color.CURRENT else
                 if asiLine > 0 then
                 if asiLine > smoothMa then Color.GREEN else Color.DARK_GREEN else
                 if asiLine < smoothMa then Color.RED else Color.DARK_RED);

#// ~~ Divergence {
def prevASILow; #    = na
def prevPriceLow; #  = na
def prevASIHigh; #   = na
def prevPriceHigh; # = na
def bullCond; # = false
def bearCond; # = false
def lastBarL;
def prevBarL;
def plBar;
def lastBarH;
def prevBarH;
def phBar;
def phFound = ASI == highest(ASI, DivergenceLookback);
def plFound = ASI == lowest(ASI, DivergenceLookback);

if (plFound) and showDivergence {
    plBar = bar;
    if (prevASILow[1] and ASI > prevASILow[1] and low < prevPriceLow[1]) {
        bullCond = yes;
        prevASILow = ASI;
        prevPriceLow = low;
        prevBarL = plBar[1];
        lastBarL = bar;
        } else {
        prevASILow = ASI;
        prevPriceLow = low;
        bullCond = no;
        prevBarL = 0;
        lastBarL = 0;}
    } else {
    plBar = plBar[1];
    prevASILow = prevASILow[1];
    prevPriceLow = prevPriceLow[1];
    bullCond = no;
    prevBarL = 0;
    lastBarL = 0;
    }
if (phFound) and showDivergence {
    phBar = bar;
    if (prevASIHigh[1] and ASI < prevASIHigh[1] and high > prevPriceHigh[1]) {
        bearCond = yes;
        prevASIHigh = ASI;
        prevPriceHigh = high;
        prevBarH = phBar[1];
        lastBarH = bar;
        } else {
        prevASIHigh = ASI;
        prevPriceHigh = high;
        bearCond = no;
        prevBarH = 0;
        lastBarH = 0;}
    } else {
    phBar = phBar[1];
    prevASIHigh = prevASIHigh[1];
    prevPriceHigh = prevPriceHigh[1];
    bearCond = no;
    prevBarH = 0;
    lastBarH = 0;
    }

plot bullDiv = if last then na else
               if bar == highestAll(prevBarL) then ASI else
               if bar == highestAll(lastBarL) then ASI else na;
plot bearDiv = if last then na else
               if bar == highestAll(prevBarH) then ASI else
               if bar == highestAll(lastBarH) then ASI else na;
bullDiv.SetDefaultColor(Color.GREEN);
bearDiv.SetDefaultColor(Color.RED);
bullDiv.EnableApproximation();
bearDiv.EnableApproximation();

AddChartBubble(bullCond, ASI, "Bull", Color.GREEN, no); #  "ASI Bullish Divergence Label"
AddChartBubble(bearCond, ASI, "Bear", Color.RED);       #  "ASI Bearish Divergence Label"

#-- END OF CODE
 
check below.

CSS:
#// Indicator for TOS
#// © Zeiierman {
#indicator('Absolute Strength Index [ASI] (Zeiierman)', overlay = false, precision = 1
#Hint returnLookback: Sets the number of previous bars to consider when calculating returns. A higher value makes the oscillator smoother, reducing sensitivity to short-term price changes.
#hint topPercentile: (Winners): Defines the percentile threshold for identifying top-performing returns. Determines the cutoff for considering returns as winners.
#Hint bottomPercentile: (Losers): Defines the percentile threshold for identifying bottom-performing returns. Determines the cutoff for considering returns as losers.
#Hint showDivergence: Enables or disables the divergence detection feature. When enabled, the indicator will plot bullish and bearish divergence signals based on ASI and price action.
#Hint DivergenceLookback: Sets the number of bars used to detect divergences. A larger lookback period makes divergence detection less sensitive, filtering out minor fluctuations, while a smaller period increases sensitivity to recent changes.

#- Converted by Sam4Cok@Samer800    - 01/2025
declare lower;

input colorBars = no;
input returnLookback   = 15;         # 'Returns Lookback'
input topPercentile    = 0.15;       # 'Top Percentile (Winners)'
input bottomPercentile = 0.15;       # 'Bottom Percentile (Losers)'
input smoothingMovAvg  = AverageType.SIMPLE;     # "Signal Line"
input smoothingLength = 14;                      # "Signal Length"
input showDivergence = no;           # "Divergence"
input DivergenceLookback = 20;       # "lookback"

def na = Double.NaN;
def last = IsNaN(close);
def lookback = Max(returnLookback, 3);
def top = Min(0.95, Max(topPercentile, 0.05));
def bot = Min(0.95, Max(bottomPercentile, 0.05));
def n = n[1] + 1;
def bar = if !last then n else bar[1];
def FinalBar = if !IsNaN(close) then HighestAll(bar) else FinalBar[1];
def startFold = (bar - FinalBar) + 1;
def endFold = (startFold + lookback);

#Rolling Rank
def returns = if !isNaN(close[1]) and close[2] then (close[1] / close[2]) else returns[1];
def rankLab = fold i = startFold to endFold with q = 1 do
              if isNaN(GetValue(close, i) / GetValue(close, i + 1)) then q else
              if returns > (GetValue(close, i) / GetValue(close, i + 1)) then q + 1 else q;
#// Handle edge cases
def thresholdWinnerIndex = Ceil(lookback * (1 - top));
def thresholdLoserIndex  = Ceil(lookback * bot);

def sortedWin = if rankLab == thresholdWinnerIndex then returns - 1 else sortedWin[1];
def sortedLos = if rankLab == thresholdLoserIndex  then returns - 1 else sortedLos[1];
def thresholdWinner = if thresholdWinnerIndex >= 0 and thresholdWinnerIndex < lookback then sortedWin else 0;
def thresholdLoser  = if thresholdLoserIndex >= 0  and thresholdLoserIndex  < lookback then sortedLos else 0;

#// Current Return based on the oldest close in the lookback
def currentReturn = close / close[lookback] - 1;
#// Normalize Oscillator Value
def ASI;
    if !isNaN(currentReturn) and (thresholdWinner - thresholdLoser) != 0 {
        ASI = (currentReturn - thresholdLoser) / (thresholdWinner - thresholdLoser) * 2 - 1;
    } else {
        ASI = 0;
    }
def smoothingMA = MovingAverage(smoothingMovAvg, ASI, smoothingLength);

plot asiLine  = if last then na else ASI;
plot smoothMa = if last then na else smoothingMA;
plot ASIUpperBand = if last then na else 8;  # "ASI Upper Band"
plot midline      = if last then na else 0;  # "ASI Middle Band"
plot ASILowerBand = if last then na else -8; # "ASI Lower Band"

smoothMa.SetLineWeight(1);
asiLine.SetDefaultColor(Color.CYAN);
smoothMa.SetDefaultColor(Color.ORANGE);
ASIUpperBand.SetPaintingStrategy(PaintingStrategy.DASHES);
midline.SetStyle(Curve.SHORT_DASH);
ASILowerBand.SetPaintingStrategy(PaintingStrategy.DASHES);
ASIUpperBand.SetDefaultColor(Color.GRAY);
midline.SetDefaultColor(Color.DARK_GRAY);
ASILowerBand.SetDefaultColor(Color.GRAY);

AddCloud(asiLine, 8, Color.GREEN, Color.CURRENT);
AddCloud(asiLine, 5, Color.GREEN, Color.CURRENT);
AddCloud(-5, asiLine, Color.RED, Color.CURRENT);
AddCloud(-8, asiLine, Color.RED, Color.CURRENT);

#-- bar color
AssignPriceColor(if !colorBars then Color.CURRENT else
                 if asiLine > 0 then
                 if asiLine > smoothMa then Color.GREEN else Color.DARK_GREEN else
                 if asiLine < smoothMa then Color.RED else Color.DARK_RED);

#// ~~ Divergence {
def prevASILow; #    = na
def prevPriceLow; #  = na
def prevASIHigh; #   = na
def prevPriceHigh; # = na
def bullCond; # = false
def bearCond; # = false
def lastBarL;
def prevBarL;
def plBar;
def lastBarH;
def prevBarH;
def phBar;
def phFound = ASI == highest(ASI, DivergenceLookback);
def plFound = ASI == lowest(ASI, DivergenceLookback);

if (plFound) and showDivergence {
    plBar = bar;
    if (prevASILow[1] and ASI > prevASILow[1] and low < prevPriceLow[1]) {
        bullCond = yes;
        prevASILow = ASI;
        prevPriceLow = low;
        prevBarL = plBar[1];
        lastBarL = bar;
        } else {
        prevASILow = ASI;
        prevPriceLow = low;
        bullCond = no;
        prevBarL = 0;
        lastBarL = 0;}
    } else {
    plBar = plBar[1];
    prevASILow = prevASILow[1];
    prevPriceLow = prevPriceLow[1];
    bullCond = no;
    prevBarL = 0;
    lastBarL = 0;
    }
if (phFound) and showDivergence {
    phBar = bar;
    if (prevASIHigh[1] and ASI < prevASIHigh[1] and high > prevPriceHigh[1]) {
        bearCond = yes;
        prevASIHigh = ASI;
        prevPriceHigh = high;
        prevBarH = phBar[1];
        lastBarH = bar;
        } else {
        prevASIHigh = ASI;
        prevPriceHigh = high;
        bearCond = no;
        prevBarH = 0;
        lastBarH = 0;}
    } else {
    phBar = phBar[1];
    prevASIHigh = prevASIHigh[1];
    prevPriceHigh = prevPriceHigh[1];
    bearCond = no;
    prevBarH = 0;
    lastBarH = 0;
    }

plot bullDiv = if last then na else
               if bar == highestAll(prevBarL) then ASI else
               if bar == highestAll(lastBarL) then ASI else na;
plot bearDiv = if last then na else
               if bar == highestAll(prevBarH) then ASI else
               if bar == highestAll(lastBarH) then ASI else na;
bullDiv.SetDefaultColor(Color.GREEN);
bearDiv.SetDefaultColor(Color.RED);
bullDiv.EnableApproximation();
bearDiv.EnableApproximation();

AddChartBubble(bullCond, ASI, "Bull", Color.GREEN, no); #  "ASI Bullish Divergence Label"
AddChartBubble(bearCond, ASI, "Bear", Color.RED);       #  "ASI Bearish Divergence Label"

#-- END OF CODE

Thanks so much Sam! Looks great!!

Below I stacked your version on top and the trading view version below. I REALLY like how you did the gradient of a different gray from 0 to 5 and then 5 to 8 and then the different gradients for red and green look awesome.

It seems like the values are slightly different between the TV version and your TOS version but I think that has to be from how the two platforms calculate the values differently correct? Because the settings for calculated values are the same for both so it must be just a difference in how the platforms calculate values during the candle forming? Either way looks awesome and excited to play around with it and see how it performs!! Thanks again

1736516940931.png
 
Thanks so much Sam! Looks great!!

Below I stacked your version on top and the trading view version below. I REALLY like how you did the gradient of a different gray from 0 to 5 and then 5 to 8 and then the different gradients for red and green look awesome.

It seems like the values are slightly different between the TV version and your TOS version but I think that has to be from how the two platforms calculate the values differently correct? Because the settings for calculated values are the same for both so it must be just a difference in how the platforms calculate values during the candle forming? Either way looks awesome and excited to play around with it and see how it performs!! Thanks again

View attachment 23744
original code contais arrays with sorted function which not supported by TOS. this is the best I could reach.
 

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
297 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