Dominant Cycle Detection Oscillator
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
//
// © BarefootJoey
// ██████████████████████████████████████████████████████████████████████
// █▄─▄─▀██▀▄─██▄─▄▄▀█▄─▄▄─█▄─▄▄─█─▄▄─█─▄▄─█─▄─▄─███▄─▄█─▄▄─█▄─▄▄─█▄─█─▄█
// ██─▄─▀██─▀─███─▄─▄██─▄█▀██─▄███─██─█─██─███─███─▄█─██─██─██─▄█▀██▄─▄██
// █▄▄▄▄██▄▄█▄▄█▄▄█▄▄█▄▄▄▄▄█▄▄▄███▄▄▄▄█▄▄▄▄██▄▄▄██▄▄▄███▄▄▄▄█▄▄▄▄▄██▄▄▄██
//
//@version=5
indicator("Dominant Cycle Detection Oscillator", overlay=false) //, max_bars_back=5000)
import lastguru/DominantCycle/2 as BFJ1 // Thank you and shoutout to @lastguru

// ---------------------------------------- Inputs --------------------------------------------------//
logcheck  = input.bool(false, "Has the side scale been changed to Logarithmic?", tooltip="Please change the scale of this indicator's pane to logarithmic for best viewing results. See https://www.tradingview.com/chart/TSLA/9LwmqYq2-How-to-use-log-charts-and-why-they-re-important/ for more information.")
dctype    = input.string("MESA MAMA Cycle", "Cycle type    ", options=["MESA MAMA Cycle", "Pearson Autocorrelation", "DFT Cycle", "Phase Accumulation"], inline="1", 
  tooltip ="Generally, the fastest to slowest load times are MAMA (fastest) > Phase Accumulation > DFT > Pearson Autocorrelation (slowest). If you are getting errors, try narrowing the search range for each of the cycle lengths or switching to a faster loading dominant cycle detection algorithm. Pinescript has 20 second load limits for free users and 40 second limits for paid subscribers.")
source    = input(close, title="  ", inline="1")

DynamicLowh   = input.int(title="Cycle lengths", defval=3, inline="lenh") 
DynamicHighh  = input.int(title="to", defval=7, inline="lenh")
DynamicLowf   = input.int(title="Cycle lengths", defval=8, inline="lenf") 
DynamicHighf  = input.int(title="to", defval=12, inline="lenf") 
DynamicLow2   = input.int(title="Cycle lengths", defval=15, inline="len2") 
DynamicHigh2  = input.int(title="to", defval=25, inline="len2") 
DynamicLow4   = input.int(title="Cycle lengths", defval=35, inline="len4") 
DynamicHigh4  = input.int(title="to", defval=45, inline="len4") 
DynamicLow8   = input.int(title="Cycle lengths", defval=75, inline="len8") 
DynamicHigh8  = input.int(title="to", defval=85, inline="len8") 
DynamicLow16  = input.int(title="Cycle lengths", defval=155, inline="len16") 
DynamicHigh16 = input.int(title="to", defval=175, inline="len16") 
DynamicLow32  = input.int(title="Cycle lengths", defval=315, inline="len32") 
DynamicHigh32 = input.int(title="to", defval=325, inline="len32") 

text_size   = input.session('Normal', "Text Size", options=["Tiny","Small","Normal","Large"])
dash_loc    = input.session("Top Center", "Title Location", options=["Top Right","Bottom Right","Top Left","Bottom Left","Middle Right","Bottom Center", "Top Center"])
title_col   = input.color(color.gray, "Title Color")

// ---------------------------------------Calculations -------------------------------------------------//
lengthh   = BFJ1.doEstimate(dctype, source, DynamicLowh, DynamicHighh)
lengthf   = BFJ1.doEstimate(dctype, source, DynamicLowf, DynamicHighf)
length2   = BFJ1.doEstimate(dctype, source, DynamicLow2, DynamicHigh2)
length4   = BFJ1.doEstimate(dctype, source, DynamicLow4, DynamicHigh4)
length8   = BFJ1.doEstimate(dctype, source, DynamicLow8, DynamicHigh8)
length16  = BFJ1.doEstimate(dctype, source, DynamicLow16, DynamicHigh16)
length32  = BFJ1.doEstimate(dctype, source, DynamicLow32, DynamicHigh32)

// --------------------------------------- Outputs -------------------------------------------------------//
plot(lengthh!=0 ?lengthh:na, "Half Cycle", color=color.purple)
plot(lengthf!=0 ?lengthf:na, "Full Cycle", color=color.blue)
plot(length2!=0 ?length2:na, "2x Cycle", color=color.aqua)
plot(length4!=0 ?length4:na, "4x Cycle", color=color.green)
plot(length8!=0 ?length8:na, "8x Cycle", color=color.yellow)
plot(length16!=0 ?length16:na, "16x Cycle", color=color.orange)
plot(length32!=0 ?length32:na, "32x Cycle", color=color.red)

var label_text_size = text_size == 'Tiny' ? size.tiny :
  text_size == 'Small' ? size.small :
  text_size == 'Normal' ? size.normal : size.large

var label ch  = na
var label cf  = na
var label c2  = na
var label c4  = na
var label c8  = na
var label c16 = na
var label c32 = na

if  barstate.islast //and logcheck
    ch := lengthh!=0?label.new(bar_index, y=lengthh, text=str.tostring(lengthh, '#'), size=label_text_size, style=label.style_label_left, color=color.new(color.white,100), textcolor=color.new(color.purple,0), tooltip="🔄 Cycle: 5 bar/0.5x\n💪 Dominant: " + str.tostring(lengthh, '#') + "\n📡 Search Range: " + str.tostring(DynamicLowh) + " to " + str.tostring(DynamicHighh)) :na
    cf := lengthf!=0?label.new(bar_index, y=lengthf, text=str.tostring(lengthf, '#'), size=label_text_size, style=label.style_label_left, color=color.new(color.white,100), textcolor=color.new(color.blue,0), tooltip="🔄 Cycle: 10 bar/1x\n💪 Dominant: " + str.tostring(lengthf, '#') + "\n📡 Search Range: " + str.tostring(DynamicLowf) + " to " + str.tostring(DynamicHighf)) :na
    c2 := length2!=0?label.new(bar_index, y=length2, text=str.tostring(length2, '#'), size=label_text_size, style=label.style_label_left, color=color.new(color.white,100), textcolor=color.new(color.aqua,0), tooltip="🔄 Cycle: 20 bar/2x\n💪 Dominant: " + str.tostring(length2, '#') + "\n📡 Search Range: " + str.tostring(DynamicLow2) + " to " + str.tostring(DynamicHigh2)) :na
    c4 := length4!=0?label.new(bar_index, y=length4, text=str.tostring(length4, '#'), size=label_text_size, style=label.style_label_left, color=color.new(color.white,100), textcolor=color.new(color.green,0), tooltip="🔄 Cycle: 40 bar/4x\n💪 Dominant: " + str.tostring(length4, '#') + "\n📡 Search Range: " + str.tostring(DynamicLow4) + " to " + str.tostring(DynamicHigh4)) :na
    c8 := length8!=0?label.new(bar_index, y=length8, text=str.tostring(length8, '#'), size=label_text_size, style=label.style_label_left, color=color.new(color.white,100), textcolor=color.new(color.yellow,0), tooltip="🔄 Cycle: 80 bar/8x\n💪 Dominant: " + str.tostring(length8, '#') + "\n📡 Search Range: " + str.tostring(DynamicLow8) + " to " + str.tostring(DynamicHigh8)) :na
    c16 := length16!=0?label.new(bar_index, y=length16, text=str.tostring(length16, '#'), size=label_text_size, style=label.style_label_left, color=color.new(color.white,100), textcolor=color.new(color.orange,0), tooltip="🔄 Cycle: 160 Bar (20 week)/16x\n💪 Dominant: " + str.tostring(length16, '#') + "\n📡 Search Range: " + str.tostring(DynamicLow16) + " to " + str.tostring(DynamicHigh16)) :na
    c32 := length32!=0?label.new(bar_index, y=length32, text=str.tostring(length32, '#'), size=label_text_size, style=label.style_label_left, color=color.new(color.white,100), textcolor=color.new(color.red,0), tooltip="🔄 Cycle: 320 Bar (40 week)/32x\n💪 Dominant: " + str.tostring(length32, '#') + "\n📡 Search Range: " + str.tostring(DynamicLow32) + " to " + str.tostring(DynamicHigh32)) :na

    label.delete(ch[1])
    label.delete(cf[1])
    label.delete(c2[1])
    label.delete(c4[1])
    label.delete(c8[1])
    label.delete(c16[1])
    label.delete(c32[1])

var table_position = dash_loc == 'Top Left' ? position.top_left :
  dash_loc == 'Bottom Left' ? position.bottom_left :
  dash_loc == 'Middle Right' ? position.middle_right :
  dash_loc == 'Middle Left' ? position.middle_left :
  dash_loc == 'Bottom Center' ? position.bottom_center :
  dash_loc == 'Top Center' ? position.top_center :
  dash_loc == 'Top Right' ? position.top_right : position.bottom_right

var table dcTypeDisplay = table.new(table_position, 1, 12)
if barstate.islast
    table.cell(dcTypeDisplay, 0, 0, text=str.tostring(dctype), text_color=title_col, text_size=label_text_size) //, tooltip="If you dont see the rainbow🌈, please double click here to check/update the settings.")

// EoS made w/ ❤ by @BarefootJoey ✌💗📈