Nadaraya-Watson Trend [QuantAlgo] for ThinkOrSwim

chewie76

Well-known member
VIP
VIP Enthusiast
Overview
The Nadaraya-Watson Trend indicator is a non-repainting, causal kernel regression indicator that plots a smoothed trend line with optional bands.

Original Source: https://www.tradingview.com/script/DyPTog1C-Nadaraya-Watson-Trend-QuantAlgo/

Here is a 4-hour chart of /BTC.
1787270892705.png




How It Works
Rather than using a simple moving average, the indicator calculates each bar's value using a kernel-weighted average of the previous LookbackInput bars (default: 50), giving more weight to recent prices based on the selected kernel shape. Six kernel types are available — Gaussian, Epanechnikov, Triangular, Quartic, Cosine, and Rational Quadratic — each producing slightly different curve characteristics.



Visual Components
  • Trend Line — The core NW estimate, colored bull (teal) or bear (red) based on slope direction
  • Bar Coloring — Price bars colored to match trend direction
  • Inner Cloud — A teal fill (bull) or red fill (bear) between the midline and the inner band, showing near-term volatility context
  • Outer Bands — Two pairs of bands at wider residual multiples, filled with a blue cloud, marking extended price territory
Band Construction
Bands are not ATR or standard-deviation based. They are built from the weighted mean absolute residual — essentially how far prices have typically strayed from the NW estimate over the lookback period, scaled by three user-adjustable multipliers (BandMult0, BandMult, BandMult2).

Intended Use
Best used as a trend context and mean-reversion reference tool. The inner cloud gives a quick visual read on trend conviction, while the outer blue bands flag potentially overextended price conditions.

Code:
# Nadaraya-Watson Trend for ThinkOrSwim
# Original Source: https://www.tradingview.com/script/DyPTog1C-Nadaraya-Watson-Trend-QuantAlgo/
# Converted and modified by Chewie 8/14/2026

declare upper;

#─────────────────────────────────────────
#  INPUTS
#─────────────────────────────────────────

input colorbar       = yes;
input ShowBands      = yes;
input Source         = close;
input KernelType     = {default "Gaussian", "Epanechnikov", "Triangular", "Quartic", "Cosine", "RationalQuadratic"};
input LookbackInput  = 50;
input BandwidthInput = 8;
input MultInput      = 2.0;
input RelWeight      = 8.0;
input BandMult0      = 0.6;
input BandMult       = 1.8;
input BandMult2      = 2.6;

DefineGlobalColor("Bull", CreateColor(0, 255, 170));
DefineGlobalColor("Bear", CreateColor(255, 0, 0));

#─────────────────────────────────────────
#  BANDWIDTH
#─────────────────────────────────────────

def h = BandwidthInput * MultInput;

#─────────────────────────────────────────
#  KERNEL TYPE FLAGS
#─────────────────────────────────────────

def isGaussian = KernelType == KernelType."Gaussian";
def isEpan     = KernelType == KernelType."Epanechnikov";
def isTriang   = KernelType == KernelType."Triangular";
def isQuartic  = KernelType == KernelType."Quartic";
def isCosine   = KernelType == KernelType."Cosine";
def isRQ       = KernelType == KernelType."RationalQuadratic";

#─────────────────────────────────────────
#  KERNEL WEIGHT INLINE FUNCTION
#─────────────────────────────────────────

# Helper: weight for index n
def _w0 = fold i = 0 to LookbackInput + 1 with wAcc = 0 do
    wAcc + (
        if isGaussian then Exp(-(i * i) / (2.0 * h * h))
        else if isRQ   then Power(1.0 + (i * i) / (2.0 * RelWeight * h * h), -RelWeight)
        else if isEpan then (if AbsValue(i / h) <= 1.0 then 0.75 * (1.0 - (i / h) * (i / h)) else 0)
        else if isTriang  then (if AbsValue(i / h) <= 1.0 then 1.0 - AbsValue(i / h) else 0)
        else if isQuartic then (if AbsValue(i / h) <= 1.0 then (15.0 / 16.0) * Power(1.0 - (i / h) * (i / h), 2.0) else 0)
        else if isCosine  then (if AbsValue(i / h) <= 1.0 then (Double.Pi / 4.0) * Cos(Double.Pi * (i / h) / 2.0) else 0)
        else Exp(-(i * i) / (2.0 * h * h))
    );

def _p0 = fold j = 0 to LookbackInput + 1 with pAcc = 0 do
    pAcc + (
        GetValue(Source, j) * (
            if isGaussian then Exp(-(j * j) / (2.0 * h * h))
            else if isRQ   then Power(1.0 + (j * j) / (2.0 * RelWeight * h * h), -RelWeight)
            else if isEpan then (if AbsValue(j / h) <= 1.0 then 0.75 * (1.0 - (j / h) * (j / h)) else 0)
            else if isTriang  then (if AbsValue(j / h) <= 1.0 then 1.0 - AbsValue(j / h) else 0)
            else if isQuartic then (if AbsValue(j / h) <= 1.0 then (15.0 / 16.0) * Power(1.0 - (j / h) * (j / h), 2.0) else 0)
            else if isCosine  then (if AbsValue(j / h) <= 1.0 then (Double.Pi / 4.0) * Cos(Double.Pi * (j / h) / 2.0) else 0)
            else Exp(-(j * j) / (2.0 * h * h))
        )
    );

def nwVal = if _w0 != 0 then _p0 / _w0 else Double.NaN;

#─────────────────────────────────────────
#  RESIDUAL BANDS
#─────────────────────────────────────────

def sumAbsW = fold k = 0 to LookbackInput + 1 with rAcc = 0 do
    rAcc + (
        (
            if isGaussian then Exp(-(k * k) / (2.0 * h * h))
            else if isRQ   then Power(1.0 + (k * k) / (2.0 * RelWeight * h * h), -RelWeight)
            else if isEpan then (if AbsValue(k / h) <= 1.0 then 0.75 * (1.0 - (k / h) * (k / h)) else 0)
            else if isTriang  then (if AbsValue(k / h) <= 1.0 then 1.0 - AbsValue(k / h) else 0)
            else if isQuartic then (if AbsValue(k / h) <= 1.0 then (15.0 / 16.0) * Power(1.0 - (k / h) * (k / h), 2.0) else 0)
            else if isCosine  then (if AbsValue(k / h) <= 1.0 then (Double.Pi / 4.0) * Cos(Double.Pi * (k / h) / 2.0) else 0)
            else Exp(-(k * k) / (2.0 * h * h))
        ) * AbsValue(GetValue(Source, k) - nwVal)
    );

def residual  = if _w0 != 0 then sumAbsW / _w0 else Double.NaN;
def innerBandU  = nwVal + residual * BandMult0;
def innerBandD  = nwVal - residual * BandMult0;
def upperBand  = nwVal + residual * BandMult;
def lowerBand  = nwVal - residual * BandMult;
def upperBand2 = nwVal + residual * BandMult2;
def lowerBand2 = nwVal - residual * BandMult2;

#─────────────────────────────────────────
#  TREND DIRECTION & REVERSALS
#─────────────────────────────────────────

def trendUp   = nwVal > nwVal[1];
def turnedBull = nwVal[1] < nwVal[2] and nwVal > nwVal[1];
def turnedBear = nwVal[1] > nwVal[2] and nwVal < nwVal[1];

#─────────────────────────────────────────
#  MAIN TREND PLOT
#─────────────────────────────────────────

plot NWTrendLine = nwVal;
NWTrendLine.SetLineWeight(3);
NWTrendLine.AssignValueColor(if trendUp then GlobalColor("Bull") else GlobalColor("Bear"));

# Coloring Bars
AssignPriceColor(if Colorbar and trendUp then GlobalColor("Bull") else if Colorbar and !trendUp then GlobalColor("Bear") else color.current);

#─────────────────────────────────────────
#  RESIDUAL BAND PLOTS
#─────────────────────────────────────────

plot UpperBandPlot  = if ShowBands then upperBand  else Double.NaN;
plot LowerBandPlot  = if ShowBands then lowerBand  else Double.NaN;
plot UpperBandPlot2 = if ShowBands then upperBand2 else Double.NaN;
plot LowerBandPlot2 = if ShowBands then lowerBand2 else Double.NaN;

UpperBandPlot.SetLineWeight(1);
LowerBandPlot.SetLineWeight(1);
UpperBandPlot2.SetLineWeight(1);
LowerBandPlot2.SetLineWeight(1);
UpperBandPlot.SetDefaultColor(GlobalColor("Bull"));
LowerBandPlot.SetDefaultColor(GlobalColor("Bull"));
UpperBandPlot2.SetDefaultColor(GlobalColor("Bull"));
LowerBandPlot2.SetDefaultColor(GlobalColor("Bull"));

AddCloud(UpperBandPlot,  UpperBandPlot2, CreateColor(80, 170, 240), CreateColor(80, 170, 240));
AddCloud(LowerBandPlot,  LowerBandPlot2, CreateColor(80, 170, 240), CreateColor(80, 170, 240));

# Conditional inner band clouds based on trend direction
def MidForBullCloud = if ShowBands and trendUp  then nwVal else Double.NaN;
def MidForBearCloud = if ShowBands and !trendUp then nwVal else Double.NaN;
plot InnerUForCloud  = if ShowBands and trendUp  then innerBandU else Double.NaN;
plot InnerDForCloud  = if ShowBands and !trendUp then innerBandD else Double.NaN;
plot InnerUForCloudR  = if ShowBands and trendUp  then innerBandD else Double.NaN;
plot InnerDForCloudR  = if ShowBands and !trendUp then innerBandU else Double.NaN;

InnerUForCloudR.SetDefaultColor(GlobalColor("Bull"));
InnerDForCloudR.SetDefaultColor(GlobalColor("Bear"));
InnerUForCloud.SetDefaultColor(GlobalColor("Bull"));
InnerDForCloud.SetDefaultColor(GlobalColor("Bear"));

AddCloud(InnerUForCloud, MidForBullCloud, GlobalColor("Bull"), GlobalColor("Bull"));
AddCloud(MidForBearCloud, InnerDForCloud, GlobalColor("Bear"), GlobalColor("Bear"));
 
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
995 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