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

// @version=5
// @description Helps in determining the relative deviation from the open of the day compared to the high or low values.
library("DailyDeviation")
import Electrified/SessionInfo/10 as Session
import Electrified/DailyLevels/9 as Daily
import Electrified/DataCleaner/2 as Data

//////////////////////////////////////////////////
// @function Returns a set of arrays representing the daily deviation of price for a given number of days.
// @param daysPrior Number of days back to get the close from.
// @param maxDeviation Maximum deviation before a value is considered an outlier. A value of 0 will not filter results.
// @param spec session.regular (default), session.extended or other time spec.
// @param res The resolution (default = '1440').
// @returns [OH, OL, OC] Where OH = Open vs High, OL = Open vs Low, and OC = Open vs Close
export hlcDeltaArrays(
  simple int days,
  simple float maxDeviation = 3,
  simple string spec = session.regular,
  simple string res = '1440') =>
    Dopen  = Daily.openArray(days, spec, res)
    Dhigh  = Daily.highArray(days, spec, res)
    Dlow   = Daily.lowArray(days, spec, res)
    Dclose = Daily.closeArray(days, spec, res)    
    OH = array.new_float(days + 1)
    OL = array.new_float(days + 1)
    OC = array.new_float(days + 1)

    int d = 0
    while d < days
        d += 1
        o = array.get(Dopen, d)
        h = array.get(Dhigh, d)
        l = array.get(Dlow, d)
        c = array.get(Dclose, d)
        array.set(OH, d, h - o)
        array.set(OL, d, o - l)
        array.set(OC, d, c - o)

    if maxDeviation == 0
        [OH, OL, OC]
    else
        [Data.cleanArray(OH, maxDeviation), Data.cleanArray(OL, maxDeviation), Data.cleanArray(OC, maxDeviation)]  
//////////////////////////////////////////////////

//////////////////////////////////////////////////
// @function Returns a value representing the deviation from the open (to the high or low) of the current day given number of days to measure from. 
// @param daysPrior Number of days back to get the close from.
// @param maxDeviation Maximum deviation before a value is considered an outlier. A value of 0 will not filter results.
// @param comparison The value use in comparison to the current open for the day.
// @param spec session.regular (default), session.extended or other time spec.
// @param res The resolution (default = '1440').
export fromOpen(
  simple int days,
  simple float maxDeviation = 3,
  float comparison = close,
  simple string spec = session.regular,
  simple string res = '1440') =>
    if na(comparison) or not Session.isIn(spec, res)
        na
    else
        oD = Daily.O()
        [OH, OL, OC] = hlcDeltaArrays(days, maxDeviation, spec, res)
        if comparison > oD
            OHbase = oD + array.avg(OH)
            Hstdev = array.stdev(OH)
            d = OHbase + Hstdev
            if comparison < d
                (comparison - oD) / (d - oD)
            else
                d2 = d + Hstdev
                1 + (comparison - d) / Hstdev

        else if comparison < oD
            OLbase = oD - array.avg(OL)
            Lstdev = array.stdev(OL)
            d = OLbase - Lstdev
            if comparison > d
                (comparison - oD) / (oD - d)
            else
                d2 = d - Lstdev
                (comparison - d) / Lstdev - 1

        else
            0
//////////////////////////////////////////////////

days = input.int(50, "Days to Measure Deviation", minval=2)
max = input.float(3, "Data Cleaning: Maximum Deviation", minval=0)

dev = fromOpen(days, max)
plot(dev, "Deviation From Open", dev<0 ? color.blue : color.yellow, style=plot.style_area)

hline(1)
hline(2)
hline(3)
hline(-1)
hline(-2)
hline(-3)