Files
QuanTAlib/lib/numerics/normdist/Normdist.md
T

7.7 KiB
Raw Blame History

NORMDIST: Normal Distribution CDF

The normal distribution CDF is the bell curve's integral — the universal reference for probabilistic reasoning.

Property Value
Category Numeric
Inputs Source (close)
Parameters mu (default 0.0), sigma (default 1.0), period (default 14)
Outputs Single series (Normdist)
Output range Varies (see docs)
Warmup period bars
PineScript normdist.pine
  • The Normal Distribution CDF transforms a z-score normalized price into the cumulative distribution function of the Gaussian distribution, producing...
  • Trading note: Normal (Gaussian) distribution; foundational for z-scores, confidence intervals, and VaR calculations.
  • Validated against TA-Lib, Skender, and Tulip reference implementations where available.

The Normal Distribution CDF transforms a z-score normalized price into the cumulative distribution function of the Gaussian distribution, producing an output in [0, 1]. Unlike other distribution indicators in this library that use min-max normalization, NORMDIST computes a rolling mean and standard deviation over the lookback window, converting the raw price to a z-score, then applies optional \mu and \sigma parameters for further shaping. The result represents the probability that a standard normal random variable would fall at or below the observed z-score. This makes NORMDIST a direct percentile ranking under the assumption of normally distributed returns, with the output naturally centered at 0.5 when the price is at its rolling mean.

Historical Context

The normal distribution was discovered independently by Abraham de Moivre (1733) as a limit of the binomial distribution, and by Carl Friedrich Gauss (1809) in the context of astronomical measurement errors. Pierre-Simon Laplace (1812) proved the central limit theorem, establishing that sums of independent random variables converge to the normal distribution regardless of the underlying distribution.

In finance, the normal distribution assumption for asset returns was formalized by Harry Markowitz (1952) in Modern Portfolio Theory and Louis Bachelier (1900) in his thesis on speculation. Despite well-known departures (fat tails, skewness, volatility clustering), the normal CDF remains the most widely used probability transform in quantitative finance. It underpins the Black-Scholes formula, Value-at-Risk calculations, and the Sharpe ratio.

The z-score normalization approach used here is more statistically grounded than the min-max normalization used by other distribution indicators: it captures the rolling distributional properties (mean, variance) of the price series rather than just the range. This means NORMDIST adapts to both the level and the volatility of the price, making readings directly interpretable as "number of standard deviations from the mean."

Architecture and Physics

The computation follows a three-phase pipeline:

Phase 1: Rolling statistics computes the mean and standard deviation over the lookback window using a single-pass algorithm:

\bar{x} = \frac{1}{n}\sum_{i=0}^{n-1} x_i, \quad s = \sqrt{\frac{1}{n}\sum_{i=0}^{n-1} x_i^2 - \bar{x}^2}

NaN values are excluded from the count. If fewer than 2 valid values exist, the output defaults to 0.5.

Phase 2: Z-score with parameter adjustment converts the price to a z-score relative to the rolling distribution, then applies the user-specified shift and scale:

z = \frac{x - \bar{x}}{s}, \quad z_{\text{final}} = \frac{z - \mu}{\sigma}

With defaults \mu = 0, \sigma = 1, z_{\text{final}} = z (standard z-score). Increasing \sigma compresses the CDF curve (less sensitive to deviations); shifting \mu moves the midpoint away from the rolling mean.

Phase 3: Error function approximation evaluates \Phi(z) using the Abramowitz and Stegun formula (7.1.26) with 3 polynomial terms in the exponential approximation of erf:

\text{erf}(x) \approx 1 - (a_1 t + a_2 t^2 + a_3 t^3) \cdot e^{-x^2}

where t = 1/(1 + 0.47047|x|). The CDF is then \Phi(z) = 0.5(1 + \text{erf}(z/\sqrt{2})).

Accuracy: The 3-term Abramowitz-Stegun approximation achieves maximum error of \sim 2.5 \times 10^{-5}, sufficient for indicator applications. For higher precision, the 5-term version (used in LOGNORMDIST) reduces error to \sim 1.5 \times 10^{-7}.

Mathematical Foundation

The standard normal PDF and CDF:

\phi(z) = \frac{1}{\sqrt{2\pi}} e^{-z^2/2} \Phi(z) = \frac{1}{2}\left(1 + \text{erf}\!\left(\frac{z}{\sqrt{2}}\right)\right) = \int_{-\infty}^{z} \phi(t)\,dt

The error function:

\text{erf}(x) = \frac{2}{\sqrt{\pi}} \int_0^x e^{-t^2}\,dt

Abramowitz and Stegun 3-term approximation:

\text{erf}(x) \approx 1 - (a_1 t + a_2 t^2 + a_3 t^3) e^{-x^2}, \quad t = \frac{1}{1 + 0.47047\,|x|}

with a_1 = 0.3480242, a_2 = -0.0958798, a_3 = 0.7478556.

Z-score normalization (population standard deviation, not sample):

z = \frac{x - \bar{x}}{s}, \quad s = \sqrt{\frac{\sum x_i^2}{n} - \left(\frac{\sum x_i}{n}\right)^2}

Key CDF values: \Phi(0) = 0.5, \Phi(1) \approx 0.841, \Phi(2) \approx 0.977, \Phi(-1) \approx 0.159, \Phi(-2) \approx 0.023.

Parameter constraints: period > 0, \sigma > 0, \mu \in \mathbb{R}. Output is bounded [0, 1].

NORMDIST(source, period, mu, sigma):
    // Phase 1: rolling statistics
    sum = 0;  sumSq = 0;  count = 0
    for i = 0 to period-1:
        if not NaN(source[i]):
            sum += source[i]
            sumSq += source[i]^2
            count += 1
    if count < 2: return 0.5
    mean = sum / count
    variance = sumSq/count - mean^2
    stddev = sqrt(max(0, variance))

    // Phase 2: z-score with parameter adjustment
    z = stddev > 0 ? (source - mean) / stddev : 0
    z_final = (z - mu) / sigma

    // Phase 3: erf approximation -> CDF
    x = z_final / sqrt(2)
    t = 1 / (1 + 0.47047 * |x|)
    erf = 1 - (0.3480242*t + (-0.0958798)*t^2 + 0.7478556*t^3) * exp(-x^2)
    if x < 0: erf = -erf
    return 0.5 * (1 + erf)

Performance Profile

Operation Count (Streaming Mode)

Normal distribution CDF uses an erfc() rational approximation (Abramowitz & Stegun) — O(1) closed form.

Operation Count Cost (cycles) Subtotal
z = (x - mu) / sigma 1 4 cy ~4 cy
erfc(z / sqrt(2)) rational approx 1 15 cy ~15 cy
Scale by 0.5 1 1 cy ~1 cy
NaN guard + state update 1 2 cy ~2 cy
Total O(1) ~22 cy

O(1) per evaluation. The rational polynomial erfc approximation has 7-term expansion, accurate to 1e-7. Division by sigma precomputed as multiplication by 1/sigma.

Batch Mode (SIMD Analysis)

Operation Vectorizable? Notes
z = (x - mu) / sigma Yes Vector FMA
erfc() rational polynomial Partial Polynomial evaluable via Horner + Vector
Final scale Yes Vector multiply

The Horner polynomial evaluation in erfc() is SIMD-vectorizable. Expected 3× batch speedup over scalar using Vector for the polynomial terms.

Resources

  • Gauss, C.F. "Theoria Motus Corporum Coelestium." 1809.
  • Abramowitz, M. & Stegun, I. "Handbook of Mathematical Functions." NBS Applied Mathematics Series 55, 1964. Formulas 7.1.25-7.1.28.
  • Markowitz, H. "Portfolio Selection." Journal of Finance, 1952.
  • Johnson, N.L., Kotz, S. & Balakrishnan, N. "Continuous Univariate Distributions, Vol. 1." Wiley, 1994.
  • Hart, J.F. et al. "Computer Approximations." Wiley, 1968.