What it does
The Hull MA Ribbon plots two Hull moving averages (HMA), a fast one and a slow one, and fills the space between them. Each line is colored by its own slope, and the ribbon fill shows whether both slopes agree. The result is a quick visual read of short-term versus medium-term direction with less lag than a pair of simple or exponential averages.
It marks two kinds of events: the fast HMA crossing the slow HMA, and the moment the ribbon becomes fully aligned, meaning both lines slope the same way and the fast line sits on the correct side of the slow one.
How it works
The Hull moving average reduces lag by combining weighted moving averages: HMA(n) = WMA(2 × WMA(price, n/2) − WMA(price, n), √n). The script uses TradingView's built-in ta.hma for both lengths.
- A line is "rising" when its value is above the previous bar's value, and "falling" when below.
- Ribbon color: rising color when both lines rise, falling color when both fall, grey when they disagree.
- Bullish alignment: both lines rising and fast above slow. Bearish alignment: both falling and fast below slow. A label prints on the first bar of each new alignment.
- Cross markers print when the fast HMA crosses the slow HMA.
All markers and alerts are evaluated on closed bars only. You can optionally color price bars by the ribbon state.
How to use it
- Use the ribbon color as a trend filter. A grey ribbon says short- and medium-term direction disagree, which is often a pullback or a range.
- An alignment label is a stricter condition than a cross and usually appears a few bars later. Some traders wait for alignment before considering trades in that direction, and treat crosses as early warnings.
- Combine it with structure: a bullish alignment that forms just after price reclaims a support level carries more context than one in the middle of a range. The moving averages lesson covers the basics.
- It works on most liquid markets. On M1–M5 the Hull's responsiveness can turn into whipsaw, so M15 and above are a better starting point.
Settings
| Input | Default | What it changes |
|---|---|---|
| Source | close | Price fed into both averages. |
| Fast HMA length | 21 | Reaction speed of the fast line. |
| Slow HMA length | 55 | Reaction speed of the slow line. |
| Show fast/slow crosses | On | Small triangles on crosses. |
| Show ribbon alignment labels | On | Bull/Bear labels when the ribbon aligns. |
| Rising / Falling / Mixed color | teal / red / grey | Colors for lines and ribbon. |
| Ribbon transparency | 75 | Opacity of the fill. |
| Color price bars by ribbon state | Off | Paints candles with the ribbon color. |
Limitations
- The Hull average is responsive by design, so its slope can flip on small counter-moves. Expect more color changes than with an EMA pair of similar length.
- Crosses and alignments both lag the actual turning point, and neither says how far a move will go.
- In flat, choppy markets the ribbon alternates between colors and produces signals that quickly reverse.
- The indicator ignores volatility and spread; on wide-spread instruments small swings can be uneconomic to trade even when the ribbon is aligned.
Pine Script source
In TradingView open Pine Editor, paste the code, click Save and then Add to chart.
FXP_HullMARibbon.pine
61 lines
// © FXPIPS ONLINE — https://fxpips.online/tradingview-indicators/hull-ma-ribbon/
// License: MIT. Educational tool — not financial advice. Trading involves substantial risk.
//@version=6
// Fast and slow Hull moving averages drawn as a ribbon. Each line is colored by its own slope,
// the ribbon by slope agreement. Crosses and "fully aligned" states are confirmed on bar close.
indicator("FXP Hull MA Ribbon", shorttitle = "FXP HMA Ribbon", overlay = true)
// ── Inputs ─────────────────────────────────────────────────────────────
grpMa = "Moving averages"
src = input.source(close, "Source", group = grpMa)
fastLen = input.int(21, "Fast HMA length", minval = 2, group = grpMa)
slowLen = input.int(55, "Slow HMA length", minval = 2, group = grpMa)
grpSig = "Signals"
showCross = input.bool(true, "Show fast/slow crosses", group = grpSig)
showAlign = input.bool(true, "Show ribbon alignment labels", group = grpSig, tooltip = "Aligned = fast above slow and both rising (bullish), or fast below slow and both falling (bearish).")
grpVis = "Display"
colBull = input.color(#26a69a, "Rising color", group = grpVis)
colBear = input.color(#ef5350, "Falling color", group = grpVis)
colMixed = input.color(#9e9e9e, "Mixed slope color", group = grpVis)
ribbonTransp = input.int(75, "Ribbon transparency", minval = 0, maxval = 100, group = grpVis)
colorBars = input.bool(false, "Color price bars by ribbon state", group = grpVis)
// ── Calculation ────────────────────────────────────────────────────────
fastHma = ta.hma(src, fastLen)
slowHma = ta.hma(src, slowLen)
fastUp = fastHma > fastHma[1]
fastDown = fastHma < fastHma[1]
slowUp = slowHma > slowHma[1]
slowDown = slowHma < slowHma[1]
// 1 = both rising, -1 = both falling, 0 = slopes disagree
int slopeState = fastUp and slowUp ? 1 : fastDown and slowDown ? -1 : 0
ribbonColor = slopeState == 1 ? colBull : slopeState == -1 ? colBear : colMixed
bullAligned = slopeState == 1 and fastHma > slowHma
bearAligned = slopeState == -1 and fastHma < slowHma
crossUp = ta.crossover(fastHma, slowHma) and barstate.isconfirmed
crossDown = ta.crossunder(fastHma, slowHma) and barstate.isconfirmed
alignUp = bullAligned and not bullAligned[1] and barstate.isconfirmed
alignDown = bearAligned and not bearAligned[1] and barstate.isconfirmed
// ── Plots ──────────────────────────────────────────────────────────────
fastPlot = plot(fastHma, "Fast HMA", color = fastUp ? colBull : colBear, linewidth = 2)
slowPlot = plot(slowHma, "Slow HMA", color = slowUp ? colBull : colBear, linewidth = 2)
fill(fastPlot, slowPlot, color = color.new(ribbonColor, ribbonTransp), title = "Ribbon fill")
barcolor(colorBars ? ribbonColor : na, title = "Bar color")
plotshape(showCross and crossUp, "Fast crosses above slow", style = shape.triangleup, location = location.belowbar, color = colBull, size = size.tiny)
plotshape(showCross and crossDown, "Fast crosses below slow", style = shape.triangledown, location = location.abovebar, color = colBear, size = size.tiny)
plotshape(showAlign and alignUp, "Bullish alignment", style = shape.labelup, location = location.belowbar, color = colBull, text = "Bull", textcolor = color.white, size = size.small)
plotshape(showAlign and alignDown, "Bearish alignment", style = shape.labeldown, location = location.abovebar, color = colBear, text = "Bear", textcolor = color.white, size = size.small)
// ── Alerts ─────────────────────────────────────────────────────────────
alertcondition(crossUp, "HMA bullish cross", "Fast HMA crossed above slow HMA on {{ticker}} ({{interval}})")
alertcondition(crossDown, "HMA bearish cross", "Fast HMA crossed below slow HMA on {{ticker}} ({{interval}})")
alertcondition(alignUp, "HMA ribbon bullish alignment", "HMA ribbon turned fully bullish on {{ticker}} ({{interval}})")
alertcondition(alignDown, "HMA ribbon bearish alignment", "HMA ribbon turned fully bearish on {{ticker}} ({{interval}})")

