ICT Daily Levels and Zones (fadi)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © fadizeidan

//@version=5
indicator("ICT Daily Levels and Zones (fadi)", overlay = true, max_lines_count = 500, max_boxes_count = 500)

//+------------------------------------------------------------------------------------------------------------+//
//+--- Types                                                                                                ---+//
//+---   Types are data structures that allows us to hold multiple related values in a single instance      ---+//
//+--    Tradingview has some limitations so some workarounds are required.                                 ---+//
//+------------------------------------------------------------------------------------------------------------+//

//+------------------------------------------------------------------------------------------------------------+//
//+--- Zone                                                                                                 ---+//
//+---   Used to capture the start, end, and levels (box) of a zone such as:                                ---+//
//+--    Killzones, Open Range, and Open Range Gap                                                          ---+//
//+------------------------------------------------------------------------------------------------------------+//
type Zone
    float o
    float h
    float l
    float c
    int   o_time
    int   h_time
    int   l_time
    int   c_time
    box   b

//+------------------------------------------------------------------------------------------------------------+//
//+--- ohlc                                                                                                 ---+//
//+---   ohlc is used to capture the daily relevant values and when they occured.                           ---+//
//+------------------------------------------------------------------------------------------------------------+//
type ohlc
    float  o
    float  h
    float  l
    float  c
    float  o_MN
    int    o_MN_time
    float  o_830
    int    o_830_time
    float  o_930
    int    o_930_time
    int    o_time
    int    o_idx
    int    h_time
    int    l_time
    int    c_time
    line   o_line
    line   h_line
    line   l_line
    line   c_line
    line   s_line
    line   o_MN_line
    line   o_MN_thick
    line   o_830_line
    line   o_830_thick
    line   o_930_line
    line   o_930_thick
    string dow
    int    dow_index

//+------------------------------------------------------------------------------------------------------------+//
//+--- Candle                                                                                               ---+//
//+---   The daily candle drawn based on midnight level                                                     ---+//
//+---   This is similar to the MTF Candles indicator minus the time interval to map out the trace lines    ---+//
//+------------------------------------------------------------------------------------------------------------+//
type Candle
    float  o
    float  h
    float  l
    float  c 
    string dow
    box   body
    line  wick_top
    line  wick_bottom
    label lbl

//+------------------------------------------------------------------------------------------------------------+//
//+--- Projection                                                                                           ---+//
//+---   The projection level based on daily ADR range                                                      ---+//
//+------------------------------------------------------------------------------------------------------------+//
type Projection
    box  body_high
    box  body_low
    line high_third
    label high_third_label
    line low_third
    label low_third_label
    line max
    label max_label
    line min
    label min_label
//+------------------------------------------------------------------------------------------------------------+//
//+--- Settings                                                                                             ---+//
//+------------------------------------------------------------------------------------------------------------+//
type Settings
    string  hide_TF
    bool    show_session
    bool    show_open
    bool    show_high
    bool    show_low
    bool    show_close
    bool    show_MN
    bool    show_830
    bool    show_930
    int     max_days
    color   s_color
    string  s_style
    int     s_size
    bool    show_dayofweek
    color   dayofweek_color
    color   o_MN_color
    string  o_MN_style
    int     o_MN_size
    color   o_830_color
    string  o_830_style
    int     o_830_size
    color   o_930_color
    string  o_930_style
    int     o_930_size
    bool    show_asia
    color   asia_background
    color   asia_border
    string  asia_border_style
    int     asia_border_size
    int     asia_o_hour
    int     asia_o_min
    int     asia_c_hour
    int     asia_c_min
    bool    show_london
    color   london_background
    color   london_border
    string  london_border_style
    int     london_border_size
    int     london_o_hour
    int     london_o_min
    int     london_c_hour
    int     london_c_min
    bool    show_ny
    color   ny_background
    color   ny_border
    string  ny_border_style
    int     ny_border_size
    int     ny_o_hour
    int     ny_o_min
    int     ny_c_hour
    int     ny_c_min
    bool    show_openrange
    color   openrange_background
    color   openrange_border
    string  openrange_style
    int     openrange_size
    bool    openrange_extend
    int     openrange_o_hour
    int     openrange_o_min
    int     openrange_c_hour
    int     openrange_c_min
    bool    show_openrangegap
    color   openrangegap_background
    color   openrangegap_border
    string  openrangegap_style
    int     openrangegap_size
    bool    openrangegap_extend
    int     openrangegap_o_hour
    int     openrangegap_o_min
    int     openrangegap_c_hour
    int     openrangegap_c_min
    bool    show_TOD_thick
    bool    show_DC // Daily Candle
    color   DC_bullish
    color   DC_bearish
    color   DC_wick
    int     DC_buffer
    int     DC_spacing
    int     DC_count
    bool    DC_ignore_saturday
    bool    DC_ignore_sunday
    bool    ADR_show
    int     ADR_buffer
    color   ADR_bullish
    color   ADR_bearish
    bool    ADR_Trace
    color   ADR_Trace_color
    string  ADR_Trace_style
    int     ADR_Trace_size
    bool    ADR_Trace_Label
    string  ADR_Trace_Label_size
    color   ADR_Trace_Label_color
    color   ADR_Trace_Label_bgcolor
    bool    ADR_Trace_Third



//+------------------------------------------------------------------------------------------------------------+//
//+--- Variable declaration of the types                                                                    ---+//
//+------------------------------------------------------------------------------------------------------------+//
var ohlc[] OHLC                 = array.new<ohlc>()
var Candle[] DC                 = array.new<Candle>()
var Zone[] asia                 = array.new<Zone>()
var Zone[] london               = array.new<Zone>()
var Zone[] ny                   = array.new<Zone>()
var Zone[] openrange            = array.new<Zone>()
var Zone[] openrangegap         = array.new<Zone>()
var Projection projection       = Projection.new()

Settings settings = Settings.new()

//+------------------------------------------------------------------------------------------------------------+//
//+--- Prompt for the Settings                                                                              ---+//
//+------------------------------------------------------------------------------------------------------------+//
g_session       = "Session"
g_dailylevels   = "Daily Levels"
g_killzones     = "Killzones"
g_openranges    = "Open Ranges"
g_timeofday     = "Time Of Day"
g_DC            = "Daily"
g_weekdays      = "Week Days"
g_ADR           = "Projection"

settings.hide_TF            := input.timeframe("15", "Hide above ", tooltip="Any value above 15 minute can result in wrong display. This is due to how Tradingview provides the data to the indicator.")
max_days                     = input.int(10, "Limit to last X days", minval = 1, maxval = 100)
settings.max_days           := max_days
settings.show_session       := input.bool(true, "Seperator   ", inline='1', group=g_session)
settings.s_color            := input.color(color.new(color.gray, 50), "", inline='1', group=g_session)
settings.s_style            := input.string('----', '', options = ['⎯⎯⎯', '----', '····'], inline='1', group=g_session)
settings.s_size             := input.int(1, '', options = [1,2,3,4], inline='1', group=g_session)

settings.show_dayofweek     := input.bool(true, "Days of week", inline='2', group=g_session)
settings.dayofweek_color    := input.color(color.new(color.black, 0), "", inline='2', group=g_session)

settings.show_asia          := input.bool(true, "Asia  ", group=g_killzones, inline="0")
settings.asia_background    := input.color(color.new(color.green, 90), "", group=g_killzones, inline = "0")
settings.asia_border        := input.color(color.new(color.green, 0), "", group=g_killzones, inline = "0")
settings.asia_border_size   := input.int(1, "", options = [1,2,3,4], group=g_killzones, inline = "0")
settings.asia_border_style  := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], group=g_killzones, inline='0')
settings.asia_o_hour        := input.int(20, "         Open Hour", group=g_killzones, inline="1", minval = 0, maxval = 24)
settings.asia_o_min         := input.int(0, "Minute", group=g_killzones, inline="1", minval = 0, maxval = 59)
settings.asia_c_hour        := input.int(24, "         Close Hour", group=g_killzones, inline="2", minval = 1, maxval = 24)
settings.asia_c_min         := input.int(0, "Minute", group=g_killzones, inline="2", minval = 0, maxval = 59)

settings.show_london        := input.bool(true, "London", group=g_killzones, inline = "3")
settings.london_background   := input.color(color.new(color.blue, 90), "", group=g_killzones, inline = "3")
settings.london_border       := input.color(color.new(color.blue, 0), "", group=g_killzones, inline = "3")
settings.london_border_size  := input.int(1, "", options = [1,2,3,4], group=g_killzones, inline = "3")
settings.london_border_style := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], group=g_killzones, inline='3')
settings.london_o_hour      := input.int(2, "         Open Hour", group=g_killzones, inline="4", minval = 1, maxval = 24)
settings.london_o_min       := input.int(0, "Minute", group=g_killzones, inline="4", minval = 0, maxval = 59)
settings.london_c_hour      := input.int(5, "         Close Hour", group=g_killzones, inline="5", minval = 1, maxval = 24)
settings.london_c_min       := input.int(0, "Minute", group=g_killzones, inline="5", minval = 0, maxval = 59)

settings.show_ny            := input.bool(true, "NY   ", group=g_killzones, inline="6")
settings.ny_background      := input.color(color.new(color.orange, 90), "", group=g_killzones, inline = "6")
settings.ny_border          := input.color(color.new(color.orange, 0), "", group=g_killzones, inline = "6")
settings.ny_border_size     := input.int(1, "", options = [1,2,3,4], group=g_killzones, inline = "6")
settings.ny_border_style    := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], group=g_killzones, inline='6')
settings.ny_o_hour          := input.int(8, "         Open Hour", group=g_killzones, inline="7", minval = 1, maxval = 24)
settings.ny_o_min           := input.int(30, "Minute", group=g_killzones, inline="7", minval = 0, maxval = 59)
settings.ny_c_hour          := input.int(11, "         Close Hour", group=g_killzones, inline="8", minval = 1, maxval = 24)
settings.ny_c_min           := input.int(0, "Minute", group=g_killzones, inline="8", minval = 0, maxval = 59)


settings.show_openrange     := input.bool(false, "Open Range   ", group=g_openranges, inline="6")
settings.openrange_background := input.color(color.new(color.maroon, 90), "", group=g_openranges, inline = "6")
settings.openrange_border   := input.color(color.new(color.maroon, 0), "", group=g_openranges, inline = "6")
settings.openrange_size     := input.int(1, "", options = [1,2,3,4], group=g_openranges, inline = "6")
settings.openrange_style    := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], group=g_openranges, inline='6')
settings.openrange_o_hour   := input.int(9, "         Open Hour", group=g_openranges, inline="7", minval = 1, maxval = 24)
settings.openrange_o_min    := input.int(30, "Minute", group=g_openranges, inline="7", minval = 0, maxval = 59)
settings.openrange_c_hour   := input.int(10, "         Close Hour", group=g_openranges, inline="8", minval = 1, maxval = 24)
settings.openrange_c_min    := input.int(0, "Minute", group=g_openranges, inline="8", minval = 0, maxval = 59)
settings.openrange_extend   := input.bool(false, "Extend Zone", group=g_openranges, inline = "8.5")

settings.show_openrangegap  := input.bool(false, "Open Range   ", group=g_openranges, inline="9")
settings.openrangegap_background := input.color(color.new(color.yellow, 90), "", group=g_openranges, inline = "9")
settings.openrangegap_border   := input.color(color.new(color.yellow, 0), "", group=g_openranges, inline = "9")
settings.openrangegap_size     := input.int(1, "", options = [1,2,3,4], group=g_openranges, inline = "9")
settings.openrangegap_style    := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], group=g_openranges, inline='9')
settings.openrangegap_o_hour   := input.int(16, "         Open Hour", group=g_openranges, inline="10", minval = 1, maxval = 24)
settings.openrangegap_o_min    := input.int(15, "Minute", group=g_openranges, inline="10", minval = 0, maxval = 59)
settings.openrangegap_c_hour   := input.int(9, "         Close Hour", group=g_openranges, inline="10", minval = 1, maxval = 24)
settings.openrangegap_c_min    := input.int(30, "Minute", group=g_openranges, inline="10", minval = 0, maxval = 59)
settings.openrangegap_extend   := input.bool(false, "Extend Zone", group=g_openranges)

settings.show_MN           := input.bool(true, "Midnight Open", inline='1', group=g_timeofday)
settings.o_MN_color        := input.color(color.new(color.red, 0), "", inline='1', group=g_timeofday)
settings.o_MN_style        := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], inline='1', group=g_timeofday)
settings.o_MN_size         := input.int(1, '', options = [1,2,3,4], inline='1', group=g_timeofday)


settings.show_830           := input.bool(true, "8:30 Open   ", inline='2', group=g_timeofday)
settings.o_830_color        := input.color(color.new(color.blue, 0), "", inline='2', group=g_timeofday)
settings.o_830_style        := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], inline='2', group=g_timeofday)
settings.o_830_size         := input.int(1, '', options = [1,2,3,4], inline='2', group=g_timeofday)

settings.show_930           := input.bool(true, "9:30 Open   ", inline='3', group=g_timeofday)
settings.o_930_color        := input.color(color.new(color.orange, 0), "", inline='3', group=g_timeofday)
settings.o_930_style        := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], inline='3', group=g_timeofday)
settings.o_930_size         := input.int(1, '', options = [1,2,3,4], inline='3', group=g_timeofday)
settings.show_TOD_thick     := input.bool(true, "Show thick end", group=g_timeofday)

settings.show_DC            := input.bool(true, "Daily Midnight Candle", group=g_DC, inline="1")
settings.DC_bullish         := input.color(color.new(color.green, 0), "", inline='1', group=g_DC)
settings.DC_bearish         := input.color(color.new(color.red, 0), "", inline='1', group=g_DC)
settings.DC_wick            := input.color(color.new(color.black, 0), "", inline='1', group=g_DC)

settings.DC_count           := input.int(5, "Maximum number of days", group=g_DC, minval = 1)
settings.DC_buffer          := input.int(25, "Padding from current candle", group=g_DC, minval = 1)
settings.DC_spacing         := input.int(3, "Spacing between candles", group=g_DC, minval = 1)
settings.DC_ignore_saturday := input.bool(true, "Ignore Saturday", group=g_DC)
settings.DC_ignore_sunday   := input.bool(true, "Ignore Sunday", group=g_DC)

settings.ADR_show           := input.bool(true, "Average Daily Range", group=g_ADR, inline = "1", tooltip="Project possible range to the top and bottom based on the average ADR.")
settings.ADR_bullish        := input.color(color.new(color.green, 10), "", group = g_ADR, inline="1")
settings.ADR_bearish        := input.color(color.new(color.red, 10), "", group = g_ADR, inline="1")

settings.ADR_Trace          := input.bool(true, "Trace Lines", group=g_ADR, inline="2")
settings.ADR_Trace_color    := input.color(color.new(color.black, 10), "", group = g_ADR, inline="2")
settings.ADR_Trace_style    := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], inline='2', group=g_ADR)
settings.ADR_Trace_size     := input.int(1, '', options = [1,2,3,4], inline='2', group=g_ADR)
settings.ADR_Trace_Label    := input.bool(true, "Labels    ", group=g_ADR, inline="3")
settings.ADR_Trace_Label_color      := input.color(color.new(color.black, 10), "", group = g_ADR, inline="3")
settings.ADR_Trace_Label_bgcolor    := input.color(color.new(color.black, 100), "", group = g_ADR, inline="3")
settings.ADR_Trace_Label_size       := input.string(size.small, "", [size.tiny, size.small, size.normal, size.large, size.huge], group = g_ADR, inline="3")
settings.ADR_Trace_Third    := input.bool(true, "Mark Midnight 30% ADR Level", group=g_ADR)
settings.ADR_buffer         := input.int(14, "Offset from current candle", minval=1, maxval=50, group = g_ADR)

//+------------------------------------------------------------------------------------------------------------+//
//+--- Create time map for the Zones. The end result is in time(0000-0000)                                  ---+//
//+--- current time falls in that interval                                                                  ---+//
//+------------------------------------------------------------------------------------------------------------+//
tAsia           = time("1", str.tostring(settings.asia_o_hour, "00")+str.tostring(settings.asia_o_min, "00") + "-" + str.tostring(settings.asia_c_hour, "00")+str.tostring(settings.asia_c_min, "00"), "America/New_York")
tLondon         = time("1", str.tostring(settings.london_o_hour, "00")+str.tostring(settings.london_o_min, "00") + "-" + str.tostring(settings.london_c_hour, "00")+str.tostring(settings.london_c_min, "00"), "America/New_York")
tNY             = time("1", str.tostring(settings.ny_o_hour, "00")+str.tostring(settings.ny_o_min, "00") + "-" + str.tostring(settings.ny_c_hour, "00")+str.tostring(settings.ny_c_min, "00"), "America/New_York")

tOpenRange      = time("1", str.tostring(settings.openrange_o_hour, "00")+str.tostring(settings.openrange_o_min, "00") + "-" + str.tostring(settings.openrange_c_hour, "00")+str.tostring(settings.openrange_c_min, "00"), "America/New_York")
tOpenRangeGap   = time("1", str.tostring(settings.openrangegap_o_hour, "00")+str.tostring(settings.openrangegap_o_min, "00") + "-" + str.tostring(settings.openrangegap_c_hour, "00")+str.tostring(settings.openrangegap_c_min, "00"), "America/New_York")


color color_transparent     = #ffffff00

//+------------------------------------------------------------------------------------------------------------+//
//+--- Global functions                                                                                     ---+//
//+---     I need to convert these into Helper type but little lazy so will do it later                     ---+//
//+------------------------------------------------------------------------------------------------------------+//
f_get_line_style(style) =>
    out = switch style
        '⎯⎯⎯'  => line.style_solid
        '----' => line.style_dashed
        '····' => line.style_dotted

f_get_dayofweek(index) =>
    switch index
        1 =>
            "Sunday"
        2 =>
            "Monday"
        3 =>
            "Tuesday"
        4 =>
            "Wednesday"
        5 =>
            "Thursday"
        6 =>
            "Friday"
        7 =>
            "Saturday"
        na(index) =>
            ""

//+------------------------------------------------------------------------------------------------------------+//
//+--- f_get_day_offset                                                                                     ---+//
// This function calculates the length of the day taking into account Weekends                              ---+//
// This is mainly for Futures, I may need to come back and fix for forex and crypto                         ---+//
//+------------------------------------------------------------------------------------------------------------+//
f_get_day_offset(index) =>
    bar_length = time-time[1]
    switch index
        1 =>
            10800000 / bar_length
        6 =>
            32400000 / bar_length
        =>
            43200000 / bar_length

f_Validtimeframe() =>
    n1 = timeframe.in_seconds()
    n2 = timeframe.in_seconds(settings.hide_TF)

    n1 <= n2

//+------------------------------------------------------------------------------------------------------------+//
//+--- Main Methods                                                                                         ---+//
//+------------------------------------------------------------------------------------------------------------+//

//+------------------------------------------------------------------------------------------------------------+//
//+--- OHLC related methods                                                                                 ---+//
//+------------------------------------------------------------------------------------------------------------+//
method new(ohlc[] OHLC) =>
    ohlc newDay = ohlc.new()
    newDay.o            := open
    newDay.h            := high
    newDay.l            := low
    newDay.c            := close
    newDay.o_time       := time
    newDay.o_idx        := bar_index
    newDay.h_time       := time
    newDay.l_time       := time
    newDay.c_time       := time
    newDay.o_MN         := open
    newDay.o_MN_time    := time
    newDay.o_830_time   := time+30600000
    newDay.o_930_time   := time+34200000
    newDay.dow          := f_get_dayofweek(dayofweek(time, "America/New_York"))
    newDay.dow_index    := dayofweek(time, "America/New_York")

    OHLC.unshift(newDay)

    if OHLC.size() > settings.max_days
        for i = OHLC.size()-1 to settings.max_days
            ohlc del = OHLC.get(i)
            line.delete(del.o_line)
            line.delete(del.h_line)
            line.delete(del.l_line)
            line.delete(del.c_line)
            line.delete(del.s_line)
            line.delete(del.o_MN_line)
            line.delete(del.o_MN_thick)
            line.delete(del.o_830_line)
            line.delete(del.o_830_thick)
            line.delete(del.o_930_line)
            line.delete(del.o_930_thick)

    if OHLC.size() > 100
        OHLC.pop()

    if OHLC.size() > 1
        ohlc prev = OHLC.get(1)
        line.delete(prev.o_MN_thick)
        line.delete(prev.o_830_thick)
        line.delete(prev.o_930_thick)
        line.set_x2(prev.o_MN_line, prev.c_time + (time-time[1]))
        line.set_x2(prev.o_830_line, prev.c_time + (time-time[1]))
        line.set_x2(prev.o_930_line, prev.c_time + (time-time[1]))
        
        prev.c_time := time
    OHLC

method update(ohlc[] OHLC) =>
    if OHLC.size() > 0
        ohlc last = OHLC.first()

        if high > last.h
            last.h      := high
            last.h_time := time

        if low < last.l
            last.l      := low
            last.l_time := time
        last.c      := close
        last.c_time := time
    
        if time == last.o_830_time
            last.o_830 := open

        if time == last.o_930_time
            last.o_930  := open

    OHLC

method drawADRRange(ohlc[] OHLC) =>
    if settings.ADR_show
        if OHLC.size() > 7
            float r     = 0
            float part  = 0

            for i = 1 to 7
                d = OHLC.get(i)
                if d.dow != "Saturday" and d.dow != "Sunday"
                    r += d.h - d.l
            
            r       := r / 5
            part    := r*0.3

            current = OHLC.first()

            idx     = bar_index + settings.ADR_buffer
            idxb    = idx+6

            if na(projection.body_high)
                projection.body_high                := box.new(idx, current.l+r, idx+1, current.l, border_color = color_transparent, bgcolor=settings.ADR_bullish)
                if settings.ADR_Trace
                    if settings.ADR_Trace_Third
                        projection.high_third           := line.new(current.o_idx, current.o+part, idxb, current.o+part, xloc.bar_index, extend.none, settings.ADR_Trace_color, f_get_line_style(settings.ADR_Trace_style), settings.ADR_Trace_size)
                    projection.max                  := line.new(current.o_idx, current.l+r, idxb, current.o-part, xloc.bar_index, extend.none, settings.ADR_Trace_color, f_get_line_style(settings.ADR_Trace_style), settings.ADR_Trace_size)
                    if settings.ADR_Trace_Label
                        if settings.ADR_Trace_Third
                            projection.high_third_label     := label.new(idxb, current.o+part, "+0.3 ADR", xloc.bar_index, yloc.price, settings.ADR_Trace_Label_bgcolor, label.style_label_left, settings.ADR_Trace_Label_color, settings.ADR_Trace_Label_size)
                        projection.max_label            := label.new(idxb, current.l+r, "+ADR", xloc.bar_index, yloc.price, settings.ADR_Trace_Label_bgcolor, label.style_label_left, settings.ADR_Trace_Label_color, settings.ADR_Trace_Label_size)
            else
                if current.l+r > current.h
                    box.set_lefttop(projection.body_high, idx, current.l+r)
                    box.set_rightbottom(projection.body_high, idx+1, current.l)
                    line.set_xy1(projection.max, current.o_idx, current.l+r)
                    line.set_xy2(projection.max, idxb, current.l+r)
                    label.set_xy(projection.high_third_label, idxb, current.l+r)
                    label.set_xy(projection.max_label, idxb, current.l+r)
                else
                    box.set_lefttop(projection.body_high, idx, box.get_top(projection.body_low))
                    box.set_rightbottom(projection.body_high, idx+1, box.get_bottom(projection.body_low))
                    line.set_xy1(projection.max, current.o_idx, box.get_top(projection.body_low))
                    line.set_xy2(projection.max, idxb, box.get_top(projection.body_low))
                    label.set_xy(projection.max_label, idxb, box.get_top(projection.body_low))

                if settings.ADR_Trace
                    line.set_xy1(projection.high_third, current.o_idx, current.o+part)
                    line.set_xy2(projection.high_third, idxb, current.o+part)
                    label.set_xy(projection.high_third_label, idxb, current.o+part)


            if na(projection.body_low)
                projection.body_low                     := box.new(idx+2, current.h, idx+3, current.h-r, border_color = color_transparent, bgcolor=settings.ADR_bearish)
                if settings.ADR_Trace
                    if settings.ADR_Trace_Third
                        projection.low_third                := line.new(current.o_idx, current.o-part, idxb, current.o-part, xloc.bar_index, extend.none, settings.ADR_Trace_color, f_get_line_style(settings.ADR_Trace_style), settings.ADR_Trace_size)
                    projection.min                      := line.new(current.o_idx, current.h-r, idxb, current.o-part, xloc.bar_index, extend.none, settings.ADR_Trace_color, f_get_line_style(settings.ADR_Trace_style), settings.ADR_Trace_size)
                    if settings.ADR_Trace_Label
                        if settings.ADR_Trace_Third
                            projection.low_third_label      := label.new(idxb, current.o-part, "-0.3 ADR", xloc.bar_index, yloc.price, settings.ADR_Trace_Label_bgcolor, label.style_label_left, settings.ADR_Trace_Label_color, settings.ADR_Trace_Label_size)
                        projection.min_label            := label.new(idxb, current.h-r, "-ADR", xloc.bar_index, yloc.price, settings.ADR_Trace_Label_bgcolor, label.style_label_left, settings.ADR_Trace_Label_color, settings.ADR_Trace_Label_size)
            else
                if current.h-r < current.l
                    box.set_lefttop(projection.body_low, idx+2, current.h)
                    box.set_rightbottom(projection.body_low, idx+3, current.h-r)
                    line.set_xy1(projection.min, current.o_idx, current.h-r)
                    line.set_xy2(projection.min, idxb, current.h-r)
                    label.set_xy(projection.min_label, idxb, current.h-r)
                else
                    box.set_lefttop(projection.body_low, idx+2, box.get_top(projection.body_high))
                    box.set_rightbottom(projection.body_low, idx+3, box.get_bottom(projection.body_high))
                    line.set_xy1(projection.min, current.o_idx, box.get_bottom(projection.body_high))
                    line.set_xy2(projection.min, idxb, box.get_bottom(projection.body_high))
                    label.set_xy(projection.min_label, idxb, box.get_bottom(projection.body_high))
                if settings.ADR_Trace
                    line.set_xy1(projection.low_third, current.o_idx, current.o-part)
                    line.set_xy2(projection.low_third, idxb, current.o-part)
                    label.set_xy(projection.low_third_label, idxb, current.o-part)                

    OHLC
        
//+------------------------------------------------------------------------------------------------------------+//
//+--- New Day related methods                                                                              ---+//
//+------------------------------------------------------------------------------------------------------------+//
method newDC(Candle[] DC) =>
    dow = f_get_dayofweek(dayofweek(time, "America/New_York"))

    Candle candle = Candle.new()
    candle.o            := open
    candle.c            := close
    candle.h            := high
    candle.l            := low
    candle.dow          := str.substring(dow, 0, 1)

    DC.unshift(candle)

    if DC.size() > settings.DC_count
        Candle c = DC.pop()
        box.delete(c.body)
        line.delete(c.wick_top)
        line.delete(c.wick_bottom)
        label.delete(c.lbl)
    DC

method updateDC(Candle[] DC) =>
    if DC.size() > 0
        Candle candle = DC.first()
        if high > candle.h
            candle.h      := high
        if low < candle.l
            candle.l      := low
        candle.c      := close

    DC

// Draw the daily candle
method drawDC(Candle[] DC) =>
    int count = DC.size()
    if count > 0
        for i = 0 to count-1
            Candle candle = DC.get(i)
            int position = bar_index+settings.DC_buffer +((count-i)*(settings.DC_spacing+2))
            if settings.show_DC
                if na(candle.body)
                    candle.body := box.new(position, candle.o > candle.c ? candle.o : candle.c, position+2, candle.o > candle.c ? candle.c : candle.o, settings.DC_wick, 1, line.style_solid, extend.none, xloc.bar_index, candle.c > candle.o ? settings.DC_bullish : settings.DC_bearish)
                else
                    box.set_lefttop(candle.body, position, candle.o > candle.c ? candle.o : candle.c)
                    box.set_rightbottom(candle.body, position+2, candle.o > candle.c ? candle.c : candle.o)
                    box.set_bgcolor(candle.body, candle.c > candle.o ? settings.DC_bullish : settings.DC_bearish)

                if na(candle.wick_top)
                    candle.wick_top := line.new(position+1, candle.h, position+1, candle.o > candle.c ? candle.o : candle.c, xloc.bar_index, extend.none, settings.DC_wick)
                else
                    line.set_xy1(candle.wick_top, position+1, candle.h)
                    line.set_xy2(candle.wick_top, position+1, candle.o > candle.c ? candle.o : candle.c)

                if na(candle.wick_bottom)
                    candle.wick_bottom  := line.new(position+1, candle.l, position+1, candle.o > candle.c ? candle.c : candle.o, xloc.bar_index, extend.none, settings.DC_wick)
                else
                    line.set_xy1(candle.wick_bottom, position+1, candle.l)
                    line.set_xy2(candle.wick_bottom, position+1, candle.o > candle.c ? candle.c : candle.o)

                if na(candle.lbl)
                    candle.lbl := label.new(position+1, candle.h, candle.dow, textcolor=settings.DC_wick, color=color_transparent, style= label.style_label_down )
                else
                    label.set_xy(candle.lbl, position+1, candle.h)
    DC

//+------------------------------------------------------------------------------------------------------------+//
//+--- Get Current Day                                                                                      ---+//
//+------------------------------------------------------------------------------------------------------------+//
method current(ohlc[] OHLC) =>
    OHLC.size() > 0 ? OHLC.get(0) : na

//+------------------------------------------------------------------------------------------------------------+//
//+--- Create Session Seperator                                                                             ---+//
//+------------------------------------------------------------------------------------------------------------+//
method session_seperator(ohlc[] OHLC) =>
    if OHLC.size() > 0 and settings.show_session
        ohlc step = OHLC.get(0)
        if na(step.s_line)
            step.s_line := line.new(step.o_time, step.o, step.o_time, step.o+1, xloc=xloc.bar_time, extend = extend.both, color=settings.s_color, style=f_get_line_style(settings.s_style), width = settings.s_size)

method session_levels(ohlc[] OHLC) =>
    if OHLC.size() > 0
        ohlc step = OHLC.get(0)
        // We use time not bar_index because on lower timeframes, we may get too extended out and it errors
        // the way to calculate the time of each candle is to get the difference between two candles. this 
        // resolves the issue with multi timeframe calculation.
        int candletime = (time-time[1])

        if settings.show_MN
            step.o_line

        if settings.show_MN and not na(step.o_MN)
            if na(step.o_MN_line)
                step.o_MN_line    := line.new(step.o_MN_time, step.o_MN, time + (candletime*5), step.o_MN, xloc=xloc.bar_time, color=settings.o_MN_color, style=f_get_line_style(settings.o_MN_style), width = settings.o_MN_size)
                if settings.show_TOD_thick
                    step.o_MN_thick   := line.new(time + (candletime*5), step.o_MN, time + (candletime*10), step.o_MN, xloc=xloc.bar_time, color=settings.o_MN_color, style=line.style_solid, width = 4)
            else
                line.set_x2(step.o_MN_line, time + (candletime*5))
                if settings.show_TOD_thick
                    line.set_x1(step.o_MN_thick, time + (candletime*5))
                    line.set_x2(step.o_MN_thick, time + (candletime*10))

        if settings.show_830 and not na(step.o_830)
            if na(step.o_830_line)
                step.o_830_line    := line.new(step.o_830_time, step.o_830, time + (candletime*5), step.o_830, xloc=xloc.bar_time, color=settings.o_830_color, style=f_get_line_style(settings.o_830_style), width = settings.o_830_size)
                if settings.show_TOD_thick
                    step.o_830_thick   := line.new(time + (candletime*5), step.o_830, time + (candletime*10), step.o_830, xloc=xloc.bar_time, color=settings.o_830_color, style=line.style_solid, width = 4)
            else
                line.set_x2(step.o_830_line, time + (candletime*5))
                if settings.show_TOD_thick
                    line.set_x1(step.o_830_thick, time + (candletime*5))
                    line.set_x2(step.o_830_thick, time + (candletime*10))

        if settings.show_930 and not na(step.o_930)
            if na(step.o_930_line)
                step.o_930_line     := line.new(step.o_930_time, step.o_930, time + (candletime*5), step.o_930, xloc=xloc.bar_time, color=settings.o_930_color, style=f_get_line_style(settings.o_930_style), width = settings.o_930_size)
                if settings.show_TOD_thick
                    step.o_930_thick    := line.new(time + (candletime*5), step.o_930, time + (candletime*10), step.o_930, xloc=xloc.bar_time, color=settings.o_930_color, style=line.style_solid, width = 4)
            else
                line.set_x2(step.o_930_line, time + (candletime*5))
                if settings.show_TOD_thick
                    line.set_x1(step.o_930_thick, time + (candletime*5))
                    line.set_x2(step.o_930_thick, time + (candletime*10))
    OHLC

//+------------------------------------------------------------------------------------------------------------+//
//+--- Zone related methods                                                                                 ---+//
//+--   reused for the opening ranges                                                                       ---+//
//+------------------------------------------------------------------------------------------------------------+//
method start(Zone[] KZ) =>
    Zone newZone = Zone.new()
    newZone.o            := open
    newZone.h            := high
    newZone.l            := low
    newZone.c            := close
    newZone.o_time       := time
    newZone.h_time       := time
    newZone.l_time       := time
    newZone.c_time       := time

    KZ.unshift(newZone)

    KZ

method update(Zone[] KZ) =>
    if KZ.size() > 0
        Zone last = KZ.get(0)
        if high > last.h
            last.h      := high
            last.h_time := time

        if low < last.l
            last.l      := low
            last.l_time := time
        last.c      := close
        last.c_time := time
    KZ 


method startGap(Zone[] KZ) =>
    Zone newZone = Zone.new()
    newZone.o            := open
    newZone.h            := high
    newZone.l            := low
    newZone.c            := close
    newZone.o_time       := time
    newZone.h_time       := time
    newZone.l_time       := time
    newZone.c_time       := time
    KZ.unshift(newZone)
    KZ

method closeGap(Zone[] KZ) =>
    if KZ.size() > 0
        Zone last = KZ.get(0)
        last.c      := open
        last.c_time := time
    KZ 


method display(Zone[] KZ, int session) =>
    var bool show       = false
    var string style    = na
    var int width       = na
    var color bgcolor   = na
    var color bcolor    = na
    var bool  extend    = false

    if KZ.size() > 0
        Zone step = KZ.first()

        switch session
            1 =>
                show        := settings.show_asia
                width       := settings.asia_border_size
                style       := settings.asia_border_style
                bgcolor     := settings.asia_background
                bcolor      := settings.asia_border
            2 =>
                show        := settings.show_london
                width       := settings.london_border_size
                style       := settings.london_border_style
                bgcolor     := settings.london_background
                bcolor      := settings.london_border
            3 =>
                show        := settings.show_ny
                width       := settings.ny_border_size
                style       := settings.ny_border_style
                bgcolor     := settings.ny_background
                bcolor      := settings.ny_border
            4 =>
                show        := settings.show_openrange
                width       := settings.openrange_size
                style       := settings.openrange_style
                bgcolor     := settings.openrange_background
                bcolor      := settings.openrange_border
                extend      := settings.openrange_extend
            5 =>
                show        := settings.show_openrangegap
                width       := settings.openrangegap_size
                style       := settings.openrangegap_style
                bgcolor     := settings.openrangegap_background
                bcolor      := settings.openrangegap_border
                extend      := settings.openrangegap_extend

        if show and session < 5
            if na(step.b)
                step.b := box.new(step.o_time, step.h, step.c_time, step.l, bcolor, width, f_get_line_style(style), extend.none, xloc.bar_time, bgcolor)
            else
                box.set_top(step.b, step.h)
                box.set_bottom(step.b, step.l)
                if extend
                    box.set_right(step.b, time+(time-time[1]))
                else
                    box.set_right(step.b, step.c_time)
        if show and session == 5 and step.o_time != step.c_time
            if na(step.b)
                step.b := box.new(step.o_time, step.c, step.c_time, step.o, bcolor, width, f_get_line_style(style), extend.none, xloc.bar_time, bgcolor)
            else
                box.set_top(step.b, step.c)
                box.set_right(step.b, step.c_time)
            if extend
                box.set_right(step.b, time+(time-time[1]))
            else
                box.set_right(step.b, step.c_time)
    KZ
//+------------------------------------------------------------------------------------------------------------+//
//+--- Main logic that starts the process                                                                    ---+//
//+------------------------------------------------------------------------------------------------------------+//
// Did we start a new day? (Midnight)
newDay = dayofweek(time, "America/New_York") != dayofweek(time-(time-time[1]), "America/New_York")

// Do we have a valid timeframe? i.e. still under X timeframe
valid = f_Validtimeframe()
dow = f_get_dayofweek(dayofweek(time, "America/New_York"))
if valid
    // If new day, start calculating new day metrics and drae seperators if enabled
    if newDay
        OHLC.new().session_seperator()

        if (dow == "Saturday" and not settings.DC_ignore_saturday) or (dow == "Sunday" and not settings.DC_ignore_sunday) or (dow != "Saturday" and dow != "Sunday")
            DC.newDC()

    // If in Killzones
    // Asia is special because it starts before the day starts. So when we have
    // new asia session, we clear previous london and NY since they belong to
    // previous day

    if tLondon
        if not tLondon[1]
            london.start()
            if london.size() > settings.max_days
                l = london.pop()
                box.delete(l.b)

        london.update().display(2)

    if tNY
        if not tNY[1]
            ny.start()
            if ny.size() > settings.max_days
                n = ny.pop()
                box.delete(n.b)

        ny.update().display(3)

    if tAsia
        if not tAsia[1]
            asia.start()
            if asia.size() > settings.max_days
                Zone a = asia.pop()
                box.delete(a.b)

        asia.update().display(1)

    if tOpenRange
        if not tOpenRange[1]
            openrange.start()
            if openrange.size() > settings.max_days
                opr = openrange.pop()
                box.delete(opr.b)
        openrange.update()

    openrange.display(4)

    if tOpenRangeGap and not tOpenRangeGap[1]
        openrangegap.startGap()

    if tOpenRangeGap[1] and not tOpenRangeGap
        openrangegap.closeGap()

    if openrangegap.size() > settings.max_days
        oprg = openrangegap.pop()
        box.delete(oprg.b)

    openrangegap.display(5)

    OHLC.update().drawADRRange().session_levels()

    if (dow == "Saturday" and not settings.DC_ignore_saturday) or (dow == "Sunday" and not settings.DC_ignore_sunday) or (dow != "Saturday" and dow != "Sunday")
        DC.updateDC()

    DC.drawDC()
//+------------------------------------------------------------------------------------------------------------+//
//+--- Weekdays. i wish there was better way of doing this                                                  ---+//
//+------------------------------------------------------------------------------------------------------------+//
current     = OHLC.current()
day         = na(current) ? "" :  current.dow
plotshape(settings.show_dayofweek ? newDay and day == "Monday" and valid      : false, offset=na(current) ? 0 : f_get_day_offset(2)-1, style=shape.diamond, text="MON",      color=color_transparent, location = location.bottom, textcolor=settings.dayofweek_color, size=size.auto)
plotshape(settings.show_dayofweek ? newDay and day == "Tuesday" and valid     : false, offset=na(current) ? 0 : f_get_day_offset(3)-1, style=shape.diamond, text="TUE",     color=color_transparent, location = location.bottom, textcolor=settings.dayofweek_color, size=size.auto)
plotshape(settings.show_dayofweek ? newDay and day == "Wednesday" and valid   : false, offset=na(current) ? 0 : f_get_day_offset(4)-1, style=shape.diamond, text="WED",   color=color_transparent, location = location.bottom, textcolor=settings.dayofweek_color, size=size.auto)
plotshape(settings.show_dayofweek ? newDay and day == "Thursday" and valid    : false, offset=na(current) ? 0 : f_get_day_offset(5)-1, style=shape.diamond, text="THU",    color=color_transparent, location = location.bottom, textcolor=settings.dayofweek_color, size=size.auto)
plotshape(settings.show_dayofweek ? newDay and day == "Friday" and valid      : false, offset=na(current) ? 0 : f_get_day_offset(6)-1, style=shape.diamond, text="FRI",      color=color_transparent, location = location.bottom, textcolor=settings.dayofweek_color, size=size.auto)
plotshape(settings.show_dayofweek ? newDay and day == "saturday" and valid    : false, offset=na(current) ? 0 : f_get_day_offset(7), style=shape.diamond, text="SAT",    color=color_transparent, location = location.bottom, textcolor=settings.dayofweek_color, size=size.auto)
plotshape(settings.show_dayofweek ? newDay and day == "Sunday" and valid      : false, offset=na(current) ? 0 : f_get_day_offset(1), style=shape.diamond, text="SUN",      color=color_transparent, location = location.bottom, textcolor=settings.dayofweek_color, size=size.auto)

