OTT Collection
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © dg_factor [21.06.2023]

// ╠═══════════════════════════ Anıl Özekşi Library ═══════════════════════════╣

// 1) OTT            [31.05.2019]    Optimized Trend Tracker
// 2) TOTT           [01.05.2020]    Twin Ott (Ott Bands)
// 3) OTT CHANNEL    [19.03.2021]    Ott Channel (Half Channel & Fibonacci Channel)
// 4) RISOTTO        [16.04.2021]    Rsi-Ott 
// 5) SOTT           [18.04.2021]    Stochastic Ott
// 6) HOTT-LOTT      [06.03.2022]    Highest-Lowest Ott & Sum Version [07.04.2022] 
// 7) ROTT           [19.05.2022]    Relative Ott       
// 8) FT             [24.06.2022]    "Fırsatçı Trend"
// 9) RTR            [26.09.2022]    Relative True Range

// "TOTTO" and "OTTO" are not included in the script.
//      TOTTO and TOTT have the same calculations, the only difference is the length parameter.
//      OTTO has been created by another (K. H. Alpay).
// Special thanks to Kıvanç Özbilgiç for Pine Script design and calculation examples of OTT.

//@version=5
indicator("OTT Collection", precision=2)

// ╠═════════════════════════════════ Inputs ══════════════════════════════════╣

gr_sys = "╠═══════════════ SYSTEM ══════════════╣"
system = input.string(title="System ", defval="OTT", group=gr_sys, options=
  ["OTT", "TOTT", "OTT CHANNEL", "RISOTTO", "SOTT", "HOTT-LOTT", "ROTT", "FT", "RTR"])
tt_p = "Enable repating signals.\n" + 
  "(This option allows you to display consecutive signals in the same direction for TOTT & HOTT-LOTT. " + 
  "It also effects the colour of bars.)"
tt_bars = "Bars option is available for :\nOTT, TOTT, OTT CHANNEL, HOTT-LOTT, FT."  
pyr = input.bool(title="Pyramiding", defval=false, group=gr_sys, tooltip=tt_p)
gr_dis = "╠═══════════════ DISPLAY ══════════════╣"
sh_signal = input.bool(title="Signals    ", defval=true, group=gr_dis, inline="1")
sh_bar_color = input.bool(title="Barcolor    ", defval=true, group=gr_dis, inline="1")
sh_bar = input.bool(title="Bars", defval=true, group=gr_dis, inline="1", tooltip=tt_bars)
col_sup = #00bcd4
col_tar = #ff9800
col_l   = #00ff00
col_s   = #ff0000
col_n   = #333333

// ╔═══════════════════════════════════════════════════════════════════════════╗
// ║                                 FUNCTIONS                                 ║
// ╚═══════════════════════════════════════════════════════════════════════════╝

// ╠═══════════════════════════════════ VAR ═══════════════════════════════════╣

// Variable Index Dynamic Adaptive Moving Average - Tushar Chande
f_var(series float data, series int length) =>
    a = ta.sma(data, length)
    b = math.abs(ta.change(data, 9))                                                          // Momentum
    c = math.sum(math.abs(ta.change(data)), 9)                                                // Volatility
    d = c != 0 ? b / c : 0                                                                    // Efficiency Ratio
    e = 2 / (length + 1)
    r = 0.0, r := length == 1 ? data : na(r[1]) ? a : d * e * (data - nz(r[1])) + nz(r[1])    // Matriks design
    // r = 0.0, r := d * e * (data - nz(r[1])) + nz(r[1])                                     // Output used in previously published versions on Tradingview 
//

// ╠═══════════════════════════════════ OTT ═══════════════════════════════════╣

// Optimized Trend Tracker - Anıl Özekşi
f_ott(series float data, series float multiplier) =>
    a = multiplier / 100
    b = data * a, c = data - b, d = data + b
    c := c > nz(c[1]) or data < nz(c[1]) ? c : nz(c[1])
    d := d < nz(d[1]) or data > nz(d[1]) ? d : nz(d[1])
    e = 0.0, e := data > nz(e[1]) ? c : data < nz(e[1]) ? d : nz(e[1])    // MOST - by Anıl Özekşi :)
    f = 1 + a / 2
    g = 1 - a / 2
    h = data > e ? e * f : e * g
    r = nz(h[2])
//

// ╔═══════════════════════════════════════════════════════════════════════════╗
// ║                               CALCULATIONS                                ║
// ╚═══════════════════════════════════════════════════════════════════════════╝

// ╠═══════════════════════════════════ OTT ═══════════════════════════════════╣

// Inputs
string gr_ott = "╠═══════════════ OTT ════════════════╣"
ott_u = input.int(title="Length ", defval=20, step=5, group=gr_ott, tooltip="MA Length [20, 60]")
ott_k = input.float(title="Multiplier ", defval=1.5, step=0.1, group=gr_ott, tooltip="OTT Multiplier")

// Calcs
ott_support = f_var(close, ott_u)
ott_line    = f_ott(ott_support, ott_k)

// Signals
ott_long  = ott_support > ott_line    // ta.crossover(ott_support,  ott_line)
ott_short = ott_support < ott_line    // ta.crossunder(ott_support, ott_line)

// ╠══════════════════════════════════ TOTT ═══════════════════════════════════╣

// Inputs
string gr_tott = "╠═══════════════ TOTT ═══════════════╣"
tott_u  = input.int(title="Length ", defval=35, step=5, group=gr_tott, tooltip="MA Length [15, 45]")
tott_k1 = input.float(title="Multiplier ", defval=0.5, step=0.1, group=gr_tott, tooltip="OTT Multiplier [0.3, 0.6]")
tott_k2 = input.float(title="Band Multiplier ", defval=0.0006, step=0.0001, group=gr_tott, tooltip="[0.0004, 0.0006]")

// Calcs
tott_support = f_var(close, int(tott_u / 2))
tott_up      = f_ott(f_var(tott_support, 2), tott_k1) * (1 + tott_k2)
tott_dn      = f_ott(f_var(tott_support, 2), tott_k1) * (1 - tott_k2)

// Signals
tott_long  = tott_support > tott_up   // ta.crossover(tott_support,  tott_up)
tott_short = tott_support < tott_dn   // ta.crossunder(tott_support, tott_dn)

// ╠═══════════════════════════════ OTT CHANNEL ═══════════════════════════════╣

// Inputs
string gr_ottc = "╠════════════ OTT CHANNEL ════════════╣"
string ottc_t1 = "You can use this parameter to optimize '[Channel] Upper Line' manually."
string ottc_t2 = "You can use this parameter to optimize '[Channel] Lower Line' manually."
string ottc_t3 = "It is recommended to hide the channel levels to see the trends correctly while you're setting the manuel parameter optimization."
ottc_t  = input.string(title="Channel Type", defval="Half Channel", options=["Half Channel", "Fibonacci Channel", "Both"], group=gr_ottc)
ottc_u  = input.int(title="Length ", defval=2, group=gr_ottc, tooltip="MA Length")
ottc_k1 = input.float(title="Multiplier ", defval=1.4, group=gr_ottc, tooltip="OTT Multiplier")
ottc_k2 = input.float(title="Upper Line Multiplier", defval=0.01, step=0.01, group=gr_ottc, tooltip=ottc_t1)
ottc_k3 = input.float(title="Lower Line Multiplier", defval=0.01, step=0.01, group=gr_ottc, tooltip=ottc_t2)
ottc_h1 = input.bool(title="Hide Upper & Lower Lines", defval=false, group=gr_ottc)
ottc_h2 = input.bool(title="Hide Channel Lines", defval=false, group=gr_ottc, tooltip=ottc_t3)

// Ottc Mid Line
ottc_m = f_ott(f_var(close, ottc_u), ottc_k1)

// Channel Calcs
ottc_1 = ottc_m * (1 + ottc_k2)
ottc_2 = ottc_m * (1 + ottc_k2 * 0.618)
ottc_3 = ottc_m * (1 + ottc_k2 * 0.500)
ottc_4 = ottc_m * (1 + ottc_k2 * 0.382)
ottc_5 = ottc_m * (1 - ottc_k3 * 0.382)
ottc_6 = ottc_m * (1 - ottc_k3 * 0.500)
ottc_7 = ottc_m * (1 - ottc_k3 * 0.618)
ottc_8 = ottc_m * (1 - ottc_k3)

// Signals
// There're no any referenced conditions to generate signals for Ott Channel. 
// It is recommended to use Channels as support and resistance levels. 

// ╠═════════════════════════════════ RISOTTO ═════════════════════════════════╣

// Inputs
string gr_risotto = "╠═════════════ RISOTTO ═══════════════╣"
risotto_u1 = input.int(title="Length 1", defval=100, group=gr_risotto, tooltip="RSI Length") 
risotto_u2 = input.int(title="Length 2", defval=50, group=gr_risotto, tooltip="MA Length")
risotto_k  = input.float(title="Multiplier ", defval=0.2, group=gr_risotto, tooltip="OTT Multiplier")

// Calcs
risotto_support = f_var(ta.rsi(close, risotto_u1), risotto_u2) + 1000
risotto_line    = f_ott(f_var(risotto_support, 2), risotto_k)

// Signals
risotto_long  = risotto_support > risotto_line    // ta.crossover(risotto_support,  risotto_line)
risotto_short = risotto_support < risotto_line    // ta.crossunder(risotto_support, risotto_line)

// ╠══════════════════════════════════ SOTT ═══════════════════════════════════╣

// Inputs
string gr_sott = "╠═══════════════ SOTT ═══════════════╣"
sott_u1 = input.int(title="Length 1", defval=500, group=gr_sott, tooltip="Stochastic %k Length") 
sott_u2 = input.int(title="Length 2", defval=200, group=gr_sott, tooltip="Stochastic %d Length")
sott_k  = input.float(title="Multiplier ", defval=0.5, group=gr_sott, tooltip="OTT Multiplier")

// Calcs
sott_support = f_var(ta.stoch(close, high, low, sott_u1), sott_u2) + 1000
sott_line    = f_ott(f_var(sott_support, 2), sott_k)

// Signals
sott_long  = sott_support > sott_line   // ta.crossover(sott_support,  sott_line)
sott_short = sott_support < sott_line   // ta.crossunder(sott_support, sott_line)

// ╠═══════════════════════════════ HOTT & LOTT ═══════════════════════════════╣

// Inputs
string gr_hl = "╠════════════ HOTT & LOTT ═════════════╣"
string hl_t1 = "If you activate this option, signals will be generated according to the confirmation concept for N bars. \n\n" + 
  "Long : If the 'High' price is higher than Hott for N bars.\n\n" +
  "Short : If the 'Low' price is lower than Lott for N bars."
hl_u     = input.int(title="Length ", defval=10, step=5, group=gr_hl, tooltip="ta.highest() & ta.lowest() Length\n[10, 30]")
hl_k     = input.float(title="Multiplier ", defval=0.6, step=0.1, group=gr_hl, tooltip="OTT Multiplier [0.3, 0.6]")
hl_sum   = input.bool(title="Sum N bars", defval=false, group=gr_hl, inline="1")
hl_sum_n = input.int(title="          ", defval=3, group=gr_hl, inline="1", tooltip=hl_t1)

// Calcs
hott = f_ott(f_var(ta.highest(hl_u), 2), hl_k)
lott = f_ott(f_var(ta.lowest(hl_u),  2), hl_k)

// Signals
hl_long  = not hl_sum ? high > hott : math.sum(high > hott ? 1 : 0, hl_sum_n) == hl_sum_n   // ta.crossover(high, hott)
hl_short = not hl_sum ? low  < lott : math.sum(low  < lott ? 1 : 0, hl_sum_n) == hl_sum_n   // ta.crossunder(low, lott)

// ╠══════════════════════════════════ ROTT ═══════════════════════════════════╣

// Inputs
string gr_rott = "╠═══════════════ ROTT ═══════════════╣"
rott_u = input.int(title="Length ", defval=200, group=gr_rott, tooltip="MA Length [100, 300]")
rott_k = input.float(title="Multiplier ", defval=1.0, group=gr_rott, tooltip="OTT Multiplier")

// Calcs
rott_support = f_var(close, rott_u) * 2
rott_line    = f_ott(f_var(rott_support, 2), rott_k)

// Signals
rott_long  = rott_support > rott_line   // ta.crossover(rott_support,  rott_line)
rott_short = rott_support < rott_line   // ta.crossunder(rott_support, rott_line)

// ╠═══════════════════════════════════ FT ════════════════════════════════════╣

// Inputs
string gr_ft = "╠════════════════ FT ════════════════╣"
ft_u  = input.int(title="Length ", defval=30, step=10, group=gr_ft, tooltip="MA Length [20, 40]")
ft_k1 = input.float(title="Major Multiplier", defval=3.6, group=gr_ft, tooltip="Major OTT Multiplier")
ft_k2 = input.float(title="Minor Multiplier", defval=1.8, group=gr_ft, tooltip="Minor OTT Multiplier")

// Calcs
ft_support   = f_var(close, ft_u)
major_trend  = f_ott(ft_support, ft_k1)
minor_trend  = f_ott(ft_support, ft_k2)
ft_line      = (minor_trend + (2 * minor_trend - major_trend)[100]) / 2

// Signals
ft_long  = ft_support > ft_line   // ta.crossover(ft_support,  ft_line)
ft_short = ft_support < ft_line   // ta.crossunder(ft_support, ft_line)

// ╠═══════════════════════════════════ RTR ═══════════════════════════════════╣

// Inputs
string gr_rtr = "╠═══════════════ RTR ════════════════╣"
rtr_u1 = input.int(title="Length 1", defval=10, group=gr_rtr, tooltip="ATR Length [10, 20]")
rtr_u2 = input.int(title="Length 2", defval=200, group=gr_rtr, tooltip="MA Length [200, 500]")

// Calcs
rtr_line = close / f_var(close / ta.atr(rtr_u1), rtr_u2)

// Signals
// There're no any referenced conditions to generate signals for Relative True Range. 
// It is recommended to use RTR as a volatility indicator.

// ╔═══════════════════════════════════════════════════════════════════════════╗
// ║                                  RETURN                                   ║
// ╚═══════════════════════════════════════════════════════════════════════════╝

// ╠═════════════════════════════ Support & Lines ═════════════════════════════╣

_support = 
  system == "OTT"     ? ott_support     :  
  system == "TOTT"    ? tott_support    :  
  system == "RISOTTO" ? risotto_support : 
  system == "SOTT"    ? sott_support    : 
  system == "ROTT"    ? rott_support    : 
  system == "FT"      ? ft_support      : 
  na
//

_target = 
  system == "OTT"     ? ott_line     :
  system == "RISOTTO" ? risotto_line :
  system == "SOTT"    ? sott_line    :
  system == "ROTT"    ? rott_line    :
  system == "FT"      ? ft_line      :
  system == "RTR"     ? rtr_line     :
  na
//

_line_up = 
  system == "TOTT"      ? tott_up :  
  system == "HOTT-LOTT" ? hott    : 
  na
//

_line_dn = 
  system == "TOTT"      ? tott_dn :  
  system == "HOTT-LOTT" ? lott    : 
  na
//

// ╠═════════════════════════════════ Signals ═════════════════════════════════╣

long = 
  system == "OTT"       ? ott_long     : 
  system == "TOTT"      ? tott_long    : 
  system == "RISOTTO"   ? risotto_long : 
  system == "SOTT"      ? sott_long    : 
  system == "HOTT-LOTT" ? hl_long      : 
  system == "ROTT"      ? rott_long    : 
  system == "FT"        ? ft_long      : 
  na
//

short = 
  system == "OTT"       ? ott_short     : 
  system == "TOTT"      ? tott_short    : 
  system == "RISOTTO"   ? risotto_short : 
  system == "SOTT"      ? sott_short    : 
  system == "HOTT-LOTT" ? hl_short      : 
  system == "ROTT"      ? rott_short    : 
  system == "FT"        ? ft_short      : 
  na
//

// Fix Signal
var bool l = na
var bool s = na
ls = not s and long
ss = not l and short
if ls
    l := false
    s := true
if ss
    l := true
    s := false
int dir = 0
dir := pyr ? long ? 1 : short ? -1 : 0 : ls ? 1 : ss ? -1 : nz(dir[1])
long_signal  = pyr ? not long[1]  and long  : ls 
short_signal = pyr ? not short[1] and short : ss 
total_signals = ta.cum(long_signal or short_signal ? 1 : 0)

// ╠═══════════════════════════════ Plotshapes ════════════════════════════════╣

plotshape(sh_signal ? long_signal : na,  "Long Signal",  shape.triangleup,   location.bottom, col_l, size=size.tiny)
plotshape(sh_signal ? short_signal : na, "Short Signal", shape.triangledown, location.top,    col_s, size=size.tiny)

// ╠══════════════════════════ Plot Support & Lines ═══════════════════════════╣

plot(_support, color=col_sup, title="Support ")
plot(_target,  color=col_tar, title="Target")
plot(_line_up, color=#00bb00, title="Upper Line")
plot(_line_dn, color=#fb0000, title="Lower Line")

// ╠══════════════════════════════ Plot Channels ══════════════════════════════╣

bool ottc_none = system != "OTT CHANNEL"
bool ottc_half = ottc_t == "Both" or ottc_t == "Half Channel"
bool ottc_fibo = ottc_t == "Both" or ottc_t == "Fibonacci Channel"

plot(ottc_none or ottc_h1 ? na : ottc_1,                  color=#00bb00, title="[Channel] Upper Line")
plot(ottc_none or ottc_h2 ? na : ottc_fibo ? ottc_2 : na, color=#8c00ff, title="[Channel] ⮝ 0.618") 
plot(ottc_none or ottc_h2 ? na : ottc_half ? ottc_3 : na, color=#00bcd4, title="[Channel] ⮝ Half Line")
plot(ottc_none or ottc_h2 ? na : ottc_fibo ? ottc_4 : na, color=#1848cc, title="[Channel] ⮝ 0.382")
plot(ottc_none or ottc_h2 ? na : ottc_m,                  color=#787B86, title="[Channel] Mid Line")
plot(ottc_none or ottc_h2 ? na : ottc_fibo ? ottc_5 : na, color=#945100, title="[Channel] ⮟ 0.382")
plot(ottc_none or ottc_h2 ? na : ottc_half ? ottc_6 : na, color=#ff9800, title="[Channel] ⮟ Half Line")
plot(ottc_none or ottc_h2 ? na : ottc_fibo ? ottc_7 : na, color=#a4a600, title="[Channel] ⮟ 0.618")
plot(ottc_none or ottc_h1 ? na : ottc_8,                  color=#fb0000, title="[Channel] Lower Line")

// ╠════════════════════════════════ Barcolor ═════════════════════════════════╣

no_color = system == "OTT CHANNEL" or system == "RTR"
bar_color = 
  no_color ? na : 
  dir == 1 ? col_l : dir == -1 ? col_s : col_n
barcolor(sh_bar_color ? bar_color : na, title="Barcolor")

// ╠═══════════════════════════════ Plotcandle ════════════════════════════════╣

no_bars = system == "RISOTTO" or system == "SOTT" or system == "ROTT" or system == "RTR"  
candle_color = close>open ? #08998175 : close<open ? #f2364575 : #33333375
plotshape(barstate.isfirst, title="╠═════ OHLC ═════╣", location=location.bottom, color=#00000000, editable=false) 
plotcandle(
  no_bars ? na : sh_bar ? open  : na, 
  no_bars ? na : sh_bar ? high  : na, 
  no_bars ? na : sh_bar ? low   : na, 
  no_bars ? na : sh_bar ? close : na, 
  title="Bars", color=candle_color, bordercolor=candle_color, wickcolor=candle_color)
//

// ╠═══════════════════════════════ Parameters ════════════════════════════════╣

p_ott = 
  "Length : " + str.tostring(ott_u) + "\n\n" + 
  "Multiplier : " + str.tostring(ott_k)
p_tott = 
  "Length : " + str.tostring(tott_u) + "\n\n" + 
  "Multiplier : " + str.tostring(tott_k1) + "\n\n" + 
  "Band Multiplier : " + str.tostring(tott_k2)
p_ottc = 
  "Length : " + str.tostring(ottc_u) + "\n\n" +  
  "Multiplier : " + str.tostring(ottc_k1) + "\n\n" + 
  "Upper Line Multiplier : " + str.tostring(ottc_k2) + "\n\n" + 
  "Lower Line Multiplier : " + str.tostring(ottc_k3)
p_risotto = 
  "Rsi Length : " + str.tostring(risotto_u1) + "\n\n" + 
  "Ott Length : " + str.tostring(risotto_u2) + "\n\n" + 
  "Multplier : " + str.tostring(risotto_k) 
p_sott = 
  "Stochastic %k Length : " + str.tostring(sott_u1) + "\n\n" + 
  "Stochastic %d Length : " + str.tostring(sott_u2) + "\n\n" + 
  "Multplier : " + str.tostring(sott_k)    
pp_sum = 
  hl_sum ? "Sum Option : On" + "\n\n" + "Sum N Bars : " + str.tostring(hl_sum_n) : "" 
p_hl = 
  "Length : " + str.tostring(hl_u) + "\n\n" +     
  "Multiplier : " + str.tostring(hl_k) + "\n\n" +
  pp_sum
p_rott = 
  "Length : " + str.tostring(rott_u)+ "\n\n" +
  "Multiplier : " + str.tostring(rott_k)
p_ft = 
  "Length : " + str.tostring(ft_u) + "\n\n" +
  "Major Multiplier : " + str.tostring(ft_k1) + "\n\n" +
  "Minor Multiplier : " + str.tostring(ft_k2)
p_rtr = 
  "Atr Length : " + str.tostring(rtr_u1) + "\n\n" +
  "Var Length : " + str.tostring(rtr_u2)
//

parameter = 
  system == "OTT"         ? p_ott     : 
  system == "TOTT"        ? p_tott    : 
  system == "OTT CHANNEL" ? p_ottc    : 
  system == "RISOTTO"     ? p_risotto : 
  system == "SOTT"        ? p_sott    : 
  system == "HOTT-LOTT"   ? p_hl      : 
  system == "ROTT"        ? p_rott    : 
  system == "FT"          ? p_ft    : 
  system == "RTR"         ? p_rtr     : 
  na
//

// ╠══════════════════════════════════ Table ══════════════════════════════════╣

var tb = table.new(position.top_right, 1, 10)
if barstate.islast
    table.cell(tb, 0, 0, ottc_none ? "\n\n" + system : "\n\n" + system + "\n\n[" + ottc_t + "]", text_color=color.blue, text_halign=text.align_left)
    table.cell(tb, 0, 1, parameter, text_color=#686868, text_halign=text.align_left)
    table.cell(tb, 0, 2, "\n\nChart Info", text_color=color.blue, text_halign=text.align_left)
    table.cell(tb, 0, 3, "Bars : " + str.tostring(bar_index + 1), text_color=#686868, text_halign=text.align_left)
    table.cell(tb, 0, 4, "Signals : " + str.tostring(total_signals), text_color=#686868, text_halign=text.align_left)
//

// Direction
plot(dir, title="Direction", display=display.data_window, editable=false)

// Bitti :)
plotshape(barstate.isfirst, title="@ dg_factor", location=location.bottom, color=#00000000, editable=false) 
