Cycles: 4x dual inputs: Swing / Time Cycles projected forward
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © twingall

//@version=5
indicator("Future cycles: 4x dual inputs", overlay = true, max_lines_count = 500)

var grp1 = "~~~~~~~~~ Confuence Line ~~~~~~~~~"
var grp2 = "~~~~~~~~~ Primary Cycle ~~~~~~~~~"
var grp3 = "~~~~~~~~~ Cycle 2 ~~~~~~~~~"
var grp4 = "~~~~~~~~~ Cycle 3 ~~~~~~~~~"
var grp5 = "~~~~~~~~~ Cycle 4 ~~~~~~~~~"

showConfLn = input.bool(true, "Show Confluence Line ||", group = grp1, inline = '0')
dev= input.int(0, "deviation (+/- bars)", minval = 0,  group = grp1, inline = '0', tooltip = "say deviation = 'x', then each of cycle 2, 3, 4 lines (so long as they are included for confluence) must be within 'X' bars of the primary cycle line\n\nIf so, then that particular primary cycle line will be painted in the foloowing color/style")
color0 = input.color(color.purple, "color:", group = grp1, inline = '1')
linestyle0 = input.string(line.style_dashed, "style", options = [line.style_solid, line.style_dotted, line.style_dashed], group = grp1, inline = '1')
width0 = input.int(3, "width", group = grp1, inline = '1')

startDate1= input.time(timestamp("21 Jul 2021 00:00 -0400"), "Primary Cycle Start Date", confirm =true, group = grp2)
endDate1= input.time(timestamp("9 Nov 2021 00:00 -0400"), "Primary Cycle End Date", confirm = true, group = grp2)
showCycle1 = input.bool(true, "Show |", group = grp2, inline = '1')
color1 = input.color(color.red, "line color", group = grp2, inline = '1')
linestyle1 = input.string(line.style_dashed, "style", options = [line.style_solid, line.style_dotted, line.style_dashed], group = grp2, inline = '1')
width1 = input.int(1, "width", group = grp2, inline = '1')


startDate2= input.time(timestamp("28 Jan 2021 00:00 -0400"), "Start Date2", confirm =true, group = grp3, inline = '2')
endDate2= input.time(timestamp("22 Feb 2021 00:00 -0400"), "End Date2", confirm = true, group = grp3, inline = '3')
showCycle2 = input.bool(true, "Show lines |", group = grp3, inline = '5')
color2 = input.color(color.blue, "", group = grp3, inline = '5')
linestyle2 = input.string(line.style_dashed, "style", options = [line.style_solid, line.style_dotted, line.style_dashed], group = grp3, inline = '5')
width2 = input.int(1, "width", group = grp3, inline = '5')
conf2 = input.bool(true, "include in confluence calculation", group = grp3, inline = '6')


startDate3= input.time(timestamp("15 Apr 2021 00:00 -0400"), "Start Date3", confirm =true, group = grp4, inline = '6')
endDate3= input.time(timestamp("19 May 2021 00:00 -0400"), "End Date3", confirm = true, group = grp4, inline = '7')
showCycle3 = input.bool(true, "Show lines |", group = grp4, inline = '9')
color3 = input.color(color.black, "", group = grp4, inline = '9')
linestyle3 = input.string(line.style_dashed, "style", options = [line.style_solid, line.style_dotted, line.style_dashed], group = grp4, inline = '9')
width3 = input.int(1, "width", group = grp4, inline = '9')
conf3 = input.bool(true, "include in confluence calculation", group = grp4, inline = '10')

startDate4= input.time(timestamp("21 Jun 2021 00:00 -0400"), "Start Date4", confirm =true, group = grp5, inline = '10')
endDate4= input.time(timestamp("9 Nov 2021 00:00 -0400"), "End Date4", confirm = true, group = grp5, inline = '11')
showCycle4 = input.bool(true, "Show lines |", group = grp5, inline = '13')
color4 = input.color(color.green, "", group = grp5, inline = '13')
linestyle4 = input.string(line.style_dashed, "style", options = [line.style_solid, line.style_dotted, line.style_dashed], group = grp5, inline = '13')
width4 = input.int(1, "width", group = grp5, inline = '13')
conf4 = input.bool(true, "include in confluence calculation", group = grp5, inline = '14')

boxTransp= input.int(80, "box transparancy (100 = invisible)", maxval = 100, minval = 0)

cycleBoxAndLines(int _timeS, int _timeE, color _col, string _style, int _width, bool _showCycle)=>  
    var int strtInd = na
    var int endInd = na
    var array<int> lnFwdInd = array.new<int>(na)
    if time>=_timeS and time[1]<=_timeS
        strtInd:= bar_index-1
    if time>=_timeE and time[1]<=_timeE
        endInd:= bar_index-1
    int len = endInd-strtInd
    horizon = (last_bar_index+10000)- endInd 
    totLines = int(horizon/len)
    midInd = int(strtInd+(len/2))
    if barstate.islast and endInd>strtInd 
        line.new(strtInd, high, strtInd, high+1, extend = extend.both, width=1, color = color.fuchsia, style = line.style_dotted)
        line.new(endInd, high, endInd, high+1, extend = extend.both, width=1, color = color.fuchsia, style = line.style_dotted)
        top = math.max(high[last_bar_index-strtInd],high[last_bar_index-endInd])
        bottom= math.min(low[last_bar_index-strtInd],low[last_bar_index-endInd])
        box.new(strtInd,top, endInd, bottom, bgcolor = color.new(_col, boxTransp), border_color = color.new(color.white, 100), text = str.tostring(len)+ " bars", text_valign = text.align_top, text_halign = text.align_center, text_size = size.normal, text_color=color.new(_col,22))
        label.new(midInd, close[last_bar_index-strtInd], style = label.style_none, size = size.normal)
        for i = 1 to totLines
            if endInd+(i*len) < last_bar_index+500 // TV won't let you plot lines more than 500 bars into future using bar_index as ref
                if _showCycle
                    line.new(endInd+(i*len), high, endInd+(i*len), high+1, color = _col, extend = extend.both, style = _style, width = _width)
                lnFwdInd.push(endInd+(i*len))
        lnFwdInd

arrFwd1 = cycleBoxAndLines(startDate1, endDate1, color1, linestyle1, width1, showCycle1) 
arrFwd2 =cycleBoxAndLines(startDate2, endDate2, color2, linestyle2, width2, showCycle2) 
arrFwd3 =cycleBoxAndLines(startDate3, endDate3, color3, linestyle3, width3, showCycle3) 
arrFwd4 =cycleBoxAndLines(startDate4, endDate4, color4, linestyle4, width4, showCycle4) 

paintConfluence()=>
    var bool result = false
    if arrFwd1.size()>0 
        for i = 0 to arrFwd1.size()-1
            ind = arrFwd1.get(i)
            cond2 = false
            for j= -dev to dev
                if arrFwd2.includes(ind+j)
                    cond2:= true
            cond3 = false
            for j= -dev to dev
                if arrFwd3.includes(ind+j)
                    cond3:= true
            cond4 = false
            for j= -dev to dev
                if arrFwd4.includes(ind+j)
                    cond4:= true
            if conf2?cond2:true
                if conf3?cond3:true
                    if conf4?cond4:true
                        line.new(ind, high, ind, high+1, width = width0, color = color0, style =linestyle0, extend = extend.both)

if barstate.islast and showConfLn 
    paintConfluence()
