Indicator · Pine Script v6 · Own pane

ADF - Augmented Dickey-Fuller Test

by mihakralj· code credited to QuanTAlib

The Augmented Dickey-Fuller indicator calculates statistical stationarity and tests for unit roots in price series over a rolling window.

View on GitHub

GitHub stars99on the repository
Pine versionv6current
Lines of code129
Settings3inputs
LicenceApache-2.0
Last update4 weeks ago27 Sep 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

129 lines of Pine Script v6 from lib/statistics/adf/adf.pine, published under Apache-2.0. Keep the author's credit and licence lines when you reuse it.

adf.pine
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0
// https://mozilla.org/MPL/2.0/
// © QuanTAlib

//@version=6
indicator("ADF - Augmented Dickey-Fuller Test", shorttitle="ADF", overlay=false, precision=4)

// ─── Inputs ────────────────────────────────────────────────────────────
int    period     = input.int(50, "Period", minval=20, maxval=500)
int    maxLag     = input.int(0,  "Max Lag (0=auto)", minval=0, maxval=10)
string regModel   = input.string("Constant", "Regression", options=["NoConstant", "Constant", "ConstantAndTrend"])

// ─── Helper: OLS solve 2×2 (constant + gamma, no lags for simplicity) ──
// Full ADF with Cholesky is too complex for Pine; this is a reference only.
// For production use, the C# implementation is authoritative.

adf_pvalue(float[] data, int p, int mLag, string reg) =>
    int n = array.size(data)
    if n < 20
        1.0
    else
        // Compute first differences
        int nd = n - 1
        float[] dy = array.new_float(nd, 0.0)
        for i = 0 to nd - 1
            array.set(dy, i, array.get(data, i + 1) - array.get(data, i))

        // Simple ADF: regress dy on y_{t-1} (constant model, no lags)
        // X = [1, y_{t-1}], Y = dy_t
        float sx = 0.0, sy = 0.0, sxx = 0.0, sxy = 0.0, syy = 0.0
        int startIdx = math.max(mLag, 0)
        int nObs = nd - startIdx
        if nObs < 3
            1.0
        else
            for t = startIdx to nd - 1
                float x = array.get(data, t)  // y_{t-1} in level
                float y = array.get(dy, t)
                sx += x
                sy += y
                sxx += x * x
                sxy += x * y
                syy += y * y

            // OLS for constant model: [alpha, gamma]
            float xbar = sx / nObs
            float ybar = sy / nObs
            float denom = sxx - sx * sx / nObs
            if math.abs(denom) < 1e-15
                1.0
            else
                float gamma = (sxy - sx * sy / nObs) / denom
                float alpha = ybar - gamma * xbar

                // RSS
                float rss = 0.0
                for t = startIdx to nd - 1
                    float x = array.get(data, t)
                    float y = array.get(dy, t)
                    float resid = y - alpha - gamma * x
                    rss += resid * resid

                float s2 = rss / (nObs - 2)
                if s2 <= 0
                    1.0
                else
                    float se = math.sqrt(s2 / denom)
                    if se <= 1e-15
                        1.0
                    else
                        float tStat = gamma / se

                        // MacKinnon (1994) p-value for N=1, regression-dependent
                        float tauStar = reg == "NoConstant" ? -1.04 : reg == "ConstantAndTrend" ? -2.89 : -1.61
                        float tauMin  = reg == "NoConstant" ? -19.04 : reg == "ConstantAndTrend" ? -16.18 : -18.83
                        float tauMax  = reg == "NoConstant" ? 1e308 : reg == "ConstantAndTrend" ? 0.70 : 2.74

                        if tStat < tauMin
                            0.0
                        else if tStat > tauMax
                            1.0
                        else
                            float poly = 0.0
                            if tStat <= tauStar
                                // Small-p coefficients (regression-dependent)
                                if reg == "NoConstant"
                                    poly := 0.6344 + 1.2378 * tStat + 0.032496 * tStat * tStat
                                else if reg == "ConstantAndTrend"
                                    poly := 3.2512 + 1.6047 * tStat + 0.049588 * tStat * tStat
                                else
                                    poly := 2.1659 + 1.4412 * tStat + 0.038269 * tStat * tStat
                            else
                                // Large-p coefficients (regression-dependent)
                                float t2 = tStat * tStat
                                float t3 = t2 * tStat
                                if reg == "NoConstant"
                                    poly := 0.4797 + 0.93557 * tStat - 0.06999 * t2 + 0.033066 * t3
                                else if reg == "ConstantAndTrend"
                                    poly := 2.5261 + 0.61654 * tStat - 0.37956 * t2 - 0.060285 * t3
                                else
                                    poly := 1.7339 + 0.93202 * tStat - 0.12745 * t2 - 0.010368 * t3

                            // Normal CDF via A&S 7.1.26 erf → Φ(x) = 0.5·(1 + erf(x/√2))
                            int    sgn  = poly < 0 ? -1 : 1
                            float  z    = math.abs(poly) * 0.70710678118654752
                            float  tt   = 1.0 / (1.0 + 0.3275911 * z)
                            float  tt2  = tt * tt
                            float  tt3  = tt2 * tt
                            float  tt4  = tt3 * tt
                            float  tt5  = tt4 * tt
                            float  erfcZ = (0.254829592 * tt - 0.284496736 * tt2 + 1.421413741 * tt3 - 1.453152027 * tt4 + 1.061405429 * tt5) * math.exp(-z * z)
                            float  erfZ  = 1.0 - erfcZ
                            float  result = 0.5 * (1.0 + sgn * erfZ)
                            result

// ─── Main ──────────────────────────────────────────────────────────────
float[] window = array.new_float(0)
for i = 0 to period - 1
    array.push(window, close[period - 1 - i])

float pval = adf_pvalue(window, period, maxLag, regModel)

// ─── Plot ──────────────────────────────────────────────────────────────
plot(pval, "ADF p-value", color=color.blue, linewidth=2)
hline(0.01, "1% significance", color=color.red, linestyle=hline.style_dotted)
hline(0.05, "5% significance", color=color.orange, linestyle=hline.style_dashed)
hline(0.10, "10% significance", color=color.gray, linestyle=hline.style_dotted)

bgcolor(pval < 0.05 ? color.new(color.green, 90) : na)

Overview

ADF - Augmented Dickey-Fuller Test performs ordinary least squares regression on differenced historical price data to compute a t-statistic and an estimated p-value using MacKinnon critical values. Configurable settings allow adjustments to the lookback period, maximum lag depth, and regression model type. The script draws the resulting statistical p-value in a separate indicator pane.

Details

Published by

mihakralj on GitHub

Code credit

QuanTAlib, as written in the script's header

Type

Indicator, Pine Script v6

Draws

Separate pane below the chart

Category

Mean reversion, Trend

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Topics

algorithmic-tradingcsharpdotnetpinescriptpythonquantitative-financesimdta-libtechnical-analysistechnical-indicators

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Periodint50period
Max Lag (0=auto)int0maxLag
RegressionstringConstantregModel
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

AutoCorrelation Function

by Anderson-ALGO
9 stars

This indicator calculates sample autocorrelation across multiple lag intervals for a selected price series. It computes correlation values over a user-specified lookback period using raw prices, log returns, absolute log returns, or squared log returns. Plotte

Indicator v4 TrendMean reversion
Updated 5 years ago · None stated GitHub repository of AutoCorrelation Function

Calculates a composite carry and decay oscillator fusing impulse-autocorrelation half-life, a Hurst exponent approximation, path efficiency, and range expansion ratios. It evaluates whether an impulse is likely to persist or mean-revert, plotting the oscillato

Indicator v6 TrendOscillators & momentum
Updated yesterday · MIT GitHub repository of Market Memory & Decay Oscillator [WavesUnchained]
257 stars

This indicator plots auto trade signals for E-mini S&P 500 futures on the price chart. It computes an EMA200 filter along with day ETH RTH session levels and percentage-based entry zones. Signals trigger CALL or PUT cases when price crosses defined thresholds

Indicator v6 TrendSupport & resistance
Updated 6 weeks ago · None stated GitHub repository of Auto Trade Futures ES

Peak Reversal v3

by Zettt
43 stars

Peak Reversal v3 identifies potential mean-reversion points by plotting configurable Keltner Channels alongside a squeeze detector directly on the price chart. It detects momentum extremes when candles cross or trade completely outside the inner or outer chann

Indicator v6 Mean reversionVolatility & bands
Updated 1 year ago · None stated GitHub repository of Peak Reversal v3
6 stars

This indicator classifies price action into four distinct market regimes: Trend, Expansion, Compression, or Mean Reversion. It determines states using a simplified Hurst exponent estimate, ADX slope thresholds, and realized volatility measurements. Based on th

Indicator v6 TrendVolatility & bands
Updated 8 weeks ago · MIT GitHub repository of Capital41 Regime Matrix v3

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers