// Licensed under the Apache License, Version 2.0 // © mihakralj //@version=6 indicator("Double Weighted Moving Average (DWMA)", "DWMA", overlay=true) //@function Calculates DWMA using double weighted smoothing with inline O(1) WMA //@param source Series to calculate DWMA from //@param period Lookback period for both smoothing passes //@returns DWMA value, calculates from first bar using available data //@optimized Uses two inline O(1) WMA calculations for combined O(1) complexity per bar dwma(series float source, simple int period) => if period <= 0 runtime.error("Period must be greater than 0") var array buffer1 = array.new_float(period, na) var int head1 = 0 var float sum1 = 0.0 var float weighted_sum1 = 0.0 var int count1 = 0 var float norm1 = 0.0 var array buffer2 = array.new_float(period, na) var int head2 = 0 var float sum2 = 0.0 var float weighted_sum2 = 0.0 var int count2 = 0 var float norm2 = 0.0 float oldest1 = array.get(buffer1, head1) float current1 = nz(source) if not na(oldest1) float old_sum1 = sum1 sum1 -= oldest1 sum1 += current1 weighted_sum1 := weighted_sum1 - old_sum1 + (period * current1) else count1 += 1 sum1 += current1 weighted_sum1 := weighted_sum1 + (count1 * current1) norm1 := count1 * (count1 + 1) * 0.5 array.set(buffer1, head1, current1) head1 := (head1 + 1) % period float wma1 = weighted_sum1 / norm1 float oldest2 = array.get(buffer2, head2) float current2 = nz(wma1) if not na(oldest2) float old_sum2 = sum2 sum2 -= oldest2 sum2 += current2 weighted_sum2 := weighted_sum2 - old_sum2 + (period * current2) else count2 += 1 sum2 += current2 weighted_sum2 := weighted_sum2 + (count2 * current2) norm2 := count2 * (count2 + 1) * 0.5 array.set(buffer2, head2, current2) head2 := (head2 + 1) % period weighted_sum2 / norm2 // ---------- Main loop ---------- // Inputs i_period = input.int(10, "Period", minval=1) i_source = input.source(close, "Source") // Calculation dwma_value = dwma(i_source, i_period) // Plot plot(dwma_value, "DWMA", color=color.yellow, linewidth=2)