Fractional Differentiation
Stationarity with memory preservation for predictive time series
Price levels are non-stationary (trending mean), so ML models trained on them don’t generalize. Taking full returns (d=1) makes them stationary but destroys all memory of price levels. Fractional differentiation lets you pick a d between 0 and 1 that makes the series just barely stationary while keeping as much memory as possible.
From AFML Chapter 5.
Compute weights
python
import horizon as hz
weights = hz.frac_diff_weights(d=0.4, threshold=1e-5)
# Returns the filter coefficients for fractional differencing at order d
Apply fractional differencing
python
series = [100.0, 101.5, 99.8, 102.3, ...] # price series
diffed = hz.frac_diff_ffd(series, d=0.4, threshold=1e-5)
The ffd (fixed-width window) variant truncates the filter at threshold, making it practical for long series.
Finding the right d
Start at d=0 and increase until the series passes an ADF stationarity test. Typical values for daily equity prices: d ≈ 0.3 to 0.5.
python
for d in [0.1, 0.2, 0.3, 0.4, 0.5, 0.6]:
diffed = hz.frac_diff_ffd(prices, d=d, threshold=1e-5)
# run ADF test on diffed
# stop when p-value < 0.05
When to use
- Preprocessing price series for ML models (instead of raw returns)
- When you want stationarity but also want the model to “remember” price levels
- Feature engineering for strategies that need both trend and level information