{"id":237602,"date":"2026-01-27T13:30:02","date_gmt":"2026-01-27T18:30:02","guid":{"rendered":"https:\/\/ibkrcampus.com\/campus\/?p=237602"},"modified":"2026-01-27T13:53:24","modified_gmt":"2026-01-27T18:53:24","slug":"statistical-tests-for-mean-reversion-stationarity","status":"publish","type":"post","link":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/","title":{"rendered":"Statistical Tests for Mean Reversion (Stationarity)"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\" id=\"h-adf-kpss-variance-ratio-and-the-practical-issues-you-actually-run-into\">ADF, KPSS, Variance Ratio, and the Practical Issues You Actually Run Into<br><\/h2>\n\n\n\n<h2 class=\"wp-block-heading\">1. Context and the Basic Distinction<\/h2>\n\n\n\n<p>Let me start with the obvious thing that people&nbsp;<em>think<\/em>&nbsp;they understand until they actually try to trade it: a random walk is very different from something that is mean reverting.<\/p>\n\n\n\n<p>A random walk wanders. If it goes up for a while, it can stay up for a long time. If it crosses the mean again, that can just be chance. Importantly, being far from the mean does&nbsp;<em>not<\/em>&nbsp;create a stronger pull back.<\/p>\n\n\n\n<p>A mean reverting process is centered around some level, and the further away it gets, the stronger the expected pull back. This is the difference between something that crosses the mean rarely and something that crosses it many times.<\/p>\n\n\n\n<p>The classic econometric framing is: many of the statistics you want to use require stationarity. If something is a random walk, you typically difference it first. If it is already stationary, you can regress it, fit AR models, and so on, without everything falling apart.<\/p>\n\n\n\n<p>Two canonical toy models:<\/p>\n\n\n\n<p><strong>Random walk (unit root).<\/strong><\/p>\n\n\n\n<math display=\"block\">\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>=<\/mo>\n  <msub>\n    <mi>y<\/mi>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>t<\/mi>\n      <mo>&#x2212;<\/mo>\n      <mn>1<\/mn>\n    <\/mrow>\n  <\/msub>\n  <mo>+<\/mo>\n  <msub>\n    <mi>&#x3B5;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>,<\/mo>\n  <mstyle scriptlevel=\"0\">\n    <mspace width=\"2em\"><\/mspace>\n  <\/mstyle>\n  <msub>\n    <mi>&#x3B5;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>&#x223C;<\/mo>\n  <mo stretchy=\"false\">(<\/mo>\n  <mn>0<\/mn>\n  <mo>,<\/mo>\n  <msup>\n    <mi>&#x3C3;<\/mi>\n    <mn>2<\/mn>\n  <\/msup>\n  <mo stretchy=\"false\">)<\/mo>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<p><br><strong>Mean reversion (AR(1),&nbsp;<\/strong>|p|&lt;1)<\/p>\n\n\n\n<math display=\"block\">\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>=<\/mo>\n  <mi>&#x3C1;<\/mi>\n  <msub>\n    <mi>y<\/mi>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>t<\/mi>\n      <mo>&#x2212;<\/mo>\n      <mn>1<\/mn>\n    <\/mrow>\n  <\/msub>\n  <mo>+<\/mo>\n  <msub>\n    <mi>&#x3B5;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>,<\/mo>\n  <mstyle scriptlevel=\"0\">\n    <mspace width=\"2em\"><\/mspace>\n  <\/mstyle>\n  <mrow data-mjx-texclass=\"ORD\">\n    <mo stretchy=\"false\">|<\/mo>\n  <\/mrow>\n  <mi>&#x3C1;<\/mi>\n  <mrow data-mjx-texclass=\"ORD\">\n    <mo stretchy=\"false\">|<\/mo>\n  <\/mrow>\n  <mo>&lt;<\/mo>\n  <mn>1.<\/mn>\n<\/math>\n\n\n\n<p><\/p>\n\n\n\n<p>The whole point of the tests below is to distinguish &#8220; <em>p = 1&#8221;<\/em> from &#8220; <em>p &lt; 1&#8221;<\/em> in a statistically disciplined way.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-2-augmented-dickey-fuller-adf-test\"><strong>2. Augmented Dickey\u2013Fuller (ADF) Test<\/strong><\/h2>\n\n\n\n<p>The ADF test is the standard workhorse. Conceptually it is very simple: we regress changes on lagged levels and ask whether the level term has a negative coefficient.<\/p>\n\n\n\n<p>Start from an AR(1):<\/p>\n\n\n\n<math display=\"block\">\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>=<\/mo>\n  <mi>&#x3C1;<\/mi>\n  <msub>\n    <mi>y<\/mi>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>t<\/mi>\n      <mo>&#x2212;<\/mo>\n      <mn>1<\/mn>\n    <\/mrow>\n  <\/msub>\n  <mo>+<\/mo>\n  <msub>\n    <mi>&#x3B5;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<p>Subtract&nbsp;y<sub>t-1<\/sub>:<\/p>\n\n\n\n<math display=\"block\">\n  <mi mathvariant=\"normal\">&#x394;<\/mi>\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>=<\/mo>\n  <mo stretchy=\"false\">(<\/mo>\n  <mi>&#x3C1;<\/mi>\n  <mo>&#x2212;<\/mo>\n  <mn>1<\/mn>\n  <mo stretchy=\"false\">)<\/mo>\n  <msub>\n    <mi>y<\/mi>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>t<\/mi>\n      <mo>&#x2212;<\/mo>\n      <mn>1<\/mn>\n    <\/mrow>\n  <\/msub>\n  <mo>+<\/mo>\n  <msub>\n    <mi>&#x3B5;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<p>Define <math>\n  <mi>&#x3B2;<\/mi>\n  <mo>:=<\/mo>\n  <mi>&#x3C1;<\/mi>\n  <mo>&#x2212;<\/mo>\n  <mn>1<\/mn>\n<\/math>, so<\/p>\n\n\n\n<math display=\"block\">\n  <mi mathvariant=\"normal\">&#x394;<\/mi>\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>=<\/mo>\n  <mi>&#x3B2;<\/mi>\n  <msub>\n    <mi>y<\/mi>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>t<\/mi>\n      <mo>&#x2212;<\/mo>\n      <mn>1<\/mn>\n    <\/mrow>\n  <\/msub>\n  <mo>+<\/mo>\n  <msub>\n    <mi>&#x3B5;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<p>If \n<math>\n  <mi>&#x3C1;<\/mi>\n  <mo>=<\/mo>\n  <mn>1<\/mn>\n<\/math>\n\nthen \n\n<math>\n  <mi>&#x3B2;<\/mi>\n  <mo>=<\/mo>\n  <mn>0<\/mn>\n<\/math>\n\n\n, and you have:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<math display=\"block\">\n  <mi mathvariant=\"normal\">&#x394;<\/mi>\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>=<\/mo>\n  <msub>\n    <mi>&#x3B5;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>,<\/mo>\n<\/math>\n\n\n\n<p><\/p>\n\n\n\n<p>which is exactly the &#8220;increments are white noise&#8221; property of a random walk.<\/p>\n\n\n\n<p>The&nbsp;<em>augmented<\/em>&nbsp;form adds lagged differences to mop up autocorrelation in the residuals:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<math display=\"block\">\n  <mi mathvariant=\"normal\">&#x394;<\/mi>\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>=<\/mo>\n  <mi>&#x3B2;<\/mi>\n  <msub>\n    <mi>y<\/mi>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>t<\/mi>\n      <mo>&#x2212;<\/mo>\n      <mn>1<\/mn>\n    <\/mrow>\n  <\/msub>\n  <mo>+<\/mo>\n  <munderover>\n    <mo data-mjx-texclass=\"OP\">&#x2211;<\/mo>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>i<\/mi>\n      <mo>=<\/mo>\n      <mn>1<\/mn>\n    <\/mrow>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>p<\/mi>\n    <\/mrow>\n  <\/munderover>\n  <msub>\n    <mi>&#x3B3;<\/mi>\n    <mi>i<\/mi>\n  <\/msub>\n  <mi mathvariant=\"normal\">&#x394;<\/mi>\n  <msub>\n    <mi>y<\/mi>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>t<\/mi>\n      <mo>&#x2212;<\/mo>\n      <mi>i<\/mi>\n    <\/mrow>\n  <\/msub>\n  <mo>+<\/mo>\n  <msub>\n    <mi>&#x3B5;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<h3 class=\"wp-block-heading\">2.1. Hypotheses<\/h3>\n\n\n\n<p>ADF is usually written as:<\/p>\n\n\n\n<math display=\"block\">\n  <msub>\n    <mi>H<\/mi>\n    <mn>0<\/mn>\n  <\/msub>\n  <mo>:<\/mo>\n  <mi>&#x3B2;<\/mi>\n  <mo>=<\/mo>\n  <mn>0<\/mn>\n  <mstyle scriptlevel=\"0\">\n    <mspace width=\"1em\"><\/mspace>\n  <\/mstyle>\n  <mo stretchy=\"false\">(<\/mo>\n  <mtext>unit root \/ random walk<\/mtext>\n  <mo stretchy=\"false\">)<\/mo>\n  <mo>,<\/mo>\n  <mstyle scriptlevel=\"0\">\n    <mspace width=\"2em\"><\/mspace>\n  <\/mstyle>\n  <msub>\n    <mi>H<\/mi>\n    <mn>1<\/mn>\n  <\/msub>\n  <mo>:<\/mo>\n  <mi>&#x3B2;<\/mi>\n  <mo>&lt;<\/mo>\n  <mn>0<\/mn>\n  <mstyle scriptlevel=\"0\">\n    <mspace width=\"1em\"><\/mspace>\n  <\/mstyle>\n  <mo stretchy=\"false\">(<\/mo>\n  <mtext>stationary \/ mean reverting<\/mtext>\n  <mo stretchy=\"false\">)<\/mo>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<h3 class=\"wp-block-heading\">2.2. The part people get wrong: it is&nbsp;<em>not<\/em>&nbsp;a Student-t test<\/h3>\n\n\n\n<p>Even though the regression\u00a0<em>looks<\/em>\u00a0like a normal regression, the test statistic under\u00a0<em>H<sub>0<\/sub><\/em>\u00a0does not follow a Student\u00a0<em>t<\/em>\u00a0distribution. It follows a Dickey\u2013Fuller type distribution. That is why ADF uses special critical values.<\/p>\n\n\n\n<p>If you treat it like a standard t-test, you are going to fool yourself.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-2-3-choosing-the-lag-length-p\">2.3. Choosing the lag length <em>p<\/em><\/h3>\n\n\n\n<p>You have to choose&nbsp;<em>p<\/em>. Different&nbsp;<em>p<\/em>&nbsp;gives you a different test. The standard practice is to pick&nbsp;<em>p<\/em>&nbsp;by minimizing an information criterion such as AIC or BIC.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-aic\">AIC.<\/h3>\n\n\n\n<math display=\"block\">\n  <mi>A<\/mi>\n  <mi>I<\/mi>\n  <mi>C<\/mi>\n  <mo>=<\/mo>\n  <mo>&#x2212;<\/mo>\n  <mn>2<\/mn>\n  <mi>log<\/mi>\n  <mo data-mjx-texclass=\"NONE\">&#x2061;<\/mo>\n  <mi>L<\/mi>\n  <mo>+<\/mo>\n  <mn>2<\/mn>\n  <mi>k<\/mi>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-bic\">BIC.<\/h3>\n\n\n\n<math display=\"block\">\n  <mi>B<\/mi>\n  <mi>I<\/mi>\n  <mi>C<\/mi>\n  <mo>=<\/mo>\n  <mo>&#x2212;<\/mo>\n  <mn>2<\/mn>\n  <mi>log<\/mi>\n  <mo data-mjx-texclass=\"NONE\">&#x2061;<\/mo>\n  <mi>L<\/mi>\n  <mo>+<\/mo>\n  <mi>k<\/mi>\n  <mi>log<\/mi>\n  <mo data-mjx-texclass=\"NONE\">&#x2061;<\/mo>\n  <mi>T<\/mi>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<p><\/p>\n\n\n\n<p>Here&nbsp;<em>L<\/em>&nbsp;is the likelihood,&nbsp;<em>k<\/em>&nbsp;is the number of estimated parameters, and&nbsp;<em>T<\/em>&nbsp;is sample size. AIC and BIC are both &#8220;goodness of fit minus a penalty.&#8221; They are conceptually similar to how people think about cross-validation: you do not just maximize fit, you penalize complexity.<\/p>\n\n\n\n<p>You&nbsp;<em>can<\/em>&nbsp;pick lags visually using ACF\/PACF rules of thumb. People do that. But if you&#8217;re running systematic tests, letting the routine pick&nbsp;<em>p<\/em>&nbsp;by AIC\/BIC is a perfectly reasonable default.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-2-4-python-example-adf-with-autolag-aic\"><strong>2.4. Python example (ADF with autolag AIC)<\/strong><\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import numpy as np\nfrom statsmodels.tsa.stattools import adfuller\n\nnp.random.seed(0)\n\n# Example 1: random walk\ny_rw = np.cumsum(np.random.randn(2000))\n\n# Example 2: AR(1) mean reverting\neps = np.random.randn(2000)\nrho = 0.95\ny_ar = np.zeros_like(eps)\nfor t in range(1, len(eps)):\n    y_ar[t] = rho * y_ar[t-1] + eps[t]\n\nfor name, y in [(\"Random Walk\", y_rw), (\"AR(1) Mean Reverting\", y_ar)]:\n    stat, pval, used_lag, nobs, crit, icbest = adfuller(y, autolag=\"AIC\")\n    print(\"\\n---\", name, \"---\")\n    print(\"ADF stat:\", stat)\n    print(\"p-value:\", pval)\n    print(\"lags used:\", used_lag)\n    print(\"nobs:\", nobs)\n    print(\"crit:\", crit)<\/pre>\n\n\n\n<p>In trading I am not religious about the 5% line. I care whether the series is&nbsp;<em>clearly<\/em>&nbsp;mean reverting or it is&nbsp;<em>basically<\/em>&nbsp;a random walk. A p-value that barely tips under a threshold is not the same thing as a statistic that is strongly on one side.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-3-why-the-t-statistic-fails-in-time-series-unit-root-regressions\">3. Why the t-statistic fails in time series unit-root regressions<\/h2>\n\n\n\n<p>In a textbook regression, you write:<\/p>\n\n\n\n<math display=\"block\">\n  <mi>t<\/mi>\n  <mo>=<\/mo>\n  <mfrac>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mover>\n        <mi>&#x3B2;<\/mi>\n        <mo stretchy=\"false\">^<\/mo>\n      <\/mover>\n    <\/mrow>\n    <mrow>\n      <mi>S<\/mi>\n      <mi>E<\/mi>\n      <mo stretchy=\"false\">(<\/mo>\n      <mrow data-mjx-texclass=\"ORD\">\n        <mover>\n          <mi>&#x3B2;<\/mi>\n          <mo stretchy=\"false\">^<\/mo>\n        <\/mover>\n      <\/mrow>\n      <mo stretchy=\"false\">)<\/mo>\n    <\/mrow>\n  <\/mfrac>\n<\/math>\n\n\n\n<p>and you compare to a Student-t distribution.<\/p>\n\n\n\n<p>In unit root settings, the asymptotics are different. Under the unit root null, the process behaves like Brownian motion in the limit. The distribution of the statistic depends on functionals of Brownian motion, not a Student-t.<\/p>\n\n\n\n<p>One way to write the limiting idea (schematically) is that you get ratios of integrals involving Brownian motion&nbsp;<em>W (.)<\/em>:<\/p>\n\n\n\n<math display=\"block\">\n  <mfrac>\n    <mrow>\n      <msubsup>\n        <mo data-mjx-texclass=\"OP\">&#x222B;<\/mo>\n        <mn>0<\/mn>\n        <mn>1<\/mn>\n      <\/msubsup>\n      <mi>W<\/mi>\n      <mo stretchy=\"false\">(<\/mo>\n      <mi>r<\/mi>\n      <mo stretchy=\"false\">)<\/mo>\n      <mstyle scriptlevel=\"0\">\n        <mspace width=\"0.167em\"><\/mspace>\n      <\/mstyle>\n      <mi>d<\/mi>\n      <mi>W<\/mi>\n      <mo stretchy=\"false\">(<\/mo>\n      <mi>r<\/mi>\n      <mo stretchy=\"false\">)<\/mo>\n    <\/mrow>\n    <mrow>\n      <msubsup>\n        <mo data-mjx-texclass=\"OP\">&#x222B;<\/mo>\n        <mn>0<\/mn>\n        <mn>1<\/mn>\n      <\/msubsup>\n      <mi>W<\/mi>\n      <mo stretchy=\"false\">(<\/mo>\n      <mi>r<\/mi>\n      <msup>\n        <mo stretchy=\"false\">)<\/mo>\n        <mn>2<\/mn>\n      <\/msup>\n      <mstyle scriptlevel=\"0\">\n        <mspace width=\"0.167em\"><\/mspace>\n      <\/mstyle>\n      <mi>d<\/mi>\n      <mi>r<\/mi>\n    <\/mrow>\n  <\/mfrac>\n  <mo>,<\/mo>\n<\/math>\n\n\n\n<p><\/p>\n\n\n\n<p>which is&nbsp;<em>not<\/em>&nbsp;the same object as the usual regression t-statistic limit.<\/p>\n\n\n\n<p>So: use the Dickey\u2013Fuller critical values. That is the point of the test.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. KPSS: Reversing the Null Hypothesis<\/h2>\n\n\n\n<p>KPSS is useful because it flips the null and the alternative compared to ADF.<\/p>\n\n\n\n<p>ADF says:&nbsp;<em>assume unit root, try to reject it.<\/em><br>KPSS says:&nbsp;<em>assume stationarity, try to reject it.<\/em><\/p>\n\n\n\n<p>The model can be written as:<\/p>\n\n\n\n<math display=\"block\">\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>=<\/mo>\n  <msub>\n    <mi>&#x3BC;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>+<\/mo>\n  <msub>\n    <mi>&#x3B5;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>,<\/mo>\n  <mstyle scriptlevel=\"0\">\n    <mspace width=\"2em\"><\/mspace>\n  <\/mstyle>\n  <msub>\n    <mi>&#x3BC;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>=<\/mo>\n  <msub>\n    <mi>&#x3BC;<\/mi>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>t<\/mi>\n      <mo>&#x2212;<\/mo>\n      <mn>1<\/mn>\n    <\/mrow>\n  <\/msub>\n  <mo>+<\/mo>\n  <msub>\n    <mi>u<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\nIf <math>\n  <mrow data-mjx-texclass=\"ORD\">\n    <mi data-mjx-auto-op=\"false\">Var<\/mi>\n  <\/mrow>\n  <mo stretchy=\"false\">(<\/mo>\n  <msub>\n    <mi>u<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo stretchy=\"false\">)<\/mo>\n  <mo>=<\/mo>\n  <mn>0<\/mn>\n<\/math>\n, then <math>\n  <msub>\n    <mi>&#x3BC;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n<\/math>\n is constant and <math>\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n<\/math>\n is stationary around a mean. If <math>\n  <mrow data-mjx-texclass=\"ORD\">\n    <mi data-mjx-auto-op=\"false\">Var<\/mi>\n  <\/mrow>\n  <mo stretchy=\"false\">(<\/mo>\n  <msub>\n    <mi>u<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo stretchy=\"false\">)<\/mo>\n  <mo>&gt;<\/mo>\n  <mn>0<\/mn>\n<\/math>\n, then <math>\n  <msub>\n    <mi>&#x3BC;<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n<\/math>\n wanders and you have a unit root type behavior.\n\n\n\n<p><\/p>\n\n\n\nOperationally, KPSS is built from residual partial sums. Regress <math>\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n<\/math> on a constant (or constant+trend), take residuals <math>\n  <msub>\n    <mi>e<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n<\/math>, define partial sums:\n\n\n\n<p><\/p>\n\n\n\n<math display=\"block\">\n  <msub>\n    <mi>S<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo>=<\/mo>\n  <munderover>\n    <mo data-mjx-texclass=\"OP\">&#x2211;<\/mo>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>i<\/mi>\n      <mo>=<\/mo>\n      <mn>1<\/mn>\n    <\/mrow>\n    <mi>t<\/mi>\n  <\/munderover>\n  <msub>\n    <mi>e<\/mi>\n    <mi>i<\/mi>\n  <\/msub>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<p>Then the statistic is:<\/p>\n\n\n\n<math display=\"block\">\n  <mi>K<\/mi>\n  <mi>P<\/mi>\n  <mi>S<\/mi>\n  <mi>S<\/mi>\n  <mo>=<\/mo>\n  <mfrac>\n    <mn>1<\/mn>\n    <mrow>\n      <msup>\n        <mi>T<\/mi>\n        <mn>2<\/mn>\n      <\/msup>\n      <msup>\n        <mrow data-mjx-texclass=\"ORD\">\n          <mover>\n            <mi>&#x3C3;<\/mi>\n            <mo stretchy=\"false\">^<\/mo>\n          <\/mover>\n        <\/mrow>\n        <mn>2<\/mn>\n      <\/msup>\n    <\/mrow>\n  <\/mfrac>\n  <munderover>\n    <mo data-mjx-texclass=\"OP\">&#x2211;<\/mo>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>t<\/mi>\n      <mo>=<\/mo>\n      <mn>1<\/mn>\n    <\/mrow>\n    <mi>T<\/mi>\n  <\/munderover>\n  <msubsup>\n    <mi>S<\/mi>\n    <mi>t<\/mi>\n    <mn>2<\/mn>\n  <\/msubsup>\n  <mo>,<\/mo>\n<\/math>\n\n\n\n<p><\/p>\n\n\n\nwhere \n<math>\n  <msup>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mover>\n        <mi>&#x3C3;<\/mi>\n        <mo stretchy=\"false\">^<\/mo>\n      <\/mover>\n    <\/mrow>\n    <mn>2<\/mn>\n  <\/msup>\n<\/math> is an estimate of the long-run variance.\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-4-1-hypotheses\">4.1. Hypotheses<\/h3>\n\n\n\n<math display=\"block\">\n  <msub>\n    <mi>H<\/mi>\n    <mn>0<\/mn>\n  <\/msub>\n  <mo>:<\/mo>\n  <mtext>stationary<\/mtext>\n  <mo>,<\/mo>\n  <mstyle scriptlevel=\"0\">\n    <mspace width=\"2em\"><\/mspace>\n  <\/mstyle>\n  <msub>\n    <mi>H<\/mi>\n    <mn>1<\/mn>\n  <\/msub>\n  <mo>:<\/mo>\n  <mtext>unit root \/ non-stationary<\/mtext>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-4-2-python-example-kpss\">4.2. Python example (KPSS)<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from statsmodels.tsa.stattools import kpss\n\n# Using the same y_rw and y_ar from earlier\nfor name, y in [(\"Random Walk\", y_rw), (\"AR(1) Mean Reverting\", y_ar)]:\n    stat, pval, lags, crit = kpss(y, regression=\"c\", nlags=\"auto\")\n    print(\"\\n---\", name, \"---\")\n    print(\"KPSS stat:\", stat)\n    print(\"p-value:\", pval)\n    print(\"lags used:\", lags)\n    print(\"crit:\", crit)<\/pre>\n\n\n\n<p>How I actually use it.<\/p>\n\n\n\n<p>I like ADF and KPSS together because they are complementary. If ADF fails to reject a unit root and KPSS rejects stationarity, you are not looking at mean reversion. If both are ambiguous, you are probably in the grey zone, and you should stop pretending a binary label is going to save you.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-5-variance-ratio-test-lo-mackinlay\">5. Variance Ratio Test (Lo\u2013MacKinlay)<\/h2>\n\n\n\n<p id=\"h-5-variance-ratio-test-lo-mackinlay\">Variance ratio is more intuitive than people give it credit for. It is based on scaling properties of a random walk:<\/p>\n\n\n\nIf <math>\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n<\/math> is a random walk, then:\n\n\n\n<p><\/p>\n\n\n\n<math display=\"block\">\n  <mrow data-mjx-texclass=\"ORD\">\n    <mi data-mjx-auto-op=\"false\">Var<\/mi>\n  <\/mrow>\n  <mo stretchy=\"false\">(<\/mo>\n  <msub>\n    <mi>y<\/mi>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>t<\/mi>\n      <mo>+<\/mo>\n      <mi>k<\/mi>\n    <\/mrow>\n  <\/msub>\n  <mo>&#x2212;<\/mo>\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo stretchy=\"false\">)<\/mo>\n  <mo>=<\/mo>\n  <mi>k<\/mi>\n  <mstyle scriptlevel=\"0\">\n    <mspace width=\"0.167em\"><\/mspace>\n  <\/mstyle>\n  <mrow data-mjx-texclass=\"ORD\">\n    <mi data-mjx-auto-op=\"false\">Var<\/mi>\n  <\/mrow>\n  <mo stretchy=\"false\">(<\/mo>\n  <msub>\n    <mi>y<\/mi>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>t<\/mi>\n      <mo>+<\/mo>\n      <mn>1<\/mn>\n    <\/mrow>\n  <\/msub>\n  <mo>&#x2212;<\/mo>\n  <msub>\n    <mi>y<\/mi>\n    <mi>t<\/mi>\n  <\/msub>\n  <mo stretchy=\"false\">)<\/mo>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<p>Define:<\/p>\n\n\n\n<math display=\"block\">\n  <mi>V<\/mi>\n  <mi>R<\/mi>\n  <mo stretchy=\"false\">(<\/mo>\n  <mi>k<\/mi>\n  <mo stretchy=\"false\">)<\/mo>\n  <mo>=<\/mo>\n  <mfrac>\n    <mrow>\n      <mrow data-mjx-texclass=\"ORD\">\n        <mi data-mjx-auto-op=\"false\">Var<\/mi>\n      <\/mrow>\n      <mo stretchy=\"false\">(<\/mo>\n      <msub>\n        <mi>y<\/mi>\n        <mrow data-mjx-texclass=\"ORD\">\n          <mi>t<\/mi>\n          <mo>+<\/mo>\n          <mi>k<\/mi>\n        <\/mrow>\n      <\/msub>\n      <mo>&#x2212;<\/mo>\n      <msub>\n        <mi>y<\/mi>\n        <mi>t<\/mi>\n      <\/msub>\n      <mo stretchy=\"false\">)<\/mo>\n    <\/mrow>\n    <mrow>\n      <mi>k<\/mi>\n      <mstyle scriptlevel=\"0\">\n        <mspace width=\"0.167em\"><\/mspace>\n      <\/mstyle>\n      <mrow data-mjx-texclass=\"ORD\">\n        <mi data-mjx-auto-op=\"false\">Var<\/mi>\n      <\/mrow>\n      <mo stretchy=\"false\">(<\/mo>\n      <msub>\n        <mi>y<\/mi>\n        <mrow data-mjx-texclass=\"ORD\">\n          <mi>t<\/mi>\n          <mo>+<\/mo>\n          <mn>1<\/mn>\n        <\/mrow>\n      <\/msub>\n      <mo>&#x2212;<\/mo>\n      <msub>\n        <mi>y<\/mi>\n        <mi>t<\/mi>\n      <\/msub>\n      <mo stretchy=\"false\">)<\/mo>\n    <\/mrow>\n  <\/mfrac>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<p>Interpretation:<\/p>\n\n\n\n<math display=\"block\">\n  <mi>V<\/mi>\n  <mi>R<\/mi>\n  <mo stretchy=\"false\">(<\/mo>\n  <mi>k<\/mi>\n  <mo stretchy=\"false\">)<\/mo>\n  <mo>=<\/mo>\n  <mn>1<\/mn>\n  <mo stretchy=\"false\">&#x21D2;<\/mo>\n  <mtext>random walk<\/mtext>\n  <mo>,<\/mo>\n  <mstyle scriptlevel=\"0\">\n    <mspace width=\"2em\"><\/mspace>\n  <\/mstyle>\n  <mi>V<\/mi>\n  <mi>R<\/mi>\n  <mo stretchy=\"false\">(<\/mo>\n  <mi>k<\/mi>\n  <mo stretchy=\"false\">)<\/mo>\n  <mo>&lt;<\/mo>\n  <mn>1<\/mn>\n  <mo stretchy=\"false\">&#x21D2;<\/mo>\n  <mtext>mean reversion \/ negative autocorrelation<\/mtext>\n  <mo>,<\/mo>\n  <mstyle scriptlevel=\"0\">\n    <mspace width=\"2em\"><\/mspace>\n  <\/mstyle>\n  <mi>V<\/mi>\n  <mi>R<\/mi>\n  <mo stretchy=\"false\">(<\/mo>\n  <mi>k<\/mi>\n  <mo stretchy=\"false\">)<\/mo>\n  <mo>&gt;<\/mo>\n  <mn>1<\/mn>\n  <mo stretchy=\"false\">&#x21D2;<\/mo>\n  <mtext>trend \/ momentum<\/mtext>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<p><\/p>\n\n\n\n<p>The reason I like this test is that you can compute it across multiple horizons&nbsp;<em>k<\/em> and see the structure. It is a very visual diagnostic.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-5-1-python-example-simple-variance-ratio-across-horizons\">5.1. Python example (simple variance ratio across horizons)<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import numpy as np\n\ndef variance_ratio(y, k):\n    y = np.asarray(y)\n    dy1 = np.diff(y)\n    dyk = y[k:] - y[:-k]\n    return np.var(dyk, ddof=1) \/ (k * np.var(dy1, ddof=1))\n\nks = [2, 5, 10, 20, 50]\n\nfor name, y in [(\"Random Walk\", y_rw), (\"AR(1) Mean Reverting\", y_ar)]:\n    print(\"\\n---\", name, \"---\")\n    for k in ks:\n        print(f\"k={k:>3d}  VR={variance_ratio(y, k):.4f}\")<\/pre>\n\n\n\n<p><br><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-\"><\/h2>\n\n\n\n<p>In practice, I care less about whether&nbsp;<em>V R(k)<\/em>&nbsp;is &#8220;statistically significant&#8221; at 5% and more about&nbsp;<em>how far<\/em>&nbsp;it is from one. If it is barely below one, it is usually not worth trading. If it is meaningfully below one, you often see better risk-adjusted behavior. This is not magic: stronger negative autocorrelation is a stronger economic effect.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. Lag Length Choice: AIC, BIC, PACF (and why it matters)<\/h2>\n\n\n\n<p>In ADF, the whole &#8220;augmented&#8221; part is the lagged differences:<\/p>\n\n\n\n<math display=\"block\">\n  <munderover>\n    <mo data-mjx-texclass=\"OP\">&#x2211;<\/mo>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>i<\/mi>\n      <mo>=<\/mo>\n      <mn>1<\/mn>\n    <\/mrow>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>p<\/mi>\n    <\/mrow>\n  <\/munderover>\n  <msub>\n    <mi>&#x3B3;<\/mi>\n    <mi>i<\/mi>\n  <\/msub>\n  <mi mathvariant=\"normal\">&#x394;<\/mi>\n  <msub>\n    <mi>y<\/mi>\n    <mrow data-mjx-texclass=\"ORD\">\n      <mi>t<\/mi>\n      <mo>&#x2212;<\/mo>\n      <mi>i<\/mi>\n    <\/mrow>\n  <\/msub>\n  <mo>.<\/mo>\n<\/math>\n\n\n\n<p><\/p>\n\n\n\n<p>If you use too few lags, you leave autocorrelation in residuals and contaminate the test. If you use too many, you eat degrees of freedom and lose power.<\/p>\n\n\n\n<p>There are multiple ways to pick&nbsp;<em>p<\/em>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>AIC\/BIC: automated, objective-ish, and widely used in practice.<\/li>\n\n\n\n<li>PACF: common visual heuristic for AR order selection; people do this.<\/li>\n<\/ul>\n\n\n\n<p>I would not pretend there is a universal &#8220;correct&#8221;&nbsp;p. If your series is high frequency, your effective dynamics are different from daily. Use AIC\/BIC as a default, and if you are building a strategy, treat&nbsp;<em>p<\/em>&nbsp;as a hyperparameter you stress-test.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-7-putting-it-together-how-i-would-actually-screen-mean-reversion\">7. Putting It Together: How I Would Actually Screen Mean Reversion<\/h2>\n\n\n\n<p>If you are screening a spread or a residual for mean reversion:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Run ADF (unit root null). Check whether you can reject.<\/li>\n\n\n\n<li>Run KPSS (stationarity null). Check whether it rejects stationarity.<\/li>\n\n\n\n<li>Compute variance ratios across horizons. Ask: is it meaningfully below 1?<\/li>\n<\/ol>\n\n\n\n<p>If the outputs disagree, that is information, not a nuisance. It usually means you are in a borderline case where you should not be overly confident.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-8-final-remarks-from-trading-reality\">8. Final Remarks (from trading reality)<\/h2>\n\n\n\n<p>A few points that matter more than people admit:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>These tests tell you what the data&nbsp;<em>looked like<\/em>. They do not guarantee persistence.<\/li>\n\n\n\n<li>A series can be mean reverting in one period and then stop. Mean reversion is often episodic.<\/li>\n\n\n\n<li>Statistical significance is not the same thing as tradability. Transaction costs and turnover matter.<\/li>\n\n\n\n<li>Do not treat a p-value as a trading signal. Use it as a filter, then backtest the whole pipeline.<\/li>\n<\/ul>\n\n\n\n<p>And the last thing: the reason we do this is not because statistics make money. We do this because statistics stop us from fooling ourselves too easily.<\/p>\n\n\n\n<p>Other articles by Quant Insider include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/why-microarchitecture-matters-more-than-algorithms-in-high-frequency-trading\/\">Why Microarchitecture Matters More Than Algorithms in High-Frequency Trading<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/a-practical-breakdown-of-vector-based-vs-event-based-backtesting\/\">A Practical Breakdown of Vector-Based vs. Event-Based Backtesting<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>The classic econometric framing is: many of the statistics you want to use require stationarity. <\/p>\n","protected":false},"author":1641,"featured_media":38256,"comment_status":"open","ping_status":"closed","sticky":true,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[339,343,349,338,341],"tags":[4922,1006,8448,1225,595,4939],"contributors-categories":[19857],"class_list":{"0":"post-237602","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-data-science","8":"category-programing-languages","9":"category-python-development","10":"category-ibkr-quant-news","11":"category-quant-development","12":"tag-econometrics","13":"tag-fintech","14":"tag-mean-reversion","15":"tag-numpy","16":"tag-python","17":"tag-statistics","18":"contributors-categories-quant-insider"},"pp_statuses_selecting_workflow":false,"pp_workflow_action":"current","pp_status_selection":"publish","acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Statistical Tests for Mean Reversion (Stationarity)<\/title>\n<meta name=\"description\" content=\"The classic econometric framing is: many of the statistics you want to use require stationarity.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.interactivebrokers.com\/campus\/wp-json\/wp\/v2\/posts\/237602\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Statistical Tests for Mean Reversion (Stationarity) | IBKR Campus US\" \/>\n<meta property=\"og:description\" content=\"The classic econometric framing is: many of the statistics you want to use require stationarity.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/\" \/>\n<meta property=\"og:site_name\" content=\"IBKR Campus US\" \/>\n<meta property=\"article:published_time\" content=\"2026-01-27T18:30:02+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-01-27T18:53:24+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2020\/03\/digital-code-abstract.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"900\" \/>\n\t<meta property=\"og:image:height\" content=\"538\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Tribhuvan Bisen\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tribhuvan Bisen\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\n\t    \"@context\": \"https:\\\/\\\/schema.org\",\n\t    \"@graph\": [\n\t        {\n\t            \"@type\": \"NewsArticle\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/statistical-tests-for-mean-reversion-stationarity\\\/#article\",\n\t            \"isPartOf\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/statistical-tests-for-mean-reversion-stationarity\\\/\"\n\t            },\n\t            \"author\": {\n\t                \"name\": \"Tribhuvan Bisen\",\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/person\\\/9d33390fc6ad294459c7d636bb4962b9\"\n\t            },\n\t            \"headline\": \"Statistical Tests for Mean Reversion (Stationarity)\",\n\t            \"datePublished\": \"2026-01-27T18:30:02+00:00\",\n\t            \"dateModified\": \"2026-01-27T18:53:24+00:00\",\n\t            \"mainEntityOfPage\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/statistical-tests-for-mean-reversion-stationarity\\\/\"\n\t            },\n\t            \"wordCount\": 1558,\n\t            \"commentCount\": 0,\n\t            \"publisher\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/statistical-tests-for-mean-reversion-stationarity\\\/#primaryimage\"\n\t            },\n\t            \"thumbnailUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2020\\\/03\\\/digital-code-abstract.jpg\",\n\t            \"keywords\": [\n\t                \"Econometrics\",\n\t                \"fintech\",\n\t                \"Mean-reversion\",\n\t                \"NumPy\",\n\t                \"Python\",\n\t                \"statistics\"\n\t            ],\n\t            \"articleSection\": [\n\t                \"Data Science\",\n\t                \"Programming Languages\",\n\t                \"Python Development\",\n\t                \"Quant\",\n\t                \"Quant Development\"\n\t            ],\n\t            \"inLanguage\": \"en-US\",\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"CommentAction\",\n\t                    \"name\": \"Comment\",\n\t                    \"target\": [\n\t                        \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/statistical-tests-for-mean-reversion-stationarity\\\/#respond\"\n\t                    ]\n\t                }\n\t            ]\n\t        },\n\t        {\n\t            \"@type\": \"WebPage\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/statistical-tests-for-mean-reversion-stationarity\\\/\",\n\t            \"url\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/statistical-tests-for-mean-reversion-stationarity\\\/\",\n\t            \"name\": \"Statistical Tests for Mean Reversion (Stationarity) | IBKR Campus US\",\n\t            \"isPartOf\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#website\"\n\t            },\n\t            \"primaryImageOfPage\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/statistical-tests-for-mean-reversion-stationarity\\\/#primaryimage\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/statistical-tests-for-mean-reversion-stationarity\\\/#primaryimage\"\n\t            },\n\t            \"thumbnailUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2020\\\/03\\\/digital-code-abstract.jpg\",\n\t            \"datePublished\": \"2026-01-27T18:30:02+00:00\",\n\t            \"dateModified\": \"2026-01-27T18:53:24+00:00\",\n\t            \"description\": \"The classic econometric framing is: many of the statistics you want to use require stationarity.\",\n\t            \"inLanguage\": \"en-US\",\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"ReadAction\",\n\t                    \"target\": [\n\t                        \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/statistical-tests-for-mean-reversion-stationarity\\\/\"\n\t                    ]\n\t                }\n\t            ]\n\t        },\n\t        {\n\t            \"@type\": \"ImageObject\",\n\t            \"inLanguage\": \"en-US\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/statistical-tests-for-mean-reversion-stationarity\\\/#primaryimage\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2020\\\/03\\\/digital-code-abstract.jpg\",\n\t            \"contentUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2020\\\/03\\\/digital-code-abstract.jpg\",\n\t            \"width\": 900,\n\t            \"height\": 538,\n\t            \"caption\": \"Quant\"\n\t        },\n\t        {\n\t            \"@type\": \"WebSite\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#website\",\n\t            \"url\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/\",\n\t            \"name\": \"IBKR Campus US\",\n\t            \"description\": \"Financial Education from Interactive Brokers\",\n\t            \"publisher\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\"\n\t            },\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"SearchAction\",\n\t                    \"target\": {\n\t                        \"@type\": \"EntryPoint\",\n\t                        \"urlTemplate\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/?s={search_term_string}\"\n\t                    },\n\t                    \"query-input\": {\n\t                        \"@type\": \"PropertyValueSpecification\",\n\t                        \"valueRequired\": true,\n\t                        \"valueName\": \"search_term_string\"\n\t                    }\n\t                }\n\t            ],\n\t            \"inLanguage\": \"en-US\"\n\t        },\n\t        {\n\t            \"@type\": \"Organization\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\",\n\t            \"name\": \"Interactive Brokers\",\n\t            \"alternateName\": \"IBKR\",\n\t            \"url\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/\",\n\t            \"logo\": {\n\t                \"@type\": \"ImageObject\",\n\t                \"inLanguage\": \"en-US\",\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/logo\\\/image\\\/\",\n\t                \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/05\\\/ibkr-campus-logo.jpg\",\n\t                \"contentUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/05\\\/ibkr-campus-logo.jpg\",\n\t                \"width\": 669,\n\t                \"height\": 669,\n\t                \"caption\": \"Interactive Brokers\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/logo\\\/image\\\/\"\n\t            },\n\t            \"publishingPrinciples\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/about-ibkr-campus\\\/\",\n\t            \"ethicsPolicy\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/cyber-security-notice\\\/\"\n\t        },\n\t        {\n\t            \"@type\": \"Person\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/person\\\/9d33390fc6ad294459c7d636bb4962b9\",\n\t            \"name\": \"Tribhuvan Bisen\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/author\\\/tribhuvan1bisen\\\/\"\n\t        }\n\t    ]\n\t}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Statistical Tests for Mean Reversion (Stationarity)","description":"The classic econometric framing is: many of the statistics you want to use require stationarity.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.interactivebrokers.com\/campus\/wp-json\/wp\/v2\/posts\/237602\/","og_locale":"en_US","og_type":"article","og_title":"Statistical Tests for Mean Reversion (Stationarity) | IBKR Campus US","og_description":"The classic econometric framing is: many of the statistics you want to use require stationarity.","og_url":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/","og_site_name":"IBKR Campus US","article_published_time":"2026-01-27T18:30:02+00:00","article_modified_time":"2026-01-27T18:53:24+00:00","og_image":[{"width":900,"height":538,"url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2020\/03\/digital-code-abstract.jpg","type":"image\/jpeg"}],"author":"Tribhuvan Bisen","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Tribhuvan Bisen","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/#article","isPartOf":{"@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/"},"author":{"name":"Tribhuvan Bisen","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/person\/9d33390fc6ad294459c7d636bb4962b9"},"headline":"Statistical Tests for Mean Reversion (Stationarity)","datePublished":"2026-01-27T18:30:02+00:00","dateModified":"2026-01-27T18:53:24+00:00","mainEntityOfPage":{"@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/"},"wordCount":1558,"commentCount":0,"publisher":{"@id":"https:\/\/ibkrcampus.com\/campus\/#organization"},"image":{"@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/#primaryimage"},"thumbnailUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2020\/03\/digital-code-abstract.jpg","keywords":["Econometrics","fintech","Mean-reversion","NumPy","Python","statistics"],"articleSection":["Data Science","Programming Languages","Python Development","Quant","Quant Development"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/","url":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/","name":"Statistical Tests for Mean Reversion (Stationarity) | IBKR Campus US","isPartOf":{"@id":"https:\/\/ibkrcampus.com\/campus\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/#primaryimage"},"image":{"@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/#primaryimage"},"thumbnailUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2020\/03\/digital-code-abstract.jpg","datePublished":"2026-01-27T18:30:02+00:00","dateModified":"2026-01-27T18:53:24+00:00","description":"The classic econometric framing is: many of the statistics you want to use require stationarity.","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/statistical-tests-for-mean-reversion-stationarity\/#primaryimage","url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2020\/03\/digital-code-abstract.jpg","contentUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2020\/03\/digital-code-abstract.jpg","width":900,"height":538,"caption":"Quant"},{"@type":"WebSite","@id":"https:\/\/ibkrcampus.com\/campus\/#website","url":"https:\/\/ibkrcampus.com\/campus\/","name":"IBKR Campus US","description":"Financial Education from Interactive Brokers","publisher":{"@id":"https:\/\/ibkrcampus.com\/campus\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ibkrcampus.com\/campus\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ibkrcampus.com\/campus\/#organization","name":"Interactive Brokers","alternateName":"IBKR","url":"https:\/\/ibkrcampus.com\/campus\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/logo\/image\/","url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/05\/ibkr-campus-logo.jpg","contentUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/05\/ibkr-campus-logo.jpg","width":669,"height":669,"caption":"Interactive Brokers"},"image":{"@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/logo\/image\/"},"publishingPrinciples":"https:\/\/www.interactivebrokers.com\/campus\/about-ibkr-campus\/","ethicsPolicy":"https:\/\/www.interactivebrokers.com\/campus\/cyber-security-notice\/"},{"@type":"Person","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/person\/9d33390fc6ad294459c7d636bb4962b9","name":"Tribhuvan Bisen","url":"https:\/\/www.interactivebrokers.com\/campus\/author\/tribhuvan1bisen\/"}]}},"jetpack_featured_media_url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2020\/03\/digital-code-abstract.jpg","_links":{"self":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts\/237602","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/users\/1641"}],"replies":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/comments?post=237602"}],"version-history":[{"count":0,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts\/237602\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/media\/38256"}],"wp:attachment":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/media?parent=237602"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/categories?post=237602"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/tags?post=237602"},{"taxonomy":"contributors-categories","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/contributors-categories?post=237602"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}