GMT Offset, without using security fn - showcase
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// This script is a demo of how one can avoid the use of the request.security function and get values for a number of previous day's open/high/low/close
// where the user can define a custom "tart of the day" using the GMT input. This allows the user to be independent of the exchange timezone 
// that the security function uses internally.

// Implications of this include:
// Suppose you want to treat the start of your day as the NZX market open which is at 2000 UTC+0 and base you indicator calculations
// on the NZK market midnight as opposed to the chart exchange timezone. 
// The indicator purpose is to showcase how that can be achieved in code. 

// If security function in the future is modified to accept a timezone parameter - obviously this code will no longer be needed as such.

// We do two things here:
// We plot the values for open high low close using the calc_ohlc_daysback as circles
// Then we use the f_security function to get the same values but using security and plot them using solid lines
// We do this both on the daily and weekly values.
// What we expect to see is the lines matching thus proving that the calc_ohlc_daysback works correctly as compared to security function.

// Note - the chart gmt default value is set to 0 which means the comparison will work correctly out of the box on exchanges that have weekend data.
// The script is designed to work on intraday timeframes highest being 4 hour and lowest being 3 min
// (programmatically the script is no bounded as sich to the intraday timeframe however if not enough data is present at a particular timeframe
// values needed to display the lines will be null and hence the lines will not print.)
// You can get the same results on other exchanges but might need to change the value of chart gmt
// Script does not work on exchanges that have gaps on the weekend at this time

// Now all of this can obviously be done with the security function - why go through the trouble? Well with security function you are bound to
// the timezone of the exchange you are on. Doing it this way you are no longer bound by the exchange timezone and you can effectively change
// the time at which the day starts independent of any exchange. Go ahead - change the GMT offset in settings


// Future enhancements:
// a) Deal with exchanges where "bar merge" is required - if possible (detect that an exchange does not have weekend data basically) 
// b) Deal with lower timeframes if possible (on the minute timeframe there is usually not enough data in the series to calc values several weeks back)
// c) Make a library for this functionality - this will be optimal so one does not need to copy paste code. 
// d) Expand library to add GMT auto adjust (specifically around DST in different countries). Today this is a challenge as no relizble way exists to 
// extract the UTC offset from an syminfo.timezone given that syminfo.timezone returns text such as "America/New York"
// For example - one might have 3 session thst they want to work with. Tokio, London and New York. Tokio does not follow DST so the market session starts at the same time all year round. London observes DST but at a different time from New York. So in order to have all this in the same chart and have it auto adjust is a bit of a challenge. With the DST offset functions - this is possible to do. (
// Well, that is unless the awesome TV devs push out v6 where that is build in the security function (for it to accept a timezone offset other) in which case the code here will become useless.


// Foot notes:
// This script is inspired by Traders Reality indicator by @infernixx (developed by @plasmapug with additional modifications by @infernixx and @Peshocore)
// Special thanks to @JayRogers for INSECURITY() which inspired the development of calc_ohlc_daysback

//@version=5
indicator('GMT Offset, without using security fn - showcase', overlay=true)


// Config
int chartGmt = input.int(group='gmt offset ', title='GTM Offset hours', defval=0, minval=-12, maxval=14, step=1, tooltip='This allows you to move the start of session independent of the exchange timezone to some desired time like for example the start of Sydney as oposed to exchange midnight. Negative values move line to the right, positive values move line to the left.')
showTable = input.bool(group='Show Table', title='Show Table', defval=true, inline='showT')
choiceTable = input.string(group='Show Table', title='Table postion', inline='showT', defval='bottom_right', options=['top_right', 'top_left', 'bottom_right', 'bottom_left'])
tableBgColor = input.color(group='Show Table', title='Table Background Color', inline='showT', defval=color.rgb(93, 96, 107, 70))
tableTxtColor = input.color(group='Show Table', title='Text Color', inline='showT', defval=color.rgb(31, 188, 211, 0))

showDOpenSec = input.bool(group="Using security fn", title="Show Yesterday's Daily Open using security fn", defval=true, inline='showDS')
showDHighSec = input.bool(group="Using security fn", title="Show Yesterday's Daily High using security fn", defval=true, inline='showDS')
showDLowSec = input.bool(group="Using security fn", title="Show Yesterday's Daily Low using security fn", defval=true, inline='showDS')
showDCloseSec = input.bool(group="Using security fn", title="Show Yesterday's Daily Close using security fn", defval=true, inline='showDS')

showWOpenSec = input.bool(group="Using security fn", title="Show Last Week Open using security fn", defval=true, inline='showDS')
showWHighSec = input.bool(group="Using security fn", title="Show Last Week High using security fn", defval=true, inline='showDS')
showWLowSec = input.bool(group="Using security fn", title="Show Last Week Low using security fn", defval=true, inline='showDS')
showWCloseSec = input.bool(group="Using security fn", title="Show Lost Week Close using security fn", defval=true, inline='showDS')

showDOpen = input.bool(group="Without Using security fn", title="Show Yesterday's Daily Open without security fn", defval=true, inline='showD')
showDHigh = input.bool(group="Without Using security fn", title="Show Yesterday's Daily High without security fn", defval=true, inline='showD')
showDLow = input.bool(group="Without Using security fn", title="Show Yesterday's Daily Low without security fn", defval=true, inline='showD')
showDClose = input.bool(group="Without Using security fn", title="Show Yesterday's Daily Close without security fn", defval=true, inline='showD')

showWOpen = input.bool(group="Without Using security fn", title="Show Last Week Open without security fn", defval=true, inline='showD')
showWHigh = input.bool(group="Without Using security fn", title="Show Last Week High without security fn", defval=true, inline='showD')
showWLow = input.bool(group="Without Using security fn", title="Show Last Week Low without security fn", defval=true, inline='showD')
showWClose = input.bool(group="Without Using security fn", title="Show Lost Week Close without security fn", defval=true, inline='showD')

// Only render intraday
validTimeFrame = timeframe.isintraday == true and timeframe.isminutes == true
validDHLTimeFrame = timeframe.isintraday == true and timeframe.isminutes == true
validWHLTimeFrame = (timeframe.isintraday == true and timeframe.isminutes == true) or timeframe.isdaily == true


calc_gmt_offset(gmtOffsetVar) =>
    gmtVar = 'GMT+0'
    if gmtOffsetVar > -1
        gmtVar := 'GMT+' + str.tostring(math.abs(gmtOffsetVar))
        gmtVar
    else
        gmtVar := 'GMT-' + str.tostring(math.abs(gmtOffsetVar))
        gmtVar
    gmtVar

is_newbar(resX, sessionStringX, gmtX) =>
    t = time(resX, sessionStringX, gmtX)
    ta.change(t) != 0 ? 1 : 0


calc_bars_back(int hours=24) =>
    //TODO need to keep under 5000 bars - so this means it will not work on lower timeframes for weekly
    barsback = 0
    
    if timeframe.isminutes
        //convert hours to minutes (as we are only looking for intraday sessions from 1min to 240min then devide by the period
        //example how many bars back in 24 hours at the 3 min res => 24*60/3 = 480 
        barsback := 60*hours/timeframe.multiplier
        
        
    barsback


//When days back = 0 you get yesterday's values. When days back = 1 you get values from 2 days ago, etc. as long as there is enough data on the chart
//Expected res "D" or "W". Expected session 24x7
calc_ohlc_daysback(res, session, gmt, daysback, hoursInResolution) =>
    // Detect New Day
    new_day = is_newbar(res,session,gmt)
    //so basically - at the start of a new day, the the highest/lowest of the previous x number of bars and the offset by some number of days.
    //where x number of bars depends on the chart period and resolution requested where allowed values for resolution are "D" or "W"
    //the [1] is these because we need to leave out the last bar in a 24 hour session becuase that bar will belong to the next new day.
    last_high = ta.valuewhen(new_day,ta.highest(high, calc_bars_back(hoursInResolution))[1],daysback)
    last_low = ta.valuewhen(new_day,ta.lowest(low, calc_bars_back(hoursInResolution))[1],daysback)
    last_open = ta.valuewhen(new_day, open, daysback+1)
    last_close = ta.valuewhen(new_day, open, daysback)
    
    [last_high, last_low, last_open, last_close]

[last_high, last_low, last_open, last_close] = calc_ohlc_daysback("D","24x7",calc_gmt_offset(chartGmt),0, 24)
[last_highW, last_lowW, last_openW, last_closeW] = calc_ohlc_daysback("W","24x7",calc_gmt_offset(chartGmt),0, 7*24)
//Two ways to get x days ago (replace x with 1,2,3,4,5 etc where 1 will get you 2 days back):
//1) calc_ohlc_daysback("D","24x7",calc_gmt_offset(chartGmt),x)
//2) last_high[calc_bars_back("D")*x]
//if you are in a for loop you will need to use the latter



plot(validDHLTimeFrame and showDHigh ? last_high : na, linewidth=2, color=color.white, style=plot.style_circles, title="Last Day High")
if validDHLTimeFrame and showDHigh 
    line_label = label.new(timenow+(timeframe.multiplier*25*60*1000), last_high, "Last Day High", xloc=xloc.bar_time, textcolor=color.white, style=label.style_none, size=size.normal)
    label.delete(line_label[1])

plot(validDHLTimeFrame and showDLow ? last_low : na, linewidth=2, color=color.white, style=plot.style_circles, title="Last Day Low")
if validDHLTimeFrame and showDLow
    line_label = label.new(timenow+(timeframe.multiplier*25*60*1000), last_low, "Last Day Low", xloc=xloc.bar_time, textcolor=color.white, style=label.style_none, size=size.normal)
    label.delete(line_label[1])

plot(validDHLTimeFrame and showDOpen ? last_open : na, linewidth=2, color=color.white, style=plot.style_circles, title="Last Day Open")
if validDHLTimeFrame and showDOpen
    line_label = label.new(timenow+(timeframe.multiplier*25*60*1000), last_open, "Last Day Open", xloc=xloc.bar_time, textcolor=color.white, style=label.style_none, size=size.normal)
    label.delete(line_label[1])

plot(validDHLTimeFrame and showDClose ? last_close : na, linewidth=2, color=color.white, style=plot.style_circles, title="Last Day Close")
if validDHLTimeFrame and showDClose
    line_label = label.new(timenow+(timeframe.multiplier*25*60*1000), last_close, "Last Day Close", xloc=xloc.bar_time, textcolor=color.white, style=label.style_none, size=size.normal)
    label.delete(line_label[1])
    

plot(validWHLTimeFrame and showWHigh ? last_highW : na, linewidth=2, color=color.red, style=plot.style_circles, title="Last Weekly High")
if validWHLTimeFrame and showWHigh
    line_label = label.new(timenow+(timeframe.multiplier*25*60*1000), last_highW, "Last Week High", xloc=xloc.bar_time, textcolor=color.red, style=label.style_none, size=size.normal)
    label.delete(line_label[1])
 
plot(validWHLTimeFrame and showWLow ? last_lowW : na, linewidth=2, color=color.red, style=plot.style_circles, title="Last Weekly Low")
if validWHLTimeFrame and showWLow
    line_label = label.new(timenow+(timeframe.multiplier*25*60*1000), last_lowW, "Last Week low", xloc=xloc.bar_time, textcolor=color.red, style=label.style_none, size=size.normal)
    label.delete(line_label[1])
 
plot(validWHLTimeFrame and showWOpen ? last_openW : na, linewidth=2, color=color.red, style=plot.style_circles, title="Last Weekly Open")
if validWHLTimeFrame and showWOpen
    line_label = label.new(timenow+(timeframe.multiplier*25*60*1000), last_openW, "Last Week Open", xloc=xloc.bar_time, textcolor=color.red, style=label.style_none, size=size.normal)
    label.delete(line_label[1])


plot(validWHLTimeFrame and showWClose ? last_closeW: na, linewidth=2, color=color.red, style=plot.style_circles, title="Last Weekly Close")
if validWHLTimeFrame and showWClose
    line_label = label.new(timenow+(timeframe.multiplier*25*60*1000), last_closeW, "Last Week Close", xloc=xloc.bar_time, textcolor=color.red, style=label.style_none, size=size.normal)
    label.delete(line_label[1])
 


// Get Daily price data
dayHigh = request.security(syminfo.tickerid, "D", high[false ? 0 : barstate.isrealtime ? 1 : 0])[false ? 0 : barstate.isrealtime ? 0 : 1]
dayLow = request.security(syminfo.tickerid, "D", low[false ? 0 : barstate.isrealtime ? 1 : 0])[false ? 0 : barstate.isrealtime ? 0 : 1]
dayOpen = request.security(syminfo.tickerid, "D", open[false ? 0 : barstate.isrealtime ? 1 : 0])[false ? 0 : barstate.isrealtime ? 0 : 1]
dayClose = request.security(syminfo.tickerid, "D", close[false ? 0 : barstate.isrealtime ? 1 : 0])[false ? 0 : barstate.isrealtime ? 0 : 1]


plot(validDHLTimeFrame and showDHighSec ? dayHigh : na, linewidth=1, color=color.blue, style=plot.style_linebr, title="Last Day High (security)")
if validDHLTimeFrame and showDHighSec 
    line_label = label.new(timenow+(timeframe.multiplier*90*60*1000), dayHigh, "Last Day High (sec)", xloc=xloc.bar_time, textcolor=color.blue, style=label.style_none, size=size.normal)
    label.delete(line_label[1])

plot(validDHLTimeFrame and showDLowSec ? dayLow : na, linewidth=1, color=color.blue, style=plot.style_linebr, title="Last Day Low (security)")
if validDHLTimeFrame and showDLowSec 
    line_label = label.new(timenow+(timeframe.multiplier*90*60*1000), dayLow, "Last Day Low (sec)", xloc=xloc.bar_time, textcolor=color.blue, style=label.style_none, size=size.normal)
    label.delete(line_label[1])

plot(validDHLTimeFrame and showDOpenSec ? dayOpen : na, linewidth=1, color=color.blue, style=plot.style_linebr, title="Last Day Open (security)")
if validDHLTimeFrame and showDOpenSec 
    line_label = label.new(timenow+(timeframe.multiplier*90*60*1000), dayOpen, "Last Day Open (sec)", xloc=xloc.bar_time, textcolor=color.blue, style=label.style_none, size=size.normal)
    label.delete(line_label[1])

plot(validDHLTimeFrame and showDCloseSec? dayClose : na, linewidth=1, color=color.blue, style=plot.style_linebr, title="Last Day Close (security)")
if validDHLTimeFrame and showDCloseSec 
    line_label = label.new(timenow+(timeframe.multiplier*90*60*1000), dayClose, "Last Day Close (sec)", xloc=xloc.bar_time, textcolor=color.blue, style=label.style_none, size=size.normal)
    label.delete(line_label[1])


// Weekly H/L
weekHigh = request.security(syminfo.tickerid, "W", high[false ? 0 : barstate.isrealtime ? 1 : 0])[false ? 0 : barstate.isrealtime ? 0 : 1]
weekLow = request.security(syminfo.tickerid, "W", low[false ? 0 : barstate.isrealtime ? 1 : 0])[false ? 0 : barstate.isrealtime ? 0 : 1]
weekOpen = request.security(syminfo.tickerid, "W", open[false ? 0 : barstate.isrealtime ? 1 : 0])[false ? 0 : barstate.isrealtime ? 0 : 1]
weekClose = request.security(syminfo.tickerid, "W", close[false ? 0 : barstate.isrealtime ? 1 : 0])[false ? 0 : barstate.isrealtime ? 0 : 1]

plot(validWHLTimeFrame and showWHighSec ? weekHigh : na, linewidth=1, color=color.green, style=plot.style_linebr, title="Last Weekly High (security)")
if validWHLTimeFrame and showWHighSec 
    line_label = label.new(timenow+(timeframe.multiplier*90*60*1000), weekHigh, "Last Week High (sec)", xloc=xloc.bar_time, textcolor=color.green, style=label.style_none, size=size.normal)
    label.delete(line_label[1])

plot(validWHLTimeFrame and showWLowSec  ? weekLow : na, linewidth=1, color=color.green, style=plot.style_linebr, title="Last Weekly Low (security)")
if validWHLTimeFrame and showWLowSec 
    line_label = label.new(timenow+(timeframe.multiplier*90*60*1000), weekLow, "Last Week Low (sec)", xloc=xloc.bar_time, textcolor=color.green, style=label.style_none, size=size.normal)
    label.delete(line_label[1])

plot(validWHLTimeFrame and showWOpenSec  ? weekOpen : na, linewidth=1, color=color.green, style=plot.style_linebr, title="Last Weekly Open (security)")
if validWHLTimeFrame and showWOpenSec 
    line_label = label.new(timenow+(timeframe.multiplier*90*60*1000), weekOpen, "Last Week Open (sec)", xloc=xloc.bar_time, textcolor=color.green, style=label.style_none, size=size.normal)
    label.delete(line_label[1])

plot(validWHLTimeFrame and showWCloseSec  ? weekClose: na, linewidth=1, color=color.green, style=plot.style_linebr, title="Last Weekly Close (security)")
if validWHLTimeFrame and showWCloseSec 
    line_label = label.new(timenow+(timeframe.multiplier*90*60*1000), weekClose, "Last Week Close (sec)", xloc=xloc.bar_time, textcolor=color.green, style=label.style_none, size=size.normal)
    label.delete(line_label[1])



if showTable
    var table panelx = table.new(choiceTable, 4, 8, bgcolor=tableBgColor)

    table.cell(panelx, 0, 0, str.tostring("Prior Day Open (security)"), text_color=tableTxtColor)
    table.cell(panelx, 1, 0, str.tostring("Prior Day High (security)"), text_color=tableTxtColor)
    table.cell(panelx, 2, 0, str.tostring("Prior Day Low (security)"), text_color=tableTxtColor)
    table.cell(panelx, 3, 0, str.tostring("Prior Day Close (security)"), text_color=tableTxtColor)

    
    table.cell(panelx, 0, 1, str.tostring(dayOpen), text_color=tableTxtColor)
    table.cell(panelx, 1, 1, str.tostring(dayHigh), text_color=tableTxtColor)
    table.cell(panelx, 2, 1, str.tostring(dayLow), text_color=tableTxtColor)
    table.cell(panelx, 3, 1, str.tostring(dayClose), text_color=tableTxtColor)
 
    table.cell(panelx, 0, 2, str.tostring("Prior Day Open (no security)"), text_color=tableTxtColor)
    table.cell(panelx, 1, 2, str.tostring("Prior Day High (no security)"), text_color=tableTxtColor)
    table.cell(panelx, 2, 2, str.tostring("Prior Day Low (no security)"), text_color=tableTxtColor)
    table.cell(panelx, 3, 2, str.tostring("Prior Day Close (no security)"), text_color=tableTxtColor)
    
    table.cell(panelx, 0, 3, str.tostring(last_open), text_color=tableTxtColor)
    table.cell(panelx, 1, 3, str.tostring(last_high), text_color=tableTxtColor)
    table.cell(panelx, 2, 3, str.tostring(last_low), text_color=tableTxtColor)
    table.cell(panelx, 3, 3, str.tostring(last_close), text_color=tableTxtColor)
    
    table.cell(panelx, 0, 4, str.tostring("Prior Week Open (security)"), text_color=tableTxtColor)
    table.cell(panelx, 1, 4, str.tostring("Prior Week High (security)"), text_color=tableTxtColor)
    table.cell(panelx, 2, 4, str.tostring("Prior Week Low (security)"), text_color=tableTxtColor)
    table.cell(panelx, 3, 4, str.tostring("Prior Week Close (security)"), text_color=tableTxtColor)
    
    table.cell(panelx, 0, 5, str.tostring(weekOpen), text_color=tableTxtColor)
    table.cell(panelx, 1, 5, str.tostring(weekHigh), text_color=tableTxtColor)
    table.cell(panelx, 2, 5, str.tostring(weekLow), text_color=tableTxtColor)
    table.cell(panelx, 3, 5, str.tostring(weekClose), text_color=tableTxtColor)
    
    table.cell(panelx, 0, 6, str.tostring("Prior Week Open (no security)"), text_color=tableTxtColor)
    table.cell(panelx, 1, 6, str.tostring("Prior Week High (no security)"), text_color=tableTxtColor)
    table.cell(panelx, 2, 6, str.tostring("Prior Week Low (no security)"), text_color=tableTxtColor)
    table.cell(panelx, 3, 6, str.tostring("Prior Week Close (no security)"), text_color=tableTxtColor)
    
    table.cell(panelx, 0, 7, str.tostring(last_openW), text_color=tableTxtColor)
    table.cell(panelx, 1, 7, str.tostring(last_highW), text_color=tableTxtColor)
    table.cell(panelx, 2, 7, str.tostring(last_lowW), text_color=tableTxtColor)
    table.cell(panelx, 3, 7, str.tostring(last_closeW), text_color=tableTxtColor)


