JV Sessions
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/


 
//Session	            Local Time	                   DST OFF (UCT+0)	DST ON (UTC+0)	DST ON 2022	  DST OFF 2022	DST ON 2023	  DST OFF 2023	  DST ON 2024	DST OFF 2024
//London	            8am-430pm	                   0800-1630	    0700-1530	    March, 27	  October, 30	March, 26	  October, 29	  March, 31	    October, 27
//NewYork	            930am-4pm	                   1430-2100	    1330-2000	    March, 13	  November, 6	March, 12	  November, 5	  March, 10	    November, 3
//Tokyo	                9am-3pm	                       0000-0600	    0000-0600	    N/A	          N/A	        N/A	          N/A	          N/A	        N/A
//HongKong	            930am-4pm	                   0130-0800	    0130-0800	    N/A	          N/A	        N/A	          N/A	          N/A	        N/A
//Sydney (NZX+ASX)	    NZX start 10am, ASX end 4pm	   2200-0600	    2100-0500	    October, 2	  April, 3	    October, 1	  April, 2	      October, 6	April, 7
//EU Brinx	            800am-900am	                   0800-0900	    0700-0800	    March, 27	  October, 30	March, 26	  October, 29	  March, 31	    October, 27
//US Brinx	            900am-10am	                   1400-1500	    1300-1400	    March, 13	  November, 6	March, 12	  November, 5	  March, 10	    November, 3
//Frankfurt	            800am-530pm	                   0700-1630	    0600-1530	    March, 27	  October, 30	March, 26	  October, 29	  March, 31	    October, 27
 

//@version=5
indicator('JV Sessions', overlay=true, max_bars_back=300,max_boxes_count=500, max_lines_count=500, max_labels_count=500)


// Config

label_x_offset = time_close + 5 * timeframe.multiplier * 60 * 1000


// Basic vars (needed in functions)

// Only render intraday
validTimeFrame = timeframe.isintraday == true

// If above the 5 minute, we start drawing yesterday. below, we start today
levelsstart = timeframe.isseconds == true or timeframe.isminutes == true and timeframe.multiplier < 5 ? time('D') : time('D') - 86400 * 1000
//levelsstartbar = ta.barssince(levelsstart)


// Functions
// new_bar: check if we're on a new bar within the session in a given resolution
new_bar(res) =>
    ta.change(time(res)) != 0
    
//Right_Label
r_label(ry, rtext, rstyle, rcolor, valid) =>
    var label rLabel = na
    if valid and barstate.isrealtime
        rLabel := label.new(x=label_x_offset, y=ry, text=rtext, xloc=xloc.bar_time, style=rstyle, textcolor=rcolor, textalign=text.align_right)
        label.delete(rLabel[1])
    rLabel

//Right_Label
r_label_offset(ry, rtext, rstyle, rcolor, valid, labelOffset) =>
    if valid and barstate.isrealtime
        rLabel = label.new(x=labelOffset, y=ry, text=rtext, xloc=xloc.bar_time, style=rstyle, textcolor=rcolor, textalign=text.align_right)
        label.delete(rLabel[1])


draw_line(x_series, res, tag, xColor, xStyle, xWidth, xExtend, isLabelValid, xLabelOffset) =>
    var line x_line = na

    if validTimeFrame and new_bar(res) //and barstate.isnew
        x_line := line.new(bar_index, x_series, bar_index+1, x_series, extend=xExtend, color=xColor, style=xStyle, width=xWidth)
        line.delete(x_line[1])

    if not na(x_line) and not new_bar(res)//and line.get_x2(x_line) != bar_index
        line.set_x2(x_line, bar_index)
        line.set_y1(x_line,x_series)
        line.set_y2(x_line,x_series)

    if isLabelValid  //showADRLabels and validTimeFrame
        x_label = label.new(xLabelOffset, x_series, tag, xloc=xloc.bar_time, style=label.style_none, textcolor=xColor)
        label.delete(x_label[1])

draw_line_DO(x_series, res, tag, xColor, xStyle, xWidth, xExtend, isLabelValid, xLabelOffset) =>
    var line x_line = na

    if new_bar(res) and validTimeFrame
        line.set_x2(x_line, bar_index)
        line.set_extend(x_line, extend.none)

        x_line := line.new(bar_index, x_series, bar_index, x_series, extend=xExtend, color=xColor, style=xStyle, width=xWidth)
        line.delete(x_line[1])

    if not na(x_line) and line.get_x2(x_line) != bar_index
        line.set_x2(x_line, bar_index)

    if isLabelValid  //showADRLabels and validTimeFrame
        x_label = label.new(xLabelOffset, x_series, tag, xloc=xloc.bar_time, style=label.style_none, textcolor=xColor)
        label.delete(x_label[1])
        
draw_pivot(pivot_level, res, tag, pivotColor, pivotLabelColor, pivotStyle, pivotWidth, pivotExtend, isLabelValid) =>
    var line pivot_line = na

/// market boxes and daily open only on intraday
bool show = timeframe.isminutes and timeframe.multiplier <= 240 and timeframe.multiplier >= 1
time_now_exchange = timestamp(year, month, dayofmonth, hour, minute, second)
bool show_dly = timeframe.isminutes  //and timeframe.multiplier < 240
bool show_rectangle9 = input.bool(group='Daily Open', defval=true, title='Show: line ?', inline='dopenconf') and show_dly
bool show_label9 = input.bool(group='Daily Open', defval=true, title='Label?', inline='dopenconf') and show_rectangle9 and show_dly
bool showallDly = input.bool(group='Daily Open', defval=false, title='Show historical daily opens?', inline='dopenconf')
color sess9col = input.color(group='Daily Open', title='Daily Open Color', defval=color.rgb(254, 234, 78, 0), inline='dopenconf1')

string rectStyle = input.string(group='Market sessions', defval='Dashed', title='Line style of Market Session hi/lo line', options=['Dashed', 'Solid'])
sessLineStyle = line.style_dashed
bool show_markets = input.bool(true, group='Market sessions', title='Show Market Sessions?', tooltip='Turn on or off all market sessions') and show
bool show_markets_weekends = input.bool(false, group='Market sessions', title='Show Market Session on Weekends?', tooltip='Turn on or off market sessions in the weekends. Note do not turn this on for exchanges that dont have weekend data like OANDA') and show
string weekend_sessions = ':1234567'
string no_weekend_sessions = ':23456'

bool show_rectangle1 = input.bool(group='Market session: London (0800-1630 UTC+0) - DST Aware', defval=true, title='Show: session?', inline='session1conf', tooltip='If this checkbox is off, Label and Open Range have no effect') and show_markets
bool show_label1 = input.bool(group='Market session: London (0800-1630 UTC+0) - DST Aware', defval=true, title='Label?', inline='session1conf') and show_rectangle1 and show_markets
bool show_or1 = input.bool(group='Market session: London (0800-1630 UTC+0) - DST Aware', defval=true, title='Opening Range?', inline='session1conf', tooltip='This controls the shaded area for the session') and show_rectangle1 and show_markets
string sess1Label = input.string(group='Market session: London (0800-1630 UTC+0) - DST Aware', defval='London', title='Name:', inline='session1style')
color sess1col = input.color(group='Market session: London (0800-1630 UTC+0) - DST Aware', title='Color: Box', defval=color.rgb(120, 123, 134, 75), inline='session1style')
color sess1colLabel = input.color(group='Market session: London (0800-1630 UTC+0) - DST Aware', title='Label', defval=color.rgb(120, 123, 134, 0), inline='session1style')
string sess1TimeX = '0800-1630'//input.session(group='Market session: London (0800-1630 UTC+0)', defval='0800-1630', title='Time (UTC+0):', inline='session1style', tooltip='Normally you will not want to adjust these times. Defaults are taken as if the session is NOT in DST and times must be in UTC+0. Note due to limitations of pinescript some values sellected here other than the default might not work correctly on all exchanges.')
sess1Time = show_markets_weekends ? sess1TimeX + weekend_sessions : sess1TimeX + no_weekend_sessions


bool show_rectangle2 = input.bool(group='Market session: New York (1430-2100 UTC+0) - DST Aware', defval=true, title='Show: session?', inline='session2conf', tooltip='If this checkbox is off, Label and Open Range have no effect') and show_markets
bool show_label2 = input.bool(group='Market session: New York (1430-2100 UTC+0) - DST Aware', defval=true, title='Label?', inline='session2conf') and show_rectangle2 and show_markets
bool show_or2 = input.bool(group='Market session: New York (1430-2100 UTC+0) - DST Aware', defval=true, title='Opening Range?', inline='session2conf', tooltip='This controls the shaded area for the session') and show_rectangle2 and show_markets
string sess2Label = input.string(group='Market session: New York (1430-2100 UTC+0) - DST Aware', defval='NewYork', title='Name:', inline='session2style')
color sess2col = input.color(group='Market session: New York (1430-2100 UTC+0) - DST Aware', title='Color: Box', defval=color.rgb(251, 86, 91, 75), inline='session2style')
color sess2colLabel = input.color(group='Market session: New York (1430-2100 UTC+0) - DST Aware', title='Label', defval=color.rgb(253, 84, 87, 25), inline='session2style')
string sess2TimeX = '1430-2100'//input.session(group='Market session: New York (1430-2100 UTC+0)', defval='1430-2100', title='Time (UTC+0):', inline='session2style', tooltip='Normally you will not want to adjust these times. Defaults are taken as if the session is NOT in DST times must be in UTC+0. Note due to limitations of pinescript some values sellected here other than the default might not work correctly on all exchanges.')
sess2Time = show_markets_weekends ? sess2TimeX + weekend_sessions : sess2TimeX  + no_weekend_sessions


bool show_rectangle3 = input.bool(group='Market session: Tokyo (0000-0600 UTC+0) - DST Aware', defval=true, title='Show: session?', inline='session3conf', tooltip='If this checkbox is off, Label and Open Range have no effect') and show_markets
bool show_label3 = input.bool(group='Market session: Tokyo (0000-0600 UTC+0) - DST Aware', defval=true, title='Label?', inline='session3conf') and show_rectangle3 and show_markets
bool show_or3 = input.bool(group='Market session: Tokyo (0000-0600 UTC+0) - DST Aware', defval=true, title='Opening Range?', inline='session3conf', tooltip='This controls the shaded area for the session') and show_rectangle3 and show_markets
string sess3Label = input.string(group='Market session: Tokyo (0000-0600 UTC+0) - DST Aware', defval='Tokyo', title='Name:', inline='session3style')
color sess3col = input.color(group='Market session: Tokyo (0000-0600 UTC+0) - DST Aware', title='Color: Box', defval=color.rgb(80, 174, 85, 75), inline='session3style')
color sess3colLabel = input.color(group='Market session: Tokyo (0000-0600 UTC+0) - DST Aware', title='Label', defval=color.rgb(80, 174, 85, 25), inline='session3style')
string sess3TimeX = '0000-0600'//input.session(group='Market session: Tokyo (0000-0600 UTC+0)', defval='0000-0600', title='Time (UTC+0):', inline='session3style', tooltip='Normally you will not want to adjust these times. Defaults are taken as if the session is NOT in DST times must be in UTC+0. Note due to limitations of pinescript some values sellected here other than the default might not work correctly on all exchanges.')
sess3Time = show_markets_weekends ? sess3TimeX + weekend_sessions : sess3TimeX + no_weekend_sessions


bool show_rectangle4 = input.bool(group='Market session: Hong Kong (0130-0800 UTC+0) - DST Aware', defval=true, title='Show: session?', inline='session4conf', tooltip='If this checkbox is off, Label and Open Range have no effect') and show_markets
bool show_label4 = input.bool(group='Market session: Hong Kong (0130-0800 UTC+0) - DST Aware', defval=true, title='Label?', inline='session4conf') and show_rectangle4 and show_markets
bool show_or4 = input.bool(group='Market session: Hong Kong (0130-0800 UTC+0) - DST Aware', defval=true, title='Opening Range?', inline='session4conf', tooltip='This controls the shaded area for the session') and show_rectangle4 and show_markets
string sess4Label = input.string(group='Market session: Hong Kong (0130-0800 UTC+0) - DST Aware', defval='HongKong', title='Name:', inline='session4style')
color sess4col = input.color(group='Market session: Hong Kong (0130-0800 UTC+0) - DST Aware', title='Color: Box', defval=color.rgb(128, 127, 23, 75), inline='session4style')
color sess4colLabel = input.color(group='Market session: Hong Kong (0130-0800 UTC+0) - DST Aware', title='Label', defval=color.rgb(128, 127, 23, 25), inline='session4style')
string sess4TimeX = '0130-0800'//input.session(group='Market session: Hong Kong (0130-0800 UTC+0)', defval='0130-0800', title='Time (UTC+0):', inline='session4style', tooltip='Normally you will not want to adjust these times. Defaults are taken as if the session is NOT in DST times must be in UTC+0. Note due to limitations of pinescript some values sellected here other than the default might not work correctly on all exchanges.')
sess4Time = show_markets_weekends ? sess4TimeX + weekend_sessions : sess4TimeX + no_weekend_sessions

bool show_rectangle5 = input.bool(group='Market session: Sydney (NZX+ASX 2200-0600 UTC+0) - DST Aware', defval=true, title='Show: session?', inline='session5conf', tooltip='If this checkbox is off, Label and Open Range have no effect') and show_markets
bool show_label5 = input.bool(group='Market session: Sydney (NZX+ASX 2200-0600 UTC+0) - DST Aware', defval=true, title='Label?', inline='session5conf') and show_rectangle5 and show_markets
bool show_or5 = input.bool(group='Market session: Sydney (NZX+ASX 2200-0600 UTC+0) - DST Aware', defval=true, title='Opening Range?', inline='session5conf', tooltip='This controls the shaded area for the session') and show_rectangle5 and show_markets
string sess5Label = input.string(group='Market session: Sydney (NZX+ASX 2200-0600 UTC+0) - DST Aware', defval='Sydney', title='Name:', inline='session5style')
color sess5col = input.color(group='Market session: Sydney (NZX+ASX 2200-0600 UTC+0) - DST Aware', title='Color: Box', defval=color.rgb(37, 228, 123, 75), inline='session5style')
color sess5colLabel = input.color(group='Market session: Sydney (NZX+ASX 2200-0600 UTC+0) - DST Aware', title='Label', defval=color.rgb(37, 228, 123, 25), inline='session5style')
string sess5TimeX = '2200-0600'//input.session(group='Market session: Sydney (NZX+ASX 2200-0600 UTC+0)', defval='2200-0600', title='Time (UTC+0):', inline='session5style', tooltip='Normally you will not want to adjust these times. Defaults are taken as if the session is NOT in DST times must be in UTC+0. Note due to limitations of pinescript some values sellected here other than the default might not work correctly on all exchanges.')
sess5Time = show_markets_weekends ? sess5TimeX + weekend_sessions : sess5TimeX + no_weekend_sessions

bool show_rectangle6 = input.bool(group='Market session: EU Brinks (0800-0900 UTC+0) - DST Aware', defval=true, title='Show: session?', inline='session6conf', tooltip='If this checkbox is off, Label and Open Range have no effect') and show_markets
bool show_label6 = input.bool(group='Market session: EU Brinks (0800-0900 UTC+0) - DST Aware', defval=true, title='Label?', inline='session6conf') and show_rectangle6 and show_markets
bool show_or6 = input.bool(group='Market session: EU Brinks (0800-0900 UTC+0) - DST Aware', defval=true, title='Opening Range?', inline='session6conf', tooltip='This controls the shaded area for the session') and show_rectangle6 and show_markets
string sess6Label = input.string(group='Market session: EU Brinks (0800-0900 UTC+0) - DST Aware', defval='EU Brinks', title='Name:', inline='session6style')
color sess6col = input.color(group='Market session: EU Brinks (0800-0900 UTC+0) - DST Aware', title='Color: Box', defval=color.rgb(255, 255, 255, 65), inline='session6style')
color sess6colLabel = input.color(group='Market session: EU Brinks (0800-0900 UTC+0) - DST Aware', title='Label', defval=color.rgb(255, 255, 255, 25), inline='session6style')
string sess6TimeX = '0800-0900'//input.session(group='Market session: EU Brinks (0800-0900 UTC+0)', defval='0800-0900', title='Time (UTC+0):', inline='session6style', tooltip='Normally you will not want to adjust these times. Defaults are taken as if the session is NOT in DST times must be in UTC+0. Note due to limitations of pinescript some values sellected here other than the default might not work correctly on all exchanges.')
sess6Time = show_markets_weekends ? sess6TimeX + weekend_sessions : sess6TimeX + no_weekend_sessions

bool show_rectangle7 = input.bool(group='Market session: US Brinks (1400-1500 UTC+0) - DST Aware', defval=true, title='Show: session?', inline='session7conf', tooltip='If this checkbox is off, Label and Open Range have no effect') and show_markets
bool show_label7 = input.bool(group='Market session: US Brinks (1400-1500 UTC+0) - DST Aware', defval=true, title='Label?', inline='session7conf') and show_rectangle7 and show_markets
bool show_or7 = input.bool(group='Market session: US Brinks (1400-1500 UTC+0) - DST Aware', defval=true, title='Opening Range?', inline='session7conf', tooltip='This controls the shaded area for the session') and show_rectangle7 and show_markets
string sess7Label = input.string(group='Market session: US Brinks (1400-1500 UTC+0) - DST Aware', defval='US Brinks', title='Name:', inline='session7style')
color sess7col = input.color(group='Market session: US Brinks (1400-1500 UTC+0) - DST Aware', title='Color: Box', defval=color.rgb(255, 255, 255, 65), inline='session7style')
color sess7colLabel = input.color(group='Market session: US Brinks (1400-1500 UTC+0) - DST Aware', title='Label', defval=color.rgb(255, 255, 255, 25), inline='session7style')
string sess7TimeX = '1400-1500'//input.session(group='Market session: US Brinks (1400-1500 UTC+0)', defval='1400-1500', title='Time (UTC+0):', inline='session7style', tooltip='Normally you will not want to adjust these times. Defaults are taken as if the session is NOT in DST times must be in UTC+0. Note due to limitations of pinescript some values sellected here other than the default might not work correctly on all exchanges.')
sess7Time = show_markets_weekends ? sess7TimeX + weekend_sessions : sess7TimeX + no_weekend_sessions

bool show_rectangle8 = input.bool(group='Market session: Frankfurt (0700-1630 UTC+0) - DST Aware', defval=false, title='Show: session?', inline='session8conf', tooltip='If this checkbox is off, Label and Open Range have no effect') and show_markets
bool show_label8 = input.bool(group='Market session: Frankfurt (0700-1630 UTC+0) - DST Aware', defval=true, title='Label?', inline='session8conf') and show_rectangle8 and show_markets
bool show_or8 = input.bool(group='Market session: Frankfurt (0700-1630 UTC+0) - DST Aware', defval=true, title='Opening Range?', inline='session8conf', tooltip='This controls the shaded area for the session') and show_rectangle8 and show_markets
string sess8Label = input.string(group='Market session: Frankfurt (0700-1630 UTC+0) - DST Aware', defval='Frankfurt', title='Name:', inline='session8style')
color sess8col = input.color(group='Market session: Frankfurt (0700-1630 UTC+0) - DST Aware', title='Color: Box', defval=color.rgb(253, 152, 39, 75), inline='session8style')
color sess8colLabel = input.color(group='Market session: Frankfurt (0700-1630 UTC+0) - DST Aware', title='Label', defval=color.rgb(253, 152, 39, 25), inline='session8style')
string sess8TimeX = '0700-1630'//input.session(group='Market session: Frankfurt (0700-1630 UTC+0)', defval='0700-1630', title='Time (UTC+0):', inline='session8style', tooltip='Normally you will not want to adjust these times. Defaults are taken as if the session is NOT in DST times must be in UTC+0. Note due to limitations of pinescript some values sellected here other than the default might not work correctly on all exchanges.')
sess8Time = show_markets_weekends ? sess8TimeX + weekend_sessions : sess8TimeX + no_weekend_sessions


bool showPsy = timeframe.isminutes and (timeframe.multiplier == 60 or timeframe.multiplier == 30 or timeframe.multiplier == 15 or timeframe.multiplier == 5 or timeframe.multiplier == 3 or timeframe.multiplier == 1)   
bool show_psylevels = input.bool(group='Weekly Psy Levels (valid tf 1h/30min/15min/5min/3min/1min)', defval=true, title='Show: Levels?', inline='psyconf') and showPsy
bool show_psylabel = input.bool(group='Weekly Psy Levels (valid tf 1h/30min/15min/5min/3min/1min)', defval=true, title='Labels?', inline='psyconf', tooltip="The Psy High/Low will only show on these timeframes: 1h/30min/15min/5min/3min/1min. It is disabled on all others. This is because the calculation requires a candle to start at the correct time for Sydney/Tokyo but in other timeframes the data does not have values at the designated time for the Sydney/Tokyo sessions.") and show_psylevels
bool showallPsy = input.bool(group='Weekly Psy Levels (valid tf 1h/30min/15min/5min/3min/1min)', defval=false, title='Show historical psy levels?', inline='psyconf') and show_psylevels
color psycolH = input.color(group='Weekly Psy Levels (valid tf 1h/30min/15min/5min/3min/1min)', title='Psy Hi Color', defval=color.new(color.orange, 30), inline='psyconf1') 
color psycolL = input.color(group='Weekly Psy Levels (valid tf 1h/30min/15min/5min/3min/1min)', title='Psy Low Color', defval=color.new(color.orange, 30), inline='psyconf1') 
string psyType = input.string(group='Weekly Psy Levels (valid tf 1h/30min/15min/5min/3min/1min)', defval='crypto', title='Psy calc type', options=['crypto', 'forex'], inline='psyconf12', tooltip="Are you looking at Crypto or Forex? Crypto calculations start with the Sydney session on Saturday night. Forex calculations start with the Tokyo session on Monday morning. Note some exchanges like Oanda do not have sessions on the weekends so you might be forced to select Forex for exchanges like Oanda even when looking at symbols like BITCOIN on Oanda.")





//*****************
// Market sessions
//*****************
splitSessionString(sessXTime) =>
    //session stirng looks like this: 0000-0000:1234567 ie start time, end time, day of the week
    //we need to parse the sessXTime string into hours and min for start and end times so we can use those in the timestampfunction below

    //string times contains "0000-2300" as an example
    string times = array.get(str.split(sessXTime, ':'), 0)

    //string startTime contains "0000"
    string startTime = array.get(str.split(times, '-'), 0)
    //string endTime contains "2300"
    string endTime = array.get(str.split(times, '-'), 1)

    //now we need to get the start hour and start min, sing 0 index - hour is the characters in index 0 and index 1 while min is the chars at index 2 and 3
    string[] startTimeChars = str.split(startTime, '')
    string[] endTimeChars = str.split(endTime, '')

    //so now startHour contains 00 and start min contains 00
    string startHour = array.get(startTimeChars, 0) + array.get(startTimeChars, 1)
    string startMin = array.get(startTimeChars, 2) + array.get(startTimeChars, 3)

    //so now endHour contains 23 and end min contains 00
    string endHour = array.get(endTimeChars, 0) + array.get(endTimeChars, 1)
    string endMin = array.get(endTimeChars, 2) + array.get(endTimeChars, 3)
    [startHour, startMin, endHour, endMin]
    
calc_session_startend(sessXTime, gmt) =>
    [startHour, startMin, endHour, endMin] = splitSessionString(sessXTime)
    targetstartTimeX = timestamp(gmt, year, month, dayofmonth, math.round(str.tonumber(startHour)), math.round(str.tonumber(startMin)), 00)
    targetendTimeX = timestamp(gmt, year, month, dayofmonth, math.round(str.tonumber(endHour)), math.round(str.tonumber(endMin)), 00)
    time_now = timestamp(year, month, dayofmonth, hour, minute, 00) 
    midnight_exchange = timestamp(year, month, dayofmonth, 00, 00, 00)  


    //if start hour is greater than end hour we are dealing with a session that starts towards the end of one day 
    //and ends the next day. ie advance the end time by 24 hours - its the next day
    bool adjusted = false
    if gmt == 'GMT+0'
        if math.round(str.tonumber(startHour)) > math.round(str.tonumber(endHour))
            if time_now - targetstartTimeX >= 0
                targetendTimeX := targetendTimeX + 24 * 60 * 60 * 1000
                adjusted := true
                targetendTimeX
    if gmt == 'GMT+1'
        if math.round(str.tonumber(startHour)) == 0
            startHour := '24'
        if math.round(str.tonumber(endHour)) == 0
            endHour := '24'    
        if math.round(str.tonumber(startHour))-1 > math.round(str.tonumber(endHour))-1
            if time_now - targetstartTimeX >= 0
                targetendTimeX := targetendTimeX + 24 * 60 * 60 * 1000
                adjusted := true
                targetendTimeX
    
    //now is the exchange is at some utc offset and the market session crosses days even when start hour is not greater than end hour
    //we still need to adjust the end time. 
    
    if targetstartTimeX < midnight_exchange and midnight_exchange < targetendTimeX and not adjusted
        targetendTimeX := targetendTimeX + 24 * 60 * 60 * 1000
        targetendTimeX                
            
    [targetstartTimeX,targetendTimeX]
                

draw_open_range(sessXTime, sessXcol, show_orX, gmt)=>
    if show_orX
        // Initialize variables on bar zero only, so they preserve their values across bars.
        var hi = float(na)
        var lo = float(na)
        var box hiLoBox = na
        // Detect changes in timeframe.
        session = time(timeframe.period, sessXTime, gmt)
        bool newTF = session and not session[1]
        if newTF
            // New bar in higher timeframe; reset values and create new lines and box.
            [targetstartTimeX,targetendTimeX] = calc_session_startend(sessXTime, gmt)
            sessionDuration = math.round(math.abs(time  - targetendTimeX)/(timeframe.multiplier*60*1000))
   
            hi := high
            lo := low
            hiLoBox := box.new(bar_index, hi, timeframe.multiplier == 1? bar_index : bar_index+sessionDuration, lo, border_color = na, bgcolor = sessXcol)
            int(na)
        else
            if timeframe.multiplier == 1 and (na(session[1]) and not na(session) or session[1] < session)
                box.set_right(hiLoBox, bar_index+1)
            int(na)
draw_session_hilo(sessXTime, show_rectangleX, show_labelX, sessXcolLabel, sessXLabel, gmt)=>
    if show_rectangleX
        // Initialize variables on bar zero only, so they preserve their values across bars.
        var hi = float(0)
        var lo = float(10000000000.0)
       
        var line line_t = na
        var line line_b = na
        var label line_label = na
        // var box hiLoBox = na
        // Detect changes in timeframe.
        session = time(timeframe.period, sessXTime, gmt)
        sessLineStyleX = rectStyle == 'Solid' ? line.style_solid : line.style_dashed
        bool newTF = session and not session[1]
        hi := newTF ? high : session ? math.max(high, hi[1]) : hi[1]
        lo := newTF ? low : session ? math.min(low, lo[1]) : lo[1]
          
        if newTF
            beginIndex = bar_index 
            [targetstartTimeX,targetendTimeX] = calc_session_startend(sessXTime, gmt)
            sessionDuration = math.round(math.abs(time  - targetendTimeX)/(timeframe.multiplier*60*1000))
        
            line_t := line.new(beginIndex, hi, timeframe.multiplier == 1? bar_index : bar_index+sessionDuration, hi, xloc=xloc.bar_index, style=sessLineStyleX, color=sessXcolLabel)
            line_b := line.new(beginIndex, lo, timeframe.multiplier == 1? bar_index : bar_index+sessionDuration, lo, xloc=xloc.bar_index, style=sessLineStyleX, color=sessXcolLabel)
            line.delete(line_t[1])
            line.delete(line_b[1])
            if show_labelX
                line_label := label.new(beginIndex, hi, sessXLabel, xloc=xloc.bar_index, textcolor=sessXcolLabel, style=label.style_none, size=size.normal, textalign=text.align_right)
                label.delete(line_label[1])
  
            int(na)
        else
            if na(session[1]) and not na(session) or session[1] < session
                if timeframe.multiplier == 1
                    line.set_x2(line_t,bar_index+1)
                    line.set_x2(line_b,bar_index+1)
                line.set_y1(line_t,hi)
                line.set_y2(line_t,hi)
                line.set_y1(line_b,lo)
                line.set_y2(line_b,lo)
                if show_labelX and not na(line_label)
                    label.set_y(line_label, hi)
            int(na)




//*****************************//
// Daylight Savings Time Flags //
//*****************************//

int previousSunday = dayofmonth - dayofweek + 1
bool nyDST = na
bool ukDST = na
bool sydDST = na

if month < 3 or month > 11
    nyDST := false
    ukDST := false
    sydDST := true
else if month > 4 and month < 10
    nyDST := true
    ukDST := true
    sydDST := false
else if month == 3
    nyDST := previousSunday >= 8
    ukDST := previousSunday >= 24
    sydDST := true
else if month == 4
    nyDST := true
    ukDST := true
    sydDST := previousSunday <= 0
else if month == 10
    nyDST := true
    ukDST := previousSunday <= 24
    sydDST := previousSunday >= 0
else // month == 11
    nyDST := previousSunday <= 0
    ukDST := false
    sydDST := true
    


            
if ukDST
    draw_open_range(sess1Time,sess1col,show_or1,'GMT+1')
    draw_session_hilo(sess1Time, show_rectangle1, show_label1, sess1colLabel, sess1Label, 'GMT+1')
else
    draw_open_range(sess1Time,sess1col,show_or1,'GMT+0')
    draw_session_hilo(sess1Time, show_rectangle1, show_label1, sess1colLabel, sess1Label, 'GMT+0')

if nyDST
    draw_open_range(sess2Time,sess2col,show_or2,'GMT+1')
    draw_session_hilo(sess2Time, show_rectangle2, show_label2, sess2colLabel, sess2Label, 'GMT+1')
else
    draw_open_range(sess2Time,sess2col,show_or2,'GMT+0')
    draw_session_hilo(sess2Time, show_rectangle2, show_label2, sess2colLabel, sess2Label, 'GMT+0')

// Tokyo
draw_open_range(sess3Time,sess3col,show_or3,'GMT+0')
draw_session_hilo(sess3Time, show_rectangle3, show_label3, sess3colLabel, sess3Label, 'GMT+0')

// Hong Kong
draw_open_range(sess4Time,sess4col,show_or4,'GMT+0')
draw_session_hilo(sess4Time, show_rectangle4, show_label4, sess4colLabel, sess4Label, 'GMT+0')

if sydDST
    draw_open_range(sess5Time,sess5col,show_or5,'GMT+1')
    draw_session_hilo(sess5Time, show_rectangle5, show_label5, sess5colLabel, sess5Label, 'GMT+1')
else
    draw_open_range(sess5Time,sess5col,show_or5,'GMT+0')
    draw_session_hilo(sess5Time, show_rectangle5, show_label5, sess5colLabel, sess5Label, 'GMT+0')

//eu brinks is for london
if ukDST
    draw_open_range(sess6Time,sess6col,show_or6,'GMT+1')
    draw_session_hilo(sess6Time, show_rectangle6, show_label6, sess6colLabel, sess6Label, 'GMT+1')
else
    draw_open_range(sess6Time,sess6col,show_or6,'GMT+0')
    draw_session_hilo(sess6Time, show_rectangle6, show_label6, sess6colLabel, sess6Label, 'GMT+0')

//us brinks is ny
if nyDST
    draw_open_range(sess7Time,sess7col,show_or7,'GMT+1')
    draw_session_hilo(sess7Time, show_rectangle7, show_label7, sess7colLabel, sess7Label, 'GMT+1')
else
    draw_open_range(sess7Time,sess7col,show_or7,'GMT+0')
    draw_session_hilo(sess7Time, show_rectangle7, show_label7, sess7colLabel, sess7Label, 'GMT+0')

//becuase frankfurt changes with london
if ukDST
    draw_open_range(sess8Time,sess8col,show_or8,'GMT+1')
    draw_session_hilo(sess8Time, show_rectangle8, show_label8, sess8colLabel, sess8Label, 'GMT+1')
else
    draw_open_range(sess8Time,sess8col,show_or8,'GMT+0')
    draw_session_hilo(sess8Time, show_rectangle8, show_label8, sess8colLabel, sess8Label, 'GMT+0')

// Daily open
//***********
getdayOpen()=>
    in_sessionDly = time('D', '24x7')
    bool isDly = ta.change(time('D'))//ta.change(in_sessionDly)//in_sessionDly and not in_sessionDly[1]
    var dlyOpen = float(na)
    if isDly
        dlyOpen := open
    dlyOpen
daily_open = getdayOpen()
//this plot is only to show historical values when the option is selected.
plot(show_rectangle9 and validTimeFrame and showallDly ? daily_open : na, color=sess9col, style=plot.style_stepline, linewidth=2, editable=false, title="Daily Open")
if showallDly
    //if historical values are selected to be shown - then add a label to the plot
    r_label(daily_open, 'Daily Open', label.style_none, sess9col, validTimeFrame and show_label9)
    showallDly
else
    if show_rectangle9
        //othewise we draw the line and label together - showing only todays line.
        draw_line_DO(daily_open, 'D', 'Daily Open', sess9col, line.style_solid, 1, extend.none, validTimeFrame and show_label9, label_x_offset)
    
//London DST Starts Last Sunday of March DST Edns Last Sunday of October
//New York DST Starts 2nd Sunday of March DST Edns 1st Sunday of November
//Sydney DST Start on 1st Sunday of October DST ends 1st Sunday of Arpil
//Frankfurt DST Starts Last Sunday of March DST Edns Last Sunday of October

