Range-Analysis
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © mgruner
// this script calculates the average range over the last x (default 10) days for different session types (currently 1st hour and regular trading session, but can be configured otherwise) for the current instrument

//@version=5
indicator("Range-Analysis", overlay=true)
InpFirstSessionShow = input.bool(defval=false, title="Show Session", inline="First")
InpFirstSession = input.session("0830-0930",title="First-Session times", inline="First")
InpFirstColor = input(title="First-session line", defval=color.green, inline="FirstLine")
InpFirstWidth = input.int(5,"Line width", inline="FirstLine")
InpFirstName = input("First Hour", title="First-Session Name", inline="FirstText")
InpFirstShowMax = input.bool(defval=true, title="Show Max-Values",inline="FirstText")

InpSecondSessionShow = input.bool(defval=false, title="Show Session", inline="Second")
InpSecondSession = input.session("0830-1500",title="Second-Session times", inline="Second")
InpSecondColor = input(title="Second-session line", defval=color.green, inline="SecondLine")
InpSecondWidth = input.int(5,"Line width", inline="SecondLine")
InpSecondName = input("Regular session",title="Second-Session Name", inline="SecondText")
InpSecondShowMax = input.bool(defval=false, title="Show Max-Values",inline="SecondText")

InpThirdSessionShow = input.bool(defval=false, title="Show Session", inline="Third")
InpThirdSession = input.session("1700-0830",title="Third-Session times", inline="Third")
InpThirdColor = input(title="Third-session line", defval=color.green, inline="ThirdLine")
InpThirdWidth = input.int(5,"Line width", inline="ThirdLine")
InpThirdName = input("Overnight session",title="Third-Session Name", inline="ThirdText")
InpThirdShowMax = input.bool(defval=false, title="Show Max-Values",inline="ThirdText")

InpFourthSessionShow = input.bool(defval=false, title="Show Session", inline="Fourth")
InpFourthSession = input.session("1701-1645",title="Fourth-Session times", inline="Fourth")
InpFourthColor = input(title="Fourth-session line", defval=color.green, inline="FourthLine")
InpFourthWidth = input.int(5,"Line width", inline="FourthLine")
InpFourthName = input("24 hours session",title="Fourth-Session Name", inline="FourthText")
InpFourthShowMax = input.bool(defval=false, title="Show Max-Values",inline="FourthText")

InpAvgDays = input.int(10, "Average-Days")
InpLabelOffset = input.int(title="Label-Offset", defval=20, inline="Label")
InpLabelText   = input.color(defval=color.white,title="Label-Text", inline="Label")
InpLabelBackground = input.color(defval=color.gray,title="Label-Background", inline="Label")
InpDeleteAfterSession = input.bool(defval=false,title="Delete drawings and labels after session end")

// SessionHigh() returns the highest price during the specified 
// session, optionally corrected for the given time zone.
// Returns 'na' when the session hasn't started or isn't on the chart.
SessionHigh(sessionTime, sessionTimeZone=syminfo.timezone) =>
    insideSession = not na(time(timeframe.period, sessionTime, sessionTimeZone))
    var float sessionHighPrice = na

    if insideSession and not insideSession[1]
        sessionHighPrice := high
    else if insideSession
        sessionHighPrice := math.max(sessionHighPrice, high)
    
    sessionHighPrice
SessionLow(sessionTime, sessionTimeZone=syminfo.timezone) =>
    insideSession = not na(time(timeframe.period, sessionTime, sessionTimeZone))
    var float sessionLowPrice = na

    if insideSession and not insideSession[1]
        sessionLowPrice := low
    else if insideSession
        sessionLowPrice := math.min(sessionLowPrice, low)
    
    sessionLowPrice
// IsSessionOver() returns 'true' when the current bar is the first one
// after the given session, adjusted to the specified time zone (optional).
// Returns 'false' for other bars after the session ends, bars inside the
// session, and when the time frame is daily or higher.
IsSessionOver(sessionTime, sessionTimeZone=syminfo.timezone) =>
    inSess = not na(time(timeframe.period, sessionTime, sessionTimeZone))
    not inSess and inSess[1]
// IsSessionStart() returns 'true' when the current bar is the first one
// inside the specified session, adjusted to the given time zone (optional).
// Returns 'false' for other bars inside the session, bars outside the
// session, and when the time frame is 1 day or higher.
IsSessionStart(sessionTime, sessionTimeZone=syminfo.timezone) =>
    inSess = not na(time(timeframe.period, sessionTime, sessionTimeZone))
    inSess and not inSess[1]
// InSession() returns 'true' when the current bar happens inside
// the specified session, corrected for the given time zone (optional).
// Returns 'false' when the bar doesn't happen in that time period,
// or when the chart's time frame is 1 day or higher. 
InSession(sessionTime, sessionTimeZone=syminfo.timezone) =>
    not na(time(timeframe.period, sessionTime, sessionTimeZone))
// function to draw the line and the labels
fDrawLineLabel(sSessionName, sValueName, fInstrumentValue, cColor, iWidth) =>
    lLine = line.new(bar_index-1,fInstrumentValue,bar_index+5,fInstrumentValue, color=cColor, width=iWidth)
    lLabel = label.new(bar_index+InpLabelOffset,fInstrumentValue,(sValueName + " " + sSessionName + " "+str.tostring(fInstrumentValue)),style=label.style_label_center, color=InpLabelBackground, textcolor=InpLabelText)
    [lLine, lLabel]
// function to move the lines and labels to the new instrument value    
fMoveLineLabel(sSessionName, sValueName, lLine, lLabel, fInstrumentValue) =>
    line.set_y1(lLine,fInstrumentValue)
    line.set_y2(lLine,fInstrumentValue)
    line.set_x2(lLine,bar_index+5)
    label.set_xy(lLabel,bar_index+InpLabelOffset, fInstrumentValue)
    label.set_text(lLabel,(sValueName + " " + sSessionName + " "+str.tostring(fInstrumentValue)))

fProcessSession(sSession, sSessionName, aValues, cColor, iWidth, bShowMax) =>
    /////First Session
    var SessionRange = 0.0
    
    var line lineAvgHigh = na
    var line lineAvgLow = na
    var label labelAvgHigh = na
    var label labelAvgLow = na

    var line lineMaxHigh = na
    var line lineMaxLow = na
    var label labelMaxHigh = na
    var label labelMaxLow = na

    
    SessionRange := SessionHigh(sSession)-SessionLow(sSession)
    
    if IsSessionOver(sSession)
        if array.size(aValues) > InpAvgDays-1
            array.shift(aValues)
        array.push(aValues, SessionRange)
        if InpDeleteAfterSession
            line.delete(lineAvgHigh)
            line.delete(lineAvgLow)
            label.delete(labelAvgHigh)
            label.delete(labelAvgLow)
            if bShowMax
                line.delete(lineMaxHigh)
                line.delete(lineMaxLow)
                label.delete(labelMaxHigh)
                label.delete(labelMaxLow)
    
    
    avgRangeHigh = SessionLow(sSession)+array.avg(aValues)
    avgRangeLow = SessionHigh(sSession)-array.avg(aValues)
    maxRangeHigh = SessionLow(sSession)+array.max(aValues)
    maxRangeLow = SessionHigh(sSession)-array.max(aValues)
        
    
    if IsSessionStart(sSession)
        [_lineHigh, _labelHigh] = fDrawLineLabel(sSessionName,"Avg",avgRangeHigh,cColor, iWidth)
        [_lineLow, _labelLow] = fDrawLineLabel(sSessionName,"Avg", avgRangeLow,cColor, iWidth)
        lineAvgHigh := _lineHigh
        labelAvgHigh := _labelHigh
        lineAvgLow := _lineLow
        labelAvgLow := _labelLow
        if bShowMax
            [__lineHigh, __labelHigh] = fDrawLineLabel(sSessionName,"Max",maxRangeHigh,cColor, iWidth)
            [__lineLow, __labelLow] = fDrawLineLabel(sSessionName,"Max", maxRangeLow,cColor, iWidth)
            lineMaxHigh := __lineHigh
            labelMaxHigh := __labelHigh
            lineMaxLow := __lineLow
            labelMaxLow := __labelLow
        
        
    if InSession(sSession)
        fMoveLineLabel(sSessionName, "Avg", lineAvgHigh, labelAvgHigh, avgRangeHigh)
        fMoveLineLabel(sSessionName, "Avg", lineAvgLow, labelAvgLow, avgRangeLow)
        if bShowMax
            fMoveLineLabel(sSessionName, "Max", lineMaxHigh, labelMaxHigh, maxRangeHigh)
            fMoveLineLabel(sSessionName, "Max", lineMaxLow, labelMaxLow, maxRangeLow)

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//// end of functions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

if InpFirstSessionShow
    var aFirstSessionRange = array.new_float(InpAvgDays)
    fProcessSession(InpFirstSession, InpFirstName, aFirstSessionRange, InpFirstColor, InpFirstWidth, InpFirstShowMax)
    
if InpSecondSessionShow
    var aSecondSessionRange = array.new_float(InpAvgDays)
    fProcessSession(InpSecondSession, InpSecondName, aSecondSessionRange, InpSecondColor, InpSecondWidth, InpSecondShowMax)
    
if InpThirdSessionShow
    var aThirdSessionRange = array.new_float(InpAvgDays)
    fProcessSession(InpThirdSession, InpThirdName, aThirdSessionRange, InpThirdColor, InpThirdWidth, InpThirdShowMax)

if InpFourthSessionShow
    var aFourthSessionRange = array.new_float(InpAvgDays)
    fProcessSession(InpFourthSession, InpFourthName, aFourthSessionRange, InpFourthColor, InpFourthWidth, InpFourthShowMax)

