Rajandran R Creator of OpenAlgo - OpenSource Algo Trading framework for Indian Traders. Building GenAI Applications. Telecom Engineer turned Full-time Derivative Trader. Mostly Trading Nifty, Banknifty, High Liquid Stock Derivatives. Trading the Markets Since 2006 onwards. Using Market Profile and Orderflow for more than a decade. Designed and published 100+ open source trading systems on various trading tools. Strongly believe that market understanding and robust trading frameworks are the key to the trading success. Building Algo Platforms, Writing about Markets, Trading System Design, Market Sentiment, Trading Softwares & Trading Nuances since 2007 onwards. Author of Marketcalls.in

Detecting Extreme Price Behavior and Trend Shifts Using Lowess Channel in Amibroker

4 min read

Understanding market extremes and shifts in sentiment is crucial for short-term traders and positional players alike. Today, I’m sharing an advanced Amibroker AFL script built using Lowess Smoothing logic that helps:

  • Spot extreme price zones (Overbought / Oversold)
  • Detect transitions like “Falling from Overbought” or “Rising from Oversold”
  • Visualize short-to-mid-term sentiment through trend shifts and RSI momentum
  • Present real-time insight using a GFX Table Dashboard

Core Concept: What is Lowess?

LOWESS (Locally Weighted Scatterplot Smoothing) is a powerful technique for filtering noisy price data and understanding smoothed directional bias. By wrapping it with ATR bands, we can:

  • Define overbought/oversold thresholds
  • Capture the underlying trend without lag from moving averages
  • Add contextual overlays like momentum and RSI smoothing

Key Features of the AFL

1. Lowess Channel with ATR Bands

  • A regression-smoothed line plots the central price trend.
  • Two outer bands (BandUpper2, BandLower2) derived using ATR define dynamic price envelopes.

2. Extreme Price Behavior Detector

The logic detects:

  • When price enters extreme zones
  • When it falls from Overbought
  • When it rises from Oversold
  • Or simply remains within a normal range

Each condition is color-coded:

BehaviorColor
Entered OverboughtOrange
Entered OversoldBright Green
Falling from OverboughtPink
Rising from OversoldAqua
Still OverboughtRed
Still OversoldGreen
NormalGrey

3. Trend Reversal and Momentum Detector

  • Detects slope change in the center line using a 3-bar reference
  • Plots hollow star diamonds when trend color shifts
  • Classifies trend states:
    • Uptrend Emerging, Downtrend Emerging, Trend Reversal, Stable Trend

4. Sentiment via HMA of RSI

  • Uses a double-smoothed RSI to eliminate false whipsaws
  • Highlights:
    • Bullish Bias (rising RSI)
    • Bearish Bias (falling RSI)
    • Neutral Bias (flattening RSI)

GFX Table: Your Real-Time Trading Dashboard

The script renders a floating GFX Table on the chart with live sentiment analysis:

Market InsightObservation
Extreme Price Behaviore.g., “Rising from Oversold”
Trend Reversal / Momentume.g., “Uptrend Emerging”
Short-to-Mid Term Sentimente.g., “Bullish Bias”

This makes it incredibly intuitive for discretionary or systematic traders to make decisions at a glance.


AFL Source Code

//Rajandran R - Creator of OpenAlgo
//website - openalgo.in / marketcalls.in
//Lowess Channel with Trend Sentiment Detector
//Date - 29/03/2025


_SECTION_BEGIN("Lowess Channel");

/* === Chart Settings === */
SetChartOptions(0, chartShowArrows | chartShowDates);
_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", 
    O, H, L, C, SelectedValue(ROC(C, 1))));


/* === User Inputs === */
length = Param("Lowess Length", 20, 5, 100, 1);
multi = Param("Bands Multiplier", 1.5, 0.1, 10, 0.1);
rsilength = Param("Hull of RSI Length",7,1,100,1);
atrlength = Param("ATR Length",100,1,200,1);
bandwidth = 10;

/* === ATR Calculation === */
iatr = ATR(atrlength);

/* === LOWESS Smoothing Function === */
function LowessSmooth(src, len, bw) {
    result = Null;
    for (i = len; i < BarCount; i++) {
        sumW = sumWY = sumWXY = sumWX = sumWX2 = 0;
        for (j = 0; j < len; j++) {
            x = j;
            idx = i - j;
            weight = exp(-0.5 * (x / bw) * (x / bw));
            y = Nz(src[idx], 0);
            sumW += weight;
            sumWX += weight * x;
            sumWY += weight * y;
            sumWXY += weight * x * y;
            sumWX2 += weight * x * x;
        }
        meanX = sumWX / sumW;
        meanY = sumWY / sumW;
        beta = (sumWXY - meanX * meanY * sumW) / (sumWX2 - meanX * meanX * sumW);
        alpha = meanY - beta * meanX;
        result[i] = alpha + beta * (len / 2);
    }
    return result;
}

/* === Band Calculation === */
centerLine = LowessSmooth(C + (iatr * 0), length, bandwidth);
bandUpper1 = LowessSmooth(C + (iatr * multi), length, bandwidth);
bandUpper2 = LowessSmooth(C + (iatr * multi * 2), length, bandwidth);
bandLower1 = LowessSmooth(C - (iatr * multi), length, bandwidth);
bandLower2 = LowessSmooth(C - (iatr * multi * 2), length, bandwidth);

/* === Color Detection Logic === */
trendColor = IIf(Ref(centerLine, -3) < centerLine, colorLime,
             IIf(Ref(centerLine, -3) > centerLine, colorViolet, colorGrey50));

/* === Plot Bands === */
Plot(bandUpper2, "Upper Band 2", colorYellow, styleThick);
Plot(bandUpper1, "Upper Band 1", colorDarkGreen, styleLine);
Plot(centerLine, "Lowess Center", trendColor, styleThick);
Plot(bandLower1, "Lower Band 1", colorDarkGreen, styleLine);
Plot(bandLower2, "Lower Band 2", colorYellow, styleThick);

/* === Trend Color Change Detection and Diamond Plot === */
trendChange = trendColor != Ref(trendColor, -1);
shapeY = Ref(centerLine, -1); // Diamond at previous bar’s centerLine

PlotShapes(trendChange * shapeHollowStar, trendColor, 0, shapeY, 0);

candlecolor = IIf(high>bandUpper2 AND Close>bandUpper2, colorRed, IIf(low<bandLower2,colorGreen,colorDefault));


Plot(Close, "Close", candlecolor, styleNoTitle | ParamStyle("Style") | GetPriceStyle());


_SECTION_END();


////////////////////////////////////////////////////////////////////////////////
// This AFL code enhances the GFX table by adding dynamic background colors
// to the observation values based on Lowess Channel logic.
////////////////////////////////////////////////////////////////////////////////

_SECTION_BEGIN("GFX Table - Lowess Channel Summary (Colored)");

cellHeight = 34;
cellWidth = 220;
startX = 50;
startY = 70;

tableFillColor = colorBlack;
tableBorderColor = colorBlue;

function TableCell(text, col, row, bgColor, textColor)
{
    x1 = startX + (col - 1) * cellWidth;
    y1 = startY + (row - 1) * cellHeight;
    x2 = x1 + cellWidth;
    y2 = y1 + cellHeight;
    textX = x1 + 10;
    textY = y1 + 10;

    GfxSelectPen(tableBorderColor, 1);
    GfxSelectSolidBrush(SelectedValue(bgColor));
    GfxRectangle(x1, y1, x2, y2);

    GfxSetBkColor(SelectedValue(bgColor));
    GfxSetTextAlign(0);
    GfxSetTextColor(textColor);
    GfxTextOut(text, textX, textY);
}

// === Logic Derived from Lowess Channel ===

extremeUp = High > bandUpper2 AND Close >bandUpper2;
extremeDn = Low < bandLower2;

prevExtremeUp = Ref(extremeUp, -1);
prevExtremeDn = Ref(extremeDn, -1);

// Extended Extreme Price Behavior
extremeStatus = 
    WriteIf(extremeUp AND !prevExtremeUp, "Just Entered Overbought Zone",
    WriteIf(extremeDn AND !prevExtremeDn, "Just Entered Oversold Zone",
    WriteIf(!extremeUp AND prevExtremeUp AND Close < Ref(Close,-1), "Falling from Overbought",
    WriteIf(!extremeDn AND prevExtremeDn AND Close > Ref(Close,-1), "Rising from Oversold",
    WriteIf(extremeUp, "Above Upper Band (Overbought)",
    WriteIf(extremeDn, "Below Lower Band (Oversold)", "Normal Range"))))));

// Dynamic Cell Color Coding
extremeColor =
    IIf(extremeUp AND !prevExtremeUp, colorOrange,
    IIf(extremeDn AND !prevExtremeDn, colorBrightGreen,
    IIf(!extremeUp AND prevExtremeUp, colorPink,
    IIf(!extremeDn AND prevExtremeDn, colorAqua,
    IIf(extremeUp, colorRed,
    IIf(extremeDn, colorGreen, colorDarkGrey))))));


// Trend Detection and Reversal
rising = Ref(centerLine, -3) < centerLine;
falling = Ref(centerLine, -3) > centerLine;
trendReversal = trendColor != Ref(trendColor, -1);

trendShift = WriteIf(rising AND !falling, "Uptrend Emerging", 
               WriteIf(falling AND !rising, "Downtrend Emerging", 
               WriteIf(trendReversal, "Trend Reversal", "Stable Trend")));

trendColorCell = IIf(trendReversal, colorOrange, 
                     IIf(rising, colorLime, 
                     IIf(falling, colorViolet, colorDarkGrey)));


hrsi = HMA(RSI(rsilength),rsilength);
hrsi = 2*hrsi-50;

rise = hrsi >= Ref(hrsi,-1);
fall = hrsi < Ref(hrsi,-1);


// Sentiment View
sentiment = WriteIf(rise, "Bullish Bias", 
             WriteIf(fall, "Bearish Bias", "Sideways/Neutral"));

sentimentColor = IIf(sentiment == "Bullish Bias", colorDarkGreen,
                IIf(sentiment == "Bearish Bias", colorRed, colorGrey50));

// === Table Headers ===
TableCell("Market Insight", 1, 1, colorBlue, colorWhite);
TableCell("Current Observation", 2, 1, colorBlue, colorWhite);

// === Row 1 - Price Behavior
TableCell("Extreme Price Behavior", 1, 2, colorGrey40, colorWhite);
TableCell(extremeStatus, 2, 2, extremeColor, colorWhite);

// === Row 2 - Trend Reversal
TableCell("Trend Reversal / Momentum Shift", 1, 3, colorGrey40, colorWhite);
TableCell(trendShift, 2, 3, trendColorCell, colorWhite);

// === Row 3 - Sentiment
TableCell("Short-to-Mid Term Sentiment", 1, 4, colorGrey40, colorWhite);
TableCell(sentiment, 2, 4, sentimentColor, colorWhite);

_SECTION_END();


If you’re interested in customizing it for intraday timeframes, multi-timeframe overlays, or adding trading signals — feel free to request via comment.


Applications

  • Reversal Zone Trading (mean-reversion)
  • Trend Following with Confirmation
  • Swing Trading Filters
  • Sentiment-Driven Dashboards

Download & Usage

  • Import the AFL into Amibroker
  • Apply it on higher timeframes above hourly charts with reasonable amount of historical data.
  • Adjust parameters like:
    • Lowess Length, ATR Period, RSI Hull Length
  • Hover your select the candles over the charts to read the GFX summary live

Final Thoughts

This strategy is part of a broader initiative to build visual, informative dashboards for discretionary traders in AmiBroker. It’s clean, informative, and easy to extend into trade signals or automation.

Happy Trading!

Rajandran R Creator of OpenAlgo - OpenSource Algo Trading framework for Indian Traders. Building GenAI Applications. Telecom Engineer turned Full-time Derivative Trader. Mostly Trading Nifty, Banknifty, High Liquid Stock Derivatives. Trading the Markets Since 2006 onwards. Using Market Profile and Orderflow for more than a decade. Designed and published 100+ open source trading systems on various trading tools. Strongly believe that market understanding and robust trading frameworks are the key to the trading success. Building Algo Platforms, Writing about Markets, Trading System Design, Market Sentiment, Trading Softwares & Trading Nuances since 2007 onwards. Author of Marketcalls.in

2 Replies to “Detecting Extreme Price Behavior and Trend Shifts Using Lowess…”

  1. Is it possible to add trading signals for swing trades along with backtesting parameters

Leave a Reply

Get Notifications, Alerts on Market Updates, Trading Tools, Automation & More