TradingView Backtesting

OHLC Volatility Estimators on TradingView: Parkinson and Alternatives

Parkinson volatility estimates price variability from squared log high-to-low ranges. Garman-Klass also uses the open and close; Rogers-Satchell allows nonzero drift; Yang-Zhang combines overnight returns, intraday returns and Rogers-Satchell variance. Their assumptions differ, so use the same OHLC window, session and annualization factor before comparing values. A daily range alone cannot measure a jump from the previous close to the next open.

See the decision guide

Compare drift and opening-gap assumptions

The formulas below estimate variance first, then take its square root. Their model properties concern continuous price diffusion and observed extremes. Real jumps within a session, sparse trading and erroneous highs or lows can violate those assumptions. The simplified Garman-Klass formula used here is the common no-opening-jump version implemented by TTR; it is not the separate Garman-Klass-Yang-Zhang variant.

  • For a study of full daily risk where opening gaps matter, Yang-Zhang has an explicit gap component. That does not make it the most accurate estimator for every dataset or forecasting task.
  • For strictly intraday variation, a range estimator can answer a narrower question. Label the session being measured instead of describing it as total daily risk.
  • Drift independence is a property of the variance estimator under its model. It is not a guarantee that a trending market has low trading risk.
EstimatorRequired pricesDrift treatmentOpening gap
ParkinsonHigh and lowZero-drift modelOmitted
Garman-KlassOpen, high, low, closeZero-drift modelOmitted in the formula on this page
Rogers-SatchellOpen, high, low, closeAllows nonzero driftOmitted
Yang-ZhangOHLC plus the preceding closeAllows nonzero driftExplicit close-to-open sample variance

Define the four formulas on the same window

For each of n complete observations, let u = ln(H/O), d = ln(L/O), c = ln(C/O), and o = ln(O/previous C). All logarithms are natural logs. mean means an arithmetic average over the same n observations; sampleVar subtracts the sample mean and divides by n - 1. Require n > 1 for Yang-Zhang and retain the close immediately before the first OHLC row.

  • Average the variance contributions before taking the square root. Averaging daily volatility values generally gives a different answer.
  • The Parkinson, Garman-Klass and Rogers-Satchell averages divide by n. The two centered Yang-Zhang sample variances divide by n - 1. Substituting one denominator for the other changes the estimator.
  • Yang-Zhang uses a window-dependent k with the conventional 1.34 constant here. Adding an average squared opening gap to Garman-Klass gives a different estimator, even if a script name contains Yang-Zhang.
Per-observation variance, before annualizationtext
vP  = mean((u - d)^2) / (4 * ln(2))
vGK = mean(0.5 * (u - d)^2 - (2 * ln(2) - 1) * c^2)
vRS = mean(u * (u - c) + d * (d - c))

k   = 0.34 / (1.34 + (n + 1) / (n - 1))
vYZ = sampleVar(o) + k * sampleVar(c) + (1 - k) * vRS

Per-observation volatility = sqrt(v)
Annualized volatility     = sqrt(A * v)
Percentage display        = 100 * volatility

Work through one three-day OHLC sample

Assume the close before Day 1 is 100. These are hypothetical daily prices on a consistent adjustment basis, with no missing observations. Day 2 opens above the previous close, and Day 3 opens below it. Three days make the arithmetic inspectable; they are too few to support a stable risk estimate.

  • Day 1 Parkinson contribution = ln(103/99)² / (4 ln(2)) = 0.0005658552. Averaging all three contributions gives vP = 0.0006542421.
  • The overnight log returns are 0, ln(105/102) = 0.02898754 and ln(102/103) = -0.00975617. Their centered sample variance is 0.0004060892.
  • The intraday log returns are ln(102/100), ln(103/105) and ln(101/102). Their sample variance is 0.0004151723; vRS = 0.0007958520 and k = 0.1017964.
  • Thus vYZ = 0.0004060892 + 0.1017964 × 0.0004151723 + (1 - 0.1017964) × 0.0007958520 = 0.0011631895, subject to rounding.
DayPrevious closeOpenHighLowClose
110010010399102
2102105106101103
3103102104100101

Compare daily and annualized results

Use A = 252 daily observations per year for this illustration. Each row uses the same three-day estimation window. The daily column is 100√v; the annualized column is 100√(252v). Annualization is a reporting convention under variance-scaling assumptions, not a forecast of the next year.

  • A 20-day lookback on daily bars still estimates daily variance. Do not annualize it with √(252/20); use √252 on its daily volatility.
  • Weekly observations require a weekly factor, such as an explicitly chosen 52. Daily observations in a seven-day market may use 365. Neither constant is universal; document the calendar.
  • Intraday bars need a stated session length and bars-per-year convention. Multiplying an intraday-only estimate by bars per year does not recover omitted overnight risk. Repeated time-of-day patterns also complicate simple scaling.
  • Rebuilding weekly OHLC from daily data changes the ranges and gap boundaries. It need not reproduce an annualized daily estimate even when both use the same calendar span.
EstimatorDaily variance, decimal²Daily volatilityAnnualized volatility
Parkinson0.00065424212.5578%40.6041%
Garman-Klass0.00079635592.8220%44.7975%
Rogers-Satchell0.00079585202.8211%44.7833%
Yang-Zhang0.00116318953.4106%54.1409%

Reproduce the example without a chart indicator

This Python example uses only the standard library and the exact prices above. It calculates all four estimators from one validated sample. Keep the results separate from a strategy trade report; the input here is market OHLC, not trade profits.

Python 3: the printed annualized percentages match the tablepython
from math import isfinite, log, sqrt
from statistics import mean, variance

rows = [(100, 103, 99, 102), (105, 106, 101, 103),
        (102, 104, 100, 101)]  # O, H, L, C
previous_close = 100
annual_periods = 252
n = len(rows)
if n < 2 or not isfinite(previous_close) or previous_close <= 0:
    raise ValueError("Need two OHLC rows and a positive prior close")
if not isfinite(annual_periods) or annual_periods <= 0:
    raise ValueError("Annual periods must be positive")
p, g, rs, overnight, intraday = [], [], [], [], []
for O, H, L, C in rows:
    if not all(isfinite(x) and x > 0 for x in (O, H, L, C)):
        raise ValueError("Prices must be finite and positive")
    if not (L <= min(O, C) <= max(O, C) <= H):
        raise ValueError("OHLC ordering is invalid")
    u, d, c = log(H / O), log(L / O), log(C / O)
    p.append((u - d) ** 2 / (4 * log(2)))
    g.append(0.5 * (u - d) ** 2 - (2 * log(2) - 1) * c ** 2)
    rs.append(u * (u - c) + d * (d - c))
    overnight.append(log(O / previous_close))
    intraday.append(c)
    previous_close = C
k = 0.34 / (1.34 + (n + 1) / (n - 1))
estimates = {"Parkinson": mean(p), "Garman-Klass": mean(g),
             "Rogers-Satchell": mean(rs),
             "Yang-Zhang": variance(overnight) + k * variance(intraday)
                           + (1 - k) * mean(rs)}
for name, v in estimates.items():
    print(name, f"{100 * sqrt(annual_periods * v):.4f}%")

Test gap-only days and invalid observations

A useful failure case has no trading-session range. Start with a preceding close of 100; Day 1 has O = H = L = C = 110 and Day 2 has O = H = L = C = 99. Parkinson, Garman-Klass and Rogers-Satchell all return zero. They never compare those prices with the previous close.

  • Yang-Zhang retains the overnight returns ln(1.10) and ln(0.90). With n = 2, its variance is [ln(1.10) - ln(0.90)]² / 2, which is positive. This constructed example isolates the gap term; it does not prove forecast accuracy.
  • If every overnight return is identical, its centered sample variance is zero even if each gap is large. Volatility measures dispersion under the chosen model, not the sum of absolute price moves.
  • Reject nonpositive prices, nonfinite numbers, lows above the open or close, and highs below either. Do not fix invalid data by taking absolute values or silently clipping a materially negative variance to zero.
  • A single bad high can inflate every range estimator. Missing highs and lows cannot be reconstructed from closes. Stale quotes or price limits can compress observed ranges without establishing low underlying risk.
  • Use one adjustment basis for all four fields and the preceding close. Splits, futures rolls or mixing adjusted closes with raw OHLC can create artificial gaps.

Match TradingView data and keep strategy metrics separate

Export chart data for the OHLC calculation. TradingView states that chart exports contain the data loaded on the chart. Record the symbol, exchange, bar interval, session, adjustment settings and date range. Use standard time-based bars; synthetic OHLC, including Heikin Ashi, describes a transformed price series.

  • Compare indicators only after matching the estimator formula, n, annualization factor and percentage units. Use completed bars: the current high, low and close can change before the realtime bar closes.
  • For Yang-Zhang, export the preceding close as well as the full n-row window. Check timestamps for missing intervals; do not replace missing observations with zero returns.
  • Backtest Deep Report accepts TradingView List of Trades CSV exports and calculates supported results including net profit, profit factor and drawdown from its trade-derived equity curve. Check initial capital and imported trade records before reconciling results.
  • That trade CSV is a different input from chart OHLC. This page does not claim that Backtest Deep Report provides Parkinson, Garman-Klass, Rogers-Satchell or Yang-Zhang volatility. Calculate these independently using the price series.
  • Pine Script AI Coding Agent can help draft a custom chart statistic. Supply the exact formula, session, lookback, annualization and confirmed-bar rules, then check a small sample against the independent calculation before using the output.
Where Pineify fits

Backtest Deep Report

Review supported profit and drawdown results from your TradingView trade CSV, alongside a separate OHLC volatility calculation.

Also useful: Pine Script AI Coding Agent. Draft a custom volatility display from an explicit formula and verify its values against the worked sample.

Review exported trades

Frequently asked questions

Educational information, not investment advice. Prices and calculations are hypothetical examples, not measured trading performance. Volatility estimates do not predict direction, guarantee returns or limit possible losses.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.