Skip to content

Free TradingView indicator

Pivot Points Multi

Classic, Fibonacci, Camarilla and Woodie pivot points from the previous daily, weekly, monthly or yearly bar, non-repainting.

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

What it does

Pivot points turn the previous period's high, low and close into a set of horizontal levels for the current period: a central pivot (P), resistance levels above (R1, R2...) and support levels below (S1, S2...). Because every trader using the same formula sees the same levels, they are widely watched, especially on intraday charts.

This indicator offers four common formulas, picks a sensible pivot timeframe automatically, and only uses completed higher-timeframe bars, so the levels for a period never change once that period has started.

How it works

Let H, L and C be the high, low and close of the previous completed pivot period, and R = H − L.

TypePivotLevels
ClassicP = (H + L + C) ÷ 3R1 = 2P − L, S1 = 2P − H, R2 = P + R, S2 = P − R, R3 = H + 2(P − L), S3 = L − 2(H − P)
FibonacciP = (H + L + C) ÷ 3R1/S1 = P ± 0.382R, R2/S2 = P ± 0.618R, R3/S3 = P ± 1.000R
CamarillaP = (H + L + C) ÷ 3R1/S1 = C ± 1.1R ÷ 12, R2/S2 = C ± 1.1R ÷ 6, R3/S3 = C ± 1.1R ÷ 4, R4/S4 = C ± 1.1R ÷ 2
WoodieP = (H + L + 2C) ÷ 4Same R1 to S3 structure as Classic, using the Woodie pivot

Auto timeframe: daily pivots on charts up to 1 hour, weekly on charts up to 4 hours, monthly on daily charts and yearly above that.

The previous period's values are requested with lookahead off. On historical bars the result is offset by one chart bar; on live bars the previous higher-timeframe bar is used directly. Both give the completed period's values without peeking into the future.

How to use it

Common readings:

  • Price above P is often treated as a bullish bias for the period, below P as bearish.
  • R1 and S1 are frequent first targets or reaction points intraday. R2/S2 and R3/S3 are reached less often and usually on more volatile days.
  • Camarilla levels cluster close to the previous close. Many traders watch R3/S3 for reversals and R4/S4 for breakouts.
  • Pivots work best alongside other support and resistance, such as previous highs and lows or round numbers.

Alerts are available for crosses of P, closes above R1 and closes below S1.

Settings

InputDefaultWhat it changes
Pivot typeClassicFormula used.
Pivot timeframeAutoDaily, Weekly, Monthly, Yearly or automatic.
Show level labelsonLabels with prices at the last bar.
Show R3 / S3 (and R4 / S4)onOuter levels.
Pivot / resistance / support colororange / red / tealLine colors.

Limitations

  • Pivots are calculated from the data feed's daily boundary. Forex brokers and feeds use different rollover times, so levels can differ slightly between platforms.
  • They are static for the whole period and ignore anything that happens after it starts.
  • Several formulas exist for Woodie and Camarilla pivots. This tool uses the versions shown above.
  • The pivot timeframe must be equal to or higher than the chart timeframe; otherwise the script stops with an error.

Pine Script source

In TradingView open Pine Editor, paste the code, click Save and then Add to chart.

FXP_PivotPointsMulti.pine

118 lines

// © FXPIPS ONLINE — https://fxpips.online/tradingview-indicators/pivot-points-multi/
// License: MIT. Educational tool — not financial advice. Trading involves substantial risk.
//@version=6
indicator("FXP Pivot Points Multi", shorttitle = "FXP Pivots", overlay = true, max_labels_count = 20)

// ── Inputs ─────────────────────────────────────────────────────────────
grpP      = "Pivots"
pivType   = input.string("Classic", "Pivot type", options = ["Classic", "Fibonacci", "Camarilla", "Woodie"], group = grpP)
tfSel     = input.string("Auto", "Pivot timeframe", options = ["Auto", "Daily", "Weekly", "Monthly", "Yearly"], group = grpP, tooltip = "Auto: Daily up to 1h charts, Weekly up to 4h, Monthly on daily charts, Yearly above that.")

grpVis    = "Display"
showLbl   = input.bool(true, "Show level labels on the last bar", group = grpVis)
showS3R3  = input.bool(true, "Show R3 / S3 (and R4 / S4 for Camarilla)", group = grpVis)
pCol      = input.color(color.orange, "Pivot color", group = grpVis)
rCol      = input.color(color.red, "Resistance color", group = grpVis)
sCol      = input.color(color.teal, "Support color", group = grpVis)

// ── Timeframe selection ────────────────────────────────────────────────
string autoTf = timeframe.isintraday and timeframe.multiplier <= 60 ? "D" : timeframe.isintraday ? "W" : timeframe.isdaily ? "M" : "12M"
string htf = tfSel == "Auto" ? autoTf : tfSel == "Daily" ? "D" : tfSel == "Weekly" ? "W" : tfSel == "Monthly" ? "M" : "12M"

if timeframe.in_seconds() > timeframe.in_seconds(htf)
    runtime.error("The pivot timeframe must be equal to or higher than the chart timeframe.")

// ── Previous completed higher-timeframe bar (non-repainting) ──────────
// Historical bars: take the HTF value and offset it one chart bar. Realtime bars: take the previous HTF bar.
int htfIdx = barstate.isrealtime ? 1 : 0
int chIdx  = barstate.isrealtime ? 0 : 1
[hRaw, lRaw, cRaw] = request.security(syminfo.tickerid, htf, [high[htfIdx], low[htfIdx], close[htfIdx]], lookahead = barmerge.lookahead_off)
float pH = hRaw[chIdx]
float pL = lRaw[chIdx]
float pC = cRaw[chIdx]
float rng = pH - pL

// ── Levels ─────────────────────────────────────────────────────────────
float pp = na
float r1 = na
float r2 = na
float r3 = na
float r4 = na
float s1 = na
float s2 = na
float s3 = na
float s4 = na

if pivType == "Classic"
    pp := (pH + pL + pC) / 3.0
    r1 := 2.0 * pp - pL
    s1 := 2.0 * pp - pH
    r2 := pp + rng
    s2 := pp - rng
    r3 := pH + 2.0 * (pp - pL)
    s3 := pL - 2.0 * (pH - pp)
else if pivType == "Fibonacci"
    pp := (pH + pL + pC) / 3.0
    r1 := pp + 0.382 * rng
    s1 := pp - 0.382 * rng
    r2 := pp + 0.618 * rng
    s2 := pp - 0.618 * rng
    r3 := pp + 1.000 * rng
    s3 := pp - 1.000 * rng
else if pivType == "Camarilla"
    pp := (pH + pL + pC) / 3.0
    r1 := pC + rng * 1.1 / 12.0
    s1 := pC - rng * 1.1 / 12.0
    r2 := pC + rng * 1.1 / 6.0
    s2 := pC - rng * 1.1 / 6.0
    r3 := pC + rng * 1.1 / 4.0
    s3 := pC - rng * 1.1 / 4.0
    r4 := pC + rng * 1.1 / 2.0
    s4 := pC - rng * 1.1 / 2.0
else
    pp := (pH + pL + 2.0 * pC) / 4.0
    r1 := 2.0 * pp - pL
    s1 := 2.0 * pp - pH
    r2 := pp + rng
    s2 := pp - rng
    r3 := pH + 2.0 * (pp - pL)
    s3 := pL - 2.0 * (pH - pp)

// Break the lines at each new pivot period so levels do not connect vertically.
bool newPeriod = timeframe.change(htf)
f_show(float v, bool enabled) => newPeriod or not enabled ? float(na) : v

plot(f_show(pp, true), "P", color = pCol, linewidth = 2, style = plot.style_linebr)
plot(f_show(r1, true), "R1", color = rCol, style = plot.style_linebr)
plot(f_show(r2, true), "R2", color = rCol, style = plot.style_linebr)
plot(f_show(r3, showS3R3), "R3", color = rCol, style = plot.style_linebr)
plot(f_show(r4, showS3R3), "R4", color = rCol, style = plot.style_linebr)
plot(f_show(s1, true), "S1", color = sCol, style = plot.style_linebr)
plot(f_show(s2, true), "S2", color = sCol, style = plot.style_linebr)
plot(f_show(s3, showS3R3), "S3", color = sCol, style = plot.style_linebr)
plot(f_show(s4, showS3R3), "S4", color = sCol, style = plot.style_linebr)

// ── Labels (reused, last bar only) ─────────────────────────────────────
var array<label> lbls = array.new_label()
if barstate.islast and showLbl
    array<float>  vals  = array.from(pp, r1, r2, r3, r4, s1, s2, s3, s4)
    array<string> names = array.from("P", "R1", "R2", "R3", "R4", "S1", "S2", "S3", "S4")
    if array.size(lbls) == 0
        for i = 0 to 8
            array.push(lbls, label.new(bar_index, close, "", style = label.style_label_left, color = color.new(color.black, 100), size = size.small))
    for i = 0 to 8
        label lb = array.get(lbls, i)
        float v = array.get(vals, i)
        bool hideExtra = not showS3R3 and (i == 3 or i == 4 or i == 7 or i == 8)
        label.set_xy(lb, bar_index + 1, hideExtra or na(v) ? close : v)
        label.set_text(lb, na(v) or hideExtra ? "" : array.get(names, i) + "  " + str.tostring(v, format.mintick))
        label.set_textcolor(lb, i == 0 ? pCol : i <= 4 ? rCol : sCol)

// ── Alerts ─────────────────────────────────────────────────────────────
bool xP  = ta.cross(close, pp) and barstate.isconfirmed and not newPeriod
bool xR1 = ta.crossover(close, r1) and barstate.isconfirmed and not newPeriod
bool xS1 = ta.crossunder(close, s1) and barstate.isconfirmed and not newPeriod
alertcondition(xP, "Price crossed P", "FXP Pivots: price crossed the pivot on {{ticker}} {{interval}}")
alertcondition(xR1, "Close above R1", "FXP Pivots: close above R1 on {{ticker}} {{interval}}")
alertcondition(xS1, "Close below S1", "FXP Pivots: close below S1 on {{ticker}} {{interval}}")

Key inputs

Key inputs of Pivot Points Multi
InputDefaultDescription
Pivot typeClassicClassic, Fibonacci, Camarilla or Woodie formulas.
Pivot timeframeAutoPeriod whose previous high, low and close feed the pivots.
Show level labels on the last bartrueName and price of each level at the right edge.
Show R3 / S3 (and R4 / S4 for Camarilla)trueToggle the outer levels.

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