HelperFunctions
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © cryptofnq

//@version=5
// @description apply one of Pine Script's built-in smoothing or oscillator functions to a series
library("HelperFunctions", false)

// @function Apply a built-in smoothing function to a series.
// @param method string One of['ema', 'sma', 'wma', 'vwma', 'rma', 'hma', 'none']
// @param length int The number of bars to use for the smoothing function
// @param source series The series to smooth 
// @returns A smoothed series based on the input source

export apply_smoothing(simple string method='ema', float source=hl2, simple int length=2) =>
    smoothed = switch method
        'ema' => ta.ema(source, length)
        'sma' => ta.sma(source, length)
        'wma' => ta.wma(source, length)
        'vwma' => ta.vwma(source, length)
        'rma' => ta.rma(source, length)
        'hma'  => ta.hma(source, length) 

// @function Create a basic oscillator that requres no input.
// @param method string One of ['wvad', 'iii']
// @returns A series which oscillates around zero


export create_basic_oscillator(simple string method='wvad') =>
    oscillator = switch method
        // Williams Variable Accumulation/Distribution
        'wvad' => ta.wvad
        // Intraday Intensity Index
        // adjusted to be between -1 and +1
        'iii' => ta.iii * 1000




// @function Create a simple oscillator from a series.
// @param method string One of ['wpr']
// @param length int The number of bars to use in oscillator calculation
// @returns A series which oscillates around zero


export create_simple_oscillator(simple string method='wpr', simple int length=5) =>
    oscillator = switch method
        // Williams %R returns values between 0 and -100
        // centre the oscillator by adding 50
        'wpr' => ta.wpr(length) + 50


      


// @function Create a single length oscillator from a series.
// @param method string One of ['change', 'cmo', 'rank', 'roc', 'rsi']
// @param source series The series on which to base the oscillator
// @param length int The number of bars to use in oscillator calculation
// @returns A series which oscillates around zero


export create_single_oscillator(simple string method='rsi', float source=close, simple int length=5) =>
    
    oscillator = switch method
        // Relative Strength Index
        // centre oscillator on zero
        'rsi' =>ta.rsi(source, length) - 50
        // Rate Of Change
        'roc' => ta.roc(source, length)
        // Percent of previous bars less than current
        // centre oscillator on zero
        'rank' => ta.percentrank(source, length) - 50
        // Chande Momentum Oscillator
        'cmo' => ta.cmo(source, length)
        // Change over the length
        'change' => ta.change(source, length)





// @function Create a dual length oscillator from a series.
// @param method string One of ['tsi']
// @param src series The series on which to base the oscillator
// @param fastLength int The number of bars to use in fast oscillator calculation
// @param slowLength int The number of bars to use in slow oscillator calculation
// @returns A series which oscillates around zero


export create_dual_oscillator(simple string method='tsi', float source=hl2, simple int fastLength=5, simple int slowLength=10) =>
    oscillator = switch method 
        // True Strength Index
        'tsi' => ta.tsi(source, fastLength, slowLength)




var srcTip = 'Select the series to be the base of the oscillator'
src = input.source(close,'Source', tooltip = srcTip, group = 'Global')

functionTypeTip = 'Select either oscillator or smoothing and define a method below'
functionType = input.string('smoothing', 'Function Type', ['smoothing', 'oscillator'], group = 'Global')
smoothingMethod = input.string('ema', 'Method', ['ema', 'sma', 'wma', 'vwma', 'rma', 'hma'], inline='smoothing', group = 'Smoothing')

smoothingLengthTip = 'How many bars to use in the smoothing calculations'
smoothingLength = input.int(5, 'Length', minval=2, inline='smoothing', group = 'Smoothing', tooltip = smoothingLengthTip)


oscillatorMethodTip = 'Select the type of oscillator to create, each type requires different inputs: "wvad" & "iii" require no inputs. "wpr" requires a length. "change", "cmo", "obv", "rank", "roc" & "rsi" require a length and a source. "tsi" requires two lengths and a source.'


oscillatorMethod  = input.string('rsi', 'Method', ['wvad', 'iii', 'wpr', 'change', 'cmo', 'rank', 'roc', 'rsi', 'tsi'], tooltip=oscillatorMethodTip, group = 'Oscillator')



oscillatorLengthTip = 'Select the number of bars to use in the oscillator calculation'
oscillatorLength = input.int(5, 'Length', minval=1, tooltip=oscillatorLengthTip, group = 'Simple & Single Oscillator')

oscillatorFastLength = input.int(5, 'Fast Length', minval=1, tooltip=oscillatorLengthTip, inline='dual', group = 'Dual Length Oscillator')
oscillatorSlowLength = input.int(10, 'Slow Length', minval=1, tooltip=oscillatorLengthTip, inline='dual', group = 'Dual Length Oscillator')



plotSeries = switch functionType
    'smoothing' => apply_smoothing(smoothingMethod, src, smoothingLength)
    'oscillator' =>
        if oscillatorMethod == 'wvad' or oscillatorMethod == 'iii' or oscillatorMethod == 'obv'
            create_basic_oscillator(oscillatorMethod)
        else if oscillatorMethod == 'wpr'
            create_simple_oscillator(oscillatorMethod, oscillatorLength)
        else if oscillatorMethod == 'change' or oscillatorMethod == 'cmo' or oscillatorMethod == 'rank' or oscillatorMethod == 'roc' or oscillatorMethod == 'rsi'
            create_single_oscillator(oscillatorMethod, src, oscillatorLength)
        else if oscillatorMethod == 'tsi'
            create_dual_oscillator(oscillatorMethod, src, oscillatorFastLength, oscillatorSlowLength)
        else
            create_single_oscillator(oscillatorMethod, src, oscillatorLength)
        


plot(plotSeries, color=color.blue, title='Helper Function Plot')



