1 year ROI BUY ZONE
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Vreckovka

//@version=5
indicator("1 year ROI BUY ZONE",overlay=true,max_labels_count=500)

source = input(close, "Source")
minDays = input(45, "Min. days of session")
maxIndecisionDays = input(10, "Max. indecision days")

showActual = input(false, "Show actual label")
showShoppingCart = input(false, "Show Shopping Cart")
showBullBaner = input(false, "Show Bull Baner")
showBearBaner = input(false, "Show Bear Baner")

bullColor = input(color.rgb(101, 194, 85), "Bull color")
bearColor = input(color.rgb(225, 232, 88), "Bear color")
signalColor = input(color.rgb(255, 66, 66), "Signal color")
indecisionColor = input(color.rgb(66, 138, 255), "Indecision color")
outOfRangeColor = input(color.black, "Out of range")

buyRoiSignal = input(-55,"ROI signal")
lookBackyears = input(1, "Years lookback")

YearCTD = year(time) - lookBackyears
monthCTD = month(time) 
dateCTD = dayofmonth(time) 

isMonthOlder(p_month, p_year,actualMonth,actualYear) =>
    if(p_month < actualMonth and p_year <= actualYear)
        true
    else if(p_month >= actualMonth and p_year < actualYear)
        true
    else
        false

getLastYearClose() =>
    indexOfLastYearCandle = 0
    
    for offset = 0 to lookBackyears * 380
        newTime = time[offset]
        
        if(na(newTime))
            -1
            break
        
        newYear = year(newTime)
        newMonth = month(newTime)
        newDay = dayofmonth(newTime)
        
        higherTimeFrame = false
        moreThanYear = false
        
        if(timeframe.isweekly or timeframe.ismonthly or (timeframe.isdaily and timeframe.multiplier > 1))
            higherTimeFrame := (newDay > dateCTD and isMonthOlder(newMonth,newYear,month(time), year(time)))
            
        dayDiff = time - newTime
        
        if(dayDiff >= 31536000000 * lookBackyears)
            moreThanYear := true
    
        if(newYear <= YearCTD and (isMonthOlder(newMonth,newYear,monthCTD,YearCTD) or monthCTD == newMonth) and moreThanYear)
            indexOfLastYearCandle := offset
            break
        
    indexOfLastYearCandle

lastYearCloseIndex = getLastYearClose()
dayDiff = lastYearCloseIndex > 0

lastYearClose = source[lastYearCloseIndex]
roi = ((source / lastYearClose) - 1) * 100
var bear = false
var candlesOfBear = 0
var candlesOfBull = 0
var indecisionIndex = 0

sessionIndex = candlesOfBear > candlesOfBull ? candlesOfBear : candlesOfBull
sessionDiff = (timestamp(year(time),month(time), dayofmonth(time)) - timestamp(year(time[sessionIndex]),month(time[sessionIndex]), dayofmonth(time[sessionIndex])))  / (24 * 60 * 60 * 1000)

//if(bear)
    //label.new(bar_index, na, str.tostring(sessionIndex), yloc = yloc.abovebar, style = label.style_label_down,color= color.rgb(255,50,100,75),textcolor = color.white, size = size.normal)

strDays = sessionDiff > 0 ? str.tostring(sessionDiff) + " days" : "" 
change = false


if(dayDiff)
    if(roi <= 0)
        if(not bear and (sessionDiff >= minDays or sessionIndex == 0 or indecisionIndex >= maxIndecisionDays))
            bear := true
            change := true
            candlesOfBull := 0
            candlesOfBear := 0
            indecisionIndex := 0
       
        candlesOfBear := candlesOfBear + 1
    else
        if(bear and (sessionDiff >= minDays or sessionIndex == 0 or indecisionIndex >= maxIndecisionDays))
            bear := false
            change := true
            candlesOfBull := 0
            candlesOfBear := 0
            indecisionIndex := 0

        candlesOfBull := candlesOfBull + 1


isInIndecision = ((bear and roi > 0) or (not bear and roi < 0))


if(isInIndecision)
    if(bear)
        candlesOfBear := candlesOfBear + 1
    else
        candlesOfBull := candlesOfBull + 1
        
    indecisionIndex := indecisionIndex + 1
else if(indecisionIndex > 0)
    indecisionIndex := 0


barColor = dayDiff ? isInIndecision ? indecisionColor : (bear ? roi <= buyRoiSignal ?  signalColor : bearColor : bullColor) : outOfRangeColor
labelColor = ((bear and roi > 0) or (not bear and roi < 0)) ? (color.rgb(50,50,255,75)) : (bear ? color.rgb(255,50,100,75) :  color.rgb(50,255,100,75)) 
barcolor(barColor)

singnalPrice = lastYearClose * (1 - (-0.01 *  buyRoiSignal))


if(barstate.islast and showActual)
    label.new(bar_index - lastYearCloseIndex, na, "COMPARING", yloc = yloc.abovebar,style = label.style_label_down,color= color.rgb(255,255,20,75),textcolor = color.white, size = size.small)
    
    if(bear)
        label.new(bar_index, na, "ACTUAL BEAR\n" + str.tostring(lastYearClose) + " ( " + str.tostring(roi,"##.##") + " % )\n" + str.tostring(singnalPrice) + " ( " + str.tostring(((singnalPrice / close) - 1) * 100, "##.##") + " % )" + "\n" + str.tostring(sessionDiff) + " days" + "\n " + str.tostring(sessionIndex) + " bars", yloc = yloc.belowbar,style = label.style_label_up,color= labelColor,textcolor = color.white, size = size.small)
    else
        label.new(bar_index, na, "ACTUAL BULL\n" + str.tostring(lastYearClose) + " ( " + str.tostring(roi,"##.##") + " % )\n" + str.tostring(sessionDiff) + " days" + "\n " + str.tostring(sessionIndex) + " bars", yloc = yloc.belowbar,style = label.style_label_up,color= labelColor,textcolor = color.white, size = size.small)

if(bear and roi < buyRoiSignal and showShoppingCart)    
    label.new(bar_index, na, "🛒", yloc = yloc.abovebar, style = label.style_none, textcolor = color.rgb(255,255,100), size = size.normal)

if(change)
    if(bear)
        if(showBullBaner)
            label.new(bar_index, na, "BULL END\n" + strDays + "\n " + str.tostring(sessionIndex) + " bars", yloc = yloc.abovebar, style = label.style_label_down,color= color.rgb(50,255,100,75),textcolor = color.white, size = size.normal)
    else if(showBearBaner)
        label.new(bar_index, na, "BEAR END\n" + strDays + "\n " + str.tostring(sessionIndex) + " bars", yloc = yloc.abovebar, style = label.style_label_down,color= color.rgb(255,50,100,75),textcolor = color.white, size = size.normal)