[e2] Drawing Library :: Horizontal Ray
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © e2e4mfck

//@version=5

// @description e2's drawing library.
library("e2hray", overlay = true)

// —————————— hray() {
// @function Horizontal ray.
// @param condition Boolean condition that defines the initial point of a ray.
// @param level Ray price level.
// @param color Ray color.
// @param extend (optional) Default value true, current ray levels extend to the right, if false - up to the current bar.
// @param hist_lines (optional) Default value true, shows historical ray levels that were revisited, default is dashed lines. To avoid alert problems set to 'false' before creating alerts.
// @param alert_message (optional) Default value string(na), if declared, enables alerts that fire when price revisits a line, using the text specified.
// @param alert_delay (optional) Default value int(0), if declared, represents the delay in minutes to validate the level. Alerts won't trigger if the ray is broken during 'delay'.
// @param style (optional) Default value 'line.style_solid'.
// @param hist_style (optional) Default value 'line.style_dashed'.
// @param width (optional) Default value int(1), ray width in pixel.
// @param hist_width (optional) Default value int(1), historical ray width in pixels.
// @returns void
export hray(bool condition, float level, color color, bool extend = true, bool hist_lines = true, string alert_message = na, int alert_delay = 0, string style = line.style_solid, string hist_style = line.style_dashed, int width = 1, int hist_width = 1) =>
    var line[]  hrays     = array.new_line()
    var line[]  histHrays = array.new_line()
    var int     delay     = alert_delay * 60 * 1000 // MS_IN_MIN
    
    if condition
        array.push(hrays, line.new(time[1], level, time, level, xloc = xloc.bar_time, color = color, width = width, style = style))
    
    for [i, hray] in hrays
        float price = line.get_y1(hray)
        int   since = line.get_x1(hray)
        line.set_x2(hray, time_close)
        
        bool broken = price < close[1] ? low <= price : high >= price
        
        if broken
            if hist_lines
                histHray = line.copy(hray), line.set_extend(histHray, extend.none), line.set_style(histHray, hist_style), line.set_width(histHray, hist_width), array.unshift(histHrays, histHray)
            line.delete(hray)
            
            if (time - since > delay) and (not na(alert_message))
                alert(alert_message, alert.freq_once_per_bar)
                
        else if extend
            line.set_extend(hray, extend.right) // }
                

// —————————— hrays() examples {
// —————  • Example 1. Single horizontal ray from the dynamic input. {
// inputTime = input.time(timestamp("20 Jul 2021 00:00 +0300"), "Date", confirm = true)
// inputPrice = input.price(54, 'Price Level', confirm = true)

// hray(time == inputTime, inputPrice, color.blue, alert_message = 'Ray level re-test!') 

// var label mark = label.new(inputTime, inputPrice, 'Selected point to start the ray', xloc.bar_time) // }



// —————  • Example 2. Multiple horizontal rays on the moving averages cross. {
// Intrabar Cross Value Function Library from @RicardoSantos https://www.tradingview.com/u/RicardoSantos/
import RicardoSantos/FunctionIntrabarCrossValue/1 as icv

float sma1 = ta.sma(close, 20)
float sma2 = ta.sma(close, 50)

bullishCross = ta.crossover( sma1, sma2)
bearishCross = ta.crossunder(sma1, sma2)

plot(sma1, 'sma1', color.purple)
plot(sma2, 'sma2', color.blue)

crossValue = icv.intrabar_cross_value(sma1, sma2)

// // 2a. We can use 2 function calls to distinguish long and short sides.
// hray(bullishCross, crossValue, color.green, alert_message = 'Bullish Cross Level Broken!', alert_delay = 10)
// hray(bearishCross, crossValue, color.red,   alert_message = 'Bearish Cross Level Broken!', alert_delay = 10)   

// 2b. Or a single call for both bullish and bearish side with a dynamic color.
hray(bullishCross or bearishCross, crossValue, bullishCross ? color.green : color.red) // }



// —————  • Example 3. Horizontal ray at the all time highs with an alert. alert_delay = 10 to prevent the alert trigger on consecutive break of ath {
// var float ath    = 0, ath := math.max(high, ath)
// bool      newAth = ta.change(ath)

// hray(nz(newAth[1]), high[1], color.orange, alert_message = 'All Time Highs Tested!', alert_delay = 10) // } // }