TradingView indicator guides

Normalized Smoothed MACD: Range Mapping and Pine Script | Pineify

Normalized Smoothed MACD maps an EMA difference into its recent min-max range, smooths that mapped series, and smooths it again for a signal line. A positive NSM value is not proof that the fast EMA exceeds the slow EMA. Normalization changes the meaning of zero, and the smoothing and initialization must be checked separately.

Inspect the Pine Script

Separate the five stages

The helper first computes a fast and a slow exponential recurrence from price. Their difference is M. Let L and H be the lowest and highest M values in the normalization window, including the current bar. When H differs from L, raw normalized value R = 2 × (M − L)/(H − L) − 1. When they are equal, the code sets R to zero.

The plotted value V then updates as previous V + alphaSmooth × (R − previous V). Signal S updates as previous S + alphaSignal × (V − previous S). Each alpha is 2/(max(period, 1)+1); the default smoothing and signal periods are 5 and 9, giving alpha 1/3 and 1/5.

The default call fixes close, fast 12, slow 26, signal 9, smooth 5, and normalization 20. It exposes no settings inputs. The main line is green only when it strictly rises; otherwise, including a tie, it is red. The signal line is orange and zero is a plotted horizontal reference.

Zero and 0.8 do not mean what raw MACD means

Before smoothing, R = 0 means M is at the midpoint (L + H)/2 of its current range. It does not mean M = 0. For a hypothetical range L = −10 and H = −2, M = −3.6 produces R = +0.6 even though the fast-minus-slow difference remains negative.

Now assume previous V = −0.6 and R = +0.6 with smoothing 5. The next V is −0.2. If R stays +0.6 one more bar, V becomes approximately +0.066667. The smoothed zero crossing is delayed relative to the raw range-midpoint crossing; it still does not imply a positive raw MACD.

An unsmoothed R of +0.8 means M lies 90% of the way from L to H. With L = −10 and H = −2, that value is −2.8. It is not 90% of the maximum, a percentile, a standard-deviation score, or a probability. The plotted V is additionally smoothed, so its +0.8 cannot generally be inverted to the current M using that formula.

A rolling range can change the output without a new MACD value

Hold M at −4. With L = −10 and H = −2, the raw normalized value is +0.5. If the old minimum leaves the window and the new minimum is −5 while H stays −2, R becomes −1/3. That change arises from the reference range, not a change in current M.

A tiny nonzero range does not force the indicator toward zero. For example, L = 1, H = 1.000002, and M = 1.000001 give R near zero, while either endpoint maps to −1 or +1. Tiny changes can therefore occupy the full normalized scale. Only exact equality selects the explicit zero branch.

If R becomes zero after a previously nonzero V, smoothing makes V decay toward zero rather than resetting it immediately. With normalization length 1, each current range collapses to a single value, so R remains zero and the zero-seeded V and S remain zero.

For finite valid values, current M lies inside its own min-max window. R is in [−1, 1], and the zero-seeded smoothing recurrences are convex combinations, so V and S stay in that interval in exact arithmetic. The implementation uses exact equality, not a small-range tolerance.

Initialization is not the standard price-seeded EMA

The two price recurrences use different fallbacks in the same expression: their previous-value term defaults to zero, while the subtraction’s previous value defaults to current price. On the first valid bar, both outputs are therefore zero, regardless of price. They then begin converging from zero on following bars.

For a constant price of 100 and defaults, the first three values are:

Synthetic flat-price startup
BarFastSlowMRVS
1000000
215.3846157.4074077.97720810.3333330.066667
328.40236714.26611814.13624910.5555560.164444

The apparent early momentum is an initialization artifact on a price that never changes. This page retains that helper behavior for an explicit comparison with the local implementation; it does not present it as equivalent to a standard price-seeded MACD.

There is no full 20-bar warmup gate. The extrema functions can use available observations while history is still short. Compare initialization, available history, and the entire pipeline before comparing values between implementations. Any seed correction is a deliberate algorithm change requiring its own numerical checks.

Shared scale does not calibrate different markets

For the same observation sequence and initialization, multiplying all prices by a positive constant scales both price recurrences and their difference. The factor cancels in min-max normalization. This removes that multiplicative unit scaling; it does not make unrelated market histories equivalent.

Two symbols at +0.8 can have different price trends, range widths, costs, and future outcomes. A shared numeric bound does not make a threshold equally reliable across symbols or timeframes. A normalization window is also not a fixed signal delay, and smoothing does not establish a universal reduction in false crossovers.

Ordinary MACD uses the fast-minus-slow zero directly. Keep that meaning separate from NSM’s rolling range and smoothed output. No specific NSM origin or unsupported development history is asserted here.

Turn a line comparison into an explicit event

The code plots values only. It does not detect divergence, create alerts, manage positions, or identify institutional activity. Its open-bar values can change with current close. A signal-line crossing, zero crossing, and change of line color are different conditions.

For an adaptation, define which series is crossing which, how equality is treated, whether the bar must be closed, and when a trade could first execute. Pivot-based divergence needs the future confirmation bars required by that pivot rule; it cannot be counted as known on the earlier pivot bar.

Reference: Pine live-bar and repainting behavior. Any strategy study also needs exits, sizing, costs, and independent evaluation data. No performance estimate is established here.

Pine Script v6: implementation and limits

The complete source retains the local helper’s initialization and fixed parameters so its behavior can be inspected directly. Syntax validation does not remove the documented flat-price startup artifact. No alerts, divergence detector, or orders are implemented.

Pine Script v6
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify

//@version=6
indicator(title="Normalized Smoothed MACD", overlay=false, max_labels_count=500)

// NSM Calculation — normalized and smoothed MACD variant
p_ta_nsm(series float price, simple int fastPeriod, simple int slowPeriod, simple int macdSignal, simple int smoothPeriod, simple int normPeriod) =>
    emaf = 0.0
    emas = 0.0
    val  = 0.0
    nval = 0.0
    sig  = 0.0

    alphaf   = 2.0 / (1.0 + math.max(fastPeriod, 1))
    alphas   = 2.0 / (1.0 + math.max(slowPeriod, 1))
    alphasig = 2.0 / (1.0 + math.max(macdSignal, 1))
    alphasm  = 2.0 / (1.0 + math.max(smoothPeriod, 1))

    emaf := nz(emaf[1]) + alphaf * (price - nz(emaf[1], price))
    emas := nz(emas[1]) + alphas * (price - nz(emas[1], price))
    imacd = emaf - emas

    mmax = ta.highest(imacd, normPeriod)
    mmin = ta.lowest(imacd, normPeriod)
    nval := mmin != mmax ? 2.0 * (imacd - mmin) / (mmax - mmin) - 1.0 : 0.0

    val := nz(val[1]) + alphasm * (nval - nz(val[1]))
    sig := nz(sig[1]) + alphasig * (val - nz(sig[1]))

    [val, sig]

// Apply NSM with default parameters
[p_ind_1_value, p_ind_1_signal] = p_ta_nsm(close, 12, 26, 9, 5, 20)

// Zero line
hline(0, "NSM - Zero", color=color.new(#787B86, 50))

// NSM value line — green when rising, red when falling
plot(p_ind_1_value, "NSM", p_ind_1_value > p_ind_1_value[1] ? color.rgb(76, 175, 80, 0) : color.rgb(242, 54, 69, 0), linewidth=2)

// NSM signal line — orange, 1px width
plot(p_ind_1_signal, "NSM - Signal", color.rgb(255, 109, 0, 0), linewidth=1)
Existing indicator chart preview
Existing visual preview. Verify exact values against the source; the image is not a performance result.

Specify a checkable adaptation in Pineify

Specify whether to preserve or change the price-recurrence seeds, how long to warm up, how to handle tiny normalization ranges, and which event should be confirmed. Ask the Pine Script AI Coding Agent for these choices explicitly. Compare flat-price startup, the negative-MACD positive-normalization example, and range-expiry behavior before evaluating a strategy.

Open Pine Script AI Coding Agent

Educational indicator analysis. No measured trading performance is established here. Syntax validation does not prove formula equivalence, execution assumptions or profitability.

Implementation questions

No. Raw normalization measures position relative to a rolling range midpoint, and NSM then smooths that value. It can be positive while the underlying EMA difference is negative.

No. For the unsmoothed mapping only, +0.8 corresponds to 90% of the distance from the rolling minimum to maximum. The plotted value includes smoothing and is neither a percentile nor a probability.

An old minimum or maximum can leave the normalization window, changing the reference range. Smoothing also retains prior values, so several stages can move independently.

The raw mapped value becomes zero. Previously nonzero smoothed values decay toward zero. At normalization length 1, the zero-seeded main and signal outputs remain zero.

Its fast and slow recurrences both output zero on the first bar and then converge from zero at different rates. This creates an initial difference even on constant positive prices. The limitation is shown explicitly and is not a measured market signal.

No. Its final call fixes all parameters and it plots two lines plus a zero reference. Inputs, alerts, close confirmation, divergence, and trading rules must be added and validated explicitly.