PHP Code:
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © DonovanWall
//██████╗ ██╗ ██╗
//██╔══██╗██║ ██║
//██║ ██║██║ █╗ ██║
//██║ ██║██║███╗██║
//██████╔╝╚███╔███╔╝
//╚═════╝ ╚══╝╚══╝
//@version=5
indicator(title='Range Filter [DW] & Labels', shorttitle='RF [DW] & Labels', 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
rng_size
//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=true, 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=filt_color, linewidth=3, title='Filter', transp=0)
//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', transp=100)
// Trading Conditions Logic
longCond = close > filt and close > close[1] and upward > 0 or close > filt and close < close[1] and upward > 0
shortCond = close < filt and close < close[1] and downward > 0 or close < filt and close > close[1] and downward > 0
CondIni = 0
CondIni := longCond ? 1 : shortCond ? -1 : CondIni[1]
longCondition = longCond and CondIni[1] == -1
shortCondition = shortCond and CondIni[1] == 1
// Plot Buy and Sell Labels
plotshape(longCondition, title='Buy Signal', text='BUY', textcolor=color.new(color.white, 0), style=shape.labelup, size=size.normal, location=location.belowbar, color=color.new(color.green, 0))
plotshape(shortCondition, title='Sell Signal', text='SELL', textcolor=color.new(color.white, 0), style=shape.labeldown, size=size.normal, location=location.abovebar, color=color.new(color.red, 0))
// Alerts
alertcondition(longCondition, title='Buy Alert', message='BUY')
alertcondition(shortCondition, title='Sell Alert', message='SELL')
Yer İmleri