AnyLearn
All lessons
AIadvanced

Features: Stationarity Without Erasing the Memory

Prices are non-stationary and returns are stationary but forget everything, so the standard fix throws away the level information a model needed. This lesson builds fractional differentiation, which makes the choice a dial rather than a switch, and shows by computation that most of the memory can be kept while still passing a stationarity test.

Updated · AI-authored, review-gated · how lessons are made

Not signed in: your progress and quiz score won't be saved.
Progress1 / 10

The dilemma nobody states out loud

Statistical learning wants stationary inputs: a feature whose distribution is stable, so that a relationship fitted on old data still applies to new. A price series is not that. It wanders, has no fixed mean, and a model trained when a stock was at 40 has never seen 400.

The universal fix is to difference: model returns instead of prices. That works, and it costs something rarely acknowledged.

Key idea: Differencing removes the non-stationarity by removing the memory. A return series has almost no information about where the price actually is, and level matters: distance from a 52-week high, position within a range, whether a level has been tested before. The standard fix deletes exactly the features many strategies are built on.

The question this lesson answers is whether the trade has to be all or nothing. It does not.

Full lesson text

All 10 steps on one page, for reading, reference, and search.

Show

1. The dilemma nobody states out loud

Statistical learning wants stationary inputs: a feature whose distribution is stable, so that a relationship fitted on old data still applies to new. A price series is not that. It wanders, has no fixed mean, and a model trained when a stock was at 40 has never seen 400.

The universal fix is to difference: model returns instead of prices. That works, and it costs something rarely acknowledged.

Key idea: Differencing removes the non-stationarity by removing the memory. A return series has almost no information about where the price actually is, and level matters: distance from a 52-week high, position within a range, whether a level has been tested before. The standard fix deletes exactly the features many strategies are built on.

The question this lesson answers is whether the trade has to be all or nothing. It does not.

2. Differencing as an operator with a parameter

Write the backshift operator BB, where Bxt=xt1B x_t = x_{t-1}. First differencing is (1B)(1 - B), and differencing twice is (1B)2(1 - B)^2. Nothing requires the exponent to be a whole number.

Expand (1B)d(1 - B)^d as a binomial series for real dd:

(1B)d=k=0(dk)(B)k=1dB+d(d1)2!B2d(d1)(d2)3!B3+(1 - B)^d = \sum_{k=0}^{\infty} \binom{d}{k}(-B)^k = 1 - dB + \frac{d(d-1)}{2!}B^2 - \frac{d(d-1)(d-2)}{3!}B^3 + \cdots

At d=1d = 1 the series terminates after two terms and you get the ordinary difference xtxt1x_t - x_{t-1}. At d=0d = 0 every term after the first vanishes and you get the series back unchanged. Between them the expansion does not terminate: the result is a weighted sum over the entire history, with weights that decay.

Definition: Fractional differentiation applies (1B)d(1-B)^d for non-integer dd. It is a continuous dial between the original series and its first difference, and it is what makes stationarity a quantity you buy exactly as much of as you need.

3. The weights, and why they decay

The coefficients follow a simple recursion, which is all you need to implement it:

w0=1,wk=wk1dk+1kw_0 = 1, \qquad w_k = -w_{k-1}\,\frac{d - k + 1}{k}

import numpy as np

def weights(d, size):
    w = [1.0]
    for k in range(1, size):
        w.append(-w[-1] * (d - k + 1) / k)
    return np.array(w[::-1])

def frac_diff(series, d, thresh=1e-4):
    w = weights(d, len(series))
    w = w[np.abs(w) > thresh]          # fixed-width window
    width = len(w)
    out = np.full(len(series), np.nan)
    for i in range(width, len(series) + 1):
        out[i-1] = np.dot(w, series[i-width:i])
    return out

For dd between 0 and 1 the weights alternate in sign and shrink toward zero, so distant history contributes less and less. That decay is what makes the method usable: past some depth the weights are negligible and can be dropped, giving a fixed-width window rather than an expanding one.

Gotcha: Use a fixed-width window, not an expanding one. An expanding window applies a different number of terms at every point, so the transformed series has a drifting variance and is not comparable across time, which reintroduces a non-stationarity through the back door.

4. How much memory ordinary differencing costs

Take a simulated random-walk log price of 5,000 points, apply (1B)d(1-B)^d across a range of dd, and measure the correlation between the transformed series and the original level.

Memory retained after fractional differencing
correlation with the original series00.20.40.60.81d=0d=0.1d=0.2d=0.3d=0.4d=0.5d=0.6d=0.8d=1.0
Source: Computed on a 5,000-point simulated random-walk log price, weight threshold 1e-4

At d=1d = 1, ordinary differencing, the correlation with the original level is 0.02. Essentially all of the level information is gone, which is the cost nobody quotes when they take returns.

The curve is not linear. Most of the memory survives the first part of the range and collapses in the second half, which is precisely what makes a partial dose worthwhile.

5. How little differencing you actually need

Predict first

The same 5,000-point series fails an augmented Dickey-Fuller test at d = 0, with a statistic of -2.35 against a 5 percent critical value of -2.86. How much differencing does it take to pass?

In practice: The procedure is mechanical. Sweep dd upward in small steps, run an ADF test at each, and stop at the smallest dd whose statistic clears the critical value. That value is the minimum you must pay, and paying more is a pure loss.

One honest caveat about this number. The example is a clean random walk, where a very small dd suffices. Real price series carry additional structure, so the minimum dd is usually higher, often somewhere in the range of a few tenths. The procedure is unchanged; only the answer moves.

6. Where the memory actually matters

It is worth being concrete about what is lost, because if none of it matters to your strategy then returns are fine and this whole apparatus is unnecessary.

Feature that needs the levelWhat it becomes on pure returns
Distance from the 52-week highunrecoverable without reconstructing the level
Position within a trading rangeundefined
Whether a support level has been tested beforeinvisible
Long-horizon mean reversiondestroyed, since reversion is a statement about the level
Spread between two assets in a pairs tradethe spread level is the signal

The last row is the sharpest case. A pairs or basket strategy trades the deviation of a spread from its equilibrium, so the level of the spread is the entire signal. Differencing it to stationarity in the ordinary way removes the strategy.

In practice: If your features are all short-horizon and momentum-flavoured, returns lose you little. If anything in your thesis is about where the price is rather than how it has been moving, ordinary differencing is deleting your signal before the model ever sees it.

7. The look-ahead traps hiding in feature code

Feature construction is where the future gets inserted into the past, usually through a library convenience rather than a conceptual error.

  • Centred windows. A rolling mean with center=True uses future observations. It is the default in some plotting workflows and is fatal in a feature.
  • Fitting the scaler on everything. Calling fit_transform on the full series before splitting leaks the future distribution's mean and variance into every training row.
  • Full-sample statistics. Any normalisation by a global mean, a global standard deviation, or a full-history quantile uses data that did not exist at the time.
  • Backfilled gaps. fillna(method='bfill') copies future values backwards, which is exactly what it says and rarely what was intended.
  • Resampling and alignment. Aggregating to a coarser frequency can stamp a bar with a timestamp at the start of a period whose data runs to the end of it.

Gotcha: Every one of these produces a stronger model with a better validation score and no error message. The only reliable defence is a rule rather than an audit: every feature at time tt must be computable from a stream that has only seen data up to tt, and the cheapest way to enforce it is to build features causally and test them against a replayed stream.

8. Feature importance is unreliable here, in a specific way

Having built features, the natural next step is to ask which ones matter. In this setting the standard tools mislead, and the reasons are worth knowing.

MethodHow it worksFailure mode in finance
Mean decrease in impurityin-sample, from the fitted treesinflated by leakage; biased toward high-cardinality features
Mean decrease in accuracyshuffle a feature, measure the dropmust be run inside a purged CV or it measures leakage
Substitution effectscorrelated features share credittwo near-identical features can both look unimportant

The substitution problem is the one that produces the worst decisions. Two highly correlated features split the importance between them, so each looks weak and both get dropped, removing a signal that either alone would have carried.

In practice: Cluster correlated features and measure importance at the cluster level rather than per feature. And whatever the method, compute it under the validation scheme from the next lesson: an importance ranking measured with a leaky split is a ranking of which features best exploit the leak.

9. Structural breaks as a feature, not just a nuisance

The previous lesson treated non-stationarity as something to be transformed away. There is a second use for it: the moments when a series changes behaviour are themselves informative.

Statistical tests exist to detect this, including CUSUM tests on residuals and the supremum-augmented Dickey-Fuller family used to identify explosive or bubble-like behaviour. Two applications follow.

  • As a sampling trigger. Label bars where a break is detected, rather than on a clock. This connects to the event-based sampling from the labelling lesson and concentrates the dataset on moments where something changed.
  • As a feature. Time since the last detected break, or the current test statistic, tells a model which regime it is standing in.

Key idea: Fractional differentiation and break detection are two responses to the same fact and they are not alternatives. One makes a series usable by a model that assumes stability; the other tells the model when that assumption has just stopped holding. Using both is normal, and the regime question they open is the subject of a separate course in this catalogue.

10. The feature pipeline, in order

Putting it together, the order of operations is itself a design decision.

  1. Sample. Choose bars, on activity or events rather than on the clock by default.
  2. Transform for stationarity. Sweep dd, take the smallest value that passes an ADF test, and use a fixed-width window. Record the chosen dd: it is a parameter of your dataset and should be reported alongside results.
  3. Build features causally. Every value at time tt from data at or before tt. No centred windows, no full-sample statistics, no backfill.
  4. Fit any transform inside the fold. Scalers, PCA, quantile bins and imputers are all model components and must be fitted on training data only.
  5. Assess importance under purged validation, at the cluster level for correlated features.

Gotcha: Step 4 is the one that is skipped most often, because scaling feels like preprocessing rather than modelling. It is not. A scaler carries the mean and variance of whatever it was fitted on, and fitting it before the split hands the test set's distribution to the training set. The next lesson makes the splitting itself the subject.

Check your understanding

The lesson ends with a 5-question quiz. Take it in the player above to see your score.

  1. What does ordinary first differencing cost, measured on a simulated random-walk log price?
    • Nothing: the differenced series retains the level information
    • Correlation with the original level falls to about 0.02
    • Correlation with the original level falls to about 0.55
    • It introduces non-stationarity rather than removing it
  2. In the worked example, the series first passes the ADF test at d = 0.1. What correlation with the original does it retain there?
    • About 0.50
    • About 0.83
    • About 0.985
    • About 0.02, the same as full differencing
  3. Why must fractional differencing use a fixed-width window rather than an expanding one?
    • An expanding window is too slow to compute
    • The weights become positive beyond a certain depth
    • Fixed-width windows are required by the ADF test
    • An expanding window applies a different number of terms at each point, giving the transformed series a drifting variance
  4. Which strategy type is most damaged by ordinary differencing?
    • A pairs trade, where the level of the spread is the entire signal
    • A short-horizon momentum strategy
    • A volatility-targeting overlay
    • An intraday market-making strategy
  5. Two highly correlated features both show low importance under mean decrease in accuracy. What is the likely explanation?
    • Both features are genuinely uninformative
    • The model has insufficient capacity to use them
    • A substitution effect: shuffling one leaves the other to carry the same information, so neither shows a drop
    • Mean decrease in accuracy cannot be used with tree models

Related lessons

AI
advanced

What Is Actually in an Order Book, and What a Model Can See

Before choosing an architecture you have to decide what the input is, and an order book offers several incompatible representations that are not equally informative. This lesson covers what each data level contains, why raw prices are the wrong features, and the representation choices that decide more than the model does.

10 steps·~15 min
AI
advanced

Validation: Measuring Anything at All

Shuffled cross-validation reports 54 percent accuracy on data containing no signal, because neighbouring samples share their futures. This lesson builds purging, embargo and sample uniqueness weights, shows the illusion scaling with label overlap and vanishing when the fix is applied, and covers why a single walk-forward path is weak evidence.

10 steps·~15 min
AI
advanced

Labelling: Deciding What You Are Actually Predicting

The default label, the sign of the return over a fixed horizon, describes a trade nobody would take: no stop, no target, and a holding period chosen by the modeller rather than by the market. This lesson builds the triple-barrier method and meta-labelling, and shows with computed numbers how much of a fixed-horizon dataset is fiction.

10 steps·~15 min
AI
advanced

Evaluating a Book Model Honestly

If your cost per round trip equals the move you are trying to capture, you need 100 percent directional accuracy to break even. This lesson computes that hurdle, replaces accuracy with metrics tied to a tradeable decision, and covers the capacity and latency limits that decide whether a real edge is worth anything.

10 steps·~15 min