What it does
Drawing Fibonacci levels by hand means choosing a swing high and low, and two traders rarely pick the same points. This indicator does it automatically. It finds the latest significant swing, draws retracement levels between its two ends and adds extension levels beyond it. The levels update when a new significant swing forms.
How it works
- Swing highs and lows are confirmed pivots, using the swing length on each side.
- The swings are linked into a zigzag that alternates between highs and lows. Two highs in a row keep the higher one, and two lows in a row keep the lower one.
- A new opposite swing only counts if it is at least the minimum number of ATRs (14) away from the previous swing, so small wiggles are ignored.
- The latest leg is the swing. If the last swing is a high, the leg runs from low to high (an up swing). If it is a low, the leg runs from high to low.
- Retracement level price = swing end − (swing end − swing start) × ratio. So 0 sits at the swing end and 1 at the swing start.
- Extension level price = swing start + (swing end − swing start) × ratio. With ratios above 1, these project beyond the swing end in the direction of the swing.
Illustrative example: an up swing from 1.0800 to 1.0900 puts the 0.5 level at 1.0850, the 0.618 level at 1.08382 and the 1.618 extension at 1.09618.
The 0.5 to 0.618 levels are highlighted in a separate color. All lines are redrawn on the last bar only, and the old ones are deleted first.
How to use it
- In an up swing, the retracement levels show where a pullback might pause. Many traders watch the 0.382 to 0.618 area together with other evidence such as support or a candlestick pattern.
- Extensions are commonly used as possible profit-taking areas once price moves past the swing end. See the Fibonacci retracement lesson for background.
- Increase the swing length or the minimum ATR size to anchor on bigger swings for swing trading. Lower them for intraday legs.
Alerts: price closed inside the 0.5 to 0.618 zone, and Fibonacci anchors moved to a new swing.
Settings
| Input | Default | What it changes |
|---|---|---|
| Swing length | 10 | Which pivots are found |
| Minimum swing size (x ATR) | 2.0 | Which swings are significant |
| ATR length | 14 | ATR used by the size filter |
| Retracement levels | 0 ... 1 | Ratios drawn inside the swing |
| Extension levels / show | 1.272, 1.618 / On | Ratios beyond the swing |
| Extend lines right | 15 bars | Projection past the last candle |
| Show prices / draw the swing line | On / On | Labels and swing line |
Limitations
Swings confirm after the swing length has passed, so the levels anchor late and move when a new swing confirms. Only the current swing is drawn, not past ones. The script always uses the most recent leg, so during a deep pullback it may switch to measuring the pullback itself. Fibonacci ratios are a widely used convention, not a law of the market, and price often ignores them.
Pine Script source
In TradingView open Pine Editor, paste the code, click Save and then Add to chart.
FXP_AutoFibonacci.pine
128 lines
// © FXPIPS ONLINE — https://fxpips.online/tradingview-indicators/auto-fibonacci/
// License: MIT. Educational tool — not financial advice. Trading involves substantial risk.
//@version=6
// Draws Fibonacci retracement and extension levels between the latest significant swing
// high and swing low. Swings come from confirmed pivots, alternate high/low (a zigzag),
// and must be at least a set number of ATRs apart to count as significant.
indicator("FXP Auto Fibonacci", shorttitle = "FXP Auto Fib", overlay = true, max_lines_count = 50, max_labels_count = 50)
// ── Inputs ─────────────────────────────────────────────────────────────
grpSw = "Swings"
swingLen = input.int(10, "Swing length (bars each side)", minval = 2, maxval = 100, group = grpSw)
minAtr = input.float(2.0, "Minimum swing size (x ATR)", minval = 0.0, step = 0.5, group = grpSw)
atrLen = input.int(14, "ATR length", minval = 1, group = grpSw)
grpLv = "Levels"
retrIn = input.string("0, 0.236, 0.382, 0.5, 0.618, 0.786, 1", "Retracement levels", group = grpLv, tooltip = "Comma-separated ratios. 0 = swing end, 1 = swing start.")
extIn = input.string("1.272, 1.618", "Extension levels", group = grpLv, tooltip = "Comma-separated ratios projected beyond the swing end, in the direction of the swing.")
showExt = input.bool(true, "Show extensions", group = grpLv)
grpDisp = "Display"
extendBars = input.int(15, "Extend lines right (bars)", minval = 0, maxval = 200, group = grpDisp)
showPrices = input.bool(true, "Show prices", group = grpDisp)
showSwing = input.bool(true, "Draw the swing line", group = grpDisp)
colRetr = input.color(#2962ff, "Retracement levels", group = grpDisp)
colKey = input.color(#ff9800, "0.5 - 0.618 zone", group = grpDisp)
colExt = input.color(#9c27b0, "Extension levels", group = grpDisp)
// ── Zigzag of significant swings ───────────────────────────────────────
float atr = ta.atr(atrLen)
ph = ta.pivothigh(high, swingLen, swingLen)
pl = ta.pivotlow(low, swingLen, swingLen)
var float zzHigh = na
var int zzHighBar = na
var float zzLow = na
var int zzLowBar = na
var int lastType = 0 // 1 = last swing was a high, -1 = a low
bool anchorsChanged = false
if not na(ph)
if lastType == 1
if ph > zzHigh
zzHigh := ph
zzHighBar := bar_index - swingLen
anchorsChanged := true
else if na(zzLow) or ph - zzLow >= minAtr * nz(atr)
zzHigh := ph
zzHighBar := bar_index - swingLen
lastType := 1
anchorsChanged := true
if not na(pl)
if lastType == -1
if pl < zzLow
zzLow := pl
zzLowBar := bar_index - swingLen
anchorsChanged := true
else if na(zzHigh) or zzHigh - pl >= minAtr * nz(atr)
zzLow := pl
zzLowBar := bar_index - swingLen
lastType := -1
anchorsChanged := true
bool valid = not na(zzHigh) and not na(zzLow) and lastType != 0
bool upSwing = lastType == 1 // low -> high, retracements measured down from the high
float swStart = upSwing ? zzLow : zzHigh
float swEnd = upSwing ? zzHigh : zzLow
int startBar = upSwing ? zzLowBar : zzHighBar
int endBar = upSwing ? zzHighBar : zzLowBar
float swRange = swEnd - swStart
levelPrice(float r) =>
swEnd - swRange * r
extPrice(float e) =>
swStart + swRange * e
// ── Drawing (last bar only) ────────────────────────────────────────────
var array<line> fibLines = array.new<line>()
var array<label> fibLabels = array.new<label>()
var line swingLine = na
parseLevels(string s) =>
array<string> parts = str.split(str.replace_all(s, " ", ""), ",")
array<float> out = array.new<float>()
for p in parts
float v = str.tonumber(p)
if not na(v)
out.push(v)
out
drawLevel(float price, string txt, color col, int left, int right) =>
fibLines.push(line.new(left, price, right, price, color = col, width = 1))
string full = showPrices ? txt + " (" + str.tostring(price, format.mintick) + ")" : txt
fibLabels.push(label.new(right, price, full, style = label.style_label_left, color = color.new(color.black, 100), textcolor = col, size = size.small))
true
if barstate.islast
while fibLines.size() > 0
line.delete(fibLines.pop())
while fibLabels.size() > 0
label.delete(fibLabels.pop())
line.delete(swingLine)
if valid
int left = math.min(startBar, endBar)
int right = bar_index + extendBars
array<float> retr = parseLevels(retrIn)
for r in retr
color c = r >= 0.5 and r <= 0.618 ? colKey : colRetr
drawLevel(levelPrice(r), str.tostring(r), c, left, right)
if showExt
array<float> ext = parseLevels(extIn)
for e in ext
drawLevel(extPrice(e), str.tostring(e), colExt, left, right)
if showSwing
swingLine := line.new(startBar, swStart, endBar, swEnd, color = color.new(color.gray, 40), style = line.style_dashed, width = 1)
// ── Alerts ─────────────────────────────────────────────────────────────
float lvl50 = levelPrice(0.5)
float lvl618 = levelPrice(0.618)
float zoneHi = math.max(lvl50, lvl618)
float zoneLo = math.min(lvl50, lvl618)
bool inZone = valid and close <= zoneHi and close >= zoneLo
bool enterZone = barstate.isconfirmed and inZone and not inZone[1] and not anchorsChanged
alertcondition(enterZone, "Price entered 0.5 - 0.618 zone", "{{ticker}} {{interval}}: price closed inside the 0.5 - 0.618 retracement zone at {{close}}")
alertcondition(anchorsChanged, "New Fibonacci swing", "{{ticker}} {{interval}}: Fibonacci anchors moved to a new swing")

