Fractional Differentiation
Log prices have memory but no stationarity, log returns have stationarity but no memory. Fractional differentiation lets you pick a d between 0 and 1, and on BTC the ADF test doesn't pick it as cleanly as you'd hope.
In quant finance, we use log returns instead of prices because prices are not stationary, and stationarity is necessary for an ML algorithm. But prices have a memory that we lose when we compute the log return.
In chapter 5 of Advances in Financial Machine Learning, López de Prado introduces fractional differentiation. A differentiation of order gives the log price (memory, but no stationarity), and gives the log return (stationarity, but no memory). The whole idea is to choose a between 0 and 1 to find a trade-off between stationarity and memory. That's what we will look at today, on BTC/USD daily closes.
1. Definition
Let be the log price at time . The backshift operator moves a series one step back in time:
With it, the log return is just applied to the log price:
And applying it twice gives the difference of the differences: . So in general, we want:
This is nice for an integer : the binomial theorem gives a finite sum. But our goal is a between 0 and 1, and for a real we need the generalized binomial series, which is infinite.
Let's check the two ends:
- : and every other weight is 0, so , the log price.
- : , , and the factor is 0 from on, so , the log return.
For an integer , the weights eventually hit zero and the sum is finite. For a in between, they never do: every past price keeps a small weight, and that is the memory. But what happens in the middle?
2. Fixed window
As you can see, is an infinite series, and of course our series is finite. To compute , we can either fix a number of weights (the fixed window), or expand the window as we get more and more data. We make the same choice as López de Prado and use the fixed window. But how do we fix ?
López de Prado puts a threshold on , and drops every weight below it:
The same weights are applied to every point, so the series stays consistent through time, but the first points are lost.
The smaller the threshold, the bigger . Let's see the behavior of and :
| d | (τ = 1e-4) | (τ = 1e-5) |
|---|---|---|
| 0.1 | 502 | 4,075 |
| 0.2 | 496 | 3,381 |
| 0.25 | 444 | 2,803 |
| 0.3 | 387 | 2,274 |
| 0.4 | 281 | 1,457 |
| 0.5 | 199 | 926 |
| 0.6 | 139 | 589 |
| 0.7 | 96 | 371 |
| 0.75 | 78 | 292 |
| 0.8 | 63 | 227 |
| 0.9 | 37 | 124 |
With a threshold of 1e-5, needs 2,803 points, so 7.7 years of daily data, before the first value. If you don't have enough points, that's a problem. Our BTC/USD history starts in October 2013, so at and we only keep the last 5 years, and we will see that it shows.
3. Quantify the stationarity
To check whether the series is stationary, we use the Augmented Dickey-Fuller test, with the same settings as in the book.
The idea is to find the lowest where the unit root is rejected. But rejecting the unit root doesn't mean the series is stationary, and this is what we will see below.
We also plot the correlation between and the log price on the same dates. The correlation stands for the memory: at it is 1, at it is 0, and we want to keep as much of it as we can.
| d | ADF (τ = 1e-4) | Corr (τ = 1e-4) | ADF (τ = 1e-5) | Corr (τ = 1e-5) |
|---|---|---|---|---|
| 0.15 | −2.21 | 0.990 | −2.42 | 0.844 |
| 0.2 | −2.52 | 0.981 | −3.17 | 0.806 |
| 0.25 | −3.11 | 0.969 | −4.26 | 0.779 |
| 0.3 | −3.80 | 0.955 | −5.67 | 0.613 |
| 0.4 | −6.19 | 0.916 | −9.72 | 0.458 |
| 0.5 | −10.23 | 0.850 | −14.90 | 0.354 |
| 1 | −49.65 | −0.007 | −49.65 | −0.007 |
With a threshold of 1e-4, the test accepts , with a correlation of 0.97: on paper, almost all the memory of the price, and no unit root. With 1e-5, it accepts , but the correlation curve is unclear, because the long windows leave very few points (1,361 at , against 4,246 with 1e-4).
4. What it looks like in practice
Let's plot the series at , the value the ADF test picks:
At , this isn't stationary at all. With we see the whole drift of the price, and with we don't have enough data to say anything.
Let's go further, to :
At it is more stationary, but there is a drift again with , while with it looks right.
5. Where the drift comes from
The drift has a simple cause: the truncation. For , the full infinite series of weights sums to zero, since . Once the window is cut at , the weights we keep no longer do:
The first term is a fraction of today's log price, so a piece of the trend leaks straight into the series. The second term is a weighted sum of past log returns, which is the "memory" we were looking for. The bigger , the shorter the window, and the bigger the leak:
| d | τ | Sum of kept weights | Corr with log price | Corr once the leak is removed |
|---|---|---|---|---|
| 0.25 | 1e-4 | 0.178 | 0.969 | 0.038 |
| 0.25 | 1e-5 | 0.112 | 0.779 | 0.379 |
| 0.55 | 1e-4 | 0.030 | 0.800 | 0.036 |
| 0.55 | 1e-5 | 0.013 | 0.332 | −0.080 |
At and , 17.8% of the log price goes straight into the series, and it accounts for nearly all the 0.97 correlation: subtract it, and the correlation drops to 0.04. BTC went from $100 to $100,000, so 17.8% of its log price moves by more than 1.2, which is the drift on the chart. The ADF test, with one lag and a constant, doesn't see a trend that slow.
So the correlation with the log price is a flattering measure of memory: a large part of it is just the level that the truncation lets through.
6. Conclusion
It seems that the ADF methodology presented by López de Prado isn't a reliable way to find the "stationary point" on BTC:
- with , the it picks still carries the trend of the price;
- with , the windows are so long that the low values are computed on a few years of data only.
I tried the KPSS test too, whose null hypothesis is the opposite (the series is stationary). It doesn't help much: with , it rejects stationarity for every except , which fits the leak above. With , it only stops rejecting around to , and not even consistently (at the 5% level, only passes), on series that are again short.
Maybe the best way to get a good trade-off between stationarity and memory is to choose and qualitatively, by looking at the series, rather than with a statistical test.
Before you feed a fractionally differentiated series to a model, plot it next to the price, and check how many points the window leaves you. An ADF statistic below −2.86 doesn't mean the trend is gone.
The next question is how to use this series in an ML model. That one is still open for me, and the intuition behind it isn't obvious, so it will be for another article.
Angolin serves the full BTC history at 1d, 1h and 1m granularity, and the historical universe of each exchange, delisted pairs included, to avoid survivorship bias.


