[Mad] Active Line
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © djmad //
ver = "v1.1"
//@version=5
indicator(title="[Mad] Active Line "+ver, shorttitle = "[Mad] Active Line "+ver, overlay = true, max_bars_back=1000, max_labels_count=500, max_lines_count=500, max_boxes_count=500)
///////////////////
// { Inputs

var int Entryline_1_collisions      =   0
var int Entryline_2_collisions      =   0

all_colors      =    array.new_color(16, color.gray)
all_thickness   =    array.new_int(16, 1)
all_styles       =    array.new_string(16, line.style_dotted )

int    OFFSET       = 0//input.int(0,"OFFSET TIME")*1000000

bool        ChartisLog              =   input.bool(false,'Chart-Setting is Logarithmic',group='Log-Chart',inline='1cd')

float       Entryline_1_Time_L      =   input.time(timestamp("2020-02-20"), "Entryline 1 A", inline="Entryline 1 Point Left", confirm = true,group='Line 1') +OFFSET
float       Entryline_1_Price_T     =   input.price(100, "Entryline 1 A", inline="Entryline 1 Point Left", confirm=true,group='Line 1')
float       Entryline_1_Time_R      =   input.time(timestamp("2020-02-19"), "Entryline 1 B", inline="Entryline 1 Point Right", confirm = true,group='Line 1') +OFFSET
float       Entryline_1_Price_B     =   input.price(100, "Entryline 1 B", inline="Entryline 1 Point Right", confirm=true,group='Line 1')
array.set(all_colors, 0,                input.color(color.rgb(255, 251, 0),  title='',group='Line 1',inline='1aa'))
array.set(all_thickness, 0,             input.int(1,'- thickness',group='Line 1',inline='1aa'))
array.set(all_styles, 0,                input.string(line.style_solid,' style',group='Line 1',inline='1aa',options=[line.style_dotted,line.style_solid]))
string      Entryline_1_Ext_temp    =   input.string("extend right","extend line", options=["extend right","extend none","extend left","extend both"])


bool        show_line_hori          =   input.bool(true,'Show horizontal line',group='Horizontal Line',inline='1cb')
array.set(all_colors, 2,                input.color(color.rgb(255, 251, 0),  title='',group='Horizontal Line',inline='1cc'))
array.set(all_thickness, 1,             input.int(1,'- thickness',group='Horizontal Line',inline='1cc'))
array.set(all_styles, 1,                input.string(line.style_solid,' style',group='Horizontal Line',inline='1cc',options=[line.style_dotted,line.style_solid]))
bool        infotext_right          =   input.bool(true,'Show horizontal text',group='Horizontal Line',inline='1cd')
int         infotext_right_space    =   input.int(42,'- shifting',group='Horizontal Line',inline='1cd',step=3)


bool        show_line_vert          =   input.bool(true,'Show difference line',group='Difference Line',inline='1cd')
array.set(all_colors, 3,                input.color(color.rgb(255, 251, 0),  title='',group='Difference Line',inline='1ce'))
array.set(all_thickness, 2,             input.int(1,'- thickness',group='Difference Line',inline='1ce'))
array.set(all_styles, 2,                input.string(line.style_dotted,' style',group='Difference Line',inline='1ce',options=[line.style_dotted,line.style_solid]))
bool        infotext_diff           =   input.bool(true,'Show difference text',group='Difference Line',inline='1cf')
int         infotext_diff_space     =   input.int(18,'- shifting',group='Difference Line',inline='1cf',step=3)
string      infotext_text           =   input.string("c= ",'Naming:',group='Difference Line',inline='1cf')


bool        show_markers            =   input.bool(true,'Show Dragpoints and Crosses',group='Dragpoints and Crosses')

var         infotext_size           =   input.string(size.normal, title='Label-Size', group='label settings', options=[size.tiny, size.small, size.normal, size.large, size.huge], inline='1da')
array.set(all_colors, 1,                input.color(color.white, title='- Textcolor',group='label settings', inline='1da'))
int         i_decimals              =   input.int(2,'decimals',group='label settings')
bool        debugtext_active        =   false//input.bool(false,'Debug Info',group='label settings')

int         alertnumber             =   input.int(1,'maximum alerts',group='alert settings')

var float timeto = na

// }
///////////////////
// { Functions
bool        Alert_output            =   false

roundTo(_value) => 
    str.tostring(math.round(_value * math.pow(10, i_decimals)) / math.pow(10, i_decimals))

shifting(_value) =>
    var string output = ""
    output := ""
    for i = 0 to _value by 3
        output := output + "   "

float       LOGICAL_OFFSET          =   4
float       COORD_OFFSET            =   0.0001

fromLog(series float value) =>
    float exponent = math.abs(value)
    float product  = math.pow(10, exponent - LOGICAL_OFFSET) - COORD_OFFSET
    float result   = exponent < 1e-8 ? 0 : value < 0 ? - product : product

toLog(series float value) =>
    float exponent = math.abs(value)
    float product  = math.log10(exponent + COORD_OFFSET) + LOGICAL_OFFSET
    float result   = exponent < 1e-8 ? 0 : value < 0 ? - product : product

f_getbartime() =>
    var int firstbartime = 0, var int lastbartime = 0
    var bool locked1 = false 
    var bool locked2 = false 
    var bool locked3 = false
    var int counter = 0
    var int difftime = 0
    var int timeperbar = na

    if locked1 == false
        firstbartime := time
        counter := 0
        locked1 := true

    if counter == 100 and locked2 == false
        lastbartime := time
        locked2 := true
    
    if locked3 == false and locked2 == true
        difftime := lastbartime - firstbartime
        timeperbar := difftime / counter
        locked3 := true

    if locked3 != true
        counter += 1

    timeperbar

f_calc_projection(          float Entryline_Time_L, float Entryline_Price_T, float Entryline_Time_R, float Entryline_Price_B, float relevanttime, bool chartislog) =>
    if chartislog
        fromLog(toLog(Entryline_Price_T) + (toLog(Entryline_Price_B) - toLog(Entryline_Price_T)) / (toLog(Entryline_Time_R/f_getbartime()) - toLog(Entryline_Time_L/f_getbartime())) * (toLog(relevanttime/f_getbartime()) - toLog(Entryline_Time_L/f_getbartime())))
    else if not chartislog
        Entryline_Price_T + (Entryline_Price_B - Entryline_Price_T) / (Entryline_Time_R/f_getbartime() - Entryline_Time_L/f_getbartime()) * (relevanttime/f_getbartime() - (Entryline_Time_L/f_getbartime()))

f_draw_diff_line(           float Entryline_Time_L, float Entryline_Price_T, float Entryline_Time_R, float Entryline_Price_B, string Entryline_Ext, string Entryline_dir, string Entryline_type, int Entryline_amount, string Entryline_spikes, color [] colors, int [] all_thickness, string [] all_styles) =>
    var float difference = 0
    line Line_Vertical = na
    line Line_Horizontal = na
    label Label_diff1 = na
    label Label_diff2 = na
    label Label_diff3 = na
    bool Alertoutput = false

    if Entryline_Ext == extend.right or Entryline_Ext ==  extend.both or time < Entryline_Time_R

        if show_line_hori
            Line_Horizontal := line.new(
             bar_index[2],
             f_calc_projection(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B,time,ChartisLog),
             bar_index[1],
             f_calc_projection(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B,time,ChartisLog), 
             xloc=xloc.bar_index, color=array.get(colors,2), extend=extend.right, style=array.get(all_styles,1), width=array.get(all_thickness,1))

        if infotext_right
            Label_diff3 := label.new(timenow + (time - time[1]) * 1, 
             f_calc_projection(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B,time,ChartisLog),
             shifting(infotext_right_space) + str.tostring(roundTo(f_calc_projection(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B,time,ChartisLog))),
             xloc=xloc.bar_time, textcolor=array.get(colors,1) , style=label.style_none, size=infotext_size)

        if show_line_vert
            Line_Vertical := line.new(
             time,
             close - 0.1*(close-f_calc_projection(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B,time,ChartisLog)) ,
             time,
             f_calc_projection(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B,time,ChartisLog), 
             xloc=xloc.bar_time, color=array.get(colors,3), extend=extend.none, style=array.get(all_styles,2), width=array.get(all_thickness,2))

        if infotext_diff
            Label_diff1 := label.new(time,f_calc_projection(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B,time,ChartisLog), 
             text= shifting(infotext_diff_space) + infotext_text + str.tostring(roundTo(f_calc_projection(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B,time,ChartisLog)-close))+"\n\n" ,
             xloc=xloc.bar_time, style=label.style_none, color=array.get(colors,0), textcolor=array.get(colors,1), size=infotext_size)

        if show_markers
            Label_diff2 := label.new(time,f_calc_projection(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B,time,ChartisLog), 
             text= "" ,
             xloc=xloc.bar_time, style=label.style_xcross, color=array.get(colors,0), textcolor=array.get(colors,1), size=size.tiny)

    Alertoutput := ta.cross(f_calc_projection(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B,time,ChartisLog),0)

    line.delete(Line_Vertical[1])
    line.delete(Line_Horizontal[1])
    label.delete(Label_diff1[1])      
    label.delete(Label_diff2[1])      
    label.delete(Label_diff3[1])
    Alertoutput

f_draw_entry_line(          float Entryline_Time_L, float Entryline_Price_T, float Entryline_Time_R, float Entryline_Price_B, string Entryline_Ext, string Entryline_dir, string Entryline_type, float Entryline_width, int Entryline_amount, color [] colors, int [] all_thickness, string [] all_styles) =>
    var float difference = 0
    var line Line_entryline_1 = na
    var line Line_entryline_2 = na
    var linefill Line_fill_E1_E2 = na
    var color_given = array.get(colors,0)

    Line_entryline_1 := line.new(math.floor(math.round(Entryline_Time_L,0)), Entryline_Price_T, math.floor(math.round(Entryline_Time_R,0)),   
     f_calc_projection(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B,Entryline_Time_R,ChartisLog),
     xloc=xloc.bar_time, color=color_given, extend=Entryline_Ext, style=array.get(all_styles,0), width=array.get(all_thickness,0))

    difference := close[math.floor(Entryline_Time_L)] - Entryline_Price_B
    line.delete(Line_entryline_1[1])
    line.delete(Line_entryline_2[1])
    linefill.delete(Line_fill_E1_E2[1])

    if show_markers
        Label_linestats = label.new(
         math.floor(math.round(Entryline_Time_L,0)), Entryline_Price_T,
         "" ,
         xloc=xloc.bar_time, style=label.style_xcross, color=color_given, textcolor=array.get(colors,1), size=size.tiny)
        label.delete(Label_linestats[1])     

        Label_line_endpoint = label.new(math.ceil(math.round(Entryline_Time_R,0)),Entryline_Price_B,
         text= "" ,
         xloc=xloc.bar_time, style=label.style_xcross, color=color_given, textcolor=array.get(colors,1), size=size.tiny)
        label.delete(Label_line_endpoint[1])

f_draw_entry_line_complete( float Entryline_Time_L, float Entryline_Price_T, float Entryline_Time_R, float Entryline_Price_B, string Entryline_Ext, string Entryline_dir, string Entryline_type, float Entryline_width, int Entryline_amount, string Entryline_spikes, color [] colors, int [] all_thickness, string [] all_styles) =>
    f_draw_entry_line(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B, Entryline_Ext, Entryline_dir, Entryline_type, Entryline_width, Entryline_amount, colors, all_thickness, all_styles)
    f_draw_diff_line(Entryline_Time_L, Entryline_Price_T, Entryline_Time_R, Entryline_Price_B, Entryline_Ext, Entryline_dir, Entryline_type, Entryline_amount, Entryline_spikes, colors, all_thickness, all_styles)
// }
///////////////////
//RUNTIME {
///////////////////

Entryline_1_Ext = switch Entryline_1_Ext_temp
    "extend right"  =>                          extend.right                                  
    "extend none"   =>                          extend.none                                  
    "extend left"   =>                          extend.left                                  
    "extend both"   =>                          extend.both
    =>                                          ""


if time >= Entryline_1_Time_L - 150*f_getbartime()
    Alert_output := f_draw_entry_line_complete(
     Entryline_1_Time_L,      Entryline_1_Price_T,       Entryline_1_Time_R,      Entryline_1_Price_B,            Entryline_1_Ext,    "disabled",        "disabled",     0,      0, "close", all_colors, all_thickness, all_styles)

///////////////////
//Alerts {
///////////////////
var actual_alerts = 0

if not barstate.isrealtime
    actual_alerts := 0

if Alert_output and alertnumber > actual_alerts
    actual_alerts :=+ 1
    alert("Active line is crossed @" + str.tostring(roundTo(close)) + " Nr.:" + str.tostring(actual_alerts))
