Smoothed On-Balance Volume (OBV) — Volume Drop
On-Balance Volume is the oldest volume-trend tool there is, but a raw cumulative line is noisy and hard to read against price. This drop wraps Granville's classic OBV in an EMA signal line and an optional smoothing pass so you get a clean, color-coded trigger instead of a jagged tally.
## What it does
- Builds the cumulative Granville OBV: adds full bar volume on up-closes, subtracts it on down-closes, holds flat on unchanged closes
- Plots an EMA signal line (default 20) over the OBV for a tradeable cross trigger
- Color-codes the OBV line green/red by its position relative to the signal
- Optional pre-smoothing EMA on the OBV itself for cleaner divergence reading
- Fires arrows, a status label, and bull/bear alerts on every signal cross
## Recommended settings
- Signal EMA length: 20
- OBV smoothing length: 1 (raw) — bump to 3-5 on noisy intraday charts
- Show signal line: on
- Show cross arrows: on
- Show status label: on
## Ideal timeframe
Works on any timeframe; shines on daily and 1H swing charts where accumulation/distribution builds over many bars.
## How to use
Watch the OBV line relative to its signal: above and green confirms buyers are pressing, below and red flags distribution. Cross arrows mark momentum shifts in the volume tape — but the real edge is divergence. When price makes a new high while OBV refuses to, sellers are quietly stepping in; the reverse warns of exhausted selling. Treat the signal cross as a trigger and the divergence as the thesis.
## Pine Script v5 code
```pine
//@version=5
// ─────────────────────────────────────────────
// │ MarketFragments.com | DNA & Market │
// │ info@marketfragments.com │
// │ www.marketfragments.com │
// ─────────────────────────────────────────────
// Time →
// │
// █ █ █│ █
// █ █ █ │ █ █
// █ █ █ │ █ █ █ ╭─╮
// █ █ █ │ █ █ █ █ ╭─╯ ╰─╮
// █ █ █ │ █ █ █ █ █ █ ╭─╯ ╰─╮
// █ █ █ │ █ █ █ █ █ █ █ █ ╭─╯ ╰─╮
// █ █ █ │ █ █ █ █ █ █ █ █ █ █╭─╯ ╰─╮
// █ █ █ │ █ █ █ █ █ █ █ █ ╰─╮ ╭─╯
// █ █ █ │ █ █ █ █ █ █ ╰─╮ ╭─╯
// █ █ █ │ █ █ █ █ ╰─╮ ╭─╯
// █ █ █ │ █ █ ╰─╮ ╭─╯
// █ █ █ │ █ ╰─────╯
// ──────┴──────────────────────────────────────────────────────────────
// T1 T2 T3 T4 T5 T6
//
// ============================================================
// Smoothed On-Balance Volume (OBV) | Volume category
// ------------------------------------------------------------
// Classic Granville OBV: cumulative volume that adds full bar
// volume on up-closes and subtracts it on down-closes. An EMA
// signal line turns the running tally into a tradeable trigger,
// and an optional smoothing EMA tames the raw line for cleaner
// divergence reading against price.
//
// - OBV line color-coded by position vs. its signal
// - EMA signal line (default 20)
// - Optional pre-smoothing EMA on OBV itself
// - Cross arrows + status label + bull/bear alerts
//
// Free for non-commercial use. Attribution appreciated.
// ============================================================
indicator("MarketFragments Smoothed OBV", shorttitle="MF OBV", overlay=false)
signalLength = input.int(20, "Signal EMA Length", minval=1)
smoothLength = input.int(1, "OBV Smoothing Length", minval=1)
showSignal = input.bool(true, "Show Signal Line")
showCrossArrows = input.bool(true, "Show Cross Arrows")
showLabel = input.bool(true, "Show Status Label")
// Cumulative Granville OBV
var float rawOBV = 0.0
rawOBV := close > close[1] ? rawOBV + volume : close < close[1] ? rawOBV - volume : rawOBV
obv = smoothLength <= 1 ? rawOBV : ta.ema(rawOBV, smoothLength)
signal = ta.ema(obv, signalLength)
obvColor = obv >= signal ? color.lime : color.red
plot(obv, "OBV", color=obvColor, linewidth=2)
plot(showSignal ? signal : na, "Signal", color=color.gray, linewidth=1)
bullCross = ta.crossover(obv, signal)
bearCross = ta.crossunder(obv, signal)
plotshape(showCrossArrows and bullCross, title="Bull Cross", style=shape.triangleup, location=location.bottom, color=color.aqua, size=size.tiny)
plotshape(showCrossArrows and bearCross, title="Bear Cross", style=shape.triangledown, location=location.top, color=color.fuchsia, size=size.tiny)
var label lbl = na
if showLabel and barstate.islast
label.delete(lbl)
lbl := label.new(bar_index, obv, obv >= signal ? "OBV ABOVE signal" : "OBV BELOW signal", style=label.style_label_left, color=(obv >= signal ? color.green : color.red), textcolor=color.white)
alertcondition(bullCross, "OBV Bullish Cross", "OBV crossed above its signal line")
alertcondition(bearCross, "OBV Bearish Cross", "OBV crossed below its signal line")
```
Drop your tweaks, screenshots, and questions below — that's how the library gets better.

