HTF Oscillators RSI/ROC/MFI/CCI/AO - Dynamic Smoothing
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Harrocop

////////////////////////////////////////////////////////////////////////////////////////
// HTF Oscillator multy type filter - Dynamic Smoothing
// - Option to change high time frame settings
// - Option to choose from different oscillators (RSI/ROC/MFI/CCI/AO)
// - The Dynamic smoothing makes a sleek line, taking the ratio of minutes of the higher time frame to the current time frame
// - options for notification in case of crossover / crossunder of MACD
// - Includes a table of value of all Oscillators
////////////////////////////////////////////////////////////////////////////////////////

//@version=5
indicator("HTF Oscillators RSI/ROC/MFI/CCI/AO - Dynamic Smoothing", "HTF Oscillators", overlay = false)

//////////////////////////////////////////////////////
//////////         Input MACD HTF         ////////////
//////////////////////////////////////////////////////
OSCI_settings = "Higher Time Frame MACD Settings"
Osci_Type  = input.string(defval="RSI" , options=["RSI","ROC","MFI","CCI", "AO"], title="Oscillator type", inline = "1", group = OSCI_settings)
TimeFrame_OSCI = input.timeframe(title='Higher Time Frame', defval='30', inline = "1", group = OSCI_settings)
Length = input.int(14, title="Length # Bars HTF", minval=1, inline = "2", group = OSCI_settings)
LengthSmoothing = input.int(1, title="Smoothing SMA?", minval=1, inline = "2", group = OSCI_settings)
Plot_Bands = input.bool(true, title = "plot lower and upper band?", inline = "3", group = OSCI_settings)
middle_line = input.float(50, title = "Middle line plot", minval = -1000, maxval = 1000, step = 0.1, tooltip = "change accordingly to the Oscillator you are using", inline = "3", group = OSCI_settings)
overbought_level = input.float(70, title = "overbought level", minval = -1000, maxval = 1000, step = 0.1, tooltip = "change accordingly to the Oscillator you are using", inline = "4", group = OSCI_settings)
oversold_level = input.float(30, title = "oversold level", minval = -1000, maxval = 1000, step = 0.1, tooltip = "change accordingly to the Oscillator you are using", inline = "4", group = OSCI_settings)
Plot_Signal = input.bool(true, title = "Plot Signal?", inline = "5", group = OSCI_settings)

osci(type, src, length) =>
    float result = 0
    if type == 'RSI' // Relative Strength Index
        result := ta.rsi(src, length)
        result
    if type == 'ROC' // Rate of Change
        result := 100 * (src - src[length])/src[length]
        result
    if type == 'MFI'  // Money Flow Index
        result := ta.mfi(src, length)
        result
    if type == 'CCI'  // Commodity Channel Index
        result := (src -ta.sma(src, length)) / (0.015 * ta.dev(src, length))
        result
    if type == 'AO'  // Awesome Oscillator
        ao = ta.sma(hl2,5) - ta.sma(hl2,34)
        diff = ao - ao[1]
        result := diff
        result
    result

Oscillator_type = osci(Osci_Type, close, Length)
Osci_HTF = request.security(syminfo.ticker, TimeFrame_OSCI, Oscillator_type)


// Get minutes for current and higher timeframes
// Function to convert a timeframe string to its equivalent in minutes
timeframeToMinutes(tf) =>
    multiplier = 1
    if (str.endswith(tf, "D"))
        multiplier := 1440
    else if (str.endswith(tf, "W"))
        multiplier := 10080
    else if (str.endswith(tf, "M"))
        multiplier := 43200
    else if (str.endswith(tf, "H"))
        multiplier := int(str.tonumber(str.replace(tf, "H", "")))
    else
        multiplier := int(str.tonumber(str.replace(tf, "m", "")))
    multiplier

// Get minutes for current and higher timeframes
currentTFMinutes = timeframeToMinutes(timeframe.period)
higherTFMinutes = timeframeToMinutes(TimeFrame_OSCI)

// Calculate the smoothing factor
dynamicSmoothing = math.round(higherTFMinutes / currentTFMinutes)
Osci_HTF_Dynamic = ta.sma(Osci_HTF, dynamicSmoothing)
Osci_HTF_Smooth = ta.sma(Osci_HTF_Dynamic, LengthSmoothing)

// calc signals
LongCondition = ta.crossover(Osci_HTF_Smooth, oversold_level)
ShortCondition = ta.crossunder(Osci_HTF_Smooth, overbought_level)

/////////////////////////////////////////////////
///////////         Plots        ////////////////
/////////////////////////////////////////////////
hline(Plot_Bands ? middle_line : na, "Zero Line", color=color.new(#ffffff, 50))
upperband = plot(Plot_Bands ? overbought_level : na, "overbought level", color = color.orange)
lowerband = plot(Plot_Bands ? oversold_level : na, "oversold level", color = color.orange)
plot(Osci_HTF_Smooth, title="Oscillator", color=#7E57C2)
fill(upperband, lowerband, color=color.rgb(126, 87, 194, 90), title="Background Fill")

plot(Plot_Signal ? LongCondition ? oversold_level : na : na, "Long Condition", style = plot.style_circles, color = color.rgb(0, 255, 8), linewidth = 4)
plot(Plot_Signal ? ShortCondition ? overbought_level : na : na, "Short Condition", style = plot.style_circles, color = color.rgb(255, 0, 0), linewidth = 4)

// Oscillator Values for the table
RSI_value = request.security(syminfo.ticker, TimeFrame_OSCI, osci("RSI", close, Length))
ROC_value = request.security(syminfo.ticker, TimeFrame_OSCI, osci("ROC", close, Length))
MFI_value = request.security(syminfo.ticker, TimeFrame_OSCI, osci("MFI", close, Length))
CCI_value = request.security(syminfo.ticker, TimeFrame_OSCI, osci("CCI", close, Length))
AO_value = request.security(syminfo.ticker, TimeFrame_OSCI, osci("AO", close, Length))

// Create Table
var table panel = table.new("top_right", 2, 7) // Now, 7 rows: 1 for the header, 5 for the oscillators, and 1 for the HTF and TimeFrame

if barstate.islast // Only update the table on the last bar to minimize computation
    // Table Headers
    table.cell(panel, 0, 0, "Indicator", bgcolor=color.new(color.blue, 90), text_color=color.white, text_size = size.large)
    table.cell(panel, 1, 0, "Value", bgcolor=color.new(color.blue, 90), text_color=color.white, text_size = size.large)
    
    // HTF and TimeFrame
    table.cell(panel, 0, 1, "HTF_min", bgcolor=color.new(color.blue, 90), text_color=color.white, text_size = size.large)
    table.cell(panel, 1, 1, TimeFrame_OSCI, bgcolor=color.new(color.blue, 90), text_color=color.white, text_size = size.large)
    
    // RSI
    table.cell(panel, 0, 2, "RSI", bgcolor=color.new(color.gray, 70), text_color=color.white, text_size = size.large)
    table.cell(panel, 1, 2, str.tostring(RSI_value, format.mintick), bgcolor=color.new(color.gray, 90), text_color=color.white, text_size = size.large)
    
    // ROC
    table.cell(panel, 0, 3, "ROC", bgcolor=color.new(color.gray, 70), text_color=color.white, text_size = size.large)
    table.cell(panel, 1, 3, str.tostring(ROC_value, format.mintick), bgcolor=color.new(color.gray, 90), text_color=color.white, text_size = size.large)
    
    // MFI
    table.cell(panel, 0, 4, "MFI", bgcolor=color.new(color.gray, 70), text_color=color.white, text_size = size.large)
    table.cell(panel, 1, 4, str.tostring(MFI_value, format.mintick), bgcolor=color.new(color.gray, 90), text_color=color.white, text_size = size.large)

    // CCI
    table.cell(panel, 0, 5, "CCI", bgcolor=color.new(color.gray, 70), text_color=color.white, text_size = size.large)
    table.cell(panel, 1, 5, str.tostring(CCI_value, format.mintick), bgcolor=color.new(color.gray, 90), text_color=color.white, text_size = size.large)
    
    // AO
    table.cell(panel, 0, 6, "AO", bgcolor=color.new(color.gray, 70), text_color=color.white, text_size = size.large)
    table.cell(panel, 1, 6, str.tostring(AO_value, format.mintick), bgcolor=color.new(color.gray, 90), text_color=color.white, text_size = size.large)