VWMA/SMA Delta Volatility (Statistical Anomaly Detector)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © tkarolak
//@version=5

// ====================
// ==== Background ====
// ====================

// This indicator detects and visualizes market volatility by
// analyzing the difference between VWMA and SMA to spot price anomalies.
// Calculation involves statistical analysis, including standard deviation and Z-score.
// Visualize results through histograms and a Z-score channel.
// Red hisogram bars indicate negative, green bars positive, and silver bars normal values.
// Utilize this tool to detect abnormal price movements and adapt trading strategies.
// Enhance market analysis during periods of increased volatility.
// Spot potential market anomalies and make informed trading decisions.
// A valuable addition to your trading toolkit for better risk management.
// MA Delta above 0 may signal a bullish reversal, 
// while crossing below 0 suggests a bearish sentiment reversal.

// Use in conjunction with other analysis methods for better results.

indicator("VWMA/SMA Delta Volatility (Statistical Anomaly Detector)", "MAs Delta Volatility (SAD)", overlay = false, precision = 2)

type SettingsSad
    float   source
    int     lenght
    int     sampleSize
    float   zScore
    bool    showChannel

// Tooltips
string ttSourceSad      = "Source for MAs delta calculations"
string ttLenghtSad      = "MAs length"
string ttSampleSizeSad	= "Dataset length for statistical computations in deriving a normal distribution, used to identify data points (MA delta), meeting criteria exceeding the standard deviation multiplied by the Z-score coefficient"
string ttZscoreSad		  = "The Z-scores multiplier serves as a filtering mechanism, providing insight into the extent to which a data point (MA delta) deviates from the mean in terms of standard deviations."
string ttHistogramSad	  = "Displays a Z-score channel, acting as filter"

string gSad = "Statistical Anomaly Detector"
SettingsSad settingsSad =
 SettingsSad.new(
   input.source (close, "Source",                   group=gSad, tooltip = ttSourceSad),
   input.int    (14,    "MAs Length",               group=gSad, minval = 3, tooltip = ttLenghtSad),
   input.int	  (100,   "Statistical sample size",  group=gSad, step = 1, minval = 100, maxval = 500, tooltip = ttSampleSizeSad),
   input.float	(2.0,   "Z-score",                  group=gSad, step = 0.1, minval = 1.0, maxval = 3.0, tooltip = ttZscoreSad),
   input.bool	  (true,  "Z-score channel",          group=gSad, tooltip=ttHistogramSad)
 )

// Functions
// Normalization function
calcNormalized(series float _src, float _additional1, float _additional2, int _len, float _scaleMin, float _scaleMax) =>
    float _srcLowest =  10e10
    float _srcHigest = -10e10
    _srcLowest := math.min(nz(ta.lowest(_src, _len)),_srcLowest)
    _srcHigest := math.max(nz(ta.highest(_src, _len)),_srcHigest)
    float _scaleRange = _scaleMax - _scaleMin
    float _normalized      = _scaleMin + _scaleRange * (_src - _srcLowest) / math.max(_srcHigest - _srcLowest, 10e-10)
    float _normalized_add1 = _scaleMin + _scaleRange * (_additional1 - _srcLowest) / math.max(_srcHigest - _srcLowest, 10e-10)
    float _normalized_add2 = _scaleMin + _scaleRange * (_additional2 - _srcLowest) / math.max(_srcHigest - _srcLowest, 10e-10)
    [_normalized, _normalized_add1, _normalized_add2]

// Calculate moving average delta (MA Delta), MA, standard deviation, and filters
sadDelta = ta.vwma(settingsSad.source, settingsSad.lenght)-ta.sma(settingsSad.source, settingsSad.lenght)
sadMa = ta.sma(sadDelta, settingsSad.sampleSize)
sadStdDev = ta.stdev(sadDelta, settingsSad.sampleSize)
sadLowerFilter = sadMa - settingsSad.zScore * sadStdDev
sadUpperFilter = sadMa + settingsSad.zScore * sadStdDev

// Normalization taking place here
[normalizedDelta, normalizedlowerFilter, normalizedupperFilter] = calcNormalized(sadDelta, sadLowerFilter, sadUpperFilter, settingsSad.sampleSize, -100, 100)

// Plots
colorDelta = sadDelta < 0 and sadDelta < sadLowerFilter ? color.red : sadDelta > 0 and sadDelta > sadUpperFilter ?  color.green : color.new(color.silver, 80)

hline(0, "Base Line", color.new(color.orange, 50), hline.style_dotted)
plot(normalizedDelta, "Delta", color=colorDelta, style=plot.style_histogram)
plot(settingsSad.showChannel ? normalizedlowerFilter : na, color=color.new(color.gray, 70), display = display.pane)
plot(settingsSad.showChannel ? normalizedupperFilter : na, color=color.new(color.gray, 70), display = display.pane)

//easy peasy