2nd 3rd 4th Order Pivots
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © schroederjoa

// This indicator calculates pivots of 2nd, 3rd and 4th order in the current timeframe.
// The idea is borrowed from the book "The Art and Science of Technical Trading" by Adam Grimes: 
// "A pivot high is a bar that has a higher high than the bar that came before it and the bar that comes after it"
// "Second-order pivot highs are first-order pivot highs that are preceded and followed by lower first-order pivot highs.
// The type of picot calculation can be found as well in script "Higher Order Pivots" by rumpypumpydumpy.
// However, this script is different in the following ways:
// 1. Shows pivots of order 2, 3 and 4
// 2. The chart timeframe can be different than the pivot timeframe, allowing e.g. to map daily pivots to intraday charts via lines
// 2. Labels and/or Lines can be used to show pivot points
// 3. Use of extended session data be be enabled/disabled, independently from the current chart settings
// 4. To disable older pivots, a starting time for the pivot calculation can be set 

// Please consider following limitations:
// 1. Maximum of 500 drawing objects per chart: Use Notification option to keep track of when running out of chart objects.
// 2. Lookback history: The max lookback history is limited by the currently selected timeframe. E.g. on a 5min timeframe,
// 20000 bars (Premium Plan) result in approx. 5 months of lookback period, meaning you may want to have a 30 min or higher 
// chart open to get a complete picture of pivots, while trading on a lower timeframe.


//@version=5
indicator("2nd 3rd 4th Order Pivots", shorttitle="234 Piv", overlay=true, max_lines_count=500, max_labels_count=500)

f_print(_text) => var _label = label.new(bar_index, na, _text, xloc.bar_index, yloc.price, color(na), label.style_none, color.orange, size.large, text.align_right), label.set_xy(_label, bar_index, ta.highest(10)[1]), label.set_text(_label, _text)

tfInput = input.string("D", "Timeframe", options = ["Current","1","3","5","10","15","30","60","120","180","240","D","W","M"])
var bool time_skip = input.bool(false, title="",inline = "21")
var time_start = input.time(timestamp("01 Jan 2022 09:30:00 UTC-5"), "Only consider data after",inline = "21")
bool max_objects_notify = input.bool(true, title="Enable Notification for > 480 drawing Objects")

var g01 = "Pivots 2nd Order"
show_order_2_labels = input.bool(false, title="Show Labels", group=g01)
show_order_2_lines = input.bool(false, title="Show Lines", group=g01)
width_order_2 = input.int(1, title="Line Width", group=g01)
col_order_2_h    = input(color.new(color.teal, 40), title = "Pivot High Color", group=g01)
col_order_2_l    = input(color.new(color.maroon, 40), title = "Pivot Low Color", group=g01)

var g02 = "Pivots 3rd Order"
show_order_3_labels = input.bool(true, title="Show Labels", group=g02)
show_order_3_lines = input.bool(true, title="Show Lines", group=g02)
width_order_3 = input.int(2, title="Line Width", group=g02)
col_order_3_h    = input(color.new(color.teal, 20), title = "Pivot High Color", group=g02)
col_order_3_l    = input(color.new(color.maroon, 20), title = "Pivot Low Color", group=g02)

var g03 = "Pivots 4th Order"
show_order_4_labels = input.bool(true, title="Show Labels", group=g03)
show_order_4_lines = input.bool(true, title="Show Lines", group=g03)
width_order_4 = input.int(3, title="Line Width", group=g03)
col_order_4_h = input(color.new(color.teal, 0), title = "Pivot High Color", group=g03)
col_order_4_l = input(color.new(color.maroon, 0), title = "Pivot Low Color", group=g03)


f_is_order_1_pivot() =>
    [high[1] > high and high[1] > high[2],high[1], low[1] < low and low[1] < low[2], low[1], time[1]]


ticker =  ticker.new(syminfo.prefix, syminfo.ticker, syminfo.session)
[is_1st_pivot_high, hval, is_1st_pivot_low, lval, ti] = request.security(ticker, tfInput == "Current" ? timeframe.period : tfInput, f_is_order_1_pivot())

// array definitions for pivot low and highs, each with its value and time
var arr_order_1_vh = array.new_float(0)
var arr_order_1_th = array.new_int(0)
var arr_order_2_vh = array.new_float(0)
var arr_order_2_th = array.new_int(0)
var arr_order_3_vh = array.new_float(0)
var arr_order_3_th = array.new_int(0)
var arr_order_4_vh = array.new_float(0)
var arr_order_4_th = array.new_int(0)

var arr_order_1_vl = array.new_float(0)
var arr_order_1_tl = array.new_int(0)
var arr_order_2_vl = array.new_float(0)
var arr_order_2_tl = array.new_int(0)
var arr_order_3_vl = array.new_float(0)
var arr_order_3_tl = array.new_int(0)
var arr_order_4_vl = array.new_float(0)
var arr_order_4_tl = array.new_int(0)

// create 1st order pivots as starting point
if is_1st_pivot_high and not (time_skip and ti < time_start) and ti != ti[1]
    array.push(arr_order_1_vh, hval)
    array.push(arr_order_1_th, ti)
    
if is_1st_pivot_low and not (time_skip and ti < time_start) and ti != ti[1]
    array.push(arr_order_1_vl, lval)
    array.push(arr_order_1_tl, ti)

num_objects = 0
if barstate.islast

    array.clear(arr_order_2_th)
    array.clear(arr_order_2_vh)
    // calculate 2nd, 3rd and 4th order arrays, always based on the lower order arrays
    // if it has minimum 3 entries, a possible higher order pivot can be determined
    if array.size(arr_order_1_vh) > 3
        for i = 1 to array.size(arr_order_1_vh) - 2
            if array.get(arr_order_1_vh,i) > array.get(arr_order_1_vh,i-1) and array.get(arr_order_1_vh,i) > array.get(arr_order_1_vh,i+1)
                array.push(arr_order_2_th,array.get(arr_order_1_th,i))
                array.push(arr_order_2_vh,array.get(arr_order_1_vh,i))

    array.clear(arr_order_2_tl)
    array.clear(arr_order_2_vl)
    if array.size(arr_order_1_vl) > 3
        for i = 1 to array.size(arr_order_1_vl) - 2
            if array.get(arr_order_1_vl,i) < array.get(arr_order_1_vl,i-1) and array.get(arr_order_1_vl,i) < array.get(arr_order_1_vl,i+1)
                array.push(arr_order_2_tl,array.get(arr_order_1_tl,i))
                array.push(arr_order_2_vl,array.get(arr_order_1_vl,i))

    array.clear(arr_order_3_th)
    array.clear(arr_order_3_vh)
    if array.size(arr_order_2_vh) > 3
        for i = 1 to array.size(arr_order_2_vh) - 2
            if array.get(arr_order_2_vh,i) > array.get(arr_order_2_vh,i-1) and array.get(arr_order_2_vh,i) > array.get(arr_order_2_vh,i+1)
                array.push(arr_order_3_th,array.get(arr_order_2_th,i))
                array.push(arr_order_3_vh,array.get(arr_order_2_vh,i))

    array.clear(arr_order_3_tl)
    array.clear(arr_order_3_vl)
    if array.size(arr_order_2_vl) > 3
        for i = 1 to array.size(arr_order_2_vl) - 2
            if array.get(arr_order_2_vl,i) < array.get(arr_order_2_vl,i-1) and array.get(arr_order_2_vl,i) < array.get(arr_order_2_vl,i+1)
                array.push(arr_order_3_tl,array.get(arr_order_2_tl,i))
                array.push(arr_order_3_vl,array.get(arr_order_2_vl,i))
 
    array.clear(arr_order_4_th)
    array.clear(arr_order_4_vh)                
    if array.size(arr_order_3_vh) > 3
        for i = 1 to array.size(arr_order_3_vh) - 2
            if array.get(arr_order_3_vh,i) > array.get(arr_order_3_vh,i-1) and array.get(arr_order_3_vh,i) > array.get(arr_order_3_vh,i+1)
                array.push(arr_order_4_th,array.get(arr_order_3_th,i))
                array.push(arr_order_4_vh,array.get(arr_order_3_vh,i))
                
    array.clear(arr_order_4_tl)
    array.clear(arr_order_4_vl)
    if array.size(arr_order_3_vl) > 3
        for i = 1 to array.size(arr_order_3_vl) - 2
            if array.get(arr_order_3_vl,i) < array.get(arr_order_3_vl,i-1) and array.get(arr_order_3_vl,i) < array.get(arr_order_3_vl,i+1)
                array.push(arr_order_4_tl,array.get(arr_order_3_tl,i))
                array.push(arr_order_4_vl,array.get(arr_order_3_vl,i))
    
    if show_order_2_labels or show_order_2_lines            
        for i = 0 to (array.size(arr_order_2_th) == 0 ? na : array.size(arr_order_2_th) - 1)
            t = array.get(arr_order_2_th,i)
            v = array.get(arr_order_2_vh,i)
            if show_order_2_lines 
                line.new(t, v, t+1, v, xloc=xloc.bar_time, color=col_order_2_h, style=line.style_solid, width=width_order_2, extend=extend.right)
                num_objects := num_objects + 1
            if show_order_2_labels
                label.new(x=t, y=v, xloc=xloc.bar_time, color=col_order_2_h, style=label.style_label_down, size = size.tiny)
                num_objects := num_objects + 1
                
        for i = 0 to (array.size(arr_order_2_tl) == 0 ? na : array.size(arr_order_2_tl) - 1)
            t = array.get(arr_order_2_tl,i)
            v = array.get(arr_order_2_vl,i)
            if show_order_2_lines 
                line.new(t, v, t+1, v, xloc=xloc.bar_time, color=col_order_2_l, style=line.style_solid, width=width_order_2, extend=extend.right)
                num_objects := num_objects + 1
            if show_order_2_labels
                label.new(x=t, y=v, xloc=xloc.bar_time, color=col_order_2_l, style=label.style_label_up, size = size.tiny) 
                num_objects := num_objects + 1

    if show_order_3_labels or show_order_3_lines            
        for i = 0 to (array.size(arr_order_3_th) == 0 ? na : array.size(arr_order_3_th) - 1)
            t = array.get(arr_order_3_th,i)
            v = array.get(arr_order_3_vh,i)
            if show_order_3_lines 
                line.new(t, v, t+1, v, xloc=xloc.bar_time, color=col_order_3_h, style=line.style_solid, width=width_order_3, extend=extend.right)
                num_objects := num_objects + 1
            if show_order_3_labels
                label.new(x=t, y=v, xloc=xloc.bar_time, color=col_order_3_h, style=label.style_label_down, size = size.small) 
                num_objects := num_objects + 1
               
        for i = 0 to (array.size(arr_order_3_tl) == 0 ? na : array.size(arr_order_3_tl) - 1)
            t = array.get(arr_order_3_tl,i)
            v = array.get(arr_order_3_vl,i)
            if show_order_3_lines 
                line.new(t, v, t+1, v, xloc=xloc.bar_time, color=col_order_3_l, style=line.style_solid, width=width_order_3, extend=extend.right)
                num_objects := num_objects + 1
            if show_order_3_labels
                label.new(x=t, y=v, xloc=xloc.bar_time, color=col_order_3_l, style=label.style_label_up, size = size.small) 
                num_objects := num_objects + 1
               
    if show_order_4_labels or show_order_4_lines            
        for i = 0 to (array.size(arr_order_4_th) == 0 ? na : array.size(arr_order_4_th) - 1)
            t = array.get(arr_order_4_th,i)
            v = array.get(arr_order_4_vh,i)
            if show_order_4_lines 
                line.new(t, v, t+1, v, xloc=xloc.bar_time, color=col_order_4_h, style=line.style_solid, width=width_order_4, extend=extend.right)    
                num_objects := num_objects + 1
            if show_order_4_labels
                label.new(x=t, y=v, xloc=xloc.bar_time, color=col_order_4_h, style=label.style_label_down, size = size.normal) 
                num_objects := num_objects + 1
                
        for i = 0 to (array.size(arr_order_4_tl) == 0 ? na : array.size(arr_order_4_tl) - 1)
            t = array.get(arr_order_4_tl,i)
            v = array.get(arr_order_4_vl,i)
            if show_order_4_lines 
                line.new(t, v, t+1, v, xloc=xloc.bar_time, color=col_order_4_l, style=line.style_solid, width=width_order_4, extend=extend.right) 
                num_objects := num_objects + 1
            if show_order_4_labels
                label.new(x=t, y=v, xloc=xloc.bar_time, color=col_order_4_l, style=label.style_label_up, size = size.normal) 
                num_objects := num_objects + 1

info_str = ""
if num_objects > 480 and max_objects_notify
    info_str := info_str + str.tostring(num_objects) + " Drawing Objects (max 500 per chart!)"

f_print(info_str)




























