KINSKI Multi Trend Oscillator
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © KINSKI

//@version=5
indicator('KINSKI Multi Trend Oscillator', shorttitle='Multi Trend Oscillator', format=format.price, precision=2, overlay=false)


//************  Colors
color valColorsUpTrendHistogram = #007007, color valColorsUpTrendStrongHistogram = #00FF11, color valColorsUpWeakHistogram = #007a08, color valColorsUpTrendStrongHintHistogram = #e8be00
color valColorsDownTrendHistogram = #8A0002, color valColorsDownTrendStrongHistogram = #FF0004, color valColorsDownTrendWeakHistogram = #750001

color valColorsUpTrend = #003307, color valColorsUpTrendStrong = #00610d, color valColorsUpTrendStrongHint = #615100
color valColorsDownTrend = #330000, color valColorsDownTrendStrong = #610000

color valColorsNeutral = #4f4f4f, color valColorMA = #9900FF


//********** Functions
_funcPercent(_val, _different) =>
    100 * _val / _different

// Calculate Uptrend/Downtrend Volume
_funcRate(_cond, _cwT, _cwB, _cwBody) =>
    _tmp = 0.5 * (_cwT + _cwB + (_cond ? 2 * _cwBody : 0)) / (_cwT + _cwB + _cwBody)
    na(_tmp) ? 0.5 : _tmp

// Calculate Regression Slope for Uptrend/Downtrend Volumes
_funcTrend(_len, _cwT, _cwB, _cwBody) =>
    _tmpUp = volume * _funcRate(open <= close, _cwT, _cwB, _cwBody)
    _tmpDown = volume * _funcRate(open > close, _cwT, _cwB, _cwBody)

    volumeUp = ta.linreg(_tmpUp, _len, 0) - ta.linreg(_tmpUp, _len, 1)
    volumeDown = ta.linreg(_tmpDown, _len, 0) - ta.linreg(_tmpDown, _len, 1)
    [volumeUp, volumeDown]

_funcGetBuySell(_val, _levelOverBought, _levelOverSold) =>
    tmpIsUptrend = _val > _val[1]
    tmpRuleBuy = (ta.crossover(_val, _levelOverBought) or (_val < _levelOverSold or _val < _levelOverBought)) and (tmpIsUptrend)
    tmpRuleSell = (ta.crossunder(_val, _levelOverBought) or (_val >= _levelOverBought)) and not tmpIsUptrend
    [tmpRuleBuy, tmpRuleSell, tmpIsUptrend]

_funcCalcHistogramColor(_val) =>
    conditionColors_1 = _val > nz(_val[1]) ? valColorsUpTrendStrongHistogram : valColorsUpTrendHistogram
    conditionColors_2 = _val < nz(_val[1]) ? valColorsDownTrendStrongHistogram : valColorsDownTrendHistogram
    (_val == -0.00 or _val == 0.00) ? valColorsNeutral : _val > 0 ? conditionColors_1 : conditionColors_2

_funcCalcRating(_buy, _sell) =>
    int tmpRating = 0
    color tmpRatingColorTable = valColorsNeutral
    string tmpRatingStatus = "Neutral"

    if _buy
        tmpRating := 1
        tmpRatingStatus := "Uptrend"
        tmpRatingColorTable := valColorsUpTrend
    else if _sell
        tmpRating := 0
        tmpRatingStatus := "Downtrend"
        tmpRatingColorTable := valColorsDownTrend

    [tmpRating, tmpRatingStatus, tmpRatingColorTable]

_funcCalcRatingTotalCompare(_ratingMaxCount, _ratingThresholdSellStrong, _ratingThresholdNeutralStart, _ratingThresholdNeutralEnd, _ratingThresholdBuyStrong) =>
    _tmpCompareSellStrong = _ratingMaxCount * _ratingThresholdSellStrong
    _tmpCompareMidStart = _ratingMaxCount * _ratingThresholdNeutralStart
    _tmpCompareMidEnd = _ratingMaxCount * _ratingThresholdNeutralEnd
    _tmpCompareBuyStrong = _ratingMaxCount * _ratingThresholdBuyStrong
    [_tmpCompareSellStrong, _tmpCompareMidStart, _tmpCompareMidEnd, _tmpCompareBuyStrong]

_funcCalcRatingTotalStatus(_rating, _ratingMaxCount, _histogram, _ratingThresholdSellStrong, _ratingThresholdNeutralStart, _ratingThresholdNeutralEnd, _ratingThresholdBuyStrong) =>
    [_tmpCompareSellStrong, _tmpCompareMidStart, _tmpCompareMidEnd, _tmpCompareBuyStrong] = _funcCalcRatingTotalCompare(_ratingMaxCount, _ratingThresholdSellStrong, _ratingThresholdNeutralStart, _ratingThresholdNeutralEnd, _ratingThresholdBuyStrong)

    color tmpRatingColor = valColorsNeutral
    color tmpRatingColorTable = valColorsNeutral
    string tmpRatingStatus = "Neutral"

    float prevRating = nz(_rating[1])
    bool isInNeutralRange = _rating >= _tmpCompareMidStart and _rating <= _tmpCompareMidEnd

    if isInNeutralRange
        tmpRatingStatus := tmpRatingStatus
        tmpRatingColorTable := tmpRatingColorTable
        tmpRatingColor := tmpRatingColor
    else if _rating >= _tmpCompareBuyStrong and _rating > _tmpCompareMidEnd
        tmpPrevSame = prevRating >= _tmpCompareBuyStrong
        tmpRatingStatus := tmpPrevSame ? "Strong Uptrend\nBut Downtrend coming" : "Strong Uptrend"
        tmpRatingColorTable := tmpPrevSame ? valColorsUpTrendStrongHint : valColorsUpTrendStrong
        tmpRatingColor := tmpPrevSame ? valColorsUpTrendStrongHintHistogram : valColorsUpTrendStrongHistogram
    else if _rating < _tmpCompareBuyStrong and _rating > _tmpCompareMidEnd
        tmpRatingStatus := "Uptrend"
        tmpRatingColorTable := valColorsUpTrend
        tmpRatingColor := valColorsUpTrendHistogram
    else if _rating <= _tmpCompareSellStrong and _rating < _tmpCompareMidStart
        tmpRatingStatus := "Strong Downtrend"
        tmpRatingColorTable := valColorsDownTrendStrong
        tmpRatingColor := valColorsDownTrendStrongHistogram
    else if _rating > _tmpCompareSellStrong and _rating < _tmpCompareMidStart
        tmpRatingStatus := "Downtrend"
        tmpRatingColorTable := valColorsDownTrend
        tmpRatingColor := valColorsDownTrendHistogram

    [tmpRatingColor, tmpRatingColorTable, tmpRatingStatus]

// Smoothed Moving Average (SMMA)
_funcSMMA(_src, _len) =>
    tmpSMA = ta.sma(_src, _len)
    tmpVal = 0.0
    na(tmpVal[1]) ? tmpSMA : (tmpVal[1] * (_len - 1) + _src) / _len

// Triple EMA (TEMA)
_funcTEMA(_src, _len) =>
    ema1 = ta.ema(_src, _len)
    ema2 = ta.ema(ema1, _len)
    ema3 = ta.ema(ema2, _len)
    3 * (ema1 - ema2) + ema3

// Double Expotential Moving Average (DEMA)
_funcDEMA(_src, _len) =>
    2 * ta.ema(_src, _len) - ta.ema(ta.ema(_src, _len), _len)

// Exponential Hull Moving Average (EHMA)
_funcEHMA(_src, _len) =>
    tmpVal = math.max(2, _len)
    ta.ema(2 * ta.ema(_src, tmpVal / 2) - ta.ema(_src, tmpVal), math.round(math.sqrt(tmpVal)))

// Kaufman's Adaptive Moving Average (KAMA)
_funcKAMA(_src, _len) =>
    tmpVal = 0.0
    sum_1 = math.sum(math.abs(_src - _src[1]), _len)
    sum_2 = math.sum(math.abs(_src - _src[1]), _len)
    nz(tmpVal[1]) + math.pow((sum_1 != 0 ? math.abs(_src - _src[_len]) / sum_2 : 0) * (0.666 - 0.0645) + 0.0645, 2) * (_src - nz(tmpVal[1]))

// Variable Index Dynamic Average (VIDYA)
_funcVIDYA(_src, _len) =>
    _diff = ta.change(_src)
    _uppperSum = math.sum(_diff > 0 ? math.abs(_diff) : 0, _len)
    _lowerSum = math.sum(_diff < 0 ? math.abs(_diff) : 0, _len)
    _chandeMomentumOscillator = (_uppperSum - _lowerSum) / (_uppperSum + _lowerSum)
    _factor = 2 / (_len + 1)
    tmpVal = 0.0
    _src * _factor * math.abs(_chandeMomentumOscillator) + nz(tmpVal[1]) * (1 - _factor * math.abs(_chandeMomentumOscillator))

// Coefficient of Variation Weighted Moving Average (COVWMA)
_funcCOVWMA(_src, _len) =>
    _coefficientOfVariation = ta.stdev(_src, _len) / ta.sma(_src, _len)
    _cw = _src * _coefficientOfVariation
    math.sum(_cw, _len) / math.sum(_coefficientOfVariation, _len)

// Fractal Adaptive Moving Average (FRAMA)
_funcFRAMA(_src, _len) =>
    _coefficient = -4.6
    _n3 = (ta.highest(high, _len) - ta.lowest(low, _len)) / _len
    _hd2 = ta.highest(high, _len / 2)
    _ld2 = ta.lowest(low, _len / 2)
    _n2 = (_hd2 - _ld2) / (_len / 2)
    _n1 = (_hd2[_len / 2] - _ld2[_len / 2]) / (_len / 2)
    _dim = _n1 > 0 and _n2 > 0 and _n3 > 0 ? (math.log(_n1 + _n2) - math.log(_n3)) / math.log(2) : 0
    _alpha = math.exp(_coefficient * (_dim - 1))
    _sc = _alpha < 0.01 ? 0.01 : _alpha > 1 ? 1 : _alpha
    ta.cum(1) <= 2 * _len ? _src : _src * _sc + nz(_src[1]) * (1 - _sc)

// Karobein
_funcKarobein(_src, _len) =>
    tmpMA = ta.ema(_src, _len)
    tmpUpper  = ta.ema(tmpMA < tmpMA[1] ? tmpMA/tmpMA[1] : 0, _len)
    tmpLower  = ta.ema(tmpMA > tmpMA[1] ? tmpMA/tmpMA[1] : 0, _len)
    tmpRescaleResult  = (tmpMA/tmpMA[1]) / (tmpMA/tmpMA[1] + tmpLower)
    (2*((tmpMA/tmpMA[1]) / (tmpMA/tmpMA[1] + tmpRescaleResult * tmpUpper)) - 1) * 100

// RSX based Noise Remover based Noise Remover
_funcRemoveNoise(_src, _len) =>
    f8 = 100 * _src
    f10 = nz(f8[1])
    v8 = f8 - f10

    f18 = 3 / (_len + 2)
    f20 = 1 - f18

    f28 = 0.0
    f28 := f20 * nz(f28[1]) + f18 * v8

    f30 = 0.0
    f30 := f18 * f28 + f20 * nz(f30[1])
    vC = f28 * 1.5 - f30 * 0.5

    f38 = 0.0
    f38 := f20 * nz(f38[1]) + f18 * vC

    f40 = 0.0
    f40 := f18 * f38 + f20 * nz(f40[1])
    v10 = f38 * 1.5 - f40 * 0.5

    f48 = 0.0
    f48 := f20 * nz(f48[1]) + f18 * v10

    f50 = 0.0
    f50 := f18 * f48 + f20 * nz(f50[1])
    v14 = f48 * 1.5 - f50 * 0.5

    f58 = 0.0
    f58 := f20 * nz(f58[1]) + f18 * math.abs(v8)

    f60 = 0.0
    f60 := f18 * f58 + f20 * nz(f60[1])
    v18 = f58 * 1.5 - f60 * 0.5

    f68 = 0.0
    f68 := f20 * nz(f68[1]) + f18 * v18

    f70 = 0.0
    f70 := f18 * f68 + f20 * nz(f70[1])
    v1C = f68 * 1.5 - f70 * 0.5

    f78 = 0.0
    f78 := f20 * nz(f78[1]) + f18 * v1C

    f80 = 0.0
    f80 := f18 * f78 + f20 * nz(f80[1])
    v20 = f78 * 1.5 - f80 * 0.5

    f88_ = 0.0
    f90_ = 0.0

    f88 = 0.0
    f90_ := nz(f90_[1]) == 0 ? 1 : nz(f88[1]) <= nz(f90_[1]) ? nz(f88[1]) + 1 : nz(f90_[1]) + 1
    f88 := nz(f90_[1]) == 0 and _len - 1 >= 5 ? _len - 1 : 5

    f0 = f88 >= f90_ and f8 != f10 ? 1 : 0
    f90 = f88 == f90_ and f0 == 0 ? 0 : f90_

    v4_ = f88 < f90 and v20 > 0 ? (v14 / v20 + 1) * 50 : 50
    v4_ > 100 ? 100 : v4_ < 0 ? 0 : v4_

// calculate the moving average with the transferred settings
_funcCalcMA(_type, _src, _len) =>
    float ma = switch _type
        "COVWMA" => _funcCOVWMA(_src, _len)
        "DEMA" => _funcDEMA(_src, _len)
        "EMA" => ta.ema(_src, _len)
        "EHMA" => _funcEHMA(_src, _len)
        "HMA" => ta.hma(_src, _len)
        "KAMA" => _funcKAMA(_src, _len)
        "RMA" => ta.rma(_src, _len)
        "RSX based Noise Remover" => _funcRemoveNoise(_src, _len)
        "SMA" => ta.sma(_src, _len)
        "SMMA" => _funcSMMA(_src, _len)
        "TEMA" => _funcTEMA(_src, _len)
        "FRAMA" => _funcFRAMA(_src, _len)
        "VWMA" => ta.vwma(_src, _len)
        "VIDYA" => _funcVIDYA(_src, _len)
        "WMA" => ta.wma(_src, _len)
        "Karobein" => _funcKarobein(_src, _len)
        =>
            float(na)

_funcGetVal(_val, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased) =>
    tmpVal = _enableStochasticBased ? ta.sma(ta.stoch(_val, _val, _val, _len), 3) : _val
    tmpValAlternative = _smoothingType != 'DISABLED' ? _funcCalcMA(_smoothingType, tmpVal, _smoothingPeriod) : tmpVal
    _smoothingType != 'DISABLED' ? tmpValAlternative : tmpVal

_funcGetFinalVal(_src, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold) =>
    tmpValFinal = _funcGetVal(_src, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased)

    [tmpRuleBuy, tmpRuleSell, tmpIsUptrend] = _funcGetBuySell(tmpValFinal, levelOverBought, levelOverSold)
    [tmpRating, tmpRatingStatus, tmpRatingColorTable] = _funcCalcRating(tmpRuleBuy, tmpRuleSell)

    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable]

_funcGetFinalValNullLine(_src, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased) =>
    tmpValFinal = _funcGetVal(_src, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased)
    tmpIsUptrend = tmpValFinal > tmpValFinal[1]

    tmpRuleBuy = tmpIsUptrend and (ta.crossover(tmpValFinal, 0) or (tmpValFinal >= 0))
    tmpRuleSell = not tmpIsUptrend and (ta.crossunder(tmpValFinal, 0) or (tmpValFinal < 0))
    [tmpRating, tmpRatingStatus, tmpRatingColorTable] = _funcCalcRating(tmpRuleBuy, tmpRuleSell)

    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable]

// Average Directional Index (ADX)
_funcADX(_len, _smoothingType, _smoothingPeriod, _enableStochasticBased) =>
    float adxValue = na, float adxPlus = na, float adxMinus = na
    [plus, minus, value] = ta.dmi(_len, _len)
    adxValue := value
    adxPlus := plus
    adxMinus := minus

    tmpTA = math.abs(adxPlus - adxMinus) / (adxValue == 0 ? 1 : adxValue)
    tmpValFinal = 100 * _funcGetVal(tmpTA, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased)
    tmpIsUptrend = tmpValFinal > tmpValFinal[1]

    tmpRuleBuy = tmpIsUptrend and (tmpValFinal > 20 and adxPlus[1] < adxMinus[1] and adxPlus > adxMinus)
    tmpRuleSell = not tmpIsUptrend and (tmpValFinal > 20 and adxPlus[1] > adxMinus[1] and adxPlus < adxMinus)
    [tmpRating, tmpRatingStatus, tmpRatingColorTable] = _funcCalcRating(tmpRuleBuy, tmpRuleSell)

    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable]

// Awesome Oscillator
_funcAwesomeOscillator(_src, _lenFast, _lenSlow, _smoothingType, _smoothingPeriod, _enableStochasticBased) =>
    tmpTA = ta.sma(_src, _lenFast) - ta.sma(_src, _lenSlow)
    tmpValFinal = _funcGetVal(tmpTA, _lenFast, _smoothingType, _smoothingPeriod, _enableStochasticBased)
    tmpIsUptrend = tmpValFinal > tmpValFinal[1]

    tmpRuleBuy = ta.crossover(tmpValFinal, 0) or (tmpValFinal > 0 and tmpValFinal[1] > 0 and tmpValFinal > tmpValFinal[1] and tmpValFinal[2] > tmpValFinal[1])
    tmpRuleSell = ta.crossunder(tmpValFinal, 0) or (tmpValFinal < 0 and tmpValFinal[1] < 0 and tmpValFinal < tmpValFinal[1] and tmpValFinal[2] < tmpValFinal[1])
    [tmpRating, tmpRatingStatus, tmpRatingColorTable] = _funcCalcRating(tmpRuleBuy, tmpRuleSell)

    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable]

// Ultimate Oscillator
_funcUltimateOscillator(_src, _lenShort, _lenMid, _lenLong, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold) =>
    tmpNewSrc = _src[1] < low ? _src[1]: low
    tmpVal1 = math.sum(ta.tr, _lenShort)
    tmpVal2 = math.sum(ta.tr, _lenMid)
    tmpVal3 = math.sum(ta.tr, _lenLong)
    tmpVal4 = math.sum(_src - tmpNewSrc, _lenShort)
    tmpVal5 = math.sum(_src - tmpNewSrc, _lenMid)
    tmpVal6 = math.sum(_src - tmpNewSrc, _lenLong)

    float tmpTA = na
    if tmpVal1 != 0 and tmpVal2 != 0 and tmpVal3 != 0
        var0 = _lenLong / _lenShort
        var1 = _lenLong / _lenMid
        tmpVal7 = (tmpVal4 / tmpVal1) * (var0)
        tmpVal8 = (tmpVal5 / tmpVal2) * (var1)
        tmpVal9 = (tmpVal6 / tmpVal3)
        tmpTA := (tmpVal7 + tmpVal8 + tmpVal9) / (var0 + var1 + 1)
        tmpTA := tmpTA * 100

    tmpValFinal = _funcGetVal(tmpTA, _lenShort, _smoothingType, _smoothingPeriod, _enableStochasticBased)

    [tmpRuleBuy, tmpRuleSell, tmpIsUptrend] = _funcGetBuySell(tmpValFinal, levelOverBought, levelOverSold)
    [tmpRating, tmpRatingStatus, tmpRatingColorTable] = _funcCalcRating(tmpRuleBuy, tmpRuleSell)

    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable]

// Volume Regression Trend (VRT)
_funcVRT(_src, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased) =>
    // determine the price of the regression slope
    slopePrice = ta.linreg(_src, _len, 0) - ta.linreg(_src, _len, 1)
    slopePriceFinal = _smoothingType == 'DISABLED' ? slopePrice : _funcCalcMA(_smoothingType, slopePrice, _smoothingPeriod)

    // get sizes of the candles
    candleWidthTop = high - math.max(open, close)
    candleWidthBottom = math.min(open, close) - low
    candleWidthBody = math.abs(close - open)

    // determine upward and downward movement of the regression slope
    [volumeUp, volumeDown] = _funcTrend(_len, candleWidthTop, candleWidthBottom, candleWidthBody)

    // alternative histogram color
    color tmpRatingColorHistogram = slopePriceFinal > 0 ? volumeUp > 0 ? volumeUp > volumeDown ? valColorsUpTrendStrongHistogram : valColorsUpTrendHistogram : valColorsUpWeakHistogram : slopePriceFinal < 0 ? volumeDown > 0 ? volumeUp < volumeDown ? valColorsDownTrendStrongHistogram : valColorsDownTrendHistogram : valColorsDownTrendWeakHistogram : valColorsNeutral

    tmpTA = slopePriceFinal * _len
    tmpValFinal = _funcGetVal(tmpTA, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased)
    tmpIsUptrend = tmpValFinal > tmpValFinal[1]

    tmpRuleBuy = tmpIsUptrend and (slopePriceFinal > 0 and volumeUp > 0 and volumeUp > volumeDown)
    tmpRuleSell = not tmpIsUptrend and (slopePriceFinal < 0 and volumeDown > 0 and volumeUp < volumeDown)
    [tmpRating, tmpRatingStatus, tmpRatingColorTable] = _funcCalcRating(tmpRuleBuy, tmpRuleSell)

    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable, tmpRatingColorHistogram]

_funcControl(_src, _timeframe, _type, _period) =>
    tmpValFinal = request.security(syminfo.tickerid, _timeframe, _funcCalcMA(_type, _src, _period))
    tmpIsUptrend = (tmpValFinal > tmpValFinal[1]) and (_src > tmpValFinal)
    [tmpRating, tmpRatingStatus, tmpRatingColorTable] = _funcCalcRating(tmpIsUptrend, (not tmpIsUptrend))
    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable]

// Williams Percent Range
_funcWPR(_len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold) =>
    tmpTA = ta.wpr(_len)
    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable] = _funcGetFinalVal(tmpTA, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold)

_funcMomentum(_src, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased) =>
    tmpTA = ta.mom(_src, _len)
    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable] = _funcGetFinalValNullLine(tmpTA, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased)

// Detrended Price Oscillator (DPO)
_funcDPO(_src, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased) =>
    tmpLookBarsBack = _len / 2 + 1
    tmpSMA = ta.sma(_src, _len)
    tmpTA = _src - tmpSMA[tmpLookBarsBack]

    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable] = _funcGetFinalValNullLine(tmpTA, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased)

// Klinger Oscillator
_funcKlinger(_src, _lenFast, _lenSlow, _smoothingType, _smoothingPeriod, _enableStochasticBased) =>
    tmpVolumeForce = ta.change(_src) >= 0 ? volume : -volume
    tmpTA = ta.ema(tmpVolumeForce, _lenFast) - ta.ema(tmpVolumeForce, _lenSlow)

    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable] = _funcGetFinalValNullLine(tmpTA, _lenFast, _smoothingType, _smoothingPeriod, _enableStochasticBased)

// Chaikin Oscillator (CO)
_funcCO(_src, _lenFast, _lenSlow, _smoothingType, _smoothingPeriod, _enableStochasticBased) =>
    tmpTA = ta.ema(ta.accdist, _lenFast) - ta.ema(ta.accdist, _lenSlow)

    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable] = _funcGetFinalValNullLine(tmpTA, _lenFast, _smoothingType, _smoothingPeriod, _enableStochasticBased)

// Chande Momentum Oscillator (CMO)
_funcCMO(_src, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold) =>
    _diff = ta.change(_src)

    m1 = _diff >= 0.0 ? _diff : 0.0
    m2 = _diff >= 0.0 ? 0.0 : -_diff

    sm1 = math.sum(m1, _len)
    sm2 = math.sum(m2, _len)

    tmpTA = _funcPercent(sm1-sm2, sm1+sm2)

    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable] = _funcGetFinalVal(tmpTA, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold)

_funcRSI(_src, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold) =>
    tmpTA = ta.rsi(_src, _len)
    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable] = _funcGetFinalVal(tmpTA, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold)

_funcRSX(_src, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold) =>
    tmpTA = _funcRemoveNoise(_src, _len)
    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable] = _funcGetFinalVal(tmpTA, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold)

// Money Flow Index (MFI)
_funcMFI(_src, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold) =>
    tmpChange = ta.change(_src)
    tmpMoneyFlowRatio = math.sum(volume * (tmpChange <= 0 ? 0 : _src), _len)
    tmpMoneyFlowIndex = math.sum(volume * (tmpChange >= 0 ? 0 : _src), _len)

    tmpTA = 100.0 - 100.0 / (1.0 + tmpMoneyFlowRatio / tmpMoneyFlowIndex)
    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable] = _funcGetFinalVal(tmpTA, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold)

// Commodity Channel Index (CCI)
_funcCCI(_src, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold) =>
    tmpTA = ta.cci(_src, _len)
    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable] = _funcGetFinalVal(tmpTA, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold)

_funcLaguerreFilter(_src, _len, _gammaFactor, _smoothingFactor, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold) =>
    _tmpGamma = 1 - _gammaFactor

    _tmpFilter_0 = 0.0
    _tmpFilter_0 := ((1 - _tmpGamma) * _src) + (_tmpGamma * nz(_tmpFilter_0[1]))

    _tmpFilter_1 = 0.0
    _tmpFilter_1 := (-_tmpGamma * _tmpFilter_0) + nz(_tmpFilter_0[1]) + (_tmpGamma * nz(_tmpFilter_1[1]))

    _tmpFilter_2 = 0.0
    _tmpFilter_2 := (-_tmpGamma * _tmpFilter_1) + nz(_tmpFilter_1[1]) + (_tmpGamma * nz(_tmpFilter_2[1]))

    _tmpFilter_3 = 0.0
    _tmpFilter_3 := (-_tmpGamma * _tmpFilter_2) + nz(_tmpFilter_2[1]) + (_tmpGamma * nz(_tmpFilter_3[1]))

    _tmpFilterUpTrend = (_tmpFilter_0 > _tmpFilter_1 ? _tmpFilter_0 - _tmpFilter_1 : 0) + (_tmpFilter_1 > _tmpFilter_2 ? _tmpFilter_1 - _tmpFilter_2 : 0) + (_tmpFilter_2 > _tmpFilter_3 ? _tmpFilter_2 - _tmpFilter_3 : 0)
    _tmpFilterDownTrend = (_tmpFilter_0 < _tmpFilter_1 ? _tmpFilter_1 - _tmpFilter_0 : 0) + (_tmpFilter_1 < _tmpFilter_2 ? _tmpFilter_2 - _tmpFilter_1 : 0) + (_tmpFilter_2 < _tmpFilter_3 ? _tmpFilter_3 - _tmpFilter_2 : 0)

    _tmpFilterTemp = (_tmpFilterUpTrend + _tmpFilterDownTrend == 0) ? -1 : (_tmpFilterUpTrend + _tmpFilterDownTrend)
    _tmpFilterSmoothed = _smoothingFactor > 1 ? ta.ema(_tmpFilterTemp, _smoothingFactor) : _tmpFilterTemp

    _tmpFilterVal = _tmpFilterSmoothed == -1 ? 0 : (_tmpFilterUpTrend / _tmpFilterSmoothed)

    tmpTA = (100 * _tmpFilterVal)
    [tmpValFinal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable] = _funcGetFinalVal(tmpTA, _len, _smoothingType, _smoothingPeriod, _enableStochasticBased, levelOverBought, levelOverSold)

_funcHistogramMACD(_src, _fastType, _fastPeriod, _slowType, _slowPeriod, _signalType, _signalPeriod, _enableStochasticBased) =>
    tmpFastMA = _funcCalcMA(_fastType, _src, _fastPeriod)
    tmpSlowMA = _funcCalcMA(_slowType, _src, _slowPeriod)
    tmpMACD = tmpFastMA - tmpSlowMA

    tmpTA = _funcCalcMA(_signalType, tmpMACD, _signalPeriod)
    tmpHistogramSignal = _enableStochasticBased ? ta.sma(ta.stoch(tmpTA, tmpTA, tmpTA, _signalPeriod), 3) : tmpTA
    tmpIsUptrend = tmpHistogramSignal > tmpHistogramSignal[1]

    tmpHistogram = tmpMACD - tmpHistogramSignal

    tmpRuleBuy = tmpIsUptrend and (tmpMACD > tmpHistogramSignal)
    tmpRuleSell = not tmpIsUptrend and (tmpMACD < tmpHistogramSignal)
    [tmpRating, tmpRatingStatus, tmpRatingColorTable] = _funcCalcRating(tmpRuleBuy, tmpRuleSell)

    tmpAdvancedRatingColor = _funcCalcHistogramColor(tmpHistogram)

    [tmpHistogramSignal, tmpRating, tmpRatingStatus, tmpIsUptrend, tmpRatingColorTable, tmpHistogram, tmpAdvancedRatingColor]

_funcHistogramRatingTotal(_type, _len, _rating, _ratingMaxCount, _ratingThresholdSellStrong, _ratingThresholdNeutralStart, _ratingThresholdNeutralEnd, _ratingThresholdBuyStrong) =>
    tmpHistogramSignal = _funcCalcMA(_type, _rating, _len)
    tmpHistogram = _rating - tmpHistogramSignal

    [tmpAdvancedRatingColor, tmpAdvancedRatingColorTable, tmpAdvancedRatingStatus] = _funcCalcRatingTotalStatus(_rating, _ratingMaxCount, tmpHistogram, _ratingThresholdSellStrong, _ratingThresholdNeutralStart, _ratingThresholdNeutralEnd, _ratingThresholdBuyStrong)
    [tmpHistogram, tmpAdvancedRatingColor, tmpAdvancedRatingColorTable, tmpAdvancedRatingStatus]

_funcHistogram(_type, _src, _len) =>
    tmpHistogramSignal = _funcCalcMA(_type, _src, _len)
    tmpHistogram = _src - tmpHistogramSignal
    tmpAdvancedRatingColor = _funcCalcHistogramColor(tmpHistogram)

    [tmpHistogram, tmpAdvancedRatingColor]

_funcFillTableCell(_table, _column, _row, _showValues, _showLabelShort, _label, _labelShort, _color, _transparency, _trend, _value, _valueRating, _isUptrend, _showTotalOnly, _valueWeighting) =>
    tmpTextSize = _showTotalOnly ? size.normal : size.small
    tmpValue = _showValues ? ':' + '\n' + str.tostring(_value, '0.00') + '\n' + (_isUptrend ? 'Uptrend' : 'Downtrend') + '\n' + _trend + ': ' + str.tostring(_valueRating) + ' Point' : '\n' + _trend
    if str.tostring(_valueRating) != '0' and _valueWeighting > 0
        tmpValue := tmpValue + ' + ' + str.tostring(_valueWeighting) + ' (Weighting)'
    if _label == 'TOTAL RATING'
        tmpValue := _showValues ? ':' + '\n' + str.tostring(_valueRating) + '\n' + _trend : '\n' + _trend
    _cellText = (_showLabelShort ? _labelShort : _label) + tmpValue
    table.cell(_table, _column, _row, _cellText, bgcolor=color.new(_color, _transparency), text_color=color.silver, text_size=tmpTextSize)
    if _label == 'TOTAL RATING'
        table.merge_cells(_table, _column, _row, _column, _row+1)



//********** Inputs
inputCalculationSource = input(title='Calculation Source', group='Global Settings', defval=close)

// Rating Threshold
float inputRatingThresholdSellStrong = input.float(title="Downtrend Strong", group='Rating Threshold', defval=0.30, minval=0.10, maxval=0.90, step=0.10)
float inputRatingThresholdNeutralRangeStart = input.float(title="Neutral: Start", group='Rating Threshold', defval=0.45, minval=0.10, maxval=0.90, step=0.05)
float inputRatingThresholdNeutralRangeEnd = input.float(title="Neutral: End", group='Rating Threshold', defval=0.55, minval=0.10, maxval=0.90, step=0.05)
float inputRatingThresholdBuyStrong = input.float(title="Uptrend Strong", group='Rating Threshold', defval=0.70, minval=0.10, maxval=0.90, step=0.10)

// Total
bool inputPanelShowTotalOnly = input.bool(title='Show Total Only', group='Panel', defval=true)
bool inputPanelShowValues = input.bool(title='Show Details', group='Panel', defval=true)
bool inputPanelShowLabelShort = input.bool(title='Show Short Labels', group='Panel', defval=true)
string inputPanelYposInput = input.string("middle", "Position:", inline="11", options = ["top", "middle", "bottom"], group='Panel')
string inputPanelXposInput = input.string("right", "", inline="11", options = ["left", "center", "right"], group='Panel')
int inputPanelTransparency = input.int(title='Transparency:', group="Panel", defval=0, minval=0, maxval=100, step=5)

// Histogram
string inputHistogramVariant = input.string(title='Show:', group='Histogram', defval='Total Rating (Summary of all Oscillator)', options=['DISABLED', 'Total Rating (Summary of all Oscillator)', 'Awesome Oscillator', 'ADX', 'CCI', 'Chande Momentum Oscillator', 'Chaikin Oscillator', 'Control Primary', 'Control Secondary', 'Detrended Price Oscillator', 'Klinger', 'MFI', 'MACD', 'Momentum', 'RSI', 'RSI Laguerre', 'RSX', 'Ultimate Oscillator', 'Volume Regression Trend', 'Williams Percent Range'])
string inputHistogramType = input.string(title='Smoothing:', group='Histogram', defval='SMA', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputHistogramLength = input.int(title='Period:', group='Histogram', defval=8, maxval=100)
int inputHistogramTransparency = input.int(title='Transparency:', group="Histogram", defval=5, minval=0, maxval=100, step=5)

// Total Rating
string inputTotalRatingSmoothingType = input.string(title='MA Line: Type', group='Total Rating', defval='RMA', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputTotalRatingSmoothingPeriod = input.int(title='MA Line: Smoothing Period', group='Total Rating', minval=1, defval=5)

// Relative Strength Index (RSI)
bool inputRsiEnableVolumeBased = input.bool(title='Volume Based Calculation On/Off', group='Relative Strength Index (RSI)', defval=false)
bool inputRsiEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Relative Strength Index (RSI)', defval=false)
int inputRsiWeighting = input.int(title='Weighting', group='Relative Strength Index (RSI)', minval=0, maxval=3, defval=3)
int inputRsiLength = input.int(title='Period', group='Relative Strength Index (RSI)', minval=1, defval=14)
string inputRsiSmoothingType = input.string(title='Smoothing Type', group='Relative Strength Index (RSI)', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputRsiSmoothingPeriod = input.int(title='Smoothing Period', group='Relative Strength Index (RSI)', minval=1, defval=5)
int inputRsiLevelOverBought = input(title='Level Overbought', group='Relative Strength Index (RSI)', defval=75)
int inputRsiLevelOverSold = input(title='Level Oversold', group='Relative Strength Index (RSI)', defval=25)

// Noise free Relative Strength Index (RSX)
bool inputRsxEnableVolumeBased = input.bool(title='Volume Based Calculation On/Off', group='Noise free Relative Strength Index (RSX)', defval=false)
bool inputRsxEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Noise free Relative Strength Index (RSX)', defval=false)
int inputRsxWeighting = input.int(title='Weighting', group='Noise free Relative Strength Index (RSX)', minval=0, maxval=3, defval=0)
int inputRsxLength = input.int(title='Period', group='Noise free Relative Strength Index (RSX)', minval=1, defval=14)
string inputRsxSmoothingType = input.string(title='Smoothing Type', group='Noise free Relative Strength Index (RSX)', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputRsxSmoothingPeriod = input.int(title='Smoothing Period', group='Noise free Relative Strength Index (RSX)', minval=1, defval=5)
int inputRsxLevelOverBought = input(title='Level Overbought', group='Noise free Relative Strength Index (RSX)', defval=75)
int inputRsxLevelOverSold = input(title='Level Oversold', group='Noise free Relative Strength Index (RSX)', defval=25)

// Relative Strength Index Laguerre (RSI-L)
bool inputLaguerreEnableVolumeBased = input.bool(title='Volume Based Calculation On/Off', group='Relative Strength Index Laguerre (RSI-L)', defval=false)
bool inputLaguerreEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Relative Strength Index Laguerre (RSI-L)', defval=false)
int inputLaguerreWeighting = input.int(title='Weighting', group='Relative Strength Index Laguerre (RSI-L)', minval=0, maxval=3, defval=0)
int inputLaguerreLength = input.int(title='Period', group='Relative Strength Index Laguerre (RSI-L)', minval=1, defval=14)
int inputLaguerreFilterSmoothingFactor = input.int(title="Smoothing Factor", group='Relative Strength Index Laguerre (RSI-L)', minval=1, maxval=100, defval=1)
float inputLaguerreFilterGamma = input.float(title="Gamma Factor", group='Relative Strength Index Laguerre (RSI-L)', defval=0.20, minval=0.01, step=0.001)
string inputLaguerreSmoothingType = input.string(title='Smoothing Type', group='Relative Strength Index Laguerre (RSI-L)', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputLaguerreSmoothingPeriod = input.int(title='Smoothing Period', group='Relative Strength Index Laguerre (RSI-L)', minval=1, defval=5)
int inputLaguerreLevelOverBought = input(title='Level Overbought', group='Relative Strength Index Laguerre (RSI-L)', defval=95)
int inputLaguerreLevelOverSold = input(title='Level Oversold', group='Relative Strength Index Laguerre (RSI-L)', defval=5)

// Money Flow Index (MFI)
bool inputMfiEnableVolumeBased = input.bool(title='Volume Based Calculation On/Off', group='Money Flow Index (MFI)', defval=false)
bool inputMfiEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Money Flow Index (MFI)', defval=false)
int inputMfiWeighting = input.int(title='Weighting', group='Money Flow Index (MFI)', minval=0, maxval=3, defval=0)
int inputMfiLength = input.int(title='Period', group='Money Flow Index (MFI)', minval=1, defval=14)
string inputMfiSmoothingType = input.string(title='Smoothing Type', group='Money Flow Index (MFI)', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputMfiSmoothingPeriod = input.int(title='Smoothing Period', group='Money Flow Index (MFI)', minval=1, defval=5)
int inputMfiLevelOverBought = input(title='Level Overbought', group='Money Flow Index (MFI)', defval=80)
int inputMfiLevelOverSold = input(title='Level Oversold', group='Money Flow Index (MFI)', defval=20)

// Commodity Channel Index (CCI)
bool inputCciEnableVolumeBased = input.bool(title='Volume Based Calculation On/Off', group='Commodity Channel Index (CCI)', defval=false)
bool inputCciEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Commodity Channel Index (CCI)', defval=false)
int inputCciWeighting = input.int(title='Weighting', group='Commodity Channel Index (CCI)', minval=0, maxval=3, defval=0)
int inputCciLength = input.int(title='Period', group='Commodity Channel Index (CCI)', minval=1, defval=20)
string inputCciSmoothingType = input.string(title='Smoothing Type', group='Commodity Channel Index (CCI)', defval='HMA', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputCciSmoothingPeriod = input.int(title='Smoothing Period', group='Commodity Channel Index (CCI)', minval=1, defval=5)
int inputCciLevelOverBought = input(title='Level Overbought', group='Commodity Channel Index (CCI)', defval=100)
int inputCciLevelOverSold = input(title='Level Oversold', group='Commodity Channel Index (CCI)', defval=-100)

// Moving Average Convergence/Divergence (MACD)
bool inputMacdEnableVolumeBased = input.bool(title='Volume Based Calculation On/Off', group='Moving Average Convergence/Divergence (MACD)', defval=false)
bool inputMacdEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Moving Average Convergence/Divergence (MACD)', defval=false)
int inputMacdWeighting = input.int(title='Weighting', group='Moving Average Convergence/Divergence (MACD)', minval=0, maxval=3, defval=3)
string inputMacdFastSmoothingType = input.string(title='Fast: Smoothing Type', group='Moving Average Convergence/Divergence (MACD)', defval='EMA', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputMacdFastPeriod = input.int(title='Fast: Period', group='Moving Average Convergence/Divergence (MACD)', defval=13, minval=1)
string inputMacdSlowSmoothingType = input.string(title='Slow: Smoothing Type', group='Moving Average Convergence/Divergence (MACD)', defval='EMA', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputMacdSlowPeriod = input.int(title='Slow: Period', group='Moving Average Convergence/Divergence (MACD)', defval=21, minval=1)

// Klinger
bool inputKlingerEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Klinger', defval=false)
int inputKlingerWeighting = input.int(title='Weighting', group='Klinger', minval=0, maxval=3, defval=0)
int inputKlingerPeriodFast = input.int(title='Period Fast', group='Klinger', minval=1, defval=34)
int inputKlingerPeriodSlow = input.int(title='Period Slow', group='Klinger', minval=1, defval=55)
string inputKlingerSmoothingType = input.string(title='Smoothing Type', group='Klinger', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputKlingerSmoothingPeriod = input.int(title='Smoothing Period', group='Klinger', minval=1, defval=5)

// Average Directional Index (ADX)
bool inputAdxEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Average Directional Index (ADX)', defval=false)
int inputAdxWeighting = input.int(title='Weighting', group='Average Directional Index (ADX)', minval=0, maxval=3, defval=3)
int inputAdxLength = input.int(title='Period', group='Average Directional Index (ADX)', minval=1, defval=14)
string inputAdxSmoothingType = input.string(title='Smoothing Type', group='Average Directional Index (ADX)', defval='RMA', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputAdxSmoothingPeriod = input.int(title='Smoothing Period', group='Average Directional Index (ADX)', minval=1, defval=14)

// Awesome Oscillator
bool inputAoEnableVolumeBased = input.bool(title='Volume Based Calculation On/Off', group='Awesome Oscillator', defval=false)
bool inputAoEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Awesome Oscillator', defval=false)
int inputAoWeighting = input.int(title='Weighting', group='Awesome Oscillator', minval=0, maxval=3, defval=3)
int inputAoLengthShort = input.int(title='Period Short', group='Awesome Oscillator', minval=1, defval=5)
int inputAoLengthLong = input.int(title='Period Long', group='Awesome Oscillator', minval=1, defval=34)
string inputAoSmoothingType = input.string(title='Smoothing Type', group='Awesome Oscillator', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputAoSmoothingPeriod = input.int(title='Smoothing Period', group='Awesome Oscillator', minval=1, defval=5)

// Williams Percent Range
bool inputWprEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Williams Percent Range', defval=false)
int inputWprWeighting = input.int(title='Weighting', group='Williams Percent Range', minval=0, maxval=3, defval=0)
int inputWprLength = input.int(title='Period', group='Williams Percent Range', minval=1, defval=14)
string inputWprSmoothingType = input.string(title='Smoothing Type', group='Williams Percent Range', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'WPR based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputWprSmoothingPeriod = input.int(title='Smoothing Period', group='Williams Percent Range', minval=1, defval=5)
int inputWprLevelOverBought = input(title='Level Overbought', group='Williams Percent Range', defval=-20)
int inputWprLevelOverSold = input(title='Level Oversold', group='Williams Percent Range', defval=-80)

// Ultimate Oscillator
bool inputUoEnableVolumeBased = input.bool(title='Volume Based Calculation On/Off', group='Ultimate Oscillator', defval=false)
bool inputUoEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Ultimate Oscillator', defval=false)
int inputUoWeighting = input.int(title='Weighting', group='Ultimate Oscillator', minval=0, maxval=3, defval=0)
int inputUoShortLength = input.int(title='Period Short', group='Ultimate Oscillator', minval=1, defval=7)
int inputUoMidLength = input.int(title='Period Middle', group='Ultimate Oscillator', minval=1, defval=14)
int inputUoLongLength = input.int(title='Period Long', group='Ultimate Oscillator', minval=1, defval=28)
string inputUoSmoothingType = input.string(title='Smoothing Type', group='Ultimate Oscillator', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputUoSmoothingPeriod = input.int(title='Smoothing Period', group='Ultimate Oscillator', minval=1, defval=5)
int inputUoLevelOverBought = input(title='Level Overbought', group='Ultimate Oscillator', defval=70)
int inputUoLevelOverSold = input(title='Level Oversold', group='Ultimate Oscillator', defval=30)

// Momentum
bool inputMomentumEnableVolumeBased = input.bool(title='Volume Based Calculation On/Off', group='Momentum', defval=false)
bool inputMomentumEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Momentum', defval=false)
int inputMomentumWeighting = input.int(title='Weighting', group='Momentum', minval=0, maxval=3, defval=0)
int inputMomentumLength = input.int(title='Period', group='Momentum', minval=1, defval=10)
string inputMomentumSmoothingType = input.string(title='Smoothing Type', group='Momentum', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputMomentumSmoothingPeriod = input.int(title='Smoothing Period', group='Momentum', minval=1, defval=5)

// Volume Regression Trend (VRT)
bool inputVrtEnableVolumeBased = input.bool(title='Volume Based Calculation On/Off', group='Volume Regression Trend (VRT)', defval=false)
bool inputVrtEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Volume Regression Trend (VRT)', defval=false)
int inputVrtWeighting = input.int(title='Weighting', group='Volume Regression Trend (VRT)', minval=0, maxval=3, defval=3)
int inputVrtLength = input.int(title='Period', group='Volume Regression Trend (VRT)', minval=1, defval=4)
string inputVrtSmoothingType = input.string(title='Smoothing Type', group='Volume Regression Trend (VRT)', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputVrtSmoothingPeriod = input.int(title='Smoothing Period', group='Volume Regression Trend (VRT)', minval=1, defval=5)

// Chande Momentum Oscillator (CMO)
bool inputCmoEnableVolumeBased = input.bool(title='Volume Based Calculation On/Off', group='Chande Momentum Oscillator (CMO)', defval=false)
bool inputCmoEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Chande Momentum Oscillator (CMO)', defval=false)
int inputCmoWeighting = input.int(title='Weighting', group='Chande Momentum Oscillator (CMO)', minval=0, maxval=3, defval=0)
int inputCmoLength = input.int(title='Period', group='Chande Momentum Oscillator (CMO)', minval=1, defval=9)
string inputCmoSmoothingType = input.string(title='Smoothing Type', group='Chande Momentum Oscillator (CMO)', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputCmoSmoothingPeriod = input.int(title='Smoothing Period', group='Chande Momentum Oscillator (CMO)', minval=1, defval=5)
int inputCmoLevelOverBought = input(title='Level Overbought', group='Chande Momentum Oscillator (CMO)', defval=75)
int inputCmoLevelOverSold = input(title='Level Oversold', group='Chande Momentum Oscillator (CMO)', defval=25)

// Detrended Price Oscillator (DPO)
bool inputDpoEnableVolumeBased = input.bool(title='Volume Based Calculation On/Off', group='Detrended Price Oscillator (DPO)', defval=false)
bool inputDpoEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Detrended Price Oscillator (DPO)', defval=false)
int inputDpoWeighting = input.int(title='Weighting', group='Detrended Price Oscillator (DPO)', minval=0, maxval=3, defval=0)
int inputDpoLength = input.int(title='Period', group='Detrended Price Oscillator (DPO)', minval=1, defval=21)
string inputDpoSmoothingType = input.string(title='Smoothing Type', group='Detrended Price Oscillator (DPO)', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputDpoSmoothingPeriod = input.int(title='Smoothing Period', group='Detrended Price Oscillator (DPO)', minval=1, defval=5)

// Chaikin Oscillator (CO)
bool inputCoEnableStochasticBased = input.bool(title='Stochastic Based Calculation On/Off', group='Chaikin Oscillator (CO)', defval=false)
int inputCoWeighting = input.int(title='Weighting', group='Chaikin Oscillator (CO)', minval=0, maxval=3, defval=0)
int inputCoPeriodFast = input.int(title='Period Fast', group='Chaikin Oscillator (CO)', minval=1, defval=3)
int inputCoPeriodSlow = input.int(title='Period Slow', group='Chaikin Oscillator (CO)', minval=1, defval=10)
string inputCoSmoothingType = input.string(title='Smoothing Type', group='Chaikin Oscillator (CO)', defval='DISABLED', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputCoSmoothingPeriod = input.int(title='Smoothing Period', group='Chaikin Oscillator (CO)', minval=1, defval=5)

// Control Primary
inputControlPrimaryTimeframe = input.timeframe("", "Resolution:", group="Control Primary Line")
string inputControlPrimaryType = input.string(title='Type:', group='Control Primary Line', defval='EHMA', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputControlPrimaryLength = input.int(title='Period:', group='Control Primary Line', defval=21, maxval=1000)
int inputControlPrimaryWeighting = input.int(title='Weighting', group='Control Primary Line', minval=0, maxval=100, defval=0)

// Control Secondary
inputControlSecondaryTimeframe = input.timeframe("", "Resolution:", group="Control Secondary Line")
string inputControlSecondaryType = input.string(title='Type:', group='Control Secondary Line', defval='EHMA', options=['DISABLED', 'COVWMA', 'DEMA', 'EMA', 'EHMA', 'FRAMA', 'HMA', 'KAMA', 'Karobein', 'RMA', 'RSX based Noise Remover', 'SMA', 'SMMA', 'TEMA', 'VIDYA', 'VWMA', 'WMA'])
int inputControlSecondaryLength = input.int(title='Period:', group='Control Secondary Line', defval=34, maxval=1000)
int inputControlSecondaryWeighting = input.int(title='Weighting', group='Control Secondary Line', minval=0, maxval=100, defval=0)


//********** Calculation
float volumeBased = ta.cum(ta.change(inputCalculationSource) * volume)

// Relative Strength Index (RSI)
float inputCalculationSourceRsi = inputRsiEnableVolumeBased ? volumeBased : inputCalculationSource
[valRsi, valRsiRating, valRsiRatingStatus, valRsiIsUptrend, valRsiRatingStatusTable] = _funcRSI(inputCalculationSourceRsi, inputRsiLength, inputRsiSmoothingType, inputRsiSmoothingPeriod, inputRsiEnableStochasticBased, inputRsiLevelOverBought, inputRsiLevelOverSold)

// Relative Strength Index (RSI) Laguerre
float inputCalculationSourceLaguerre = inputLaguerreEnableVolumeBased ? volumeBased : inputCalculationSource
[valRsiLaguerre, valRsiLaguerreRating, valRsiLaguerreRatingStatus, valRsiLaguerreIsUptrend, valRsiLaguerreRatingStatusTable] = _funcLaguerreFilter(inputCalculationSourceLaguerre, inputLaguerreLength, inputLaguerreFilterGamma, inputLaguerreFilterSmoothingFactor, inputLaguerreSmoothingType, inputLaguerreSmoothingPeriod, inputLaguerreEnableStochasticBased, inputLaguerreLevelOverBought, inputLaguerreLevelOverSold)

// Noise free Relative Strength Index (RSX)
float inputCalculationSourceRsx = inputRsxEnableVolumeBased ? volumeBased : inputCalculationSource
[valRsx, valRsxRating, valRsxRatingStatus, valRsxIsUptrend, valRsxRatingStatusTable] = _funcRSX(inputCalculationSourceRsx, inputRsxLength, inputRsxSmoothingType, inputRsxSmoothingPeriod, inputRsxEnableStochasticBased, inputRsxLevelOverBought, inputRsxLevelOverSold)

// Money Flow Index (MFI)
float inputCalculationSourceMfi = inputMfiEnableVolumeBased ? volumeBased : inputCalculationSource
[valMfi, valMfiRating, valMfiRatingStatus, valMfiIsUptrend, valMfiRatingStatusTable] = _funcMFI(inputCalculationSourceMfi, inputMfiLength, inputMfiSmoothingType, inputMfiSmoothingPeriod, inputMfiEnableStochasticBased, inputMfiLevelOverBought, inputMfiLevelOverSold)

// Commodity Channel Index (CCI)
float inputCalculationSourceCci = inputCciEnableVolumeBased ? volumeBased : inputCalculationSource
[valCci, valCciRating, valCciRatingStatus, valCciIsUptrend, valCciRatingStatusTable] = _funcCCI(inputCalculationSourceCci, inputCciLength, inputCciSmoothingType, inputCciSmoothingPeriod, inputCciEnableStochasticBased, inputCciLevelOverBought, inputCciLevelOverSold)

// Klinger
[valKlinger, valKlingerRating, valKlingerRatingStatus, valKlingerIsUptrend, valKlingerRatingStatusTable] = _funcKlinger(inputCalculationSource, inputKlingerPeriodFast, inputKlingerPeriodSlow, inputKlingerSmoothingType, inputKlingerSmoothingPeriod, inputKlingerEnableStochasticBased)

// Moving Average Convergence/Divergence (MACD)
float inputCalculationSourceMacd = inputMacdEnableVolumeBased ? volumeBased : inputCalculationSource
[valMACD, valMACDRating, valMACDRatingStatus, valMACDIsUptrend, valMACDRatingStatusTable, macdHistogram, macdHistogramColor] = _funcHistogramMACD(inputCalculationSourceMacd, inputMacdFastSmoothingType, inputMacdFastPeriod, inputMacdSlowSmoothingType, inputMacdSlowPeriod, inputHistogramType, inputHistogramLength, inputMacdEnableStochasticBased)

// Average Directional Index (ADX)
[valAdx, valAdxRating, valAdxRatingStatus, valAdxIsUptrend, valAdxRatingStatusTable] = _funcADX(inputAdxLength, inputAdxSmoothingType, inputAdxSmoothingPeriod, inputAdxEnableStochasticBased)

// Awesome Oscillator
float inputCalculationSourceAo = inputAoEnableVolumeBased ? volumeBased : inputCalculationSource
[valAo, valAoRating, valAoRatingStatus, valAoIsUptrend, valAoRatingStatusTable] = _funcAwesomeOscillator(inputCalculationSourceAo, inputAoLengthShort, inputAoLengthLong, inputAoSmoothingType, inputAoSmoothingPeriod, inputAoEnableStochasticBased)

// Williams Percent Range
[valWpr, valWprRating, valWprRatingStatus, valWprIsUptrend, valWprRatingStatusTable] = _funcWPR(inputWprLength, inputWprSmoothingType, inputWprSmoothingPeriod, inputWprEnableStochasticBased, inputWprLevelOverBought, inputWprLevelOverSold)

// Ultimate Oscillator
float inputCalculationSourceUo = inputUoEnableVolumeBased ? volumeBased : inputCalculationSource
[valUo, valUoRating, valUoRatingStatus, valUoIsUptrend, valUoRatingStatusTable] = _funcUltimateOscillator(inputCalculationSourceUo, inputUoShortLength, inputUoMidLength, inputUoLongLength, inputUoSmoothingType, inputUoSmoothingPeriod, inputUoEnableStochasticBased, inputUoLevelOverBought, inputUoLevelOverSold)

// Momentum
float inputCalculationSourceMomentum = inputMomentumEnableVolumeBased ? volumeBased : inputCalculationSource
[valMomentum, valMomentumRating, valMomentumRatingStatus, valMomentumIsUptrend, valMomentumRatingStatusTable] = _funcMomentum(inputCalculationSourceMomentum, inputMomentumLength, inputMomentumSmoothingType, inputMomentumSmoothingPeriod, inputMomentumEnableStochasticBased)

// Volume Regression Trend (VRT)
float inputCalculationSourceVrt = inputVrtEnableVolumeBased ? volumeBased : inputCalculationSource
[valVrt, valVrtRating, valVrtRatingStatus, valVrtIsUptrend, valVrtRatingStatusTable, valVrtRatingColorHistogram] = _funcVRT(inputCalculationSourceVrt, inputVrtLength, inputVrtSmoothingType, inputVrtSmoothingPeriod, inputVrtEnableStochasticBased)

// Chande Momentum Oscillator (CMO)
float inputCalculationSourceCmo = inputCmoEnableVolumeBased ? volumeBased : inputCalculationSource
[valCmo, valCmoRating, valCmoRatingStatus, valCmoIsUptrend, valCmoRatingStatusTable] = _funcCMO(inputCalculationSourceCmo, inputCmoLength, inputCmoSmoothingType, inputCmoSmoothingPeriod, inputCmoEnableStochasticBased, inputCmoLevelOverBought, inputCmoLevelOverSold)

// Detrended Price Oscillator (DPO)
float inputCalculationSourceDpo = inputDpoEnableVolumeBased ? volumeBased : inputCalculationSource
[valDpo, valDpoRating, valDpoRatingStatus, valDpoIsUptrend, valDpoRatingStatusTable] = _funcDPO(inputCalculationSourceDpo, inputDpoLength, inputDpoSmoothingType, inputDpoSmoothingPeriod, inputDpoEnableStochasticBased)

// Chaikin Oscillator (CO)
[valCo, valCoRating, valCoRatingStatus, valCoIsUptrend, valCoRatingStatusTable] = _funcCO(inputCalculationSource, inputCoPeriodFast, inputCoPeriodSlow, inputCoSmoothingType, inputCoSmoothingPeriod, inputCoEnableStochasticBased)

// Control Primary
[valControlPrimary, valControlPrimaryRating, valControlPrimaryRatingStatus, valControlPrimaryIsUptrend, valControlPrimaryRatingStatusTable] = _funcControl(inputCalculationSource, inputControlPrimaryTimeframe, inputControlPrimaryType, inputControlPrimaryLength)

// Control Secondary
[valControlSecondary, valControlSecondaryRating, valControlSecondaryRatingStatus, valControlSecondaryIsUptrend, valControlSecondaryRatingStatusTable] = _funcControl(inputCalculationSource, inputControlSecondaryTimeframe, inputControlSecondaryType, inputControlSecondaryLength)

// Rating Total
float ratingTotal = 0
float ratingTotalMaxCount = 0
if not(na(valRsiRating) or na(valRsiRating[1]))
    ratingTotal := ratingTotal
    if valRsiRating > 0
        ratingTotal := ratingTotal + valRsiRating + inputRsiWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputRsiWeighting
if not(na(valRsiLaguerreRating) or na(valRsiLaguerreRating[1]))
    ratingTotal := ratingTotal
    if valRsiLaguerreRating > 0
        ratingTotal := ratingTotal + valRsiLaguerreRating + inputLaguerreWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputLaguerreWeighting
if not(na(valRsxRating) or na(valRsxRating[1]))
    ratingTotal := ratingTotal
    if valRsxRating > 0
        ratingTotal := ratingTotal + valRsxRating + inputRsxWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputRsxWeighting
if not(na(valMfiRating) or na(valMfiRating[1]))
    ratingTotal := ratingTotal
    if valMfiRating > 0
        ratingTotal := ratingTotal + valMfiRating + inputMfiWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputMfiWeighting
if not(na(valCciRating) or na(valCciRating[1]))
    ratingTotal := ratingTotal
    if valCciRating > 0
        ratingTotal := ratingTotal + valCciRating + inputCciWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputCciWeighting
if not(na(valKlingerRating) or na(valKlingerRating[1]))
    ratingTotal := ratingTotal
    if valKlingerRating > 0
        ratingTotal := ratingTotal + valKlingerRating + inputKlingerWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputKlingerWeighting
if not(na(valMACDRating) or na(valMACDRating[1]))
    ratingTotal := ratingTotal
    if valMACDRating > 0
        ratingTotal := ratingTotal + valMACDRating + inputMacdWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputMacdWeighting
if not(na(valAdxRating) or na(valAdxRating[1]))
    ratingTotal := ratingTotal
    if valAdxRating > 0
        ratingTotal := ratingTotal + valAdxRating + inputAdxWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputAdxWeighting
if not(na(valAoRating) or na(valAoRating[1]))
    ratingTotal := ratingTotal
    if valAoRating > 0
        ratingTotal := ratingTotal + valAoRating + inputAoWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputAoWeighting
if not(na(valWprRating) or na(valWprRating[1]))
    ratingTotal := ratingTotal
    if valWprRating > 0
        ratingTotal := ratingTotal + valWprRating + inputWprWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputWprWeighting
if not(na(valUoRating) or na(valUoRating[1]))
    ratingTotal := ratingTotal
    if valUoRating > 0
        ratingTotal := ratingTotal + valUoRating + inputUoWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputUoWeighting
if not(na(valMomentumRating) or na(valMomentumRating[1]))
    ratingTotal := ratingTotal
    if valMomentumRating > 0
        ratingTotal := ratingTotal + valMomentumRating + inputMomentumWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputMomentumWeighting
if not(na(valVrt) or na(valVrt[1]))
    ratingTotal := ratingTotal
    if valVrtRating > 0
        ratingTotal := ratingTotal + valVrtRating + inputVrtWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputVrtWeighting
if not(na(valCmo) or na(valCmo[1]))
    ratingTotal := ratingTotal
    if valCmoRating > 0
        ratingTotal := ratingTotal + valCmoRating + inputCmoWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputCmoWeighting
if not(na(valDpo) or na(valDpo[1]))
    ratingTotal := ratingTotal
    if valDpoRating > 0
        ratingTotal := ratingTotal + valDpoRating + inputDpoWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputDpoWeighting
if not(na(valCo) or na(valCo[1]))
    ratingTotal := ratingTotal
    if valCoRating > 0
        ratingTotal := ratingTotal + valCoRating + inputCoWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputCoWeighting
if inputControlPrimaryType != 'DISABLED' and not(na(valControlPrimaryRating) or na(valControlPrimaryRating[1]))
    ratingTotal := ratingTotal
    if valControlPrimaryRating > 0
        ratingTotal := ratingTotal + valControlPrimaryRating + inputControlPrimaryWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputControlPrimaryWeighting
if inputControlSecondaryType != 'DISABLED' and not(na(valControlSecondaryRating) or na(valControlSecondaryRating[1]))
    ratingTotal := ratingTotal
    if valControlSecondaryRating > 0
        ratingTotal := ratingTotal + valControlSecondaryRating + inputControlSecondaryWeighting
    ratingTotalMaxCount := ratingTotalMaxCount + 1 + inputControlSecondaryWeighting

[valPlotHistogramRatingTotal, valPlotHistogramRatingTotalColor, valPlotHistogramRatingTotalColorTable, valPlotHistogramRatingTotalTrend] = _funcHistogramRatingTotal(inputHistogramType, inputHistogramLength, ratingTotal, ratingTotalMaxCount, inputRatingThresholdSellStrong, inputRatingThresholdNeutralRangeStart, inputRatingThresholdNeutralRangeEnd, inputRatingThresholdBuyStrong)


//************  Plotting

// Histogram
float valPlotHistogram = na
color valPlotHistogramColor = valColorsNeutral
if inputHistogramVariant != 'DISABLED' and inputHistogramVariant != 'MACD' and inputHistogramVariant != 'Volume Regression Trend'
    float valHistogramSource = switch inputHistogramVariant
        "RSI" => valRsi
        "RSX" => valRsx
        "RSI Laguerre" => valRsiLaguerre
        "MFI" => valMfi
        "CCI" => valCci
        "Control Primary" => valControlPrimary
        "Control Secondary" => valControlSecondary
        "Klinger" => valKlinger
        "ADX" => valAdx
        "Awesome Oscillator" => valAo
        "Williams Percent Range" => valWpr
        "Ultimate Oscillator" => valUo
        "Momentum" => valMomentum
        "Chande Momentum Oscillator" => valCmo
        "Detrended Price Oscillator" => valDpo
        "Chaikin Oscillator" => valCo
        =>
            float(na)

    [tmpValPlotHistogram, tmpValPlotHistogramColor] = _funcHistogram(inputHistogramType, valHistogramSource, inputHistogramLength)
    valPlotHistogram := tmpValPlotHistogram
    valPlotHistogramColor := tmpValPlotHistogramColor

plot((ratingTotal and inputHistogramVariant != 'DISABLED' and inputHistogramVariant == 'Total Rating (Summary of all Oscillator)') ? ratingTotal : na, title='Histogram Total Rating', style=plot.style_columns, color=color.new(valPlotHistogramRatingTotalColor, inputHistogramTransparency), linewidth=2)
plot((valPlotHistogram and inputHistogramVariant != 'DISABLED' and inputHistogramVariant != 'MACD' and inputHistogramVariant != 'Total Rating (Summary of all Oscillator)' and inputHistogramVariant != 'Volume Regression Trend') ? valPlotHistogram : na, title='Histogram Default', style=plot.style_columns, color=color.new(valPlotHistogramColor, inputHistogramTransparency), linewidth=2)
plot((valVrt and inputHistogramVariant == 'Volume Regression Trend') ? valVrt : na, title='Histogram Volume Regression Trend', style=plot.style_columns, color=color.new(valVrtRatingColorHistogram, inputHistogramTransparency), linewidth=2)
plot((macdHistogram and inputHistogramVariant == 'MACD') ? macdHistogram : na, title='Histogram MACD', style=plot.style_columns, color=color.new(macdHistogramColor, inputHistogramTransparency), linewidth=2)

// Plotting MA
float plottingMA = switch inputHistogramVariant
    "Total Rating (Summary of all Oscillator)" =>
        if inputTotalRatingSmoothingType != 'DISABLED'
            _funcCalcMA(inputTotalRatingSmoothingType, ratingTotal, inputTotalRatingSmoothingPeriod)
        else
            na
    "Williams Percent Range" => (valWpr + 50)
    "Ultimate Oscillator" => (valUo - 50)
    "Awesome Oscillator" => valAo
    "ADX" => (valAdx - 50)
    "RSI" => (valRsi - 50)
    "RSI Laguerre" => (valRsiLaguerre - 50)
    "RSX" => (valRsx - 50)
    "MFI" => (valMfi - 50)
    "CCI" => valCci
    // "Control Primary" => valControlPrimary
    // "Control Secondary" => valControlSecondary
    "MACD" => valMACD
    "Klinger" => valKlinger
    "Momentum" => valMomentum
    "Chande Momentum Oscillator" => valCmo
    "Detrended Price Oscillator" => valDpo
    "Chaikin Oscillator" => valCo
    =>
        float(na)

plot(plottingMA, title='MA Line', color=color.new(valColorMA, 0), linewidth=2, style=plot.style_line)

// Table
string labelRatingTotal = str.tostring(ratingTotal) + ' of ' + str.tostring(ratingTotalMaxCount) + ' Points'
var table perfTable = table.new(inputPanelYposInput + "_" + inputPanelXposInput, 10, 2, border_width=3)

if barstate.islast
    if not inputPanelShowTotalOnly
        _funcFillTableCell(perfTable, 0, 0, inputPanelShowValues, inputPanelShowLabelShort, 'Relative Strength Index', 'RSI', valRsiRatingStatusTable, inputPanelTransparency, valRsiRatingStatus, valRsi, valRsiRating, valRsiIsUptrend, inputPanelShowTotalOnly, inputRsiWeighting)
        _funcFillTableCell(perfTable, 1, 0, inputPanelShowValues, inputPanelShowLabelShort, 'Relative Strength Index Laguerre', 'RSI-L', valRsiLaguerreRatingStatusTable, inputPanelTransparency, valRsiLaguerreRatingStatus, valRsiLaguerre, valRsiLaguerreRating, valRsiLaguerreIsUptrend, inputPanelShowTotalOnly, inputLaguerreWeighting)
        _funcFillTableCell(perfTable, 2, 0, inputPanelShowValues, inputPanelShowLabelShort, 'Relative Strength Index (Noise free)', 'RSX', valRsxRatingStatusTable, inputPanelTransparency, valRsxRatingStatus, valRsx, valRsxRating, valRsxIsUptrend, inputPanelShowTotalOnly, inputRsxWeighting)
        _funcFillTableCell(perfTable, 3, 0, inputPanelShowValues, inputPanelShowLabelShort, 'Money Flow Index', 'MFI', valMfiRatingStatusTable, inputPanelTransparency, valMfiRatingStatus, valMfi, valMfiRating, valMfiIsUptrend, inputPanelShowTotalOnly, inputMfiWeighting)
        _funcFillTableCell(perfTable, 4, 0, inputPanelShowValues, inputPanelShowLabelShort, 'Williams Percent Range', 'WPR', valWprRatingStatusTable, inputPanelTransparency, valWprRatingStatus, valWpr, valWprRating, valWprIsUptrend, inputPanelShowTotalOnly, inputWprWeighting)
        _funcFillTableCell(perfTable, 5, 0, inputPanelShowValues, inputPanelShowLabelShort, 'Momentum', 'MOM', valMomentumRatingStatusTable, inputPanelTransparency, valMomentumRatingStatus, valMomentum, valMomentumRating, valMomentumIsUptrend, inputPanelShowTotalOnly, inputMomentumWeighting)
        _funcFillTableCell(perfTable, 6, 0, inputPanelShowValues, inputPanelShowLabelShort, 'Volume Regression Trend', 'VRT', valVrtRatingStatusTable, inputPanelTransparency, valVrtRatingStatus, valVrt, valVrtRating, valVrtIsUptrend, inputPanelShowTotalOnly, inputVrtWeighting)
        _funcFillTableCell(perfTable, 7, 0, inputPanelShowValues, inputPanelShowLabelShort, 'Detrended Price Oscillator', 'DPO', valDpoRatingStatusTable, inputPanelTransparency, valDpoRatingStatus, valDpo, valDpoRating, valDpoIsUptrend, inputPanelShowTotalOnly, inputDpoWeighting)
        _funcFillTableCell(perfTable, 8, 0, inputPanelShowValues, inputPanelShowLabelShort, 'Control Primary', 'Control P', valControlPrimaryRatingStatusTable, inputPanelTransparency, valControlPrimaryRatingStatus, valControlPrimary, valControlPrimaryRating, valControlPrimaryIsUptrend, inputPanelShowTotalOnly, inputControlPrimaryWeighting)
    _funcFillTableCell(perfTable, 9, 0, inputPanelShowValues, inputPanelShowLabelShort, 'TOTAL RATING', 'TOTAL RATING', valPlotHistogramRatingTotalColorTable, inputPanelTransparency, valPlotHistogramRatingTotalTrend, valPlotHistogramRatingTotal, labelRatingTotal, false, inputPanelShowTotalOnly, 0)

    if not inputPanelShowTotalOnly
        _funcFillTableCell(perfTable, 0, 1, inputPanelShowValues, inputPanelShowLabelShort, 'Commodity Channel Index', 'CCI', valCciRatingStatusTable, inputPanelTransparency, valCciRatingStatus, valCci, valCciRating, valCciIsUptrend, inputPanelShowTotalOnly, inputCciWeighting)
        _funcFillTableCell(perfTable, 1, 1, inputPanelShowValues, inputPanelShowLabelShort, 'Moving Average Convergence/Divergence', 'MACD', valMACDRatingStatusTable, inputPanelTransparency, valMACDRatingStatus, valMACD, valMACDRating, valMACDIsUptrend, inputPanelShowTotalOnly, inputMacdWeighting)
        _funcFillTableCell(perfTable, 2, 1, inputPanelShowValues, inputPanelShowLabelShort, 'Klinger', 'KLG', valKlingerRatingStatusTable, inputPanelTransparency, valKlingerRatingStatus, valKlinger, valKlingerRating, valKlingerIsUptrend, inputPanelShowTotalOnly, inputKlingerWeighting)
        _funcFillTableCell(perfTable, 3, 1, inputPanelShowValues, inputPanelShowLabelShort, 'Average Directional Index', 'ADX', valAdxRatingStatusTable, inputPanelTransparency, valAdxRatingStatus, valAdx, valAdxRating, valAdxIsUptrend, inputPanelShowTotalOnly, inputAdxWeighting)
        _funcFillTableCell(perfTable, 4, 1, inputPanelShowValues, inputPanelShowLabelShort, 'Awesome Oscillator', 'AO', valAoRatingStatusTable, inputPanelTransparency, valAoRatingStatus, valAo, valAoRating, valAoIsUptrend, inputPanelShowTotalOnly, inputAoWeighting)
        _funcFillTableCell(perfTable, 5, 1, inputPanelShowValues, inputPanelShowLabelShort, 'Ultimate Oscillator', 'UO', valUoRatingStatusTable, inputPanelTransparency, valUoRatingStatus, valUo, valUoRating, valUoIsUptrend, inputPanelShowTotalOnly, inputUoWeighting)
        _funcFillTableCell(perfTable, 6, 1, inputPanelShowValues, inputPanelShowLabelShort, 'Chande Momentum Oscillator', 'CMO', valCmoRatingStatusTable, inputPanelTransparency, valCmoRatingStatus, valCmo, valCmoRating, valCmoIsUptrend, inputPanelShowTotalOnly, inputCmoWeighting)
        _funcFillTableCell(perfTable, 7, 1, inputPanelShowValues, inputPanelShowLabelShort, 'Chaikin Oscillator', 'CO', valCoRatingStatusTable, inputPanelTransparency, valCoRatingStatus, valCo, valCoRating, valCoIsUptrend, inputPanelShowTotalOnly, inputCoWeighting)
        _funcFillTableCell(perfTable, 8, 1, inputPanelShowValues, inputPanelShowLabelShort, 'Control Secondary', 'Control S', valControlSecondaryRatingStatusTable, inputPanelTransparency, valControlSecondaryRatingStatus, valControlSecondary, valControlSecondaryRating, valControlSecondaryIsUptrend, inputPanelShowTotalOnly, inputControlSecondaryWeighting)



//************  Alerting

// Neutral
alertcondition((valPlotHistogramRatingTotalTrend == "Neutral"), "Neutral", "Multi Trend Oscillator: Neutral")

// Downtrend
alertcondition((valPlotHistogramRatingTotalTrend == "Downtrend"), "Downtrend", "Multi Trend Oscillator: Downtrend")
alertcondition((valPlotHistogramRatingTotalTrend == "Strong Downtrend"), "Strong Downtrend", "Multi Trend Oscillator: Downtrend")

// Uptrend
alertcondition((valPlotHistogramRatingTotalTrend == "Uptrend"), "Uptrend", "Multi Trend Oscillator: Uptrend")
alertcondition((valPlotHistogramRatingTotalTrend == "Strong Uptrend"), "Strong Uptrend", "Multi Trend Oscillator: Strong Uptrend")
alertcondition((valPlotHistogramRatingTotalTrend == "Strong Uptrend\nBut Downtrend coming"), "Strong Uptrend - But Downtrend coming", "Multi Trend Oscillator: Strong Uptrend - But Downtrend coming")
