What it measures
Williams %R measures where the close sits within the high-low range of the last N bars, on a scale from 0 to −100. A reading near 0 means the bar closed near the top of the range; near −100, near the bottom.
Larry Williams introduced it in the 1970s. It is the stochastic oscillator's raw %K turned upside down: %R = %K − 100. The information is the same, the scale is different, and %R is usually shown without smoothing or a signal line, so it reacts quickly.
The formula in words
- Find the highest high and lowest low of the last N bars (14 by default).
- %R = (highest high − close) ÷ (highest high − lowest low) × −100.
The result runs from 0 (close at the highest high) to −100 (close at the lowest low). The negative scale is a convention from the original; some platforms show %R from 0 to 100 instead. Pine Script's ta.wpr(length) uses the negative scale. If the window's high equals its low, the value is undefined for that bar.
How traders read it
- Zones. Above −20 is called overbought and below −80 oversold. In a trend %R can stay in a zone for a long time, so being in a zone isn't a signal by itself.
- Leaving a zone. A more specific event is %R crossing back below −20 or back above −80: the close has moved away from the edge of the range. The script marks those crosses.
- Momentum confirmation. During a strong rally %R keeps returning to near 0. %R failing to reach −20 on a later push is read as momentum fading.
- Trend filter. Taking oversold exits only when price is above a long moving average (and overbought exits only below it) cuts signals against the trend. The script includes this as an option.
Common settings
| Setting | Typical value | Notes |
|---|---|---|
| Length | 14 | 10 is also common. Shorter lengths reach the extremes more often. |
| Levels | −20 / −80 | −10 / −90 for fewer, more extreme readings. |
| Trend filter | 200 EMA | Optional, off by default in the script. |
Because %R isn't smoothed, it's noisier than a slow stochastic of the same length.
Pine Script v6 code
The complete, self-contained script is below. Copy it into a new indicator in TradingView's Pine Editor, or download the .pine file.
//@version=6
indicator("Williams %R", shorttitle = "%R", format = format.price, precision = 2)
len = input.int(14, "Length", minval = 1, group = "Calculation")
obLevel = input.int(-20, "Overbought level", minval = -50, maxval = 0, group = "Levels")
osLevel = input.int(-80, "Oversold level", minval = -100, maxval = -50, group = "Levels")
useTrend = input.bool(false, "Only mark signals in the direction of the trend EMA", group = "Filter")
trendLen = input.int(200, "Trend EMA length", minval = 2, group = "Filter")
wr = ta.wpr(len)
trend = ta.ema(close, trendLen)
// %R leaving a zone: crossing back above oversold, or back below overbought.
leavesOversold = ta.crossover(wr, osLevel)
leavesOverbought = ta.crossunder(wr, obLevel)
bullSignal = leavesOversold and (not useTrend or close > trend)
bearSignal = leavesOverbought and (not useTrend or close < trend)
plot(wr, "%R", color = color.new(color.blue, 0), linewidth = 2)
obLine = hline(obLevel, "Overbought", color = color.gray, linestyle = hline.style_dashed)
hline(-50, "Midline", color = color.new(color.gray, 60), linestyle = hline.style_dotted)
osLine = hline(osLevel, "Oversold", color = color.gray, linestyle = hline.style_dashed)
fill(obLine, osLine, color = color.new(color.blue, 93), title = "Range")
plotshape(bullSignal, "Leaves oversold", shape.triangleup, location.bottom, color.new(color.teal, 0), size = size.tiny)
plotshape(bearSignal, "Leaves overbought", shape.triangledown, location.top, color.new(color.red, 0), size = size.tiny)
alertcondition(bullSignal, "%R leaves oversold", "Williams %R crossed back above the oversold level on {{ticker}} ({{interval}})")
alertcondition(bearSignal, "%R leaves overbought", "Williams %R crossed back below the overbought level on {{ticker}} ({{interval}})")The script plots %R in its own pane with the zone between the levels shaded, and marks the bar where %R crosses back out of a zone. An optional 200 EMA filter keeps bullish marks only above the EMA and bearish marks only below it.
Both events are available as alert conditions. Choose Once per bar close: on the live bar %R moves with every tick.
Add it to your chart
- Open any chart on TradingView and open the Pine Editor.
- Create a new indicator, delete the template code and paste the script.
- Click Save, then Add to chart. Change lengths and levels from the indicator's settings.
Stuck on an error? See how to add a Pine Script indicator to TradingView.
Pitfalls
- Selling every reading above −20. In strong uptrends %R lives near 0. Use the zones in ranges or with a trend filter.
- Expecting new information next to a stochastic. %R is the unsmoothed stochastic %K on another scale. Adding both to a chart doesn't add a second opinion.
- Scale confusion. Some platforms show %R from 0 to 100. Check the scale before copying levels from another source.
- Live-bar crosses. The close isn't final until the bar closes.
Related reading
- Pine Script alerts: alertcondition() vs alert(), messages, webhooks and frequency
- Pine Script v6 for beginners: the concepts that make everything click
- RSI Calculator (free tool)
- Risk/Reward Calculator (free tool)
The script is an educational example: test it on your own markets before relying on it. Indicators describe the past; they don't predict the future. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.