Range Filter [DW]
"Range Filter [DW]" by DonovanWall, MPL-2.0. Ported to FloScript by FloSignals; modifications under MPL-2.0. Original: Range Filter [DW] (v3.0), read 2026-10-12T15:59:37.567Z; source language v4.
Licence: Mozilla Public License 2.0 (MPL-2.0) — full text. The source is published with it, modifications included, under the same licence.
Range Filter [DW] by DonovanWall, ported from Pine v4. Overlay indicator with 4 plots, 2 fills, bar/background colouring and 9 inputs.
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © DonovanWall
//██████╗ ██╗ ██╗
//██╔══██╗██║ ██║
//██║ ██║██║ █╗ ██║
//██║ ██║██║███╗██║
//██████╔╝╚███╔███╔╝
//╚═════╝ ╚══╝╚══╝
// ------------------------------------------------------------------------------------------------
// Original author: DonovanWall
// Original title: Range Filter [DW]
// Licence: MPL-2.0 (the header above is the original notice, kept verbatim)
// Pine version: 4
// Fetched: 2026-10-12
// Ported to FloScript by FloSignals; modifications under MPL-2.0.
// Converter: @flosignals/floscript 0.1.0, strict mode, score 100/100
// ------------------------------------------------------------------------------------------------
//@floscript=1
//@version=5
// Converted by the FloScript converter from a Pine-compatible v4 source.
indicator(title="Range Filter [DW]", shorttitle="RF [DW]", overlay=true)
//This is an experimental study designed to filter out minor price action for a clearer view of trends.
//Inspired by the QQE's volatility filter, this filter applies the process directly to price rather than to a smoothed RSI.
//First, a smooth average price range is calculated for the basis of the filter and multiplied by a specified amount.
//Next, the filter is calculated by gating price movements that do not exceed the specified range.
//Lastly the target ranges are plotted to display the prices that will trigger filter movement.
//Custom bar colors are included. The color scheme is based on the filtered price trend.
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//Updates:
// -> Migrated to v4.
// -> Range Filter and the bands are now calculated in a singular function.
// -> There are now two different calculation methods for the filter. Select the type you want to use via the "Filter Type" input. Type 1 is the original formula.
// -> Multiple range sizing methods are now available. You can choose from the following scales:
// - Points
// - Pips (Works best with forex pairs, obviously)
// - Ticks
// - % of Price
// - ATR
// - Average Change (Default. This is the original sizing method.)
// - Standard Deviation
// - Absolute (Absolute numerical value)
// -> Range smoothing is now optional, and you can specify your smoothing length. Smoothing only affects dynamic scales (ATR, Average Change, and Standard Deviation).
// -> Filter movement can now be determined using wicks or close. This can be specified via the "Movement Source" input.
// -> Stability Fix: Added correction for NaN values to stabilize initial states.
// -> Reorganized the script structure.
// -> Revamped the color scheme.
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//Updates:
// - The Range Filter functions have now been rebuilt using Pine's awesome new array functions.
// - Standard deviation calculation has been adjusted to calculate the same as TV's built in stdev() function.
// - Rewritten filter direction and bar color variables.
// - Included an external output variable for trend information that can easily be sent to other scripts without hardcoding.
// The output format is 1 for bullish, and -1 for bearish.
// To use this external variable with another script, simply select it from your other script's source dropdown tab.
// - Added the ability to average range filter values based on a user defined number of filter changes.
// This averaging method utilized the Conditional Sampling EMA function I introduced in my Resampling Filter Pack and only takes a new sample when the filter changes its value.
// This opens up a whole new world of possible filter outputs.
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//Functions
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//Conditional Sampling EMA Function
Cond_EMA(x, cond, n) =>
var val = array.new_float(0)
var ema_val = array.new_float(1)
if cond
array.push(val, x)
if array.size(val) > 1
array.remove(val, 0)
if na(array.get(ema_val, 0))
array.fill(ema_val, array.get(val, 0))
array.set(ema_val, 0, (array.get(val, 0) - array.get(ema_val, 0)) * (2 / (n + 1)) + array.get(ema_val, 0))
EMA = array.get(ema_val, 0)
EMA
//Conditional Sampling SMA Function
Cond_SMA(x, cond, n) =>
var vals = array.new_float(0)
if cond
array.push(vals, x)
if array.size(vals) > n
array.remove(vals, 0)
SMA = array.avg(vals)
SMA
//Standard Deviation Function
Stdev(x, n) =>
math.sqrt(Cond_SMA(math.pow(x, 2), 1, n) - math.pow(Cond_SMA(x, 1, n), 2))
//Range Size Function
rng_size(x, scale, qty, n) =>
ATR = Cond_EMA(ta.tr(true), 1, n)
AC = Cond_EMA(math.abs(x - x[1]), 1, n)
SD = Stdev(x, n)
rng_size = scale == "Pips" ? qty * 0.0001 : scale == "Points" ? qty * syminfo.pointvalue : scale == "% of Price" ? close * qty / 100 : scale == "ATR" ? qty * ATR : scale == "Average Change" ? qty * AC : scale == "Standard Deviation" ? qty * SD : scale == "Ticks" ? qty * syminfo.mintick : qty
//Two Type Range Filter Function
rng_filt(h, l, rng_, n, type, smooth, sn, av_rf, av_n) =>
rng_smooth = Cond_EMA(rng_, 1, sn)
r = smooth ? rng_smooth : rng_
var rfilt = array.new_float(2, (h + l) / 2)
array.set(rfilt, 1, array.get(rfilt, 0))
if type == "Type 1"
if h - r > array.get(rfilt, 1)
array.set(rfilt, 0, h - r)
if l + r < array.get(rfilt, 1)
array.set(rfilt, 0, l + r)
if type == "Type 2"
if h >= array.get(rfilt, 1) + r
array.set(rfilt, 0, array.get(rfilt, 1) + math.floor(math.abs(h - array.get(rfilt, 1)) / r) * r)
if l <= array.get(rfilt, 1) - r
array.set(rfilt, 0, array.get(rfilt, 1) - math.floor(math.abs(l - array.get(rfilt, 1)) / r) * r)
rng_filt1 = array.get(rfilt, 0)
hi_band1 = rng_filt1 + r
lo_band1 = rng_filt1 - r
rng_filt2 = Cond_EMA(rng_filt1, rng_filt1 != rng_filt1[1], av_n)
hi_band2 = Cond_EMA(hi_band1, rng_filt1 != rng_filt1[1], av_n)
lo_band2 = Cond_EMA(lo_band1, rng_filt1 != rng_filt1[1], av_n)
rng_filt = av_rf ? rng_filt2 : rng_filt1
hi_band = av_rf ? hi_band2 : hi_band1
lo_band = av_rf ? lo_band2 : lo_band1
[hi_band, lo_band, rng_filt]
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//Inputs
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//Filter Type
f_type = input.string(defval="Type 1", options=["Type 1", "Type 2"], title="Filter Type")
//Movement Source
mov_src = input.string(defval="Close", options=["Wicks", "Close"], title="Movement Source")
//Range Size Inputs
rng_qty = input.float(defval=2.618, minval=0.0000001, title="Range Size")
rng_scale = input.string(defval="Average Change", options=["Points", "Pips", "Ticks", "% of Price", "ATR", "Average Change", "Standard Deviation", "Absolute"], title="Range Scale")
//Range Period
rng_per = input.int(defval=14, minval=1, title="Range Period (for ATR, Average Change, and Standard Deviation)")
//Range Smoothing Inputs
smooth_range = input(defval=true, title="Smooth Range")
smooth_per = input.int(defval=27, minval=1, title="Smoothing Period")
//Filter Value Averaging Inputs
av_vals = input(defval=false, title="Average Filter Changes")
av_samples = input.int(defval=2, minval=1, title="Number Of Changes To Average")
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//Definitions
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//High And Low Values
h_val = mov_src == "Wicks" ? high : close
l_val = mov_src == "Wicks" ? low : close
//Range Filter Values
[h_band, l_band, filt] = rng_filt(h_val, l_val, rng_size((h_val + l_val) / 2, rng_scale, rng_qty, rng_per), rng_per, f_type, smooth_range, smooth_per, av_vals, av_samples)
//Direction Conditions
var fdir = 0.0
fdir := filt > filt[1] ? 1 : filt < filt[1] ? -1 : fdir
upward = fdir == 1 ? 1 : 0
downward = fdir == -1 ? 1 : 0
//Colors
filt_color = upward ? #05ff9b : downward ? #ff0583 : #cccccc
bar_color = upward and close > filt ? (close > close[1] ? #05ff9b : #00b36b) : downward and close < filt ? (close < close[1] ? #ff0583 : #b8005d) : #cccccc
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//Outputs
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//Filter Plot
filt_plot = plot(filt, color=color.new(filt_color, 0), linewidth=3, title="Filter")
//Band Plots
h_band_plot = plot(h_band, color=color.new(#05ff9b, 100), title="High Band")
l_band_plot = plot(l_band, color=color.new(#ff0583, 100), title="Low Band")
//Band Fills
fill(h_band_plot, filt_plot, color=color.new(#00b36b, 85), title="High Band Fill")
fill(l_band_plot, filt_plot, color=color.new(#b8005d, 85), title="Low Band Fill")
//Bar Color
barcolor(bar_color)
//External Trend Output
plot(fdir, editable=false, display=display.none, title="External Output - Trend Signal", color=color.new(color.blue, 100))
This file is under the Mozilla Public License 2.0; it is a port of the original by DonovanWall, with the original licence header kept and the changes made for FloScript noted in the file.
- v2
Library refresh 2026-10-14
- v1
Library refresh 2026-10-12
Disclaimer. Scripts are written and published by members, or ported by FloSignals from open-source originals, and are their authors' own work and opinion. FloSignals does not review them for correctness and nothing in a script is financial advice or a recommendation to buy or sell anything — read the Risk Disclaimer. Posting here is under the Community Rules; a script that is not the poster's to post can be reported as the Copyright & Takedowns page says.

Comments (0)
No comments yet. Members can leave one.