Pivots library
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © boitoki

//@version=5

// @description TODO: add library description here
library("Pivots", overlay=true)

////////////////////
// Functions
////////////////////
f_pivots (_type, _open, _high, _low, _close) =>
    float PP = na
    float R1 = na, float R2 = na, float R3 = na, float R4 = na, float R5 = na
    float S1 = na, float S2 = na, float S3 = na, float S4 = na, float S5 = na
    
    if _type == 'Traditional'
        PP := (_high + _low + _close) / 3
        R1 := PP + PP - _low
        S1 := PP - (_high - PP)
        R2 := PP + _high - _low
        S2 := PP - (_high - _low)
        R3 := _high + 2 * (PP - _low)
        S3 := _low - 2 * (_high - PP)
        R4 := PP * 3 + (_high - 3 * _low)
        S4 := PP * 3 - (3 * _high - _low)
        R5 := PP * 4 + (_high - 4 * _low)
        S5 := PP * 4 - (4 * _high - _low)

    else if _type == 'Fibonacci'
        PP := (_high + _low + _close) / 3
        R1 := PP + (_high - _low) * 0.382
        S1 := PP - (_high - _low) * 0.382
        R2 := PP + (_high - _low) * 0.618
        S2 := PP - (_high - _low) * 0.618
        R3 := PP + (_high - _low) * 1.000
        S3 := PP - (_high - _low) * 1.000
        R4 := PP + (_high - _low) * 1.272
        S4 := PP - (_high - _low) * 1.272
        R5 := PP + (_high - _low) * 1.618
        S5 := PP - (_high - _low) * 1.618
    
    else if _type == 'Woodie'
        PP := (_high + _low + 2 * _open) / 4
        R1 := PP + PP - _low
        S1 := PP - (_high - PP)
        R2 := PP + _high - _low
        S2 := PP - (_high - _low)
        R3 := _high + 2 * (PP - _low)
        S3 := _low - 2 * (_high - PP)
        R4 := R3 + _high - _low
        S4 := S3 - (_high - _low)

    else if _type == 'Classic'
        PP := (_high + _low + _close) / 3
        pivot_range = _high - _low
        R1 := PP * 2 - _low
        S1 := PP * 2 - _high
        R2 := PP + 1 * pivot_range
        S2 := PP - 1 * pivot_range
        R3 := PP + 2 * pivot_range
        S3 := PP - 2 * pivot_range
        R4 := PP + 3 * pivot_range
        S4 := PP - 3 * pivot_range

    else if _type == 'DM'
        pivotX_Demark_X = _high + _low * 2 + _close

        if _close == _open
            pivotX_Demark_X := _high + _low + _close * 2
        if _close > _open
            pivotX_Demark_X := _high * 2 + _low + _close

        PP := pivotX_Demark_X / 4
        R1 := pivotX_Demark_X / 2 - _low
        S1 := pivotX_Demark_X / 2 - _high
    
    else if _type == 'Camarilla'
        PP := (_high + _low + _close) / 3
        pivot_range = _high - _low
        R1 := _close + pivot_range * 1.1 / 12.0
        S1 := _close - pivot_range * 1.1 / 12.0
        R2 := _close + pivot_range * 1.1 / 6.0
        S2 := _close - pivot_range * 1.1 / 6.0
        R3 := _close + pivot_range * 1.1 / 4.0
        S3 := _close - pivot_range * 1.1 / 4.0
        R4 := _close + pivot_range * 1.1 / 2.0
        S4 := _close - pivot_range * 1.1 / 2.0

    else if _type == 'Floor'
        PP := math.avg(_high, _low, _close)
        S1 := (PP * 2) - _high
        S2 := PP - (_high - _low)
        S3 := _low - 2 * (_high - PP)
        R1 := (PP * 2) - _low
        R2 := PP + (_high - _low)
        R3 := _high + 2 * (PP - _low)

    else if _type == 'Tom DeMarks Pivots'
        var x = 0.0

        if _close < _open
            x := _high + (2 * _low) + _close
        else if _close > _open
            x := (2 * _high) + _low + _close
        else
            x := _high + _low + (2 * _close)

        PP := x / 4
        S1 := (x / 2) - _high
        R1 := (x / 2) - _low

    else if _type == 'Expected Pivot Points'
        PP := (_high + _low + _close) / 3
        R1 := PP * 2 - _low
        S1 := PP * 2 - _high
        R2 := PP + (R1 - S1)
        S2 := PP - (R1 - S1)

    else if _type == 'Zone Analysis'
        PP := math.avg(_high, _low)
        R1 := math.avg(PP, _high)
        S1 := math.avg(PP, _low)

    else if _type == 'HL2'
        PP := math.avg(_high, _low)

    else
        PP := (_high + _low + _close) / 3

    [PP, R1, S1, R2, S2, R3, S3, R4, S4, R5, S5]

f_cpr (_high, _low, _close) =>
    PP = (_high + _low + _close) / 3
    BC = (_high + _low) / 2
    TC = PP - BC + PP
    CPR = math.abs(TC - BC)

    [BC, TC, CPR]

f_htf_ohlc (_htf) =>
    var htf_o  = 0., var htf_h  = 0., var htf_l  = 0.,     htf_c  = close
    var htf_ox = 0., var htf_hx = 0., var htf_lx = 0., var htf_cx = 0.

    if ta.change(time(_htf)) != 0
        htf_ox := htf_o, htf_o := open
        htf_hx := htf_h, htf_h := high
        htf_lx := htf_l, htf_l := low
        htf_cx := htf_c[1]
    else
        htf_h  := math.max(high, htf_h)
        htf_l  := math.min(low , htf_l)

    [htf_ox, htf_hx, htf_lx, htf_cx, htf_o, htf_h, htf_l, htf_c]

////////////////////
// Inputs
////////////////////
i_pivots_type = input.string('Traditional', 'Pivots type', options=['Traditional', 'Fibonacci', 'Woodie', 'Classic', 'DM', 'Camarilla', 'Floor', 'Tom DeMarks Pivots', 'Expected Pivot Points', 'PP only', 'Zone Analysis', 'HL2'])
i_htf_type = input.string('D', 'Pivots timeframe', options=['60', '120', '240', '360', '720', 'D', 'W', 'M', '6M', '12M'])


////////////////////
// Exports
////////////////////

// @function Calculates the pivot point and returns its value.
// @param _type Specifies the type of pivot point.
// @param _open The open price
// @param _high The high price
// @param _low The low price
// @param _clsoe The close price
// @returns Returns the value of the calculated pivot point as a tuple.
export pivots (simple string _type, float _open, float _high, float _low, float _close) => 
    f_pivots(_type, _open, _high, _low, _close)

// @function Calculate the Central Pivot Range
// @param _high The high price
// @param _low The low price
// @param _clsoe The close price
// @returns Returns the values as a tuple.
export cpr (float _high, float _low, float _close) => f_cpr(_high, _low, _close)

// @function Calculate the HTF values
// @param _htf Resolution
// @returns Returns the values as a tuple.
export htf_ohlc (simple string _htf) => f_htf_ohlc(_htf)


////////////////////
// Sample codes
////////////////////
[O1, H1, L1, C1, O0, H0, L0, C0] = htf_ohlc(i_htf_type)
[PP, R1, S1, R2, S2, R3, S3, R4, S4, R5, S5] = pivots(i_pivots_type, O1, H1, L1, C1)
[BC, TC, CPR] = cpr(H1, L1, C1)

f_render_candle (htf) =>
    is_htf_session_broken = ta.change(time(htf)) != 0

    time_x11  = ta.valuewhen(is_htf_session_broken, time, 1)
    time_x1   = ta.valuewhen(is_htf_session_broken, time, 0)
    offset    = math.round(ta.change(time))
    time_x2   = (2 * time_x1 - time_x11) - offset

    color0  = O0 < C0 ? color.green : color.red
    color01 = color.new(color0, 90)
    color1  = O1 < C1 ? color.green : color.red
    color11 = color.new(color1, 90)
    
    var box oc = na, var box hl = na

    if ta.change(time(htf))
        oc := box.new(time_x1, O1, time_x2, C1, bgcolor=color.new(color0, 90), border_color=color.new(color0, 30), xloc=xloc.bar_time)
        hl := box.new(time_x1, H1, time_x2, L1, bgcolor=color.new(color0, 90), border_color=color.new(color0, 30), border_style=line.style_dotted, xloc=xloc.bar_time)
        
        true

    else
        box.set_top(oc, math.max(O0, C0))
        box.set_bottom(oc, math.min(O0, C0))
        box.set_bgcolor(hl, color.new(color0, 90))
        box.set_border_color(hl, color.new(color01, 30))
        
        box.set_top(hl, H0)
        box.set_bottom(hl, L0)
        box.set_bgcolor(oc, color.new(color0, 90))
        box.set_border_color(oc, color.new(color01, 30))
        
        true

// Example (Pivots)
f_render_pivots (htf) =>
    is_htf_session_broken = ta.change(time(htf)) != 0

    time_x11  = ta.valuewhen(is_htf_session_broken, time, 1)
    time_x1   = ta.valuewhen(is_htf_session_broken, time, 0)
    offset    = math.round(ta.change(time))
    time_x2   = (2 * time_x1 - time_x11) - offset
    color1    = color.orange
    label l_PP = na
    label l_R1 = na, label l_S1 = na
    label l_R2 = na, label l_S2 = na
    label l_R3 = na, label l_S3 = na
    label l_R4 = na, label l_S4 = na
    label l_R5 = na, label l_S5 = na

    if ta.change(time(htf))
        line.new(time_x1, PP, time_x2, PP, color=color1, xloc=xloc.bar_time, width=2)
        line.new(time_x1, R1, time_x2, R1, color=color1, xloc=xloc.bar_time)
        line.new(time_x1, R2, time_x2, R2, color=color1, xloc=xloc.bar_time)
        line.new(time_x1, R3, time_x2, R3, color=color1, xloc=xloc.bar_time)
        line.new(time_x1, R4, time_x2, R4, color=color1, xloc=xloc.bar_time)
        line.new(time_x1, R5, time_x2, R5, color=color1, xloc=xloc.bar_time)
        line.new(time_x1, S1, time_x2, S1, color=color1, xloc=xloc.bar_time)
        line.new(time_x1, S2, time_x2, S2, color=color1, xloc=xloc.bar_time)
        line.new(time_x1, S3, time_x2, S3, color=color1, xloc=xloc.bar_time)
        line.new(time_x1, S4, time_x2, S4, color=color1, xloc=xloc.bar_time)
        line.new(time_x1, S5, time_x2, S5, color=color1, xloc=xloc.bar_time)
        
        l_PP := label.new(time_x2, PP, 'PP', style=label.style_label_left, color=color.new(color.black, 100), textcolor=color1, xloc=xloc.bar_time), label.delete(l_PP[1])
        l_R1 := label.new(time_x2, R1, 'R1', style=label.style_label_left, color=color.new(color.black, 100), textcolor=color1, xloc=xloc.bar_time), label.delete(l_R1[1])
        l_R2 := label.new(time_x2, R2, 'R2', style=label.style_label_left, color=color.new(color.black, 100), textcolor=color1, xloc=xloc.bar_time), label.delete(l_R2[1])
        l_R3 := label.new(time_x2, R3, 'R3', style=label.style_label_left, color=color.new(color.black, 100), textcolor=color1, xloc=xloc.bar_time), label.delete(l_R3[1])
        l_R4 := label.new(time_x2, R4, 'R4', style=label.style_label_left, color=color.new(color.black, 100), textcolor=color1, xloc=xloc.bar_time), label.delete(l_R4[1])
        l_R5 := label.new(time_x2, R5, 'R5', style=label.style_label_left, color=color.new(color.black, 100), textcolor=color1, xloc=xloc.bar_time), label.delete(l_R5[1])
        l_S1 := label.new(time_x2, S1, 'S1', style=label.style_label_left, color=color.new(color.black, 100), textcolor=color1, xloc=xloc.bar_time), label.delete(l_S1[1])
        l_S2 := label.new(time_x2, S2, 'S2', style=label.style_label_left, color=color.new(color.black, 100), textcolor=color1, xloc=xloc.bar_time), label.delete(l_S2[1])
        l_S3 := label.new(time_x2, S3, 'S3', style=label.style_label_left, color=color.new(color.black, 100), textcolor=color1, xloc=xloc.bar_time), label.delete(l_S3[1])
        l_S4 := label.new(time_x2, S4, 'S4', style=label.style_label_left, color=color.new(color.black, 100), textcolor=color1, xloc=xloc.bar_time), label.delete(l_S4[1])
        l_S5 := label.new(time_x2, S5, 'S5', style=label.style_label_left, color=color.new(color.black, 100), textcolor=color1, xloc=xloc.bar_time), label.delete(l_S5[1])

f_render_pivots(i_htf_type)
f_render_candle(i_htf_type)