// This Pine Script® code is licensed under Apache-2.0
// SPDX-License-Identifier: Apache-2.0
// © PineForge contributors 2026
//
// PF probe 20 — range-filter with var-float band drift
// Purpose: parity test for `var float rangeFilter` cumulative band that drifts
// up by smoothed range when close breaks above hi-target (and vice versa) — a
// stateful filter whose value depends on every prior bar's update path.
//
//@version=6
strategy("Range Filter", overlay=true, initial_capital=1000000, process_orders_on_close=false, pyramiding=1, commission_type=strategy.commission.percent, commission_value=0, slippage=0, default_qty_type=strategy.fixed, default_qty_value=1)
// === Inputs ===
filterLen = input.int(50, "Filter Length", minval=5)
filterMult = input.float(2.5, "Range Multiplier", step=0.1)
// === Smooth Range calculation ===
avgRange = ta.ema(high - low, filterLen)
smoothRng = avgRange * filterMult
// === Range Filter using var ===
var float rangeFilter = close
var int filterDir = 0
// Upward filter
hiTarget = rangeFilter + smoothRng
loTarget = rangeFilter - smoothRng
if close > hiTarget
rangeFilter := close - smoothRng
filterDir := 1
else if close < loTarget
rangeFilter := close + smoothRng
filterDir := -1
else
if filterDir == 1
newFilter = close - smoothRng
rangeFilter := math.max(rangeFilter, newFilter)
else if filterDir == -1
newFilter = close + smoothRng
rangeFilter := math.min(rangeFilter, newFilter)
// === Direction change signals ===
longCond = filterDir == 1 and filterDir[1] != 1
shortCond = filterDir == -1 and filterDir[1] != -1
// === Strategy ===
if longCond
strategy.entry("Long", strategy.long)
if shortCond
strategy.entry("Short", strategy.short)
plot(rangeFilter, "Range Filter", color=filterDir == 1 ? color.green : color.red, linewidth=2)