> When you care more about *when* the market turns than how aggressively you can torture the noise, you reach for a Bessel.
The Bessel Filter is a 2nd-order low-pass IIR filter designed to preserve the **shape** and **timing** of price moves. Unlike sharper filters that chase steep roll-off at the expense of phase distortion, the Bessel family is engineered for a **maximally flat group delay**: signals are delayed, but not deformed.
This implementation follows John Ehlers–style adaptations for financial time series and is tuned for O(1) updates and zero heap allocations in QuanTAlib.
## The Standard
Originally derived from Friedrich Bessel’s work on Bessel polynomials and later adapted to signal processing, the Bessel filter became popular where **waveform integrity** matters more than raw attenuation: control systems, audio, and here, price series.
In trading terms:
- You keep the **relative timing** of swings.
- You avoid overshoot and ringing common in sharper filters.
- You accept a gentler roll-off as the price of cleaner turning points.
QuanTAlib implements the **2nd-order low-pass** variant used in Ehlers-style digital filters.
## Architecture & Physics
BESSEL is implemented as a **2nd-order IIR filter** with a fixed structure:
- State: last two filtered values plus last valid input
- Behavior:
- Short warmup period (a few bars)
- Stable, monotonic smoothing
- Minimal overshoot on sharp transitions
Conceptually:
- High frequencies are attenuated gradually.
- Phase is nearly linear in the passband, so local structures (peaks, troughs, breakout steps) keep their relative timing.
- It runs as an **O(1)** streaming update:
- One input in, one output out, constant work per bar.
### Specific Architectural Challenge
The main tension is:
- The design demands **IIR smoothness** and responsiveness.
- Recursive instability or phase warping in turning zones cannot be tolerated.
BESSEL solves this by:
- Fixing a 2nd-order topology with coefficients derived from the Bessel prototype.
- Using a **safe minimum length** (at least 2) to keep coefficients in a numerically stable region.
- Treating non-finite values via a last-valid-value cache so NaNs and infinities never poison the state.
## Mathematical Foundation
Let $L$ be the user-specified length (cutoff period). Internally it is clamped as
The filter maintains its state in a small set of scalar variables (`_prev1`, `_prev2`, `_lastValidValue`). No arrays or buffers are allocated during the `Update` cycle.
- **Expecting razor-sharp cutoff:** Bessel is **not** a Chebyshev or elliptic filter. Roll-off is gentler by design to preserve shape and timing. If you want violent attenuation of high-frequency noise, pick Butterworth, Chebyshev, or a band-pass.
- **Over-smoothing with large length:** Very large $L$ values will still preserve shape, but you will delay turning points more than necessary. Typical sweet spot for daily data is $L \in [10, 30]$.
- **Misinterpreting flat response as “weak” filter:** The goal is not to crush all noise. The goal is to keep enough structure that pattern recognition, divergence analysis, and multi-stream alignment still make sense.
- **Ignoring NaN propagation:** If your upstream feed throws `NaN` or infinities and you do not clean it, BESSEL will fall back to the last valid value. This is intentional. If you want gaps instead, preprocess the series and pass explicit masked values.
Used correctly, BESSEL gives you a **shape-faithful trend line** with clean timing and low overshoot, ideal for traders who care more about *when* than *how loudly* the filter shouts.