fracdiff

Defined in fynance.features.engineering

fracdiff(X, d=0.4, tol=1e-5)[source]

Fixed-width-window fractional differentiation of a price series.

Stationarizes a (typically non-stationary, e.g. price or log-price) series while retaining as much memory as possible, unlike integer differencing (d=1) which is stationary but wipes out most of the long-run dependence. Applies the fractional difference operator \((1-L)^d\) — where \(L\) is the lag operator — truncated to a fixed-width window, so that it is usable causally (online) rather than needing the full history at every step as the “expanding window” variant does.

The weights follow the binomial-series recursion

\[w_0 = 1, \qquad w_k = -w_{k-1} \frac{d - k + 1}{k},\]

truncated to the first \(K\) terms such that \(|w_K| < tol\) (\(K\) is fixed for the whole series — “fixed-width window”). The output is the causal convolution

\[y_t = \sum_{k=0}^{K-1} w_k X_{t-k}, \qquad t \ge K - 1,\]

with the first \(K - 1\) entries set to NaN (insufficient history). Only past and current values of X are used, so fracdiff is strictly causal and safe to use in a walk-forward / online setting.

Parameters:
Xnp.ndarray[float64, ndim=1 or 2]

Input series (e.g. price level). If two-dimensional, shape (T, N), each column is treated independently. Must be finite (no NaN / inf).

dfloat, optional

Order of differentiation, must lie in [0, 2]. d=0 leaves the series unchanged (post-warmup); d=1 reduces, with the default tol, to the ordinary first difference; non-integer d in between trades off memory (small d) against stationarity (large d). Default is 0.4.

tolfloat, optional

Weight-magnitude cutoff used to fix the window width \(K\) (see _fracdiff_weights). Smaller tol keeps more weights (longer memory, larger warmup) at the cost of more computation. Default is 1e-5.

Returns:
np.ndarray[float64, ndim=1 or 2]

Fractionally differentiated series, same shape as X. The first K - 1 rows are NaN. If X has fewer than K observations, the output is entirely NaN.

Raises:
ValueError

If d is not in [0, 2], if X contains non-finite values, or if X is not 1-D or 2-D.

See also

multi_resolution, adaptive_roll

Notes

There is an inherent memory-vs-stationarity trade-off (Lopez de Prado, 2018, ch. 5): larger d differentiates more aggressively, making the series more likely to be stationary (e.g. pass an ADF test) but erasing more of the long-run memory that predictive models rely on; smaller d preserves memory but may leave the series non-stationary. The common recipe is to search for the minimal d for which the fractionally differentiated series is stationary.

References

M. Lopez de Prado, “Advances in Financial Machine Learning”, Wiley, 2018, ch. 5.

Examples

>>> import numpy as np
>>> X = np.array([1.0, 2.0, 4.0, 7.0, 11.0])
>>> fracdiff(X, d=1.0)
array([nan,  1.,  2.,  3.,  4.])
>>> np.array_equal(fracdiff(X, d=1.0)[1:], np.diff(X))
True
>>> fracdiff(X, d=0.0)
array([ 1.,  2.,  4.,  7., 11.])