LOWESS Reversal & Continuation [UAlgo]LOWESS Reversal & Continuation is a trend sensitive signal indicator built around a local LOWESS style smoothing engine that adapts to both price structure and volatility. Its core objective is to separate meaningful directional shifts from routine market noise by combining smoothed trend estimation, ATR normalized slope analysis, acceleration filtering, and disciplined signal gating.
Instead of relying on a conventional moving average crossover model, the script fits a locally weighted regression over a rolling window of recent bars. This produces a smoother and more context aware estimate of price direction, while still reacting fast enough to identify emerging reversals and pullback continuation opportunities. Because the estimate is local and weighted, recent bars have greater influence than distant bars, which helps the line remain relevant to current market conditions.
The indicator classifies signals into two practical categories. Reversal signals aim to identify transitions where directional pressure flips from negative to positive, or from positive to negative. Continuation signals aim to identify pullback resumption behavior inside an already established directional regime. This makes the script suitable for traders who want a single tool that can highlight both early trend change candidates and trend following re entry points.
To improve robustness, the script also supports optional robust weighting passes. These passes reduce the influence of outlier bars on the LOWESS fit, which is especially useful during abnormal spikes, illiquid conditions, or isolated volatility shocks. In addition, all slope readings are normalized by ATR, allowing the trend filter to scale more consistently across instruments, timeframes, and volatility regimes.
From a workflow perspective, the script is designed for clean chart usage. It colors the LOWESS line according to directional bias, draws an adaptive ATR based band around the curve, supports optional signal labels, limits on chart label clutter through an internal object manager, and provides alert conditions for all signal classes. The result is a visually compact but analytically rich framework for tracking trend reversals and continuation setups in real time.
🔹 Features
🔸 LOWESS Style Local Trend Estimation
The heart of the script is a locally weighted linear regression model applied over a rolling lookback window. Each bar inside the window receives a distance based weight, meaning bars closer to the current bar have a larger impact on the estimate. This produces a smooth trend line that is more adaptive than many standard moving average techniques and better suited for identifying subtle turning points.
🔸 Optional Robust Regression Passes
The indicator can apply additional robust weighting iterations after the initial fit. Residuals are measured relative to the first regression pass, and bars with unusually large residuals receive progressively lower influence in later passes. This reduces distortion from extreme candles and helps the LOWESS curve remain stable during irregular price events.
🔸 ATR Normalized Slope Filter
The script does not use raw slope in isolation. Instead, the LOWESS slope is divided by ATR, creating a volatility adjusted slope metric. This makes the directional threshold more portable across markets and timeframes. A slope that may be meaningful on a slow instrument can be very different on a high volatility asset, so ATR normalization creates a more balanced regime filter.
🔸 Reversal Signal Detection
Bullish and bearish reversal signals are triggered when the ATR normalized slope crosses the zero line and is confirmed by directional acceleration and price location relative to the LOWESS line. In other words, the script looks for a meaningful change in smoothed directional pressure, not simply a visual bend in the curve. This makes reversal signals more selective and better aligned with structural momentum shifts.
🔸 Continuation Signal Detection
Continuation logic is designed to capture trend resumption after a pullback. The script first requires an established directional regime, then checks whether price recently interacted with the LOWESS line, and finally waits for price to reclaim the trend direction with positive confirming acceleration. This helps distinguish genuine continuation behavior from random sideways oscillation around the curve.
🔸 Pullback Validation Window
A dedicated pullback lookback parameter ensures that continuation signals only occur when price has interacted with the LOWESS line within a recent number of bars. This prevents stale continuation triggers and keeps the setup focused on recent retracement behavior rather than distant historical interactions.
🔸 Close Confirmation Option
Signals can be gated so they only become valid after bar close. This is useful for traders who want to avoid intrabar flicker and premature triggers on live candles. When disabled, the script can respond more aggressively in real time, which may suit faster execution styles.
🔸 Signal Cooldown Logic
To reduce repetitive clustering, the indicator tracks the last occurrence of each signal type and imposes a cooldown period before another signal of the same class can be printed. Separate cooldown tracking is maintained for bullish reversals, bearish reversals, bullish continuations, and bearish continuations.
🔸 Adaptive ATR Band
An optional ATR based band can be plotted around the LOWESS line. This band provides a visual sense of dynamic range around the smoothed path and can help contextualize whether price is moving in a relatively stretched or balanced position around the trend estimate.
🔸 Directional Visual Coloring
The LOWESS curve changes color according to directional bias derived from the ATR normalized slope. This gives the user an immediate visual read on whether the smoothed trend pressure is currently positive, negative, or unavailable due to insufficient historical data.
🔸 Lightweight Label Management
When signal labels are enabled, the script uses an internal label book to store and manage plotted objects. Older labels are automatically deleted once the configured maximum is exceeded, helping keep the chart readable and preventing uncontrolled label buildup.
🔸 Full Alert Support
Alert conditions are included for all four event classes:
Bullish LOWESS Reversal
Bearish LOWESS Reversal
Bullish LOWESS Continuation
Bearish LOWESS Continuation
This allows the script to be used not only as a visual analysis tool, but also as an event driven signal framework for scanning and real time notification workflows.
🔹 Calculations
1) Rolling LOWESS Window Construction
For every bar, the script loads the most recent length values of the selected source into an internal rolling window. This window becomes the data sample used for the local regression fit.
method loadWindow(LowessEngine this, float seriesValue) =>
for i = 0 to this.length - 1
array.set(this.y, i, seriesValue )
Interpretation:
The regression is always fit on the latest rolling block of data.
The rightmost point in the window corresponds to the current estimation point.
This makes the smoothing local rather than global.
2) Distance Based LOWESS Weights
The script uses a tricube kernel to assign weights based on each point’s distance from the current bar inside the regression window. Bars nearer to the most recent observation receive a larger weight, while distant bars contribute less.
method buildDistanceWeights(LowessEngine this, int spanBars) =>
int x0 = this.length - 1
float bandwidth = math.max(spanBars, 1)
for i = 0 to this.length - 1
float u = math.abs(i - x0) / bandwidth
float w = u < 1 ? math.pow(1 - math.pow(u, 3), 3) : 0.0
array.set(this.baseW, i, w)
Interpretation of the conditions:
x0 is the current evaluation point inside the rolling window.
u is normalized distance from each historical point to the current point.
The tricube weight decays smoothly as distance increases.
Bars outside the effective span receive zero weight.
This is what gives the LOWESS fit its local character and helps it stay focused on recent structure.
3) Weighted Local Linear Regression
After weights are built, the script solves a weighted linear regression over the local window. The output is a local intercept and local slope. The final LOWESS estimate is the fitted value at the most recent point in the sample.
method solveWeightedLinear(LowessEngine this, array weights) =>
float s0 = 0.0
float s1 = 0.0
float s2 = 0.0
float t0 = 0.0
float t1 = 0.0
for i = 0 to this.length - 1
float w = array.get(weights, i)
float x = array.get(this.x, i)
float y = array.get(this.y, i)
s0 += w
s1 += w * x
s2 += w * x * x
t0 += w * y
t1 += w * x * y
float den = s0 * s2 - s1 * s1
if s0 <= 1e-10 or math.abs(den) <= 1e-10
this.slope := 0.0
this.intercept := array.get(this.y, this.length - 1)
else
this.slope := (s0 * t1 - s1 * t0) / den
this.intercept := (t0 - this.slope * s1) / s0
float x0 = this.length - 1
this.yhat := this.intercept + this.slope * x0
Interpretation:
this.slope measures the local directional gradient of the LOWESS fit.
this.yhat is the current LOWESS value plotted on the chart.
If the weighted regression becomes numerically unstable, the script falls back to a flat slope and uses the latest source value as intercept.
4) Robust Reweighting Passes
To reduce the impact of outliers, the script can run additional robust passes after the initial fit. It first calculates the absolute residual of each point relative to the fitted line, then computes a median based scale estimate, and finally applies a bisquare style robust weighting function.
method updateRobustWeights(LowessEngine this) =>
for i = 0 to this.length - 1
float xi = array.get(this.x, i)
float yi = array.get(this.y, i)
float fit = this.intercept + this.slope * xi
array.set(this.residualAbs, i, math.abs(yi - fit))
float med = this.residualAbs.median()
float scale = med * 6.0
if na(scale) or scale <= 1e-10
for i = 0 to this.length - 1
array.set(this.robustW, i, 1.0)
else
for i = 0 to this.length - 1
float u = array.get(this.residualAbs, i) / scale
float rw = u < 1 ? math.pow(1 - math.pow(u, 2), 2) : 0.0
array.set(this.robustW, i, rw)
Interpretation:
Large residual bars are treated as less trustworthy observations.
The median residual acts as a robust scale anchor.
Higher residuals receive smaller robust weights in subsequent fits.
This improves stability during abnormal spikes and irregular candles.
5) ATR Normalized Slope and Acceleration
Once the LOWESS fit is complete, the script converts raw slope into a volatility aware slope by dividing it by ATR. It also computes a first-difference style acceleration term to measure whether directional pressure is strengthening or weakening.
float slopeAtr = not na(slope) and atr > 0 ? slope / atr : na
float accelAtr = slopeAtr - nz(slopeAtr )
Interpretation:
slopeAtr expresses trend slope in ATR units.
accelAtr measures change in normalized slope from one bar to the next.
Positive acceleration supports bullish developments.
Negative acceleration supports bearish developments.
This combination helps the script distinguish a genuine regime shift from a weak or decaying slope condition.
6) Directional Regime Classification
The script uses a user defined ATR normalized threshold to determine whether the current smoothed state qualifies as a bullish or bearish directional regime.
bool upRegime = not na(slopeAtr) and slopeAtr > slopeThreshold
bool downRegime = not na(slopeAtr) and slopeAtr < -slopeThreshold
Interpretation:
A positive but very small slope is not automatically treated as a valid uptrend.
A negative but very small slope is not automatically treated as a valid downtrend.
The threshold acts as a noise filter that requires the trend estimate to have enough magnitude before continuation logic becomes eligible.
7) Pullback Detection Relative to LOWESS
Continuation signals depend on recent interaction with the LOWESS line. The script checks how many bars have passed since price moved through the LOWESS curve in the opposite direction of the active regime.
int bullPbBars = int(nz(ta.barssince(low < lowess), 100000))
int bearPbBars = int(nz(ta.barssince(high > lowess), 100000))
bool bullPullbackRecent = bullPbBars <= pullbackLookback
bool bearPullbackRecent = bearPbBars <= pullbackLookback
Interpretation:
In a bullish regime, price must have recently dipped below the LOWESS line to qualify as a pullback.
In a bearish regime, price must have recently pushed above the LOWESS line to qualify as a pullback.
The pullbackLookback parameter controls how recent that interaction must be.
8) Reversal Signal Logic
Bullish and bearish reversal signals are built from zero line slope crossings, directional acceleration, and price confirmation relative to the LOWESS curve.
bool slopeCrossUp = ta.crossover(slopeAtr, 0)
bool slopeCrossDown = ta.crossunder(slopeAtr, 0)
bool bullRevRaw = enoughBars and slopeCrossUp and accelAtr > 0 and close > lowess
bool bearRevRaw = enoughBars and slopeCrossDown and accelAtr < 0 and close < lowess
Interpretation of the bullish reversal conditions:
slopeCrossUp means the normalized LOWESS slope has crossed from negative to positive.
accelAtr > 0 means the slope is improving, not merely touching zero.
close > lowess confirms that price is positioned above the smoothed trend estimate.
Interpretation of the bearish reversal conditions:
slopeCrossDown means the normalized LOWESS slope has crossed from positive to negative.
accelAtr < 0 confirms weakening trend pressure.
close < lowess confirms price is positioned below the LOWESS line.
This makes reversal signals more selective than a simple moving average crossover style event.
9) Continuation Signal Logic
Continuation signals are only allowed when a directional regime already exists, a recent pullback has occurred, price crosses back through the LOWESS line in trend direction, and acceleration confirms that the move is regaining strength.
bool priceCrossUp = ta.crossover(close, lowess)
bool priceCrossDown = ta.crossunder(close, lowess)
bool bullContRaw = enoughBars and upRegime and bullPullbackRecent and priceCrossUp and accelAtr > 0 and not bullRevRaw
bool bearContRaw = enoughBars and downRegime and bearPullbackRecent and priceCrossDown and accelAtr < 0 and not bearRevRaw
Interpretation of the bullish continuation conditions:
The LOWESS slope must already define an uptrend regime.
Price must have recently pulled back below the LOWESS line.
Price must cross back above the LOWESS line.
Acceleration must be positive.
A reversal signal takes priority, so continuation does not print if the same bar qualifies as a bullish reversal.
Interpretation of the bearish continuation conditions is the exact inverse.
10) Close Confirmation and Cooldown Control
The final signal is gated by an optional bar close confirmation and a per-signal cooldown filter.
bool gate = confirmClose ? barstate.isconfirmed : true
bool bullRev = gate and bullRevRaw and canBullRev(signalState, cooldownBars)
bool bearRev = gate and bearRevRaw and canBearRev(signalState, cooldownBars)
bool bullCont = gate and bullContRaw and canBullCont(signalState, cooldownBars)
bool bearCont = gate and bearContRaw and canBearCont(signalState, cooldownBars)
Interpretation:
When close confirmation is enabled, signals only become valid after the candle is closed.
Cooldown logic prevents repeated printing of the same signal class within a short number of bars.
This reduces visual clutter and avoids excessive re-triggering during choppy conditions.
11) Adaptive Band Construction
The script can draw an ATR-based envelope around the LOWESS line to provide volatility context.
float upperBand = showBand and not na(lowess) ? lowess + atr * bandAtrMult : na
float lowerBand = showBand and not na(lowess) ? lowess - atr * bandAtrMult : na
Interpretation:
The band expands and contracts with ATR.
This creates a dynamic visual frame around the LOWESS estimate.
It is not a signal by itself, but it helps contextualize the distance between current price and the smoothed trend path.
12) Visual Output and Alerts
The LOWESS line changes color according to slope direction, optional labels mark reversal and continuation events, and alert conditions are available for all four signal types.
alertcondition(bullRev, "Bullish LOWESS Reversal", "Bullish LOWESS reversal on {{ticker}}")
alertcondition(bearRev, "Bearish LOWESS Reversal", "Bearish LOWESS reversal on {{ticker}}")
alertcondition(bullCont, "Bullish LOWESS Continuation", "Bullish LOWESS continuation on {{ticker}}")
alertcondition(bearCont, "Bearish LOWESS Continuation", "Bearish LOWESS continuation on {{ticker}}")
In practical terms, this means the indicator can serve both as a visual discretionary analysis tool and as an alert driven framework for identifying smoothed trend reversals and pullback continuation opportunities with a volatility aware filter structure.
Pine Script® indicator






















