Need Help Eliminating NaN values in Indicator

armybender

Active member
Hello,

Can someone help eliminate the NaN values in these defs / plots?

More detail:
I adapted an indicator from THIS PAGE. What I'm finding is that the upperChannelData and lowerChannelData defs have NaN values. I'm trying to build something on top of this, and the NaN values make it impossible to do.

EnableApproximation is turned on for the plots, so you don't see the gaps, but if you disable that line of code the gaps become very clear.

Here's the indicator code.

Ruby:
# Adapted from https://usethinkscript.com/threads/supertrend-channels-luxalgo-for-thinkorswim.15377/

#DECLARATIONS
declare upper;


#USER INPUTS
input showSuperTrendChannel = yes;
input show2XChannel         = no;
input showCloud             = no;
input atrLength             = 14;
input atrMultiple           = 3.0;
input smoothLength          = 3;
input price                 = close;
input showDotsOnBreakout    = no;
input dotSeparationTicks    = 2;
input alertOnTouch          = no;


#GLOBAL COLOR DEFINITIONS
DefineGlobalColor("Blue" , CreateColor(33, 150, 243));
DefineGlobalColor("Green", CreateColor(0, 155, 0));
DefineGlobalColor("Red", CreateColor(225, 105, 105));
DefineGlobalColor("Gray", CreateColor(181, 181, 181));


#DEFINITIONS AND CALCULATIONS
## These variables must be declared early as they are used in preceeding calculations
def upperBand;
def lowerBand;
def max;
def min;

## Standard variable calculations
def nATR = MovingAverage(AverageType.WILDERS, TrueRange(high, close, low), atrLength) * atrMultiple;     #ATR
def up = hl2 + nATR;
def dn = hl2 - nATR;
def up1 = if (IsNaN(upperBand[1]) or upperBand[1] == 0) then up else upperBand[1];
def dn1 = if (IsNaN(lowerBand[1]) or lowerBand[1] == 0) then dn else lowerBand[1];
    upperBand = if price[1] < up1 then Min(up, up1) else up;
    lowerBand = if price[1] > dn1 then Max(dn, dn1) else dn;
def os  = if price > upperBand then yes else if price < lowerBand then no else os[1];
def spt = if os == 1 then lowerBand else upperBand;
def cross = (price > spt and price[1] <= spt[1]) or (price < spt and price[1] >= spt[1]);
def max1 = if (IsNaN(max[1]) or max[1] == 0) then price else max[1];
def min1 = if (IsNaN(min[1]) or min[1] == 0) then price else min[1];
    max = if cross then Max(max1, price) else if os == 1 then Max(price, max1) else Min(spt, max1);
    min = if cross then Min(min1, price) else if os == 0 then Min(price, min1) else Max(spt, min1);
def avg = (max + min) / 2;
def color = if avg > avg[1] and price > avg then 1 else if avg < avg[1] and price < avg then -1 else 0;

def upperChannelData = ExpAverage(if max != max[1] and os or !showSuperTrendChannel then Double.NaN else max, smoothLength);
def avgChannelData = ExpAverage(avg, smoothLength);
def lowerChannelData = ExpAverage(if min != min[1] and os or !showSuperTrendChannel then Double.NaN else min, smoothLength);
def upper2XChannelData = avgChannelData + (2 * (upperChannelData - avgChannelData));
def lower2XChannelData = avgChannelData - (2 * (avgChannelData - lowerChannelData));
def longDotData = if high >= upperChannelData then high + (dotSeparationTicks * TickSize()) else Double.NaN;
def shortDotData = if low <= lowerChannelData then low - (dotSeparationTicks * TickSize()) else Double.NaN;


#PLOTS
plot UpperChannel = upperChannelData;
plot AvgChannel = avgChannelData;
plot LowerChannel = lowerChannelData;
plot Upper2XChannel = upper2XChannelData;
plot Lower2XChannel = lower2XChannelData;
plot LongDot = longDotData;
plot shortDot = shortDotData;


#FORMATTING
UpperChannel.AssignValueColor(GlobalColor("Green"));
UpperChannel.EnableApproximation();
UpperChannel.HideBubble();
UpperChannel.HideTitle();

LowerChannel.AssignValueColor(GlobalColor("Red"));
LowerChannel.EnableApproximation();
LowerChannel.HideBubble();
LowerChannel.HideTitle();

Upper2XChannel.AssignValueColor(GlobalColor("Green"));
Upper2XChannel.EnableApproximation();
Upper2XChannel.HideBubble();
Upper2XChannel.HideTitle();
Upper2XChannel.SetHiding(!show2XChannel);

Lower2XChannel.AssignValueColor(GlobalColor("Red"));
Lower2XChannel.EnableApproximation();
Lower2XChannel.HideBubble();
Lower2XChannel.HideTitle();
Lower2XChannel.SetHiding(!show2XChannel);

AvgChannel.HideBubble();
AvgChannel.HideTitle();
AvgChannel.EnableApproximation();
AvgChannel.AssignValueColor(
    if color > 0 then GlobalColor("Green")
    else if color < 0 then GlobalColor("Red")
    else Color.DARK_GRAY
);

LongDot.AssignValueColor(GlobalColor("Green"));
LongDot.SetPaintingStrategy(PaintingStrategy.POINTS);
LongDot.SetHiding(!showDotsOnBreakout);
LongDot.HideBubble();
LongDot.HideTitle();

shortDot.AssignValueColor(GlobalColor("Red"));
shortDot.SetPaintingStrategy(PaintingStrategy.POINTS);
shortDot.SetHiding(!showDotsOnBreakout);
shortDot.HideBubble();
shortDot.HideTitle();


#CLOUDS
AddCloud(if showCloud then UpperChannel else Double.NaN, AvgChannel, GlobalColor("Green"));
AddCloud(if showCloud then AvgChannel else Double.NaN, LowerChannel, GlobalColor("Red"));

Thanks!
 
Last edited:
Hello,

Can someone help eliminate the NaN values in these defs / plots?

More detail:
I adapted an indicator from THIS PAGE. What I'm finding is that the upperChannelData and lowerChannelData defs have NaN values. I'm trying to build something on top of this, and the NaN values make it impossible to do.

EnableApproximation is turned on for the plots, so you don't see the gaps, but if you disable that line of code the gaps become very clear.

Here's the indicator code.

Ruby:
# Adapted from https://usethinkscript.com/threads/supertrend-channels-luxalgo-for-thinkorswim.15377/

#DECLARATIONS
declare upper;


#USER INPUTS
input showSuperTrendChannel = yes;
input show2XChannel         = no;
input showCloud             = no;
input atrLength             = 14;
input atrMultiple           = 3.0;
input smoothLength          = 3;
input price                 = close;
input showDotsOnBreakout    = no;
input dotSeparationTicks    = 2;
input alertOnTouch          = no;


#GLOBAL COLOR DEFINITIONS
DefineGlobalColor("Blue" , CreateColor(33, 150, 243));
DefineGlobalColor("Green", CreateColor(0, 155, 0));
DefineGlobalColor("Red", CreateColor(225, 105, 105));
DefineGlobalColor("Gray", CreateColor(181, 181, 181));


#DEFINITIONS AND CALCULATIONS
## These variables must be declared early as they are used in preceeding calculations
def upperBand;
def lowerBand;
def max;
def min;

## Standard variable calculations
def nATR = MovingAverage(AverageType.WILDERS, TrueRange(high, close, low), atrLength) * atrMultiple;     #ATR
def up = hl2 + nATR;
def dn = hl2 - nATR;
def up1 = if (IsNaN(upperBand[1]) or upperBand[1] == 0) then up else upperBand[1];
def dn1 = if (IsNaN(lowerBand[1]) or lowerBand[1] == 0) then dn else lowerBand[1];
    upperBand = if price[1] < up1 then Min(up, up1) else up;
    lowerBand = if price[1] > dn1 then Max(dn, dn1) else dn;
def os  = if price > upperBand then yes else if price < lowerBand then no else os[1];
def spt = if os == 1 then lowerBand else upperBand;
def cross = (price > spt and price[1] <= spt[1]) or (price < spt and price[1] >= spt[1]);
def max1 = if (IsNaN(max[1]) or max[1] == 0) then price else max[1];
def min1 = if (IsNaN(min[1]) or min[1] == 0) then price else min[1];
    max = if cross then Max(max1, price) else if os == 1 then Max(price, max1) else Min(spt, max1);
    min = if cross then Min(min1, price) else if os == 0 then Min(price, min1) else Max(spt, min1);
def avg = (max + min) / 2;
def color = if avg > avg[1] and price > avg then 1 else if avg < avg[1] and price < avg then -1 else 0;

def upperChannelData = ExpAverage(if max != max[1] and os or !showSuperTrendChannel then Double.NaN else max, smoothLength);
def avgChannelData = ExpAverage(avg, smoothLength);
def lowerChannelData = ExpAverage(if min != min[1] and os or !showSuperTrendChannel then Double.NaN else min, smoothLength);
def upper2XChannelData = avgChannelData + (2 * (upperChannelData - avgChannelData));
def lower2XChannelData = avgChannelData - (2 * (avgChannelData - lowerChannelData));
def longDotData = if high >= upperChannelData then high + (dotSeparationTicks * TickSize()) else Double.NaN;
def shortDotData = if low <= lowerChannelData then low - (dotSeparationTicks * TickSize()) else Double.NaN;


#PLOTS
plot UpperChannel = upperChannelData;
plot AvgChannel = avgChannelData;
plot LowerChannel = lowerChannelData;
plot Upper2XChannel = upper2XChannelData;
plot Lower2XChannel = lower2XChannelData;
plot LongDot = longDotData;
plot shortDot = shortDotData;


#FORMATTING
UpperChannel.AssignValueColor(GlobalColor("Green"));
UpperChannel.EnableApproximation();
UpperChannel.HideBubble();
UpperChannel.HideTitle();

LowerChannel.AssignValueColor(GlobalColor("Red"));
LowerChannel.EnableApproximation();
LowerChannel.HideBubble();
LowerChannel.HideTitle();

Upper2XChannel.AssignValueColor(GlobalColor("Green"));
Upper2XChannel.EnableApproximation();
Upper2XChannel.HideBubble();
Upper2XChannel.HideTitle();
Upper2XChannel.SetHiding(!show2XChannel);

Lower2XChannel.AssignValueColor(GlobalColor("Red"));
Lower2XChannel.EnableApproximation();
Lower2XChannel.HideBubble();
Lower2XChannel.HideTitle();
Lower2XChannel.SetHiding(!show2XChannel);

AvgChannel.HideBubble();
AvgChannel.HideTitle();
AvgChannel.EnableApproximation();
AvgChannel.AssignValueColor(
    if color > 0 then GlobalColor("Green")
    else if color < 0 then GlobalColor("Red")
    else Color.DARK_GRAY
);

LongDot.AssignValueColor(GlobalColor("Green"));
LongDot.SetPaintingStrategy(PaintingStrategy.POINTS);
LongDot.SetHiding(!showDotsOnBreakout);
LongDot.HideBubble();
LongDot.HideTitle();

shortDot.AssignValueColor(GlobalColor("Red"));
shortDot.SetPaintingStrategy(PaintingStrategy.POINTS);
shortDot.SetHiding(!showDotsOnBreakout);
shortDot.HideBubble();
shortDot.HideTitle();


#CLOUDS
AddCloud(if showCloud then UpperChannel else Double.NaN, AvgChannel, GlobalColor("Green"));
AddCloud(if showCloud then AvgChannel else Double.NaN, LowerChannel, GlobalColor("Red"));

Thanks!

These lines with commented(#) code remove nans, but I have not looked at the code otherwise

Code:
def upperChannelData = ExpAverage(if #max != max[1] and os or
!showSuperTrendChannel then Double.NaN else
max, smoothLength);

def lowerChannelData = ExpAverage(if #min != min[1] and os or
!showSuperTrendChannel then Double.NaN else
min, smoothLength);
 
These lines with commented(#) code remove nans, but I have not looked at the code otherwise

That will remove the NaNs, however it will also stop the indicator from calculating.

It's a rather complex series of steps it goes through (I didn't write this originally) and I'm wondering how to possibly re-write so it doesn't create NaN values but also preserves the calculation process. Essentially, wondering if it can be re-done in a way that doesn't generate NaNs.
 
That will remove the NaNs, however it will also stop the indicator from calculating.

It's a rather complex series of steps it goes through (I didn't write this originally) and I'm wondering how to possibly re-write so it doesn't create NaN values but also preserves the calculation process. Essentially, wondering if it can be re-done in a way that doesn't generate NaNs.

What if you add this subscript at the beginning:

Code:
script fixnan {
    input source = close;
    def fix = if !IsNaN(source) then source else fix[1];
    plot result = fix;
}

Then for each def or plot statement that creates nan values, change it to be wrapped in the subscript, e.g. “def variable_name = blahblahblah” becomes “def variable_name = fixnan(blahblahblah)”.

Does that fix the problem?
 
What if you add this subscript at the beginning:

Code:
script fixnan {
    input source = close;
    def fix = if !IsNaN(source) then source else fix[1];
    plot result = fix;
}

Then for each def or plot statement that creates nan values, change it to be wrapped in the subscript, e.g. “def variable_name = blahblahblah” becomes “def variable_name = fixnan(blahblahblah)”.

Does that fix the problem?

I don't believe that fixes it. It would trail the prior value. What I'm seeing is that, for example, in the "upperChannelData" variable, when os is true or max <> max[1] then it produces a Double.NaN value.

In other words, I think it might take looking back at the process to see if there's another way to calculate those values to eliminate the NaNs... not just covering them up with something that essentially breaks the calculation.

I believe the original author was relying on EnableApproximation() to produce lines that looked correct, but when you try to reference that line there's nothing there - perhaps they didn't anticipate that ever being done.
 
Hello,

Can someone help eliminate the NaN values in these defs / plots?

More detail:
I adapted an indicator from THIS PAGE. What I'm finding is that the upperChannelData and lowerChannelData defs have NaN values. I'm trying to build something on top of this, and the NaN values make it impossible to do.

EnableApproximation is turned on for the plots, so you don't see the gaps, but if you disable that line of code the gaps become very clear.

Here's the indicator code.

Ruby:
# Adapted from https://usethinkscript.com/threads/supertrend-channels-luxalgo-for-thinkorswim.15377/

#DECLARATIONS
declare upper;


#USER INPUTS
input showSuperTrendChannel = yes;
input show2XChannel         = no;
input showCloud             = no;
input atrLength             = 14;
input atrMultiple           = 3.0;
input smoothLength          = 3;
input price                 = close;
input showDotsOnBreakout    = no;
input dotSeparationTicks    = 2;
input alertOnTouch          = no;


#GLOBAL COLOR DEFINITIONS
DefineGlobalColor("Blue" , CreateColor(33, 150, 243));
DefineGlobalColor("Green", CreateColor(0, 155, 0));
DefineGlobalColor("Red", CreateColor(225, 105, 105));
DefineGlobalColor("Gray", CreateColor(181, 181, 181));


#DEFINITIONS AND CALCULATIONS
## These variables must be declared early as they are used in preceeding calculations
def upperBand;
def lowerBand;
def max;
def min;

## Standard variable calculations
def nATR = MovingAverage(AverageType.WILDERS, TrueRange(high, close, low), atrLength) * atrMultiple;     #ATR
def up = hl2 + nATR;
def dn = hl2 - nATR;
def up1 = if (IsNaN(upperBand[1]) or upperBand[1] == 0) then up else upperBand[1];
def dn1 = if (IsNaN(lowerBand[1]) or lowerBand[1] == 0) then dn else lowerBand[1];
    upperBand = if price[1] < up1 then Min(up, up1) else up;
    lowerBand = if price[1] > dn1 then Max(dn, dn1) else dn;
def os  = if price > upperBand then yes else if price < lowerBand then no else os[1];
def spt = if os == 1 then lowerBand else upperBand;
def cross = (price > spt and price[1] <= spt[1]) or (price < spt and price[1] >= spt[1]);
def max1 = if (IsNaN(max[1]) or max[1] == 0) then price else max[1];
def min1 = if (IsNaN(min[1]) or min[1] == 0) then price else min[1];
    max = if cross then Max(max1, price) else if os == 1 then Max(price, max1) else Min(spt, max1);
    min = if cross then Min(min1, price) else if os == 0 then Min(price, min1) else Max(spt, min1);
def avg = (max + min) / 2;
def color = if avg > avg[1] and price > avg then 1 else if avg < avg[1] and price < avg then -1 else 0;

def upperChannelData = ExpAverage(if max != max[1] and os or !showSuperTrendChannel then Double.NaN else max, smoothLength);
def avgChannelData = ExpAverage(avg, smoothLength);
def lowerChannelData = ExpAverage(if min != min[1] and os or !showSuperTrendChannel then Double.NaN else min, smoothLength);
def upper2XChannelData = avgChannelData + (2 * (upperChannelData - avgChannelData));
def lower2XChannelData = avgChannelData - (2 * (avgChannelData - lowerChannelData));
def longDotData = if high >= upperChannelData then high + (dotSeparationTicks * TickSize()) else Double.NaN;
def shortDotData = if low <= lowerChannelData then low - (dotSeparationTicks * TickSize()) else Double.NaN;


#PLOTS
plot UpperChannel = upperChannelData;
plot AvgChannel = avgChannelData;
plot LowerChannel = lowerChannelData;
plot Upper2XChannel = upper2XChannelData;
plot Lower2XChannel = lower2XChannelData;
plot LongDot = longDotData;
plot shortDot = shortDotData;


#FORMATTING
UpperChannel.AssignValueColor(GlobalColor("Green"));
UpperChannel.EnableApproximation();
UpperChannel.HideBubble();
UpperChannel.HideTitle();

LowerChannel.AssignValueColor(GlobalColor("Red"));
LowerChannel.EnableApproximation();
LowerChannel.HideBubble();
LowerChannel.HideTitle();

Upper2XChannel.AssignValueColor(GlobalColor("Green"));
Upper2XChannel.EnableApproximation();
Upper2XChannel.HideBubble();
Upper2XChannel.HideTitle();
Upper2XChannel.SetHiding(!show2XChannel);

Lower2XChannel.AssignValueColor(GlobalColor("Red"));
Lower2XChannel.EnableApproximation();
Lower2XChannel.HideBubble();
Lower2XChannel.HideTitle();
Lower2XChannel.SetHiding(!show2XChannel);

AvgChannel.HideBubble();
AvgChannel.HideTitle();
AvgChannel.EnableApproximation();
AvgChannel.AssignValueColor(
    if color > 0 then GlobalColor("Green")
    else if color < 0 then GlobalColor("Red")
    else Color.DARK_GRAY
);

LongDot.AssignValueColor(GlobalColor("Green"));
LongDot.SetPaintingStrategy(PaintingStrategy.POINTS);
LongDot.SetHiding(!showDotsOnBreakout);
LongDot.HideBubble();
LongDot.HideTitle();

shortDot.AssignValueColor(GlobalColor("Red"));
shortDot.SetPaintingStrategy(PaintingStrategy.POINTS);
shortDot.SetHiding(!showDotsOnBreakout);
shortDot.HideBubble();
shortDot.HideTitle();


#CLOUDS
AddCloud(if showCloud then UpperChannel else Double.NaN, AvgChannel, GlobalColor("Green"));
AddCloud(if showCloud then AvgChannel else Double.NaN, LowerChannel, GlobalColor("Red"));

Thanks!


away from computer, just thinking and typing on my cell.....

plotting with x.EnableApproximation()
, draws lines that connect valid price numbers and skips over the bars with nan values.

if you are asking,
how to create formulas to generate lines, that mimic what x.EnableApproximation() is plotting...

then on each valid number, need to calc a line slope to the next number, and add it on each bar, until the next valid number.

a loop can use while to run for as long as some formula is true, and stops when it isn't.

untested
add this to the end of your study

not sure if slope formula needs a next +0 or next+1

Code:
def data = upperChannelData;
def n = 500;

def next;
def slope;
def y;
if !isnan(data) then {
# valid #, look for next number
# count bars while reading nan values
fold a = 1 to n
with b
while isnan(getvalue(data), -a)
do b + 1;

# slope = y-y/x- x
def slope = (getvalue(data), -next) - data)/(next+0);

y = data;
} else {
next = next[1];
slope = slope[1];
y = y[1] + slope;
}

plot z = y;
 
away from computer, just thinking and typing on my cell.....

plotting with x.EnableApproximation()
, draws lines that connect valid price numbers and skips over the bars with nan values.

if you are asking,
how to create formulas to generate lines, that mimic what x.EnableApproximation() is plotting...

then on each valid number, need to calc a line slope to the next number, and add it on each bar, until the next valid number.

a loop can use while to run for as long as some formula is true, and stops when it isn't.

untested
add this to the end of your study

not sure if slope formula needs a next +0 or next+1

Code:
def data = upperChannelData;
def n = 500;

def next;
def slope;
def y;
if !isnan(data) then {
# valid #, look for next number
# count bars while reading nan values
fold a = 1 to n
with b
while isnan(getvalue(data), -a)
do b + 1;

# slope = y-y/x- x
def slope = (getvalue(data), -next) - data)/(next+0);

y = data;
} else {
next = next[1];
slope = slope[1];
y = y[1] + slope;
}

plot z = y;


That might work. I can try it, but I was really more like thinking if there is a different way to process the steps to not generate NaNs in the first place. I've tried on my own, but it's a little trickier than I can manage.
 
To my eye, and I could be wrong, you have the NaNs built in in this code:
Code:
def upperChannelData = ExpAverage(if max != max[1] and os or !showSuperTrendChannel then Double.NaN else max, smoothLength);

def lowerChannelData = ExpAverage(if min != min[1] and os or !showSuperTrendChannel then Double.NaN else min, smoothLength);

you've previously defined os to be either yes or no. Using those values, this will plot the upper bound when the chart is rinsing and the lower bound when it is not.:

Code:
def upperChannelData = ExpAverage(if (max != max[1] and os == no) or !showSuperTrendChannel then Double.NaN else max, smoothLength);

def lowerChannelData = ExpAverage(if (min != min[1] and os == yes) or !showSuperTrendChannel then Double.NaN else min, smoothLength);

I don't believe that's the intended behaviour, but it is interesting. Taking the and os bit of code out, surprisingly, didn't do much. (I also added some parens to make the logic explicit rather than ambiguous -- but it may not be correct this way.)

So there you have a bit of a try at it. Your conditions create the nans you're talking about I believe. I could be completely wrong though... been a long day so far.

-mashume
 

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