Indicator TutorialPine Script 5

How to Create Fibonacci Retracements on TradingView

Detect swing highs and lows, then project classic retracement ratios automatically.

Fibonacci retracement levels mark where price may pause or reverse within a prior impulse. Traders anchor ratios between a significant swing low and swing high (or the inverse in downtrends). This tutorial covers the standard percentages, how pivots help automate swing selection, and a complete Pine Script v5 overlay that plots key levels whenever new swings confirm.

What is a Fibonacci retracement?

A Fibonacci retracement overlays horizontal levels at key ratios—commonly 23.6%, 38.2%, 50%, 61.8%, and 78.6%—between two anchor prices (swing high and swing low).

The 50% level is not derived from the Fibonacci sequence but is widely used as a midpoint reaction zone. The 61.8% (“golden”) ratio receives outsized attention because many practitioners treat it as a deep pullback shelf.

Automating Fibs requires a rule for picking swings; pivot bars are a pragmatic heuristic on TradingView.

Why Traders Use This Indicator

  • Anticipate reaction zones for entries, stops, and profit-taking within trends.
  • Align discretionary plans with objective chart landmarks shared by many participants.
  • Combine retracement levels with order flow or candlestick confirmation.
  • Backtest structured pullback entries with explicit level definitions.
ParameterDefaultDescription
Swing anchorsPivot-confirmed barsPivot left/right widths control how strict swing detection is—wider means fewer but more significant swings.
Ratios0.236, 0.382, 0.5, 0.618, 0.786Optional extensions (1.272, 1.618, etc.) belong to projection tools, not classic retracements.
Trend directionHigh-to-low vs low-to-highIn uptrends, retracements pull back from the swing high toward the swing low anchor; mirror logic for downtrends.
TimeframeStructure timeframeHigher timeframes produce wider swings; scalping charts may over-produce pivots.

How retracement levels are placed

Let H be the swing high and L the swing low, with R = H - L.

For an upward impulse followed by a pullback, retracement prices below H are:

Level = H - R × ratio

Example: 61.8% retracement sits at H - 0.618R. For a downward impulse (price bouncing up), invert the anchors so the math still measures retracement inside the prior range.

Pine scripts often store the latest confirmed pivot high/low in var variables, then recompute levels when a new swing prints.

Signal Interpretation

Shallow pullbacks (23.6–38.2%): Suggest strong trends when reactions are brief.

Mid retracements (~50%): Common balance point between continuation and deeper repair.

Deep retracements (61.8–78.6%): May indicate late trend entries or failure zones if price cannot reclaim prior extremes.

Invalidation: Closing beyond the 100% anchor implies the prior swing structure may be broken—re-anchor pivots.

Combining with Other Indicators

Pair Fibonacci retracements with trend filters (moving averages, market structure) so levels are traded only in the dominant direction. Add volume or VWAP to see whether reactions at fibs coincide with participation. Use RSI or Stochastic for timing within the level zone.

The Hard Way: Writing Pine Script Manually

Challenges of Manual Coding

Switch from pivot-based swings to zigzag-style percent reversal rules.

Color levels differently for uptrend vs downtrend anchor ordering.

Emit labels showing the ratio and price when price first touches a level.

Export levels to a strategy for limit-order style backtests with slippage controls.

Pine Script 5
//@version=5
indicator("Auto Fib Retracement (pivot swings)", shorttitle="AutoFib", overlay=true, max_lines_count=64, max_labels_count=64)

// -----------------------------------------------------------------------------
// Inputs
// -----------------------------------------------------------------------------
leftBars = input.int(5, "Pivot left bars", minval=1)
rightBars = input.int(5, "Pivot right bars", minval=1)
showLabels = input.bool(true, "Show ratio labels")
extendBars = input.int(50, "Line extend (bars forward)", minval=5, maxval=500)

// Classic retracement ratios
r236 = input.bool(true, "Plot 23.6%")
r382 = input.bool(true, "Plot 38.2%")
r500 = input.bool(true, "Plot 50.0%")
r618 = input.bool(true, "Plot 61.8%")
r786 = input.bool(true, "Plot 78.6%")

// -----------------------------------------------------------------------------
// Pivot detection (confirmed after rightBars)
// -----------------------------------------------------------------------------
pHigh = ta.pivothigh(high, leftBars, rightBars)
pLow = ta.pivotlow(low, leftBars, rightBars)

// -----------------------------------------------------------------------------
// Track latest confirmed swings
// -----------------------------------------------------------------------------
var float swingHigh = na
var float swingLow = na

if not na(pHigh)
    swingHigh := pHigh

if not na(pLow)
    swingLow := pLow

// -----------------------------------------------------------------------------
// Determine anchor ordering (trend-agnostic mechanical rule)
// Use the most recently updated swing as "active" context; require both swings.
// -----------------------------------------------------------------------------
havePair = not na(swingHigh) and not na(swingLow)
rangeHigh = havePair ? math.max(swingHigh, swingLow) : na
rangeLow = havePair ? math.min(swingHigh, swingLow) : na
rng = havePair ? (rangeHigh - rangeLow) : na

fibLevel(ratio) =>
    rangeHigh - rng * ratio

f236 = fibLevel(0.236)
f382 = fibLevel(0.382)
f500 = fibLevel(0.500)
f618 = fibLevel(0.618)
f786 = fibLevel(0.786)

// -----------------------------------------------------------------------------
// Plot levels (horizontal segments from confirmation bar)
// -----------------------------------------------------------------------------
plot(havePair and r236 ? f236 : na, title="23.6%", color=color.new(color.teal, 0), linewidth=1, style=plot.style_linebr)
plot(havePair and r382 ? f382 : na, title="38.2%", color=color.new(color.blue, 0), linewidth=1, style=plot.style_linebr)
plot(havePair and r500 ? f500 : na, title="50.0%", color=color.new(color.gray, 0), linewidth=1, style=plot.style_linebr)
plot(havePair and r618 ? f618 : na, title="61.8%", color=color.new(color.orange, 0), linewidth=2, style=plot.style_linebr)
plot(havePair and r786 ? f786 : na, title="78.6%", color=color.new(color.red, 0), linewidth=1, style=plot.style_linebr)

// Reference chord
plot(havePair ? rangeHigh : na, title="Range high", color=color.new(color.green, 60), linewidth=1, style=plot.style_linebr)
plot(havePair ? rangeLow : na, title="Range low", color=color.new(color.maroon, 60), linewidth=1, style=plot.style_linebr)

// -----------------------------------------------------------------------------
// Simple line drawing for last bar (visual aid)
// -----------------------------------------------------------------------------
var line ln236 = na
var line ln618 = na

if barstate.islast and havePair
    if not na(ln236)
        line.delete(ln236)
    if not na(ln618)
        line.delete(ln618)
    ln236 := line.new(bar_index - 30, f236, bar_index + extendBars, f236, color=color.teal, width=1)
    ln618 := line.new(bar_index - 30, f618, bar_index + extendBars, f618, color=color.orange, width=2)

// -----------------------------------------------------------------------------
// Labels on last bar
// -----------------------------------------------------------------------------
var label lb = na
if showLabels and barstate.islast and havePair
    if not na(lb)
        label.delete(lb)
    txt = "Fib cluster | H:" + str.tostring(rangeHigh, format.mintick) + " L:" + str.tostring(rangeLow, format.mintick)
    lb := label.new(bar_index, high, txt, style=label.style_label_lower_left, color=color.new(color.black, 10), textcolor=color.white, size=size.small)

// -----------------------------------------------------------------------------
// Alerts (touch 61.8% zone loosely)
// -----------------------------------------------------------------------------
near618 = havePair and not na(f618) and math.abs(close - f618) <= rng * 0.02
alertcondition(near618, title="Near 61.8% retracement", message="Price within 2% of range to 61.8% fib")

// -----------------------------------------------------------------------------
// Info table
// -----------------------------------------------------------------------------
var table tb = table.new(position.top_left, 2, 6, border_width=1)
if barstate.islast
    table.cell(tb, 0, 0, "Swing high", text_color=color.white, bgcolor=color.new(color.gray, 35))
    table.cell(tb, 1, 0, havePair ? str.tostring(rangeHigh, format.mintick) : "-", text_color=color.white)
    table.cell(tb, 0, 1, "Swing low", text_color=color.white, bgcolor=color.new(color.gray, 35))
    table.cell(tb, 1, 1, havePair ? str.tostring(rangeLow, format.mintick) : "-", text_color=color.white)
    table.cell(tb, 0, 2, "Range", text_color=color.white, bgcolor=color.new(color.gray, 35))
    table.cell(tb, 1, 2, havePair ? str.tostring(rng, format.mintick) : "-", text_color=color.white)
    table.cell(tb, 0, 3, "61.8%", text_color=color.white, bgcolor=color.new(color.gray, 35))
    table.cell(tb, 1, 3, havePair ? str.tostring(f618, format.mintick) : "-", text_color=color.white)
    table.cell(tb, 0, 4, "50.0%", text_color=color.white, bgcolor=color.new(color.gray, 35))
    table.cell(tb, 1, 4, havePair ? str.tostring(f500, format.mintick) : "-", text_color=color.white)
    table.cell(tb, 0, 5, "Pivot L/R", text_color=color.white, bgcolor=color.new(color.gray, 35))
    table.cell(tb, 1, 5, str.tostring(leftBars) + " / " + str.tostring(rightBars), text_color=color.white)

// Educational note: refine anchor logic for strict uptrend vs downtrend if you trade directional fibs only.

Maintenance Note: Pivot-only swings are a heuristic. For production, decide explicitly how to order anchors in bull vs bear structure and whether to reset lines on each new pivot. `line.new` calls here are minimal—scale carefully to avoid hitting object limits on history scroll.

The Easy Way: Build with Pineify Visual Editor

What if you could create the same indicator without writing a single line of code? Pineify is a visual editor designed for TradingView users who want professional-grade indicators through an intuitive interface.

FeatureManual Pine ScriptPineify Visual Editor
Swing selectionTune pivot widths and edge cases by hand across symbols.Reuse parameterized pivot presets per asset class.
Level catalogDuplicate math for every ratio you enable.Toggle standard ratio sets without editing formulas.
Drawing objectsManaging line/label lifecycle is verbose.Generate consistent drawing hygiene and limits.
Strategy integrationHard to keep indicator anchors aligned with strategy state.Share anchor logic between study and strategy exports.
DocumentationTraders may misread auto anchors without inline notes.Ship tables/labels that explain active swings.

Faster tuning of pivot sensitivity for different markets.

Cleaner refactors when adding extensions or confluence zones.

Less repetitive ratio arithmetic across projects.

Step-by-Step Tutorial

1

Define swing rule

Pick pivot left/right or an alternative swing algorithm.

2

Store last highs and lows

Use `var` variables updated when pivots confirm.

3

Compute ratios

Map each enabled ratio to `high - range * ratio` pattern.

4

Plot or draw

Choose plots, lines, or both depending on visual needs.

5

Annotate

Label active range and key levels for clarity.

6

Add alerts

Fire when price approaches critical ratios with buffers.

7

Export v5

Validate against TradingView’s drawing tool for a few swings.

Trading Strategies & Pro Tips

61.8% pullback continuation

Enter in trend direction on rejection wicks at the 61.8% zone with a stop beyond the swing extreme.

Pro Tip: Confirm with smaller timeframe structure or momentum divergence filters.

50% mean hinge

Use the midpoint as a scale-in zone when higher timeframe bias remains intact.

Deep 78.6% last-chance

Treat tags near 78.6% as final trend support tests; failure can signal regime change.

Confluence scalps

Require a fib level to align with VWAP, prior day high/low, or a moving average.

Common Mistakes to Avoid

  • Mixing retracement ratios with extension levels without relabeling.
  • Anchoring to unconfirmed intrabar swings that repaint.
  • Using ultra-tight pivots on noisy symbols, producing cluttered levels.
  • Ignoring which side of the market you are retracing from in directional systems.
  • Overfitting exact tick reactions without considering liquidity zones.

Frequently Asked Questions

Automate Fibonacci workflows with Pineify

  • Iterate swing logic and ratio sets without manual copy-paste.
  • Keep plots, lines, and alerts synchronized as you extend the script.
  • Export Pine Script v5 that is ready for peer review.

Disclaimer: Trading involves significant risk. The indicators, code, and strategies provided are for educational purposes only and do not constitute financial advice. Past performance is not indicative of future results.