Take Session High/Low Alert [MsF]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Trader_Morry

//@version=5
indicator(title='Take Session High/Low Alert [MsF]', shorttitle='TS High/Low', overlay=true, max_bars_back = 5000)

////////
// Input values 
// [
var GRP1 = "--- Vertical Lines setting ---"
sessionTime_60_00 = input.session("0000-0800", title="Session time", group = GRP1)
sessionTime_40_60 = input.session("0800-1300", title="Session time", group = GRP1)
sessionTime_20_40 = input.session("1300-1900", title="Session time", group = GRP1)
sessionTime_00_20 = input.session("1900-2400", title="Session time", group = GRP1)
sessionZone       = input.string("GMT-5", title="Session time zone", group = GRP1)
lineColor_00 = input.color(defval=color.rgb( 255, 235,  59, 50), title='Basis color', inline='00', group = GRP1)
lineStyle_00 = input.string(title='Style', defval=line.style_solid, options=[line.style_dotted, line.style_dashed, line.style_solid], inline = "00", group = GRP1)
lineColor_XX = input.color(defval=color.rgb( 255, 255, 255, 70), title='Other color', inline='XX', group = GRP1)
lineStyle_XX = input.string(title='Style', defval=line.style_solid, options=[line.style_dotted, line.style_dashed, line.style_solid], inline = "XX", group = GRP1)
enableTimeLines = input.bool(defval=true, title="Enable Time Lines", group = GRP1)
var GRP2 = "--- Horizontal Lines setting ---"
lineColor_HL = input.color(defval=color.blue, title='High / Low color', inline='HL', group = GRP2)
lineStyle_HL = input.string(title='Style', defval=line.style_solid, options=[line.style_dotted, line.style_dashed, line.style_solid], inline = "HL", group = GRP2)
lineColor_CR = input.color(defval=color.red,  title='Taken Line color', inline='CR', group = GRP2)
lineStyle_CR = input.string(title='Style', defval=line.style_dotted, options=[line.style_dotted, line.style_dashed, line.style_solid], inline = "CR", group = GRP2)
iExtend      = input.bool(true, title="Extend Lines", group = GRP2)
iEBLineCnt   = input.int(0, title="Extend Broken Line Count", group = GRP2)
// ]

// *** Draw Vertical Lines ***
////////
// Preparing 
// [
// Get day open
[dailyTime, dailyOpen] = request.security(syminfo.tickerid, 'D', [time, open], lookahead=barmerge.lookahead_on)
// Get timestamp
sessionTime_00_VL_hh = str.tonumber(str.substring(sessionTime_00_20,0,2))
sessionTime_20_VL_hh = str.tonumber(str.substring(sessionTime_20_40,0,2))
sessionTime_40_VL_hh = str.tonumber(str.substring(sessionTime_40_60,0,2))
sessionTime_60_VL_hh = str.tonumber(str.substring(sessionTime_60_00,0,2))
sessionTime_00_VL_m2 = str.tonumber(str.substring(sessionTime_00_20,2,4))
sessionTime_20_VL_m2 = str.tonumber(str.substring(sessionTime_20_40,2,4))
sessionTime_40_VL_m2 = str.tonumber(str.substring(sessionTime_40_60,2,4))
sessionTime_60_VL_m2 = str.tonumber(str.substring(sessionTime_60_00,2,4))
iBaseTime_00 = timestamp(sessionZone, year, month, dayofmonth, int(sessionTime_60_VL_hh), int(sessionTime_60_VL_m2), 0) // NY time 00:00
iBaseTime_20 = timestamp(sessionZone, year, month, dayofmonth, int(sessionTime_40_VL_hh), int(sessionTime_40_VL_m2), 0) // NY time 08:00
iBaseTime_40 = timestamp(sessionZone, year, month, dayofmonth, int(sessionTime_20_VL_hh), int(sessionTime_20_VL_m2), 0) // NY time 13:00
iBaseTime_60 = timestamp(sessionZone, year, month, dayofmonth, int(sessionTime_00_VL_hh), int(sessionTime_00_VL_m2), 0) // NY time 19:00

// Initializing Flag
var iDrawTimeD_00 = 0
var iDrawTimeD_20 = 0
var iDrawTimeD_40 = 0
var iDrawTimeD_60 = 0
// ]

////////
// Function 
// [
drawing_VerticalLines(aBaseTime, aDrawTimeD, aLineStyle, aLineColor) =>
    _iDrawTimeD = aDrawTimeD

    yy = year
    mm = month
    dd = dayofmonth
    hh = hour(aBaseTime)
    m2 = minute(aBaseTime)

    iDrawTime = timestamp(yy, mm, dd, hh, m2)

    // 土曜～月曜までは休場なので線がおかしくなる。その対応
    hour_j = hour(iDrawTime, "GMT+9")
    dayofweek_j = dayofweek(iDrawTime, "GMT+9")

    iDsp = true
    if dayofweek_j == dayofweek.saturday and hour_j >= 6
        iDsp := false
    else if dayofweek_j == dayofweek.sunday
        iDsp := false
    else if dayofweek_j == dayofweek.monday and hour_j < 7
        iDsp := false

    // cryptoは24時間動いているので休場対応からは除外
    if syminfo.type == "crypto"
        iDsp := true

    // double drawing prevention
    if iDrawTime != aDrawTimeD and iDsp
        line.new(iDrawTime, dailyOpen, iDrawTime, dailyOpen + syminfo.mintick, xloc=xloc.bar_time, style=aLineStyle, extend=extend.both, color=aLineColor, width=1)
        _iDrawTimeD := iDrawTime

    _iDrawTimeD
// ]

////////
// Drawing Vertical Lines 
// [
// H1を超える時間足は出力しない
if timeframe.in_seconds(timeframe.period) <= 3600 and enableTimeLines
    iDrawTimeD_00 := drawing_VerticalLines(iBaseTime_00, iDrawTimeD_00, lineStyle_00, lineColor_00)
    iDrawTimeD_20 := drawing_VerticalLines(iBaseTime_20, iDrawTimeD_20, lineStyle_XX, lineColor_XX)
    iDrawTimeD_40 := drawing_VerticalLines(iBaseTime_40, iDrawTimeD_40, lineStyle_XX, lineColor_XX)
    iDrawTimeD_60 := drawing_VerticalLines(iBaseTime_60, iDrawTimeD_60, lineStyle_XX, lineColor_XX)
// ]



// *** Draw Horizonal Lines ***
////////
// Preparing 
// [
var max_array_size = 16
var sessionLineHArray = array.new_line()
var sessionLineLArray = array.new_line()
var sessionLineHArray_c = array.new_bool() // クロスしたかどうかのフラグは別に持つ
var sessionLineLArray_c = array.new_bool() // クロスしたかどうかのフラグは別に持つ
// ]

////////
// Function 
// [
InSession(sessionTime, sessionTimeZone=syminfo.timezone) =>
    not na(time(timeframe.period, sessionTime, sessionTimeZone))

add_to_Line(pointer, pointer_c, aLine) =>
    array.unshift(pointer, aLine)
    array.unshift(pointer_c, false)
    if array.size(pointer) > max_array_size
        array.pop(pointer)
        array.pop(pointer_c)
       
drawing_HorizonalLines(aSessionTime, aSessionZone) =>
    // Create variables
    var sessionHighPrice = 0.0
    var sessionLowPrice  = 0.0
    var sessionOpenPrice = 0.0
    var line sessionLineH = na
    var line sessionLineL = na

    // See if the session is currently active and just started
    inSession    = InSession(aSessionTime, aSessionZone) and timeframe.isintraday
    sessionStart = inSession and not inSession[1]

    // When a new session starts, set the session high and low to the data
    // of the bar in the session.
    if sessionStart
        sessionHighPrice := high
        sessionLowPrice  := low
        sessionOpenPrice := open
    // Else, during the session, track the highest high and lowest low
    else if inSession
        sessionHighPrice := math.max(sessionHighPrice, high)
        sessionLowPrice  := math.min(sessionLowPrice, low)

    // When a session begins, make a new box for that session
    if sessionStart
        sessionLineH := line.new(bar_index,na,na,na,color = color.rgb(0,0,255,100))
        sessionLineL := line.new(bar_index,na,na,na,color = color.rgb(0,0,255,100))
        add_to_Line(sessionLineHArray, sessionLineHArray_c, sessionLineH)
        add_to_Line(sessionLineLArray, sessionLineLArray_c, sessionLineL)

    // During the session, update that session's existing box
    if inSession
        line.set_y1(sessionLineH, sessionHighPrice)
        line.set_y2(sessionLineH, sessionHighPrice)
        line.set_y1(sessionLineL, sessionLowPrice)
        line.set_y2(sessionLineL, sessionLowPrice)

        line.set_x2(sessionLineH, bar_index + 1)
        line.set_x2(sessionLineL, bar_index + 1)

        if iExtend
            line.set_extend(sessionLineH, extend.right)
            line.set_extend(sessionLineL, extend.right)
// ]

////////
// Drawing Vertical Lines 
// [
// H1を超える時間足は出力しない
if timeframe.in_seconds(timeframe.period) <= 3600
    drawing_HorizonalLines(sessionTime_00_20, sessionZone)
    drawing_HorizonalLines(sessionTime_20_40, sessionZone)
    drawing_HorizonalLines(sessionTime_40_60, sessionZone)
    drawing_HorizonalLines(sessionTime_60_00, sessionZone)
// ]

// ]
// Cross the Vertical Lines  Notification
// *attention! This procesure must write before Checking Cross the Vertical Lines 
// [
check_Alert_Condition_H() =>
    crossVHLines = false
    if array.size(sessionLineHArray) > 1
        for i = 1 to array.size(sessionLineHArray)-1
            if line.get_y2(array.get(sessionLineHArray, i)) <= high
                if not array.get(sessionLineHArray_c, i)
                    crossVHLines := true
    crossVHLines
   
check_Alert_Condition_L() =>
    crossVLLines = false
    if array.size(sessionLineLArray) > 1
        for i = 1 to array.size(sessionLineLArray)-1
            if line.get_y2(array.get(sessionLineLArray, i)) >= low
                if not array.get(sessionLineLArray_c, i)
                    crossVLLines := true
    crossVLLines

alertcondition(check_Alert_Condition_H() , title='Taken High Key Lv.', message='Taken High Key Level Line Alert!')
alertcondition(check_Alert_Condition_L() , title='Taken Low Key Lv.', message='Taken Low Key Level Line Alert!')
// ]

////////
// Checking Cross the Vertical Lines 
// [
if array.size(sessionLineHArray) > 1
    for i = 1 to array.size(sessionLineHArray)-1
        if line.get_y2(array.get(sessionLineHArray, i)) <= high
            line.set_color(array.get(sessionLineHArray, i), lineColor_CR)
            line.set_style(array.get(sessionLineHArray, i), lineStyle_CR)
            if iEBLineCnt <= i
                line.set_extend(array.get(sessionLineHArray, i), extend.none)
            array.set(sessionLineHArray_c, i, true) // クロスした
        else
            if not array.get(sessionLineHArray_c, i)
                line.set_color(array.get(sessionLineHArray, i), lineColor_HL)
    
if array.size(sessionLineLArray) > 1
    for i = 1 to array.size(sessionLineLArray)-1
        if line.get_y2(array.get(sessionLineLArray, i)) >= low
            line.set_color(array.get(sessionLineLArray, i), lineColor_CR)
            line.set_style(array.get(sessionLineLArray, i), lineStyle_CR)
            if iEBLineCnt <= i
                line.set_extend(array.get(sessionLineLArray, i), extend.none)
            array.set(sessionLineLArray_c, i, true) // クロスした
        else
            if not array.get(sessionLineLArray_c, i)
                line.set_color(array.get(sessionLineLArray, i), lineColor_HL)
                line.set_style(array.get(sessionLineLArray, i), lineStyle_HL)
// ]
