What it does
The average daily range (ADR) is the average distance between the high and low of recent days. It gives a realistic sense of how far an instrument usually travels in one day. This indicator draws ADR projections from the day open and shows how much of the typical range has already been covered.
That helps answer practical questions: is a target realistic for today, has the market already made its usual move, and how wide should a daily stop be relative to normal volatility?
How it works
- ADR = simple average of (high − low) over the last N completed daily bars. The current day is never included.
- The daily values are requested with lookahead off and the documented one-bar offsets, so the ADR for a day is fixed when the day starts.
- Day open, day high and day low are tracked from the chart's own bars, starting at the first bar of each daily session.
- Projections: open + ADR, open − ADR, open + ADR ÷ 2 and open − ADR ÷ 2.
- Optional range-remaining targets: today's low + ADR and today's high − ADR. These move as the day extends.
- ADR % used = (today's high − today's low) ÷ ADR × 100.
- The panel shows ADR in price, in pips for forex symbols quoted with 5 or 3 decimals (one pip = ten ticks) and in ticks for other symbols.
Illustrative example: if a pair's 14-day ADR is 0.0080 (80 pips) and today's range so far is 0.0060, the panel shows 75% used.
How to use it
- Target sanity check: if 90% of the ADR is already used, a further 50-pip target in the same direction asks for an unusually large day.
- Late entries: many intraday traders become more cautious about chasing moves once the day's range reaches 100% of ADR.
- Stops: comparing your stop-loss distance with the ADR shows whether it sits inside normal daily noise.
- Range-remaining targets: after the low is set, low + ADR shows where an average-sized day would end.
Convert ADR distances to money with the Pip Calculator.
Settings
| Input | Default | What it changes |
|---|---|---|
| ADR length (days) | 14 | Days averaged. |
| Show day open +/- full ADR | on | Outer projections. |
| Show day open +/- half ADR | on | Inner projections. |
| Show day open | on | Open line. |
| Show range-remaining targets | off | Dynamic low + ADR and high − ADR. |
| Show ADR panel / Panel position | on / Top right | Info table. |
| Colors | red / orange / gray | Line colors. |
Limitations
- ADR is an average. Many days are much smaller or larger, especially around major news.
- The day boundary comes from the data feed and can differ from your broker's server time, which changes the day open and range.
- Day open, high and low are taken from chart bars, so the first partial day on the chart is incomplete.
- Projections from the open assume nothing about direction; price rarely reaches both sides in one day.
- Requires an intraday chart.
Pine Script source
In TradingView open Pine Editor, paste the code, click Save and then Add to chart.
FXP_AverageDailyRange.pine
88 lines
// © FXPIPS ONLINE — https://fxpips.online/tradingview-indicators/average-daily-range/
// License: MIT. Educational tool — not financial advice. Trading involves substantial risk.
//@version=6
indicator("FXP Average Daily Range", shorttitle = "FXP ADR", overlay = true)
// ── Inputs ─────────────────────────────────────────────────────────────
grpA = "ADR"
adrLen = input.int(14, "ADR length (days)", minval = 1, maxval = 200, group = grpA)
grpL = "Projections"
showFull = input.bool(true, "Show day open +/- full ADR", group = grpL)
showHalf = input.bool(true, "Show day open +/- half ADR", group = grpL)
showOpen = input.bool(true, "Show day open", group = grpL)
showDyn = input.bool(false, "Show range-remaining targets (low + ADR, high - ADR)", group = grpL)
grpVis = "Display"
showTbl = input.bool(true, "Show ADR panel", group = grpVis)
tblPos = input.string("Top right", "Panel position", options = ["Top right", "Bottom right", "Top left", "Bottom left"], group = grpVis)
fullCol = input.color(color.red, "Full ADR color", group = grpVis)
halfCol = input.color(color.orange, "Half ADR color", group = grpVis)
openCol = input.color(color.gray, "Day open color", group = grpVis)
if not timeframe.isintraday
runtime.error("Average Daily Range projections need an intraday chart.")
// ── ADR from completed daily bars (non-repainting) ─────────────────────
int htfIdx = barstate.isrealtime ? 1 : 0
int chIdx = barstate.isrealtime ? 0 : 1
float adrRaw = request.security(syminfo.tickerid, "D", ta.sma(high - low, adrLen)[htfIdx], lookahead = barmerge.lookahead_off)
float adr = adrRaw[chIdx]
// ── Today's open, high and low from chart bars ─────────────────────────
bool newDay = timeframe.change("D")
var float dOpen = na
var float dHigh = na
var float dLow = na
if newDay
dOpen := open
dHigh := high
dLow := low
else
dHigh := math.max(nz(dHigh, high), high)
dLow := math.min(nz(dLow, low), low)
float usedPct = adr > 0 and not na(dOpen) ? (dHigh - dLow) / adr * 100.0 : na
float upFull = dOpen + adr
float dnFull = dOpen - adr
float upHalf = dOpen + adr / 2.0
float dnHalf = dOpen - adr / 2.0
float upDyn = dLow + adr
float dnDyn = dHigh - adr
// ── Plots (break at each new day) ──────────────────────────────────────
plot(showOpen and not newDay ? dOpen : na, "Day open", color = openCol, style = plot.style_linebr)
plot(showFull and not newDay ? upFull : na, "Open + ADR", color = fullCol, linewidth = 2, style = plot.style_linebr)
plot(showFull and not newDay ? dnFull : na, "Open - ADR", color = fullCol, linewidth = 2, style = plot.style_linebr)
plot(showHalf and not newDay ? upHalf : na, "Open + ADR/2", color = halfCol, style = plot.style_linebr)
plot(showHalf and not newDay ? dnHalf : na, "Open - ADR/2", color = halfCol, style = plot.style_linebr)
plot(showDyn and not newDay ? upDyn : na, "Low + ADR", color = color.new(fullCol, 50), style = plot.style_circles, linewidth = 1)
plot(showDyn and not newDay ? dnDyn : na, "High - ADR", color = color.new(fullCol, 50), style = plot.style_circles, linewidth = 1)
plot(adr, "ADR", display = display.data_window)
plot(usedPct, "ADR % used", display = display.data_window)
// ── Panel ──────────────────────────────────────────────────────────────
// Pip size for forex symbols quoted with 5 or 3 decimals (one pip = ten ticks); ticks otherwise.
int decimals = math.round(-math.log10(syminfo.mintick))
bool isFx = syminfo.type == "forex"
float pipSize = isFx and (decimals == 5 or decimals == 3) ? syminfo.mintick * 10 : syminfo.mintick
string unitTxt = isFx ? "pips" : "ticks"
string posStr = tblPos == "Top right" ? position.top_right : tblPos == "Bottom right" ? position.bottom_right : tblPos == "Top left" ? position.top_left : position.bottom_left
var table tbl = table.new(posStr, 2, 3, bgcolor = color.new(color.black, 80), border_width = 1)
if barstate.islast and showTbl
table.cell(tbl, 0, 0, "ADR (" + str.tostring(adrLen) + "d)", text_color = color.white, text_size = size.small)
table.cell(tbl, 1, 0, na(adr) ? "n/a" : str.tostring(adr, format.mintick), text_color = color.white, text_size = size.small)
table.cell(tbl, 0, 1, "ADR (" + unitTxt + ")", text_color = color.white, text_size = size.small)
table.cell(tbl, 1, 1, na(adr) ? "n/a" : str.tostring(adr / pipSize, "#.#"), text_color = color.white, text_size = size.small)
table.cell(tbl, 0, 2, "Used today", text_color = color.white, text_size = size.small)
table.cell(tbl, 1, 2, na(usedPct) ? "n/a" : str.tostring(usedPct, "#") + "%", text_color = usedPct >= 100 ? color.orange : color.white, text_size = size.small)
// ── Alerts (closed bars) ───────────────────────────────────────────────
bool reachedAdr = barstate.isconfirmed and usedPct >= 100 and not (usedPct[1] >= 100) and not newDay
bool hitUpFull = barstate.isconfirmed and high >= upFull and not (high[1] >= upFull[1]) and not newDay
bool hitDnFull = barstate.isconfirmed and low <= dnFull and not (low[1] <= dnFull[1]) and not newDay
alertcondition(reachedAdr, "Day range reached ADR", "FXP ADR: today's range has reached 100% of the ADR on {{ticker}}")
alertcondition(hitUpFull, "Price reached open + ADR", "FXP ADR: price reached the day open + ADR projection on {{ticker}} {{interval}}")
alertcondition(hitDnFull, "Price reached open - ADR", "FXP ADR: price reached the day open - ADR projection on {{ticker}} {{interval}}")

