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

//@version=4
study("Relative Volume", shorttitle="RVOL", format=format.volume)

lsmalength = input(50, "LSMA Length", group="General Settings")
std = 21

ma2 = linreg(volume, lsmalength, 0)
stdev_volume = stdev(volume, std)
clean = volume - ma2

showanom = input(true, "Show Anomalies")

len = input(50, "Length")
threshold_multiplier = input(2, "Threshold Multiplier", minval=0.1, maxval=20)

avg_volume = sma(volume, len)
rvol = volume / avg_volume

// Plotting the threshold line based on the threshold multiplier
threshold_line = threshold_multiplier
plot(threshold_line, "Threshold", color=color.rgb(124, 124, 124))

// Normalize volume and anomalies
normalized_volume = volume / avg_volume
normalized_anomalies = clean / avg_volume

// Plotting the normalized volume
plot(normalized_volume, style=plot.style_columns, color=close > open ? color.rgb(101, 101, 101) : color.rgb(50, 50, 50), title="Normalized Volume", trackprice=false)

// Determine the color of anomalies
anomaly_color = close > open ? color.blue : color.red

// Plotting the normalized anomalies
plot(showanom and normalized_anomalies > stdev_volume / avg_volume ? normalized_volume : na, style=plot.style_columns, color=anomaly_color, title="Normalized Anomalies")

// Alert condition
cross_above_threshold = crossover(normalized_anomalies, threshold_line)
alertcondition(cross_above_threshold, title="Candle Crossed Threshold", message="A candle has crossed the threshold.")


// ------------------------------- Candle colour ------------------------------------------------------------

// inputs
i_src = input("Volume", title="Source", type=input.string)
lenCan = input(20, "Z-Score MA Length")
z1 = input(2.0, "Threshold z1", step=0.1)
z2 = input(2.9, "Threshold z2", step=0.1)
low_volume_threshold = input(-0.9, "Low Volume Threshold", step=0.1)

// functions
f_zscore(src, lenCan) =>
    mean = sma(src, lenCan)
    std = stdev(src, lenCan)
    z = (src - mean) / std

// calculations
z_volume = f_zscore(volume, lenCan)
z_body = f_zscore(abs(close - open), lenCan)

float z = na
if i_src == "Volume"
    z := z_volume
else if i_src == "Body size"
    z := z_body
else if i_src == "Any"
    z := max(z_volume, z_body)
else if i_src == "All"
    z := min(z_volume, z_body)
normal = z < z1
large = z >= z1 and z < z2
extreme = z >= z2

up = close >= open
down = close < open

low_volume = z_volume < low_volume_threshold

up_normal = up and normal
up_large = up and large
up_extreme = up and extreme

down_normal = down and normal
down_large = down and large
down_extreme = down and extreme

// plots
color_up = up_extreme ? color.rgb(0, 255, 8) : up_large ? color.blue : up_normal ? color.rgb(222, 222, 222) : na
color_down = down_extreme ? color.rgb(199, 22, 193) : down_large ? color.rgb(224, 75, 75) : down_normal ? color.rgb(0, 0, 0) : na

barcolor((up_normal or up_large or up_extreme) and not low_volume ? color_up : low_volume ? color.yellow : na, title="Up Bar")
barcolor((down_normal or down_large or down_extreme) and not low_volume ? color_down : low_volume ? color.yellow : na, title="Down Bar")