AI Momentum [YinYang]
// 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("AI Momentum [YinYang] ", overlay=true)

// ~~~~~~~~~~~ IMPORTS ~~~~~~~~~~~ //
//Credits go to jdehorty for the rationalQuadratic and gaussian Functions
import jdehorty/KernelFunctions/2 as kernels

// ~~~~~~~~~~~ INPUTS ~~~~~~~~~~~ //
showSignals = input.bool(true, "Show Signals", group="Momentum", tooltip="Sometimes it can be difficult to visualize the zones with signals enabled.")
factorVolume = input.bool(false, "Factor Volume", group="Momentum", tooltip="Factor Volume only applies to Overly Bullish and Bearish Signals. It's when the Volume is > VWMA Volume over the Smoothing Length.")
zoneLengths = input.int(50, "Zone Inside Length", group="Momentum", tooltip="The Zone Inside is the Inner zone of the High and Low. This is the length used to create it.")
zoneOutsideLengths = input.int(75, "Zone Outside Length", group="Momentum", tooltip="The Zone Outside is the Outer zone of the High and Low. This is the length used to create it.")
smoothingLength = input.int(14, "Smoothing length", group="Momentum", tooltip="Smoothing length is the length used to smooth out our Bullish and Bearish signals, along with our Overly Bullish and Overly Bearish Signals.")
// Kernel Settings
lookbackWindow = input.int(8, "Lookback Window", tooltip="The number of bars used for the estimation. This is a sliding value that represents the most recent historical bars. Recommended range: 3-50", group="Kernel Settings")
relativeWeighting = input.float(8., "Relative Weighting", step=0.25, tooltip="Relative weighting of time frames. As this value approaches zero, the longer time frames will exert more influence on the estimation. As this value approaches infinity, the behavior of the Rational Quadratic Kernel will become identical to the Gaussian kernel. Recommended range: 0.25-25", group="Kernel Settings")
startBar = input.int(25, "Start Regression at Bar", tooltip="Bar index on which to start regression. The first bars of a chart are often highly volatile, and omission of these initial bars often leads to a better overall fit. Recommended range: 5-25", group="Kernel Settings")

// ~~~~~~~~~~~ CALCULATIONS ~~~~~~~~~~~ //
//Kernal Zones
highestHigh = kernels.rationalQuadratic(ta.highest(high, zoneLengths), lookbackWindow, relativeWeighting, startBar)
lowestLow = kernels.rationalQuadratic(ta.lowest(low, zoneLengths), lookbackWindow, relativeWeighting, startBar)
highestHighOutside = kernels.rationalQuadratic(ta.highest(high, zoneOutsideLengths), lookbackWindow, relativeWeighting, startBar)
lowestLowOutside = kernels.rationalQuadratic(ta.lowest(low, zoneOutsideLengths), lookbackWindow, relativeWeighting, startBar)
kernClose = kernels.rationalQuadratic(close, lookbackWindow, relativeWeighting, startBar)
zoneMid = math.avg(highestHigh, lowestLow)

//Bullish and bearish (these hold momentum and may be a safe way to know if the momentum is still going strong for the trend)
bullishBar = kernels.rationalQuadratic(close, lookbackWindow, relativeWeighting, startBar) > kernels.rationalQuadratic(ta.highest(ta.vwma(ohlc4, smoothingLength), smoothingLength), lookbackWindow, relativeWeighting, startBar)
bearishBar = kernels.rationalQuadratic(close, lookbackWindow, relativeWeighting, startBar) < kernels.rationalQuadratic(ta.lowest(ta.vwma(ohlc4, smoothingLength), smoothingLength), lookbackWindow, relativeWeighting, startBar)

//Very bullish and bearish (these may represent when the momentum is about to change as they are almost TOO Bullish and Bearish
rsi = kernels.rationalQuadratic(ta.rsi(close, smoothingLength), lookbackWindow, relativeWeighting, startBar)
vol = kernels.rationalQuadratic(volume, lookbackWindow, relativeWeighting, startBar)
volAvg = kernels.rationalQuadratic(ta.vwma(volume, smoothingLength), lookbackWindow, relativeWeighting, startBar)

veryBullish = bullishBar and rsi >= 57 and (not factorVolume or vol > volAvg)
veryBearish = bearishBar and rsi <= 43 and (not factorVolume or vol > volAvg)

//Kernal Crossing Calculations
kern1 = kernels.rationalQuadratic(close, lookbackWindow, relativeWeighting, startBar)
kern2 = kernels.gaussian(close, lookbackWindow - 2, startBar)
// Kernel Crossovers
bool isBullishCross = ta.crossover(kern2, kern1)
bool isBearishCross = ta.crossunder(kern2, kern1)

// ~~~~~~~~~~~ PLOTS ~~~~~~~~~~~ //
//Bullish and bearish bars (keeping the movement strong, may be safe to stay in)
plotshape(showSignals and bullishBar and not veryBullish, style=shape.xcross, color = color.green, location=location.abovebar, title="Bullish Momentum")
plotshape(showSignals and bearishBar and not veryBearish, style=shape.xcross, color = color.red, location=location.belowbar, title="Bearish Momentum")

//Very Bullish and Bearish bars (has potential for a momentum change)
plotshape(showSignals and veryBullish, style=shape.cross, color = color.orange, location=location.abovebar, size=size.tiny, title="Overly Bullish")
plotshape(showSignals and veryBearish, style=shape.cross, color = color.teal, location=location.belowbar, size=size.tiny, title="Overly Bearish")

//Kernal Cross
plotshape(showSignals and isBullishCross, style=shape.cross, color = color.green, location=location.abovebar, size=size.small, title="Bull Cross")
plotshape(showSignals and isBearishCross, style=shape.cross, color = color.red, location=location.belowbar, size=size.small, title="Bear Cross")

//Kernal Zones
pHighInside = plot(highestHigh, color=color.orange)
pClose = plot(kernClose, color=color.white)
pLowInside = plot(lowestLow, color=color.teal)
pMid = plot(zoneMid, color=color.yellow)

pHighOutside = plot(highestHighOutside, color=color.red)
pLowOutside = plot(lowestLowOutside, color=color.green)

fillColor = kernClose > zoneMid ? color.green : color.red
fill(pClose, pMid, color=color.new(fillColor, 90))
fill(pHighInside, pHighOutside, color=color.new(color.red, 90))
fill(pLowInside, pLowOutside, color=color.new(color.green, 90))

// ~~~~~~~~~~~ END ~~~~~~~~~~~ //