// The MIT License (MIT) // © mihakralj //@version=6 indicator("VWAP with Standard Deviation Bands", "VWAPSD", overlay=true) //@function Calculate VWAP with Standard Deviation Bands //@param src Source price series (typically hlc3) //@param vol Volume series //@param reset_condition Condition to reset VWAP calculation //@param num_devs Number of standard deviations for bands //@returns [vwap, upper_band, lower_band] vwapsd(series float src, series float vol, series bool reset_condition, simple float num_devs) => if num_devs <= 0 runtime.error("Number of deviations must be greater than 0") if num_devs > 5 runtime.error("Number of deviations exceeds maximum of 5") var float sum_pv = 0.0, var float sum_vol = 0.0, var float sum_pv2 = 0.0 float current_price = nz(src), float current_vol = nz(vol, 0.0) if reset_condition sum_pv := current_vol > 0.0 ? current_price * current_vol : 0.0 sum_vol := current_vol > 0.0 ? current_vol : 0.0 sum_pv2 := current_vol > 0.0 ? current_price * current_price * current_vol : 0.0 else if current_vol > 0.0 sum_pv += current_price * current_vol sum_vol += current_vol sum_pv2 += current_price * current_price * current_vol float vwap = sum_vol > 0.0 ? sum_pv / sum_vol : src float variance = sum_vol > 0.0 ? (sum_pv2 / sum_vol) - math.pow(vwap, 2) : 0.0 float stddev = math.sqrt(math.max(0.0, variance)) float upper = vwap + (num_devs * stddev) float lower = vwap - (num_devs * stddev) [vwap, upper, lower] // ---------- Main loop ---------- // Inputs i_source = input.source(hlc3, "Source") i_session_type = input.string("1D", "Session Reset", options=["1m", "2m", "3m", "5m", "10m", "15m", "30m", "45m", "1H", "2H", "3H", "4H", "1D", "1W", "1M", "3M", "6M", "12M", "Never"]) i_num_devs = input.float(2.0, "Standard Deviations", minval=0.1, maxval=5.0, step=0.1, tooltip="Number of standard deviations for bands") // Calculate reset condition reset_condition = switch i_session_type "1m" => ta.change(time("1")) != 0 "2m" => ta.change(time("2")) != 0 "3m" => ta.change(time("3")) != 0 "5m" => ta.change(time("5")) != 0 "10m" => ta.change(time("10")) != 0 "15m" => ta.change(time("15")) != 0 "30m" => ta.change(time("30")) != 0 "45m" => ta.change(time("45")) != 0 "1H" => ta.change(time("60")) != 0 "2H" => ta.change(time("120")) != 0 "3H" => ta.change(time("180")) != 0 "4H" => ta.change(time("240")) != 0 "1D" => ta.change(time("1D")) != 0 "1W" => ta.change(time("1W")) != 0 "1M" => ta.change(time("1M")) != 0 "3M" => ta.change(time("3M")) != 0 "6M" => ta.change(time("6M")) != 0 "12M" => ta.change(time("12M")) != 0 "Never" => bar_index == 0 => false // Calculation [vwap, upper, lower] = vwapsd(i_source, volume, reset_condition, i_num_devs) // Plot plot(vwap, "VWAP", color=color.yellow, linewidth=2) plot(upper, "Upper Band", color=color.red, linewidth=1, style=plot.style_line) plot(lower, "Lower Band", color=color.green, linewidth=1, style=plot.style_line) // Fill between bands fill_color = color.new(color.gray, 90) fill(plot(upper), plot(lower), color=fill_color, title="Band Fill")