Skip to content

Free TradingView indicator

Auto Fibonacci

Draws Fibonacci retracement and extension levels automatically between the latest significant swing high and swing low.

Levelsv1.0TradingView (Pine Script v6) Non-repainting signals Alerts

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

  1. Swing highs and lows are confirmed pivots, using the swing length on each side.
  2. 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.
  3. 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.
  4. 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.
  5. Retracement level price = swing end − (swing end − swing start) × ratio. So 0 sits at the swing end and 1 at the swing start.
  6. 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

InputDefaultWhat it changes
Swing length10Which pivots are found
Minimum swing size (x ATR)2.0Which swings are significant
ATR length14ATR used by the size filter
Retracement levels0 ... 1Ratios drawn inside the swing
Extension levels / show1.272, 1.618 / OnRatios beyond the swing
Extend lines right15 barsProjection past the last candle
Show prices / draw the swing lineOn / OnLabels 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")

Key inputs

Key inputs of Auto Fibonacci
InputDefaultDescription
Swing length10Bars on each side that confirm a swing high or low.
Minimum swing size2.0 × ATRSmallest move that counts as a significant swing.
Retracement levels0, 0.236, 0.382, 0.5, 0.618, 0.786, 1Comma-separated retracement ratios.
Extension levels1.272, 1.618Comma-separated extension ratios beyond the swing end.
Extend lines right15 barsHow far the levels project past the last candle.

Educational tools, not advice. Indicators and Expert Advisors describe price; they do not predict it, and past behaviour does not guarantee future results. Test everything on a demo account first and never risk money you cannot afford to lose. See our disclaimer.

Keep exploring

Related tradingview indicators