Files

59 lines
2.3 KiB
Plaintext

// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Deviation-Scaled Moving Average (DSMA)", "DSMA", overlay=true)
//@function Calculates DSMA using standard deviation to scale the averaging factor
//@param source Series to calculate DSMA from
//@param period Length of the lookback period for both average and deviation calculation
//@param scaleFactor Combined scaling/smoothing factor (0.01-0.9)
//@returns DSMA value that adapts to market volatility through deviation scaling
//@optimized Uses circular buffer for RMS calculation and adaptive alpha for O(1) complexity
dsma(series float source, simple int period, simple float scaleFactor=0.5) =>
float a1 = math.exp(-1.414 * math.pi / (period * 0.5))
float b1 = 2.0 * a1 * math.cos(1.414 * math.pi / (period * 0.5))
float c1 = 1.0 - b1 + (a1 * a1)
float c1Half = c1 * 0.5
float periodRecip = 1.0 / period
float scaleAdjustment = scaleFactor * 5.0 * periodRecip
var float result = na
var float filt = 0.0
var float filt1 = 0.0
var float filt2 = 0.0
var float zeros1 = 0.0
var float sumSquared = 0.0
var array<float> filtSquared = array.new_float(period, 0.0)
var int bufferIndex = 0
if na(source)
result
else
if na(result)
result := source
else
float zeros = source - result
filt := c1Half * (zeros + zeros1) + b1 * filt1 - (a1 * a1) * filt2
float filtSq = filt * filt
sumSquared := sumSquared + filtSq - array.get(filtSquared, bufferIndex)
array.set(filtSquared, bufferIndex, filtSq)
bufferIndex := (bufferIndex + 1) % period
float rms = math.sqrt(math.max(sumSquared * periodRecip, 1e-10))
float alpha = math.min(scaleAdjustment * math.abs(filt / rms), 1.0)
result := alpha * source + (1 - alpha) * result
zeros1 := zeros
filt2 := filt1
filt1 := filt
result
// ---------- Main loop ----------
// Inputs
i_source = input.source(close, "Source")
i_period = input.int(25, "Period", minval=2)
i_scale = input.float(0.9, "Scale Factor", minval=0.01, maxval=0.9, step=0.01)
// Calculation
dsma_value = dsma(i_source, i_period, i_scale)
// Plot
plot(dsma_value, "DSMA", color=color.yellow, linewidth=2)