Indicator · Pine Script v6 · On the chart

Pivots + Key Levels MP

by midngtpickle· code credited to midnight pickle

This indicator calculates and plots multi-timeframe pivot points using Fibonacci or Camarilla formulas alongside key higher-timeframe and session levels directly on the price chart.

View on GitHub

Repaints

GitHub stars2on the repository
Pine versionv6current
Lines of code877
Settings40inputs
LicenceCustom licencefile: MPL-2.0
Last update4 weeks ago27 Sep 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

877 lines of Pine Script v6 from Master Suite Indicators/pivots_and_key_levels_master_.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

pivots_and_key_levels_master_.pine
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © midnight pickle
//
// ============================================================================
//  Pivots + Key Levels MP  — merged master script
//  PART 1: Pivot Enhanced (Fibonacci / Camarilla, R1-R5 / S1-S5 + alerts)
//  PART 2: Key Levels (Asia session, Monday range, D/W/M/Y highs, lows, mids, opens)
//
//  NOTE ON OBJECT BUDGET: TradingView caps a single indicator at 500 lines and
//  500 labels TOTAL. Both systems now share that budget. With default settings
//  the total is small (~50 each), but a very large Pivot "Lookback Period"
//  combined with all Key Levels enabled can hit the cap and drop oldest objects.
// ============================================================================

//@version=6
indicator('Pivots + Key Levels MP', shorttitle='Pivots+Levels MP', overlay=true, max_lines_count=500, max_labels_count=500, max_bars_back=5000)


// ============================================================================
// ██ PART 1 — PIVOTS ██
// ============================================================================

// Timeframe Options
AUTO = 'Auto'
HOURLY = 'Hourly'
DAILY = 'Daily'
WEEKLY = 'Weekly'
MONTHLY = 'Monthly'
QUARTERLY = 'Quarterly'
YEARLY = 'Yearly'
BIYEARLY = 'Biyearly'
TRIYEARLY = 'Triyearly'
QUINQUENNIAL = 'Quinquennial'

// Pivot Calculation Methods
FIBONACCI = 'Fibonacci'
CAMARILLA = 'Camarilla'

// Pivot input groups
grp_piv = '⭐ Pivots · Settings'
grp_piv_vis = '⭐ Pivots · Visuals'
grp_piv_lvl = '⭐ Pivots · Show/Hide Levels'
grp_piv_col = '⭐ Pivots · Colors'
grp_piv_alert = '⭐ Pivots · Alerts'

// Master enable for the whole pivot system
enable_pivots = input.bool(true, '🔥 Master Toggle: Pivots', group=grp_piv)

// Inputs
kind = input.string(title = 'Calculation Method', defval = 'Camarilla', options = [FIBONACCI, CAMARILLA], group = grp_piv)
pivot_time_frame = input.string(title = 'Timeframe', defval = DAILY, options = [AUTO, HOURLY, DAILY, WEEKLY, MONTHLY, QUARTERLY, YEARLY, BIYEARLY, TRIYEARLY, QUINQUENNIAL], group = grp_piv)
look_back = input.int(title = 'Lookback Period', defval = 1, minval = 1, maxval = 5000, tooltip = 'How many past periods of pivots to keep drawn. Note: total drawn objects (segments x enabled levels) share the 500 line / 500 label cap with the Key Levels below.', group = grp_piv)
is_daily_based = input.bool(title = 'Use Daily-based Values', defval = true, tooltip = 'Use daily OHLC values even on intraday charts', group = grp_piv)
show_labels = input.bool(title = 'Show Labels', defval = true, group = grp_piv_vis)
position_labels = input.string('Left', 'Label Position', options = ['Left', 'Right'], group = grp_piv_vis)

// Show/Hide Levels
show_p = input.bool(title = 'Show Pivot (P)', defval = true, group = grp_piv_lvl)
show_r1 = input.bool(title = 'Show R1/S1', defval = true, group = grp_piv_lvl)
show_r2 = input.bool(title = 'Show R2/S2', defval = true, group = grp_piv_lvl)
show_r3 = input.bool(title = 'Show R3/S3', defval = true, group = grp_piv_lvl, tooltip = 'Carries the H4/L4 value from the calculation. In published Camarilla material H4/L4 is the breakout level, so this line is not the "far extreme, rarely reached" that R3 means in standard pivot notation.')
show_r4 = input.bool(title = 'Show R4/S4', defval = true, group = grp_piv_lvl, tooltip = 'Carries the H5/L5 value from the calculation.')
show_r5 = input.bool(title = 'Show R5/S5', defval = true, group = grp_piv_lvl, tooltip = 'Carries the H6/L6 value from the calculation. TradingView\'s built-in Camarilla plots this same value at its R5, but the levels in between will not line up between the two indicators.')

// Color Settings
p_color = input.color(color.orange, 'Pivot Color', group = grp_piv_col)
s1r1_color = input.color(color.blue, 'S1/R1 Color', group = grp_piv_col)
s2r2_color = input.color(color.red, 'S2/R2 Color', group = grp_piv_col)
s3r3_color = input.color(color.purple, 'S3/R3 Color', group = grp_piv_col)
s4r4_color = input.color(color.green, 'S4/R4 Color', group = grp_piv_col)
s5r5_color = input.color(color.navy, 'S5/R5 Color', group = grp_piv_col)

// Alert Settings
use_close = input.bool(true, 'Use Close Price for Alerts', tooltip = 'When enabled, alerts trigger when the close CROSSES the level. When disabled, alerts trigger on price touch (bar range straddles the level).', group = grp_piv_alert)

// Arrays for storing pivot data
var arr_time = array.new_int()
var p = array.new_float()
var r1 = array.new_float()
var s1 = array.new_float()
var r2 = array.new_float()
var s2 = array.new_float()
var r3 = array.new_float()
var s3 = array.new_float()
var r4 = array.new_float()
var s4 = array.new_float()
var r5 = array.new_float()
var s5 = array.new_float()

// Arrays for storing line and label IDs for cleanup
var line_ids_p = array.new_line()
var line_ids_r1 = array.new_line()
var line_ids_s1 = array.new_line()
var line_ids_r2 = array.new_line()
var line_ids_s2 = array.new_line()
var line_ids_r3 = array.new_line()
var line_ids_s3 = array.new_line()
var line_ids_r4 = array.new_line()
var line_ids_s4 = array.new_line()
var line_ids_r5 = array.new_line()
var line_ids_s5 = array.new_line()

var label_ids_p = array.new_label()
var label_ids_r1 = array.new_label()
var label_ids_s1 = array.new_label()
var label_ids_r2 = array.new_label()
var label_ids_s2 = array.new_label()
var label_ids_r3 = array.new_label()
var label_ids_s3 = array.new_label()
var label_ids_r4 = array.new_label()
var label_ids_s4 = array.new_label()
var label_ids_r5 = array.new_label()
var label_ids_s5 = array.new_label()

// Variables for OHLC data
pivotX_open = float(na)
pivotX_open := nz(pivotX_open[1], open)
pivotX_high = float(na)
pivotX_high := nz(pivotX_high[1], high)
pivotX_low = float(na)
pivotX_low := nz(pivotX_low[1], low)
pivotX_prev_open = float(na)
pivotX_prev_open := nz(pivotX_prev_open[1])
pivotX_prev_high = float(na)
pivotX_prev_high := nz(pivotX_prev_high[1])
pivotX_prev_low = float(na)
pivotX_prev_low := nz(pivotX_prev_low[1])
pivotX_prev_close = float(na)
pivotX_prev_close := nz(pivotX_prev_close[1])

// Get the resolution for pivot calculation
get_pivot_resolution() =>
    resolution = 'M'
    if pivot_time_frame == AUTO
        if timeframe.isintraday
            resolution := timeframe.multiplier <= 15 ? 'D' : 'W'
            resolution
        else if timeframe.isweekly or timeframe.ismonthly
            resolution := '12M'
            resolution
    else if pivot_time_frame == HOURLY
        resolution := '60' // "Hourly" maps to 60 minutes
        resolution
    else if pivot_time_frame == DAILY
        resolution := 'D'
        resolution
    else if pivot_time_frame == WEEKLY
        resolution := 'W'
        resolution
    else if pivot_time_frame == MONTHLY
        resolution := 'M'
        resolution
    else if pivot_time_frame == QUARTERLY
        resolution := '3M'
        resolution
    else if pivot_time_frame == YEARLY or pivot_time_frame == BIYEARLY or pivot_time_frame == TRIYEARLY or pivot_time_frame == QUINQUENNIAL
        resolution := '12M'
        resolution
    resolution

// Drawing functions with ID storage
draw_line(i, pivot, col, line_array) =>
    if array.size(arr_time) > 1
        new_line = line.new(array.get(arr_time, i), array.get(pivot, i), array.get(arr_time, i + 1), array.get(pivot, i), color = col, xloc = xloc.bar_time)
        array.push(line_array, new_line)

draw_label(i, y, txt, txt_color, label_array) =>
    if show_labels
        offset = '      '
        labels_align_str_left = position_labels == 'Left' ? txt + offset : offset + txt
        x = position_labels == 'Left' ? array.get(arr_time, i) : array.get(arr_time, i + 1)
        new_label = label.new(x = x, y = y, text = labels_align_str_left, textcolor = txt_color, style = label.style_label_center, color = #00000000, xloc = xloc.bar_time)
        array.push(label_array, new_label)

// Helpers to fully clear stored drawing objects before each full redraw,
// preventing duplicate/stale line & label accumulation across realtime rollovers.
delete_lines(arr) =>
    if array.size(arr) > 0
        for ln in arr
            line.delete(ln)
        array.clear(arr)

delete_labels(arr) =>
    if array.size(arr) > 0
        for lb in arr
            label.delete(lb)
        array.clear(arr)

clear_all_drawings() =>
    delete_lines(line_ids_p),  delete_labels(label_ids_p)
    delete_lines(line_ids_r1), delete_labels(label_ids_r1)
    delete_lines(line_ids_s1), delete_labels(label_ids_s1)
    delete_lines(line_ids_r2), delete_labels(label_ids_r2)
    delete_lines(line_ids_s2), delete_labels(label_ids_s2)
    delete_lines(line_ids_r3), delete_labels(label_ids_r3)
    delete_lines(line_ids_s3), delete_labels(label_ids_s3)
    delete_lines(line_ids_r4), delete_labels(label_ids_r4)
    delete_lines(line_ids_s4), delete_labels(label_ids_s4)
    delete_lines(line_ids_r5), delete_labels(label_ids_r5)
    delete_lines(line_ids_s5), delete_labels(label_ids_s5)

// Pivot calculation methods
fibonacci() =>
    pivotX_Median = (pivotX_prev_high + pivotX_prev_low + pivotX_prev_close) / 3
    pivot_range = pivotX_prev_high - pivotX_prev_low
    array.push(p, pivotX_Median)
    array.push(r1, pivotX_Median + 0.382 * pivot_range)
    array.push(s1, pivotX_Median - 0.382 * pivot_range)
    array.push(r2, pivotX_Median + 0.618 * pivot_range)
    array.push(s2, pivotX_Median - 0.618 * pivot_range)
    array.push(r3, pivotX_Median + 1 * pivot_range)
    array.push(s3, pivotX_Median - 1 * pivot_range)
    array.push(r4, pivotX_Median + 1.272 * pivot_range)
    array.push(s4, pivotX_Median - 1.272 * pivot_range)
    array.push(r5, pivotX_Median + 1.618 * pivot_range)
    array.push(s5, pivotX_Median - 1.618 * pivot_range)

// NOTE: Camarilla math left exactly as provided (per request). This is a
// deliberate custom variant, NOT the textbook Camarilla equation. Do not
// "correct" it against published formulas.
//
// LEVEL NAMING — read this before cross-referencing any Camarilla material.
// The internal H/L values are stored into the R/S arrays with a deliberate
// one-step shift, and H1/L1 are not plotted at all:
//
//     plotted as ...  R1   R2   R3   R4   R5
//     comes from ...  H2   H3   H4   H5   H6
//     plotted as ...  S1   S2   S3   S4   S5
//     comes from ...  L2   L3   L4   L5   L6
//
// Consequences worth knowing:
//   * This script's R3/S3 carries the H4/L4 value. In published Camarilla
//     material H4/L4 is the breakout level, so R3 here is NOT the "far
//     extreme, rarely reached" that R3 means in standard pivot notation.
//   * TradingView's built-in Pivot Points Standard → Camarilla plots only
//     five levels and puts (prevHigh / prevLow) × prevClose at its R5. That
//     value lives at this script's R5 too, but the levels in between will not
//     line up, so the two indicators are not directly comparable.
camarilla() =>
    pivotX_Median = (pivotX_prev_high + pivotX_prev_low + pivotX_prev_close) / 3
    pivot_range = pivotX_prev_high - pivotX_prev_low
    H4 = pivotX_prev_close + pivot_range * 1.1 / 2
    H3 = pivotX_prev_close + pivot_range * 1.1 / 4
    H2 = pivotX_prev_close + pivot_range * 1.1 / 6
    H1 = pivotX_prev_close + pivot_range * 1.1 / 12
    L1 = pivotX_prev_close - pivot_range * 1.1 / 12
    L2 = pivotX_prev_close - pivot_range * 1.1 / 6
    L3 = pivotX_prev_close - pivot_range * 1.1 / 4
    L4 = pivotX_prev_close - pivot_range * 1.1 / 2
    L5 = L4 - 1.168 * (L3 - L4)
    H5 = H4 + 1.168 * (H4 - H3)
    H6 = pivotX_prev_high / pivotX_prev_low * pivotX_prev_close
    L6 = pivotX_prev_close - (H6 - pivotX_prev_close)
    array.push(p, pivotX_Median)
    array.push(r1, H2)
    array.push(s1, L2)
    array.push(r2, H3)
    array.push(s2, L3)
    array.push(r3, H4)
    array.push(s3, L4)
    array.push(r4, H5)
    array.push(s4, L5)
    array.push(r5, H6)
    array.push(s5, L6)

// Main logic
resolution = get_pivot_resolution()
[sec_open, sec_high, sec_low, sec_close] = request.security(syminfo.tickerid, resolution, [open, high, low, close], lookahead = barmerge.lookahead_on)
sec_open_gaps_on = request.security(syminfo.tickerid, resolution, open, gaps = barmerge.gaps_on, lookahead = barmerge.lookahead_on)

// Fixed custom years resolution handling
var int year_counter = 0
var bool is_change_years = false
var bool custom_years_resolution = pivot_time_frame == BIYEARLY or pivot_time_frame == TRIYEARLY or pivot_time_frame == QUINQUENNIAL

if custom_years_resolution and bool(ta.change(time(resolution)))
    // Increment counter on each timeframe change
    year_counter := year_counter + 1

    // Check if we've reached the target multiple
    if pivot_time_frame == BIYEARLY and year_counter % 2 == 0
        is_change_years := true
        is_change_years
    else if pivot_time_frame == TRIYEARLY and year_counter % 3 == 0
        is_change_years := true
        is_change_years
    else if pivot_time_frame == QUINQUENNIAL and year_counter % 5 == 0
        is_change_years := true
        is_change_years
    else
        is_change_years := false
        is_change_years
else
    is_change_years := false
    is_change_years

var is_change = false
var uses_current_bar = timeframe.isintraday
var change_time = int(na)
is_time_change = bool(ta.change(time(resolution))) and not custom_years_resolution or is_change_years
if is_time_change
    change_time := time
    change_time

if not uses_current_bar and is_time_change or uses_current_bar and not na(sec_open_gaps_on)
    if is_daily_based
        pivotX_prev_open := sec_open[1]
        pivotX_prev_high := sec_high[1]
        pivotX_prev_low := sec_low[1]
        pivotX_prev_close := sec_close[1]
        pivotX_open := sec_open
        pivotX_high := sec_high
        pivotX_low := sec_low
        pivotX_low
    else
        pivotX_prev_high := pivotX_high
        pivotX_prev_low := pivotX_low
        pivotX_prev_open := pivotX_open
        pivotX_open := open
        pivotX_high := high
        pivotX_low := low
        pivotX_prev_close := close[1]
        pivotX_prev_close

    if barstate.islast and not is_change and array.size(arr_time) > 0
        array.set(arr_time, array.size(arr_time) - 1, change_time)
    else
        array.push(arr_time, change_time)

    if kind == FIBONACCI
        fibonacci()
    else if kind == CAMARILLA
        camarilla()

    // Cap stored data arrays to the lookback window.
    if array.size(arr_time) > look_back
        if array.size(arr_time) > 0
            array.shift(arr_time)

        // Shift data arrays
        if array.size(p) > 0
            array.shift(p)
        if array.size(r1) > 0
            array.shift(r1)
        if array.size(s1) > 0
            array.shift(s1)
        if array.size(r2) > 0
            array.shift(r2)
        if array.size(s2) > 0
            array.shift(s2)
        if array.size(r3) > 0
            array.shift(r3)
        if array.size(s3) > 0
            array.shift(s3)
        if array.size(r4) > 0
            array.shift(r4)
        if array.size(s4) > 0
            array.shift(s4)
        if array.size(r5) > 0
            array.shift(r5)
        if array.size(s5) > 0
            array.shift(s5)
    is_change := true
    is_change
else
    if is_daily_based
        pivotX_high := math.max(pivotX_high, sec_high)
        pivotX_low := math.min(pivotX_low, sec_low)
        pivotX_low
    else
        pivotX_high := math.max(pivotX_high, high)
        pivotX_low := math.min(pivotX_low, low)
        pivotX_low

// Get current pivot values for alerts
get_current_pivot_value(arr) =>
    array.size(arr) > 0 ? array.get(arr, array.size(arr) - 1) : na

p_val = get_current_pivot_value(p)
r1_val = get_current_pivot_value(r1)
s1_val = get_current_pivot_value(s1)
r2_val = get_current_pivot_value(r2)
s2_val = get_current_pivot_value(s2)
r3_val = get_current_pivot_value(r3)
s3_val = get_current_pivot_value(s3)
r4_val = get_current_pivot_value(r4)
s4_val = get_current_pivot_value(s4)
r5_val = get_current_pivot_value(r5)
s5_val = get_current_pivot_value(s5)

// Precompute crosses so "Use Close" alerts actually fire.
p_cross  = ta.cross(close, p_val)
r1_cross = ta.cross(close, r1_val)
s1_cross = ta.cross(close, s1_val)
r2_cross = ta.cross(close, r2_val)
s2_cross = ta.cross(close, s2_val)
r3_cross = ta.cross(close, r3_val)
s3_cross = ta.cross(close, s3_val)
r4_cross = ta.cross(close, r4_val)
s4_cross = ta.cross(close, s4_val)
r5_cross = ta.cross(close, r5_val)
s5_cross = ta.cross(close, s5_val)

// Alert Conditions (gated by the pivot master toggle)
// use_close = true  -> close crosses the level
// use_close = false -> bar range straddles the level (touch)
r1_touch = enable_pivots and not na(r1_val) and (use_close ? r1_cross : (low <= r1_val and high >= r1_val))
s1_touch = enable_pivots and not na(s1_val) and (use_close ? s1_cross : (low <= s1_val and high >= s1_val))

r2_touch = enable_pivots and not na(r2_val) and (use_close ? r2_cross : (low <= r2_val and high >= r2_val))
s2_touch = enable_pivots and not na(s2_val) and (use_close ? s2_cross : (low <= s2_val and high >= s2_val))

r3_touch = enable_pivots and not na(r3_val) and (use_close ? r3_cross : (low <= r3_val and high >= r3_val))
s3_touch = enable_pivots and not na(s3_val) and (use_close ? s3_cross : (low <= s3_val and high >= s3_val))

r4_touch = enable_pivots and not na(r4_val) and (use_close ? r4_cross : (low <= r4_val and high >= r4_val))
s4_touch = enable_pivots and not na(s4_val) and (use_close ? s4_cross : (low <= s4_val and high >= s4_val))

r5_touch = enable_pivots and not na(r5_val) and (use_close ? r5_cross : (low <= r5_val and high >= r5_val))
s5_touch = enable_pivots and not na(s5_val) and (use_close ? s5_cross : (low <= s5_val and high >= s5_val))

p_touch = enable_pivots and not na(p_val) and (use_close ? p_cross : (low <= p_val and high >= p_val))

// Create alertcondition entries
alertcondition(r1_touch, title = 'R1 Touched', message = 'R1 Pivot Touched')
alertcondition(s1_touch, title = 'S1 Touched', message = 'S1 Pivot Touched')
alertcondition(r2_touch, title = 'R2 Touched', message = 'R2 Pivot Touched')
alertcondition(s2_touch, title = 'S2 Touched', message = 'S2 Pivot Touched')
alertcondition(r3_touch, title = 'R3 (Key Resistance) Touched', message = 'R3 STRONG Resistance Touched')
alertcondition(s3_touch, title = 'S3 (Key Support) Touched', message = 'S3 STRONG Support Touched')
alertcondition(r4_touch, title = 'R4 (Extreme) Touched', message = 'R4 Extreme Resistance Touched')
alertcondition(s4_touch, title = 'S4 (Extreme) Touched', message = 'S4 Extreme Support Touched')
alertcondition(r5_touch, title = 'R5 (ULTRA) Touched', message = 'R5 ULTRA Resistance Touched')
alertcondition(s5_touch, title = 'S5 (ULTRA) Touched', message = 'S5 ULTRA Support Touched')
alertcondition(p_touch, title = 'Pivot Touched', message = 'Pivot Point Touched')

// Drawing the pivot levels
if enable_pivots and barstate.islast and array.size(arr_time) > 0 and is_change
    is_change := false

    // Clear every previously drawn object before redrawing the full set.
    clear_all_drawings()

    if array.size(arr_time) > 2 and custom_years_resolution
        last_pivot_time = array.get(arr_time, array.size(arr_time) - 1)
        prev_pivot_time = array.get(arr_time, array.size(arr_time) - 2)
        estimate_pivot_time = last_pivot_time - prev_pivot_time
        array.push(arr_time, last_pivot_time + estimate_pivot_time)
    else
        array.push(arr_time, time_close(resolution))

    for i = 0 to array.size(arr_time) - 2 by 1
        if array.size(p) > 0 and show_p
            draw_line(i, p, p_color, line_ids_p)
            draw_label(i, array.get(p, i), 'P', p_color, label_ids_p)
        if array.size(r1) > 0 and show_r1
            draw_line(i, r1, s1r1_color, line_ids_r1)
            draw_label(i, array.get(r1, i), 'R1', s1r1_color, label_ids_r1)
        if array.size(s1) > 0 and show_r1
            draw_line(i, s1, s1r1_color, line_ids_s1)
            draw_label(i, array.get(s1, i), 'S1', s1r1_color, label_ids_s1)
        if array.size(r2) > 0 and show_r2
            draw_line(i, r2, s2r2_color, line_ids_r2)
            draw_label(i, array.get(r2, i), 'R2', s2r2_color, label_ids_r2)
        if array.size(s2) > 0 and show_r2
            draw_line(i, s2, s2r2_color, line_ids_s2)
            draw_label(i, array.get(s2, i), 'S2', s2r2_color, label_ids_s2)
        if array.size(r3) > 0 and show_r3
            draw_line(i, r3, s3r3_color, line_ids_r3)
            draw_label(i, array.get(r3, i), 'R3', s3r3_color, label_ids_r3)
        if array.size(s3) > 0 and show_r3
            draw_line(i, s3, s3r3_color, line_ids_s3)
            draw_label(i, array.get(s3, i), 'S3', s3r3_color, label_ids_s3)
        if array.size(r4) > 0 and show_r4
            draw_line(i, r4, s4r4_color, line_ids_r4)
            draw_label(i, array.get(r4, i), 'R4', s4r4_color, label_ids_r4)
        if array.size(s4) > 0 and show_r4
            draw_line(i, s4, s4r4_color, line_ids_s4)
            draw_label(i, array.get(s4, i), 'S4', s4r4_color, label_ids_s4)
        if array.size(r5) > 0 and show_r5
            draw_line(i, r5, s5r5_color, line_ids_r5)
            draw_label(i, array.get(r5, i), 'R5', s5r5_color, label_ids_r5)
        if array.size(s5) > 0 and show_r5
            draw_line(i, s5, s5r5_color, line_ids_s5)
            draw_label(i, array.get(s5, i), 'S5', s5r5_color, label_ids_s5)


// ============================================================================
// ██ PART 2 — KEY LEVELS ██
// ============================================================================

// 🔹 STYLE CONSTANTS
opt_solid = 'Solid'
opt_dashed = 'Dashed'
opt_dotted = 'Dotted'

// Helper function to convert string to line style
get_line_style(style_str) =>
    style_str == opt_dashed ? line.style_dashed : style_str == opt_dotted ? line.style_dotted : line.style_solid

// 🔹 MASTER CONTROLS
grp_master = '🎯 Key Levels · Master Controls'

master_key = input.bool(true, '🔥 Master Toggle: All Key Levels', group=grp_master)

master_key_col_on = input.bool(false, '🎨 Use Single Master Color', group=grp_master, inline='mkc')
master_key_col = input.color(color.white, '', group=grp_master, inline='mkc')

master_key_style_on = input.bool(false, '〰️ Use Single Master Style', group=grp_master, inline='mks')
master_key_style = input.string(opt_solid, '', options=[opt_solid, opt_dashed, opt_dotted], group=grp_master, inline='mks')

master_key_width_on = input.bool(false, '📏 Use Single Master Width', group=grp_master, inline='mkw')
master_key_width = input.int(1, '', minval=1, maxval=10, group=grp_master, inline='mkw')

// Line length + merge tolerance (defaults preserve prior behavior)
line_len = input.int(10, 'Line Length (bars)', minval=1, group=grp_master)
merge_ticks = input.float(2, 'Merge Tolerance (ticks)', minval=0, group=grp_master, tooltip='Two levels closer than this many ticks are merged onto one line.')

// 🔹 ASIA SESSION
grp_asia = '🌏 Key Levels · Asia Session'

show_asia = input.bool(true, 'Show Asia H/L', group=grp_asia)
show_asia_mid = input.bool(true, 'Show Asia 50%', group=grp_asia)
asia_live = input.bool(true, 'Track Session Live', group=grp_asia, tooltip='On: while the Asia window is open the levels update with it. Off: only the last completed session is drawn, so the levels sit still until the window closes.')
asia_sess = input.session('1600-1800', 'Session', group=grp_asia, tooltip='Default is the 16:00-18:00 New York post-US-close consolidation window (the "Asia Box"). For the full Tokyo cash session use 0900-1800 with Asia/Tokyo, or 0000-0800 with UTC.')
asia_tz = input.string('America/New_York', 'Session Timezone', options=['America/New_York', 'UTC', 'Asia/Tokyo', 'Asia/Singapore', 'Asia/Hong_Kong', 'Europe/London', 'Pacific/Auckland'], group=grp_asia, tooltip='Anchor the session to the exchange that sets the schedule, not to your own clock. New York, London and Auckland observe DST; Tokyo, Singapore, Hong Kong and UTC do not.')
col_asia = input.color(color.new(color.aqua, 20), 'Color', group=grp_asia, inline='a1')
style_asia = input.string(opt_dashed, 'Style', options=[opt_solid, opt_dashed, opt_dotted], group=grp_asia, inline='a1')
width_asia = input.int(1, 'Width', minval=1, maxval=10, group=grp_asia, inline='a1')

// 🔹 MONDAY RANGE
grp_mon = '📅 Key Levels · Monday Range'

show_mon = input.bool(true, 'Show Monday Range (H/L/O)', group=grp_mon)
col_mon = input.color(color.new(color.teal, 30), 'Color', group=grp_mon, inline='m1')
style_mon = input.string(opt_solid, 'Style', options=[opt_solid, opt_dashed, opt_dotted], group=grp_mon, inline='m1')
width_mon = input.int(1, 'Width', minval=1, maxval=10, group=grp_mon, inline='m1')

// 🔹 DAILY LEVELS
grp_daily = '📆 Key Levels · Daily'

show_do = input.bool(true, 'Show Daily Open', group=grp_daily)
show_pd = input.bool(true, 'Show Previous Day H/L', group=grp_daily)
show_pd_mid = input.bool(true, 'Show Previous Day 50%', group=grp_daily)
col_pd = input.color(color.new(color.gray, 30), 'Color', group=grp_daily, inline='d1')
style_pd = input.string(opt_solid, 'Style', options=[opt_solid, opt_dashed, opt_dotted], group=grp_daily, inline='d1')
width_pd = input.int(1, 'Width', minval=1, maxval=10, group=grp_daily, inline='d1')

// 🔹 WEEKLY LEVELS
grp_weekly = '📊 Key Levels · Weekly'

show_cw = input.bool(true, 'Show Current Week H/L', group=grp_weekly)
show_cw_mid = input.bool(true, 'Show Current Week 50%', group=grp_weekly)
col_cw = input.color(color.new(color.orange, 10), 'CW Color', group=grp_weekly, inline='w1')
style_cw = input.string(opt_solid, 'Style', options=[opt_solid, opt_dashed, opt_dotted], group=grp_weekly, inline='w1')
width_cw = input.int(2, 'Width', minval=1, maxval=10, group=grp_weekly, inline='w1')

show_pw = input.bool(true, 'Show Previous Week H/L', group=grp_weekly)
show_pw_mid = input.bool(true, 'Show Previous Week 50%', group=grp_weekly)
col_pw = input.color(color.new(color.orange, 30), 'PW Color', group=grp_weekly, inline='w2')
style_pw = input.string(opt_solid, 'Style', options=[opt_solid, opt_dashed, opt_dotted], group=grp_weekly, inline='w2')
width_pw = input.int(2, 'Width', minval=1, maxval=10, group=grp_weekly, inline='w2')

// 🔹 MONTHLY LEVELS
grp_monthly = '📈 Key Levels · Monthly'

show_cm = input.bool(true, 'Show Current Month H/L', group=grp_monthly)
show_cm_mid = input.bool(true, 'Show Current Month 50%', group=grp_monthly)
col_cm = input.color(color.new(color.red, 10), 'CM Color', group=grp_monthly, inline='mo1')
style_cm = input.string(opt_solid, 'Style', options=[opt_solid, opt_dashed, opt_dotted], group=grp_monthly, inline='mo1')
width_cm = input.int(2, 'Width', minval=1, maxval=10, group=grp_monthly, inline='mo1')

show_pm = input.bool(true, 'Show Previous Month H/L', group=grp_monthly)
show_pm_mid = input.bool(true, 'Show Previous Month 50%', group=grp_monthly)
col_pm = input.color(color.new(color.red, 30), 'PM Color', group=grp_monthly, inline='mo2')
style_pm = input.string(opt_solid, 'Style', options=[opt_solid, opt_dashed, opt_dotted], group=grp_monthly, inline='mo2')
width_pm = input.int(2, 'Width', minval=1, maxval=10, group=grp_monthly, inline='mo2')

// 🔹 YEARLY LEVELS
grp_yearly = '📅 Key Levels · Yearly'

show_cy = input.bool(true, 'Show Current Year H/L', group=grp_yearly)
show_cy_mid = input.bool(true, 'Show Current Year 50%', group=grp_yearly)
show_cy_open = input.bool(true, 'Show Current Year Open', group=grp_yearly)
col_cy = input.color(color.new(color.maroon, 10), 'CY Color', group=grp_yearly, inline='y1')
style_cy = input.string(opt_solid, 'Style', options=[opt_solid, opt_dashed, opt_dotted], group=grp_yearly, inline='y1')
width_cy = input.int(3, 'Width', minval=1, maxval=10, group=grp_yearly, inline='y1')

show_py = input.bool(true, 'Show Previous Year H/L', group=grp_yearly)
show_py_mid = input.bool(true, 'Show Previous Year 50%', group=grp_yearly)
col_py = input.color(color.new(color.maroon, 30), 'PY Color', group=grp_yearly, inline='y2')
style_py = input.string(opt_solid, 'Style', options=[opt_solid, opt_dashed, opt_dotted], group=grp_yearly, inline='y2')
width_py = input.int(3, 'Width', minval=1, maxval=10, group=grp_yearly, inline='y2')

// 🔹 KEY LEVELS LOGIC

// 1. Fetch Data
// "previous period" levels use [1] + lookahead_on (confirmed prior period, non-repainting).
// "current period" levels use no-offset + lookahead_off (developing period, updates live by design).
//
// WHY THE CURRENT-PERIOD PATTERN IS CORRECT HERE, AND WHERE IT IS NOT.
// request.security(..., lookahead_off) with no offset returns two different
// things depending on the bar: on a HISTORICAL bar it returns the last CLOSED
// higher-timeframe value (so mid-week it hands back last week's high), and on
// a REALTIME bar it returns the live developing value.
//
// That is fine in this script because every key level is drawn inside
// `if master_key and barstate.islast` — only the realtime bar is ever read, so
// only the developing value is ever displayed. Two caveats follow from that:
//   * In bar-replay, barstate.islast is a historical bar, so the "current"
//     week/month/year lines will show the PREVIOUS period's extreme.
//   * Do not reuse these variables in an alertcondition, or port them into a
//     strategy. There the historical path is evaluated on every bar and the
//     backtest silently trades a different series than the live script.
//
// Computing these natively with a timeframe.change() reset (the way the Monday
// range below is built) would fix the replay case, but it would BREAK the
// monthly and yearly levels on intraday charts: native accumulation only sees
// the bars actually loaded, which on a 5m chart is a few weeks, not a year.
// request.security is the right tool for deep periods; the constraint is that
// its result is only trustworthy on the last bar.

// --- Daily ---
d_o = request.security(syminfo.tickerid, 'D', open, lookahead=barmerge.lookahead_off)
[d_h, d_l] = request.security(syminfo.tickerid, 'D', [high[1], low[1]], lookahead=barmerge.lookahead_on)
d_mid = (d_h + d_l) / 2

// --- Weekly ---
[cw_h, cw_l] = request.security(syminfo.tickerid, 'W', [high, low], lookahead=barmerge.lookahead_off)
cw_mid = (cw_h + cw_l) / 2
[w_h, w_l] = request.security(syminfo.tickerid, 'W', [high[1], low[1]], lookahead=barmerge.lookahead_on)
w_mid = (w_h + w_l) / 2

// --- Monthly ---
[cm_h, cm_l] = request.security(syminfo.tickerid, 'M', [high, low], lookahead=barmerge.lookahead_off)
cm_mid = (cm_h + cm_l) / 2
[m_h, m_l] = request.security(syminfo.tickerid, 'M', [high[1], low[1]], lookahead=barmerge.lookahead_on)
m_mid = (m_h + m_l) / 2

// --- Yearly ---
[cy_h, cy_l, cy_o] = request.security(syminfo.tickerid, '12M', [high, low, open], lookahead=barmerge.lookahead_off)
cy_mid = (cy_h + cy_l) / 2
[py_h, py_l] = request.security(syminfo.tickerid, '12M', [high[1], low[1]], lookahead=barmerge.lookahead_on)
py_mid = (py_h + py_l) / 2

// 2. Monday Logic
var float mon_h = na
var float mon_l = na
var float mon_o = na
var bool mon_active = false

is_new_week = ta.change(time('W')) != 0

if is_new_week
    mon_h := na
    mon_l := na
    mon_o := na
    mon_active := false

is_monday = dayofweek == dayofweek.monday

if is_monday
    if not mon_active
        mon_h := high
        mon_l := low
        mon_o := open
        mon_active := true
    else
        mon_h := math.max(mon_h, high)
        mon_l := math.min(mon_l, low)

// 3. Asia Session Logic
//
// Native accumulation, not request.security. The Asia window is an intraday
// session, so its bars are already on the chart and there is nothing to fetch.
// That also means these levels are correct in bar-replay, unlike the current
// week/month/year values above.
//
// Requires an intraday chart timeframe that divides the session cleanly — 1m
// through 1H is fine. On 4H+ and daily charts no bar falls inside the window,
// asia_in is never true, and the levels stay na so nothing is drawn.

asia_in = not na(time(timeframe.period, asia_sess, asia_tz))

// Previous bar's state is carried in a var rather than read as asia_in[1].
// nz() has no series-bool overload in v6, and an unguarded asia_in[1] is na on
// bar 0, which makes the session-start test na (falsy) and silently skips the
// first session. A var initialised to false has neither problem.
var bool asia_was_in = false

var float asia_dev_h = na    // session currently forming
var float asia_dev_l = na
var float asia_h = na        // last completed session
var float asia_l = na

if asia_in and not asia_was_in
    // first bar of a new session
    asia_dev_h := high
    asia_dev_l := low
else if asia_in
    asia_dev_h := math.max(asia_dev_h, high)
    asia_dev_l := math.min(asia_dev_l, low)

if not asia_in and asia_was_in
    // session just closed — freeze it
    asia_h := asia_dev_h
    asia_l := asia_dev_l

asia_was_in := asia_in

// Draw the developing session while it is open (if wanted), else the last
// completed one. Both are na until the first session in the loaded history
// finishes, and merge_or_add_level skips na prices, so nothing is drawn.
asia_disp_h = asia_in and asia_live ? asia_dev_h : asia_h
asia_disp_l = asia_in and asia_live ? asia_dev_l : asia_l
asia_disp_mid = (asia_disp_h + asia_disp_l) / 2

// 4. Draw Active Key Levels (Smart Aggregation Engine)
var active_key_lines = array.new_line()
var active_key_labels = array.new_label()

format_price(price) =>
    if syminfo.mintick < 0.00001
        str.tostring(price, "#.#####")
    else if syminfo.mintick < 0.0001
        str.tostring(price, "#.####")
    else if syminfo.mintick < 0.001
        str.tostring(price, "#.###")
    else if syminfo.mintick < 0.01
        str.tostring(price, "#.##")
    else if syminfo.mintick < 0.1
        str.tostring(price, "#.#")
    else
        str.tostring(math.round(price))

merge_or_add_level(prices, names, colors, widths, styles, show, price, name, col, w, s) =>
    if show and not na(price)
        idx = -1
        if array.size(prices) > 0
            for i = 0 to array.size(prices) - 1
                if math.abs(array.get(prices, i) - price) <= (syminfo.mintick * merge_ticks)
                    idx := i
                    break
        if idx != -1
            existing_name = array.get(names, idx)
            array.set(names, idx, existing_name + "  |  " + name)
        else
            array.push(prices, price)
            array.push(names, name)
            array.push(colors, col)
            array.push(widths, w)
            array.push(styles, s)

if master_key and barstate.islast
    // Clean up previous tick's drawings
    if array.size(active_key_lines) > 0
        for i = 0 to array.size(active_key_lines) - 1
            line.delete(array.get(active_key_lines, i))
            label.delete(array.get(active_key_labels, i))
        array.clear(active_key_lines)
        array.clear(active_key_labels)

    // Temporary arrays to hold aggregated levels for this tick
    prices = array.new_float()
    names = array.new_string()
    colors = array.new_color()
    widths = array.new_int()
    styles = array.new_string()

    // Determine values based on master toggles
    c_asia = master_key_col_on ? master_key_col : col_asia
    s_asia = master_key_style_on ? master_key_style : style_asia
    w_asia = master_key_width_on ? master_key_width : width_asia

    c_mon = master_key_col_on ? master_key_col : col_mon
    s_mon = master_key_style_on ? master_key_style : style_mon
    w_mon = master_key_width_on ? master_key_width : width_mon

    c_pd = master_key_col_on ? master_key_col : col_pd
    s_pd = master_key_style_on ? master_key_style : style_pd
    w_pd = master_key_width_on ? master_key_width : width_pd

    c_cw = master_key_col_on ? master_key_col : col_cw
    s_cw = master_key_style_on ? master_key_style : style_cw
    w_cw = master_key_width_on ? master_key_width : width_cw

    c_pw = master_key_col_on ? master_key_col : col_pw
    s_pw = master_key_style_on ? master_key_style : style_pw
    w_pw = master_key_width_on ? master_key_width : width_pw

    c_cm = master_key_col_on ? master_key_col : col_cm
    s_cm = master_key_style_on ? master_key_style : style_cm
    w_cm = master_key_width_on ? master_key_width : width_cm

    c_pm = master_key_col_on ? master_key_col : col_pm
    s_pm = master_key_style_on ? master_key_style : style_pm
    w_pm = master_key_width_on ? master_key_width : width_pm

    c_cy = master_key_col_on ? master_key_col : col_cy
    s_cy = master_key_style_on ? master_key_style : style_cy
    w_cy = master_key_width_on ? master_key_width : width_cy

    c_py = master_key_col_on ? master_key_col : col_py
    s_py = master_key_style_on ? master_key_style : style_py
    w_py = master_key_width_on ? master_key_width : width_py

    // Add levels in order: Shortest timeframe → Longest timeframe
    // NOTE (design): first level added at a coinciding price keeps its style/color/width;
    // later ones only append their name. So shorter timeframes win styling on overlap.
    // To make the higher timeframe dominate, reverse the add order below.

    // Asia Session
    merge_or_add_level(prices, names, colors, widths, styles, show_asia, asia_disp_h, "Asia H", c_asia, w_asia, s_asia)
    merge_or_add_level(prices, names, colors, widths, styles, show_asia, asia_disp_l, "Asia L", c_asia, w_asia, s_asia)
    merge_or_add_level(prices, names, colors, widths, styles, show_asia_mid, asia_disp_mid, "Asia 50%", c_asia, w_asia, s_asia)

    // Monday Range
    merge_or_add_level(prices, names, colors, widths, styles, show_mon, mon_h, "Mon H", c_mon, w_mon, s_mon)
    merge_or_add_level(prices, names, colors, widths, styles, show_mon, mon_l, "Mon L", c_mon, w_mon, s_mon)
    merge_or_add_level(prices, names, colors, widths, styles, show_mon, mon_o, "Mon O", c_mon, w_mon, s_mon)

    // Daily Levels
    merge_or_add_level(prices, names, colors, widths, styles, show_do, d_o, "D Open", c_pd, w_pd, s_pd)
    merge_or_add_level(prices, names, colors, widths, styles, show_pd, d_h, "PDH", c_pd, w_pd, s_pd)
    merge_or_add_level(prices, names, colors, widths, styles, show_pd, d_l, "PDL", c_pd, w_pd, s_pd)
    merge_or_add_level(prices, names, colors, widths, styles, show_pd_mid, d_mid, "PD 50%", c_pd, w_pd, s_pd)

    // Current Weekly Levels
    merge_or_add_level(prices, names, colors, widths, styles, show_cw, cw_h, "CW High", c_cw, w_cw, s_cw)
    merge_or_add_level(prices, names, colors, widths, styles, show_cw, cw_l, "CW Low", c_cw, w_cw, s_cw)
    merge_or_add_level(prices, names, colors, widths, styles, show_cw_mid, cw_mid, "CW 50%", c_cw, w_cw, s_cw)

    // Previous Weekly Levels
    merge_or_add_level(prices, names, colors, widths, styles, show_pw, w_h, "PWH", c_pw, w_pw, s_pw)
    merge_or_add_level(prices, names, colors, widths, styles, show_pw, w_l, "PWL", c_pw, w_pw, s_pw)
    merge_or_add_level(prices, names, colors, widths, styles, show_pw_mid, w_mid, "PW 50%", c_pw, w_pw, s_pw)

    // Current Monthly Levels
    merge_or_add_level(prices, names, colors, widths, styles, show_cm, cm_h, "CM High", c_cm, w_cm, s_cm)
    merge_or_add_level(prices, names, colors, widths, styles, show_cm, cm_l, "CM Low", c_cm, w_cm, s_cm)
    merge_or_add_level(prices, names, colors, widths, styles, show_cm_mid, cm_mid, "CM 50%", c_cm, w_cm, s_cm)

    // Previous Monthly Levels
    merge_or_add_level(prices, names, colors, widths, styles, show_pm, m_h, "PMH", c_pm, w_pm, s_pm)
    merge_or_add_level(prices, names, colors, widths, styles, show_pm, m_l, "PML", c_pm, w_pm, s_pm)
    merge_or_add_level(prices, names, colors, widths, styles, show_pm_mid, m_mid, "PM 50%", c_pm, w_pm, s_pm)

    // Current Yearly Levels
    merge_or_add_level(prices, names, colors, widths, styles, show_cy, cy_h, "CY High", c_cy, w_cy, s_cy)
    merge_or_add_level(prices, names, colors, widths, styles, show_cy, cy_l, "CY Low", c_cy, w_cy, s_cy)
    merge_or_add_level(prices, names, colors, widths, styles, show_cy_mid, cy_mid, "CY 50%", c_cy, w_cy, s_cy)
    merge_or_add_level(prices, names, colors, widths, styles, show_cy_open, cy_o, "CY Open", c_cy, w_cy, s_cy)

    // Previous Yearly Levels
    merge_or_add_level(prices, names, colors, widths, styles, show_py, py_h, "PYH", c_py, w_py, s_py)
    merge_or_add_level(prices, names, colors, widths, styles, show_py, py_l, "PYL", c_py, w_py, s_py)
    merge_or_add_level(prices, names, colors, widths, styles, show_py_mid, py_mid, "PY 50%", c_py, w_py, s_py)

    // Draw the newly merged levels onto the chart (lines extend `line_len` bars)
    if array.size(prices) > 0
        for i = 0 to array.size(prices) - 1
            lvl_p = array.get(prices, i)
            n = array.get(names, i)
            c = array.get(colors, i)
            w = array.get(widths, i)
            s_str = array.get(styles, i)

            line_style = get_line_style(s_str)

            price_formatted = format_price(lvl_p)
            label_text = n + "  (" + price_formatted + ")"

            ln = line.new(bar_index, lvl_p, bar_index + line_len, lvl_p, color=c, width=w, style=line_style)
            lb = label.new(bar_index + line_len, lvl_p, label_text, color=na, textcolor=c, style=label.style_label_left, size=size.small)

            array.push(active_key_lines, ln)
            array.push(active_key_labels, lb)

Overview

Pivots + Key Levels MP renders support and resistance lines from S1/R1 through S5/R5 and session reference lines such as the Asia range. The script includes custom label positioning and a tick-based merging feature to clear close overlapping levels. Inputs let traders customize calculation methods, timeframes, lookback limits, line styles, and color defaults. Higher-timeframe calculations use lookahead data.

Details

Published by

midngtpickle on GitHub

Code credit

midnight pickle, as written in the script's header

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Support & resistance

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

  • Reads higher-timeframe data with lookahead on, so the history can show signals that were not there in real time

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
🔥 Master Toggle: Pivotsbooltrueenable_pivots
Calculation MethodstringCamarillakind
TimeframestringDAILYpivot_time_frame
Lookback Periodint1look_back
Use Daily-based Valuesbooltrueis_daily_based
Show Labelsbooltrueshow_labels
Label PositionstringLeftposition_labels
Show Pivot (P)booltrueshow_p
Show R1/S1booltrueshow_r1
Show R2/S2booltrueshow_r2
Show R3/S3booltrueshow_r3
Show R4/S4booltrueshow_r4
Show all 40 settings
SettingTypeDefaultVariable
Show R5/S5booltrueshow_r5
Pivot Colorcolorcolor.orangep_color
S1/R1 Colorcolorcolor.blues1r1_color
S2/R2 Colorcolorcolor.reds2r2_color
S3/R3 Colorcolorcolor.purples3r3_color
S4/R4 Colorcolorcolor.greens4r4_color
S5/R5 Colorcolorcolor.navys5r5_color
Use Close Price for Alertsbooltrueuse_close
🔥 Master Toggle: All Key Levelsbooltruemaster_key
🎨 Use Single Master Colorboolfalsemaster_key_col_on
master_key_colcolorcolor.whitemaster_key_col
〰️ Use Single Master Styleboolfalsemaster_key_style_on
master_key_stylestringopt_solidmaster_key_style
📏 Use Single Master Widthboolfalsemaster_key_width_on
master_key_widthint1master_key_width
Line Length (bars)int10line_len
Merge Tolerance (ticks)float2merge_ticks
Show Asia H/Lbooltrueshow_asia
Show Asia 50%booltrueshow_asia_mid
Track Session Livebooltrueasia_live
Sessionsession1600-1800asia_sess
Session TimezonestringAmerica/New_Yorkasia_tz
Colorcolorcolor.new(color.aqua, 20)col_asia
Stylestringopt_dashedstyle_asia
Widthint1width_asia
Show Monday Range (H/L/O)booltrueshow_mon
Colorcolorcolor.new(color.teal, 30)col_mon
Stylestringopt_solidstyle_mon
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

948 stars

Moving Average Channel plots separate simple moving averages for upper and lower bands on the price chart. It fills the space between bands with semi-transparent color and colors bars green above the upper band, red below the lower band, or gray in between. Us

Indicator v4 Moving averagesSupport & resistance
Updated 10 days ago · GPL-3.0 GitHub repository of Moving Average Channel

ICT Equal Highs and Lows

by ArunKBhaskar
575 stars

This overlay indicator finds pivot highs and lows on the price chart and compares the last two highs and the last two lows. When the percentage difference between a pair is below the Equal HL threshold, it treats them as equal levels and draws a box. Left and

Indicator v5 SMC / ICT / price actionSupport & resistance
Updated 1 year ago · MPL-2.0 GitHub repository of ICT Equal Highs and Lows
330 stars

This indicator monitors multiple cryptocurrency symbols for trading signals. It calculates and plots entry prices, take profit, and stop loss levels for each symbol including BTCUSDT, ETHUSDT, BNBUSDT and others. Price crossovers trigger buy, sell or close ale

Indicator v5 Support & resistanceScreeners & dashboards
Updated 2 months ago · None stated GitHub repository of Multi Alert Long/Short [Alorse]

This overlay indicator draws a fixed-range volume profile on the price chart, splitting traded activity into up and down volume at each price level. It also plots a sentiment profile, a developing point of control, and value-area high and low around a configur

Indicator v5 VolumeSupport & resistance
Updated 2 months ago · MIT GitHub repository of Volume Profile and Indicator by DGT

BZ-tracker

by Allen1212
303 stars

The BZ-tracker indicator marks ARK Invest buy and sell transactions on stock charts with labels. It plots green labels for purchases and red labels for sales, each annotated with a multiplier such as X1 or X2 to show the number of ARK ETFs trading the stock on

Indicator v4 Support & resistanceScreeners & dashboards
Updated 2 years ago · None stated GitHub repository of BZ-tracker

Function - Linear Regression

by ricardosantos79
261 stars

This indicator fits a linear regression through stored pivot highs and lows and draws the resulting channel on the price chart. A function returns predicted values, maximum and minimum deviations, and the average absolute deviation. Confirmed two-bar pivots up

Indicator v5 TrendSupport & resistance
Updated 4 years ago · None stated GitHub repository of Function - Linear Regression

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers