YinYang Bar Forecast
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@    ,@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@      @@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@        @@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@         @@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@           @@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@        .@@@@@@@@@@@@@@@            @@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@          *@@@@@@@@@@@@@@             @@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@         @@@@@@@@@@@@@@@               @@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@     @@@@@@@@@@@@@@@@                 @@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                  @@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                    @@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                      @@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                         @
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                             @
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,                                       @
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                                                @
// @@@@@@@@@@@@@@@@@@@@@@@@@@@                                                    @
// @@@@@@@@@@@@@@@@@@@@@@@@@                                                     @@
// @@@@@@@@@@@@@@@@@@@@@@@                                                       @@
// @@@@@@@@@@@@@@@@@@@@@@                                                       @@@
// @@@@@@@@@@@@@@@@@@@@@*                @@@@@                                 @@@@
// @@@@@@@@@@@@@@@@@@@@@               @@@@@@@@@                              @@@@@
// @@@@@@@@@@@@@@@@@@@@@              @@@@@@@@@@@                           @@@@@@@
// @@@@@@@@@@@@@@@@@@@@@               @@@@@@@@%                           @@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@                                                @@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@                                            @@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@                                        %@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@                                   @@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@                           @@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// © YinYangAlgorithms

//@version=5
indicator("YinYang Bar Forecast", overlay=true)
// ~~~~~~~~ INPUTS ~~~~~~~~ //
predictiveCount = input.int(13, "Forecast Length:", minval=1, maxval=13, tooltip="How many bars should we predict into the Future? Max 13")
eachBarLengthMult = input.int(5, "Each Bar Length Multiplier", minval=2, tooltip="For each new Forecast bar, how many more bars are averaged? Min 2")
vwmaAveragedLength = input.int(2, "VWMA Averaged Length:", minval=1, tooltip="All Forecast bars are put into a VWMA, what length should we use?")
emaAveragedLength = input.int(2, "EMA Averaged Length:", minval=1, tooltip="All Forecast bars are put into a EMA, what length should we use?")
filteredLength = input.int(10, "Filtered Length", minval=1, tooltip="What length should we use for Filtered Volume and RSI?")
emaStrengthLength = input.int(21, "EMA Strength Length:", minval=1, tooltip="What length should we use for the EMA Strength")

// ~~~~~~~~ VARIABLES ~~~~~~~~ //
//Bar values
predictiveHigh = array.new_float(predictiveCount)
predictiveLow = array.new_float(predictiveCount)
predictiveOpen = array.new_float(predictiveCount)
predictiveClose = array.new_float(predictiveCount)

// ~~~~~~~~ FUNCTIONS ~~~~~~~~ //
//Get individual source data for a bar
getSourceForecast(src, len) =>
    //Average
    returnValue = switch len
        0 => ta.ema(ta.vwma(math.avg(ta.ema(src, eachBarLengthMult >= 2 ? 2 : eachBarLengthMult), ta.vwma(src, eachBarLengthMult >= 2 ? 2 : eachBarLengthMult)), vwmaAveragedLength), emaAveragedLength)
        1 => ta.ema(ta.vwma(math.avg(ta.ema(src, eachBarLengthMult + 1), ta.vwma(src, eachBarLengthMult + 1)), vwmaAveragedLength), emaAveragedLength)
        2 => ta.ema(ta.vwma(math.avg(ta.ema(src, (eachBarLengthMult * 2) + 1), ta.vwma(src, (eachBarLengthMult * 2) + 1)), vwmaAveragedLength), emaAveragedLength)
        3 => ta.ema(ta.vwma(math.avg(ta.ema(src, (eachBarLengthMult * 3) + 1), ta.vwma(src, (eachBarLengthMult * 3) + 1)), vwmaAveragedLength), emaAveragedLength)
        4 => ta.ema(ta.vwma(math.avg(ta.ema(src, (eachBarLengthMult * 4) + 1), ta.vwma(src, (eachBarLengthMult * 4) + 1)), vwmaAveragedLength), emaAveragedLength)
        5 => ta.ema(ta.vwma(math.avg(ta.ema(src, (eachBarLengthMult * 5) + 1), ta.vwma(src, (eachBarLengthMult * 5) + 1)), vwmaAveragedLength), emaAveragedLength)
        6 => ta.ema(ta.vwma(math.avg(ta.ema(src, (eachBarLengthMult * 6) + 1), ta.vwma(src, (eachBarLengthMult * 6) + 1)), vwmaAveragedLength), emaAveragedLength)
        7 => ta.ema(ta.vwma(math.avg(ta.ema(src, (eachBarLengthMult * 7) + 1), ta.vwma(src, (eachBarLengthMult * 7) + 1)), vwmaAveragedLength), emaAveragedLength)
        8 => ta.ema(ta.vwma(math.avg(ta.ema(src, (eachBarLengthMult * 8) + 1), ta.vwma(src, (eachBarLengthMult * 8) + 1)), vwmaAveragedLength), emaAveragedLength)
        9 => ta.ema(ta.vwma(math.avg(ta.ema(src, (eachBarLengthMult * 9) + 1), ta.vwma(src, (eachBarLengthMult * 9) + 1)), vwmaAveragedLength), emaAveragedLength)
        10 => ta.ema(ta.vwma(math.avg(ta.ema(src, (eachBarLengthMult * 10) + 1), ta.vwma(src, (eachBarLengthMult * 10) + 1)), vwmaAveragedLength), emaAveragedLength)
        11 => ta.ema(ta.vwma(math.avg(ta.ema(src, (eachBarLengthMult * 11) + 1), ta.vwma(src, (eachBarLengthMult * 11) + 1)), vwmaAveragedLength), emaAveragedLength)
        12 => ta.ema(ta.vwma(math.avg(ta.ema(src, (eachBarLengthMult * 12) + 1), ta.vwma(src, (eachBarLengthMult * 12) + 1)), vwmaAveragedLength), emaAveragedLength)

    //Volume Filtered
    avgVol = ta.vwma(volume, filteredLength)
    volDiff = volume / avgVol
    midVolSmoothed = ta.vwma(returnValue * volDiff, 3)

    //RSI Filtered
    midDifference = ta.sma(ta.ema(high, filteredLength) - ta.ema(low, filteredLength), filteredLength)
    midRSI = ta.rsi(midVolSmoothed, filteredLength) * 0.01
    midAdd = midRSI * midDifference
    midAdjusted = close > open ? midAdd : midAdd * -1
    rsiFiltered = returnValue + midAdjusted

    //EMA strength
    strength = close > ta.ema(close, emaStrengthLength) ? 1 + (0.0005 * (len + 2)) : 1 - (0.0005 * (len + 2))
    strengthInterval = (rsiFiltered - (rsiFiltered * strength)) / predictiveCount
    strengthFiltered = rsiFiltered + (strengthInterval * (len + 1))

    //RSI Strength
    rsi = ta.rsi(close, 14)
    rsiMA = ta.sma(rsi, 14)
    rsiCross = ta.cross(rsi, rsiMA)
    rsiStrength = rsi >= 50 ? rsi - 50 : 50 - rsi
    if rsiCross
        rsiStrength := rsiStrength * (1 + (0.2 / (len + 1)))
    rsiDivision = rsi >= 70 or rsi <= 30 ? rsi > rsiMA ? len + 2 : len + 3 : len + 4
    rsiStrengthMult = (rsiStrength / rsiDivision) * 0.01
    rsiPriceInfluence = src * rsiStrengthMult
    rsiPriceInterval = (rsiPriceInfluence / predictiveCount) * (len + 1)
    rsiStrengthFiltered = rsi >= 50 ? strengthFiltered - rsiPriceInterval : strengthFiltered + rsiPriceInterval

    //Money Flow
    mf = ta.mfi(close, (len + 1))
    mfMA = ta.sma(mf, 14)
    mfCross = ta.cross(mf, mfMA)
    mfStrength = mf >= 50 ? mf - 50 : 50 - mf
    if mfCross
        mfStrength := mfStrength * (1 + (0.2 / (len + 1)))
    mfDivision = mf >= 70 or mf <= 30 ? mf > mfMA ? len + 1 : len + 2 : len + 3
    mfStrengthMult = (mfStrength / mfDivision) * 0.01
    mfPriceInfluence = src * mfStrengthMult
    mfPriceInterval = (mfPriceInfluence / predictiveCount) * (len + 1)
    returnValue := mf >= 50 ? rsiStrengthFiltered - mfPriceInterval : rsiStrengthFiltered + mfPriceInterval

    returnValue

// ~~~~~~~~ CALCULATIONS ~~~~~~~~ //
//Assign bar values
for i = 0 to predictiveCount - 1
    array.set(predictiveHigh, i, getSourceForecast(high, i))
    array.set(predictiveLow, i, getSourceForecast(low, i))
    array.set(predictiveOpen, i, getSourceForecast(open, i))
    array.set(predictiveClose, i, getSourceForecast(close, i))

// ~~~~~~~~ PLOTS ~~~~~~~~ //
//Draw the bars
if barstate.islast
    for i = 0 to predictiveCount - 1
        //draw
        index = i + 1
        lineHigh = line.new(bar_index + index, array.get(predictiveHigh, i), bar_index + i, array.get(predictiveHigh, i), color=color.green, width=1)
        lineLow = line.new(bar_index + index, array.get(predictiveLow, i), bar_index + i, array.get(predictiveLow, i), color=color.red, width=1)
        lineOpen = line.new(bar_index + index, array.get(predictiveOpen, i), bar_index + i, array.get(predictiveOpen, i), color=color.orange, width=1)
        lineClose = line.new(bar_index + index, array.get(predictiveClose, i), bar_index + i, array.get(predictiveClose, i), color=color.teal, width=1)

        //high zone
        if array.get(predictiveClose, i) >= array.get(predictiveOpen, i)
            linefill.new(lineClose, lineHigh, color=color.new(color.green, 95))
        else
            linefill.new(lineOpen, lineHigh, color=color.new(color.green, 95))

        //low zone
        if array.get(predictiveClose, i) < array.get(predictiveOpen, i)
            linefill.new(lineClose, lineLow, color=color.new(color.red, 95))
        else
            linefill.new(lineOpen, lineLow, color=color.new(color.red, 95))

        //Mid zone
        lineColor = color.red
        if i == 0
            if array.get(predictiveClose, i) >= close
                lineColor := color.green
        else if (i != 0 and array.get(predictiveClose, i) >= array.get(predictiveClose, nz(i - 1)))
            lineColor := color.green
        linefill.new(lineOpen, lineClose, color=color.new(lineColor, 75))
// ~~~~~~~~ END ~~~~~~~~ //