High Low Color Volume
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © MrJulius

// @version=5

// Companion to High Low Bars in Color. Color is determined by change in midpoints between high and low (hl2).

indicator("High Low Color Volume", overlay=true, scale=scale.left, format=format.volume)

// constants
string  COLOR_METHOD_TOOLTIP = "Standard deviation threshold refers to vector change in hl2 from one bar to the next. The SMA delta absolute values method uses a percentile threshold. Percent change threshold is useful for an overview of volatility. Tritone colors the bars without any in-between shading."

// inputs
color   upcolorInput             = input.color(color.rgb(0, 137, 123, 0), "Up", group = "Color Palette")
color   downcolorInput           = input.color(color.rgb(255, 82, 82, 0), "Down", group = "Color Palette")
color   flatcolorInput           = input.color(color.rgb(97, 55, 145, 0), "Flat", group = "Color Palette")
int     lumfactorInput           = input.int(160, "Luminance factor", group = "Color Palette")
string  colormethodInput         = input.string("StDev", "Color method", ["StDev", "SMA D Abs",  "Percent", "Tritone"],
                                                  COLOR_METHOD_TOOLTIP, group = "Color Method")
float   stdevInput               = input.float(1.2, "Standard deviation threshold", group = "Color Method")
int     percentileInput          = input.int(150, "Percentage of SMA for hl2 delta absolute values", group = "Color Method")
int     deltasmalengthInput      = input.int(30, "Length for St Dev or SMA", group = "Color Method")
float   percentchangeInput       = input.float(0.05, "Percent change threshold", group = "Color Method")
bool    showsmaInput             = input.bool(true, "Show SMA", group = "SMA")
int     smalengthInput           = input.int(30, "Julius volume SMA length", group = "SMA")

// set color
upcolor   = color.rgb(color.r(upcolorInput) * lumfactorInput / 255,
                      color.g(upcolorInput) * lumfactorInput / 255,
                      color.b(upcolorInput) * lumfactorInput / 255,
                      color.t(upcolorInput))
downcolor = color.rgb(color.r(downcolorInput) * lumfactorInput / 255,
                      color.g(downcolorInput) * lumfactorInput / 255,
                      color.b(downcolorInput) * lumfactorInput / 255,
                      color.t(downcolorInput))
flatcolor = color.rgb(color.r(flatcolorInput) * lumfactorInput / 255,
                      color.g(flatcolorInput) * lumfactorInput / 255,
                      color.b(flatcolorInput) * lumfactorInput / 255,
                      color.t(flatcolorInput))
difference = hl2 - hl2[1]
deltapercent = 100*difference / hl2[1]
deltastdev = ta.stdev(difference, deltasmalengthInput)
deltaabs = math.abs(difference)
deltaabssma = ta.sma(deltaabs, deltasmalengthInput)
color candlecolor = switch colormethodInput
    "StDev"     => difference > deltastdev * stdevInput ? upcolor :
                   difference > 0 ? 
                      color.from_gradient(difference * 100 / (deltastdev * stdevInput), 0, 100, flatcolor, upcolor) :
                   difference == 0 ? flatcolor :
                   difference > -1 * deltastdev * stdevInput ? 
                      color.from_gradient(difference * 100 / (deltastdev * stdevInput), -100, 0, downcolor, flatcolor) :
                   downcolor
    "SMA D Abs" => difference > deltaabssma * percentileInput / 100 ? upcolor :
                   difference > 0 ? 
                      color.from_gradient(difference * 10000 / (deltaabssma * percentileInput), 0, 100, flatcolor, upcolor) :
                   difference == 0 ? flatcolor :
                   difference > -1 * deltaabssma * percentileInput / 100 ? 
                      color.from_gradient(difference * 10000 / (deltaabssma * percentileInput), -100, 0, downcolor, flatcolor) :
                   downcolor
    "Percent"   => deltapercent > percentchangeInput ? upcolor :
                   deltapercent > 0 ? 
                      color.from_gradient(deltapercent * 100 / percentchangeInput, 0, 100, flatcolor, upcolor) :
                   deltapercent == 0 ? flatcolor :
                   deltapercent > -1 * percentchangeInput ? 
                      color.from_gradient(deltapercent * 100 / percentchangeInput, -100, 0, downcolor, flatcolor) :
                   downcolor
    "Tritone"   => hl2 > hl2[1] ? upcolor : hl2 < hl2[1] ? downcolor : flatcolor

// plot volume
plot(volume, "Color Vol", candlecolor, style=plot.style_columns)
plot(showsmaInput ? ta.sma(volume, smalengthInput) : na, "Vol SMA", color.rgb(129, 209, 255))
