Historical Volatility vs Implied Volatility
Historical volatility measures what a stock already did; implied volatility is the market's forward guess. See both computed, side by side, with real data.
Historical volatility measures how much a stock has already moved, computed from its own past closing prices. Implied volatility is the number the options market is quoting today for movement that has not happened yet. Both print in the same units, annualized percent, and that shared scale is what makes them comparable at all.
What is historical volatility?
Historical volatility, also called realized volatility, is the annualized standard deviation of a stock's daily returns over a fixed lookback window. Standard deviation is a measure of spread: how far a typical daily move lands from the average daily move. Annualizing scales that one-day spread up to a one-year figure, the convention every options screen uses.
Four choices sit inside any published HV number, and none of them are standardized across data vendors. The lookback length. The return definition, close-to-close or a range estimator that also reads the session high and low. Whether the mean return is subtracted before squaring. And the annualization factor, 252 trading days or 365 calendar days. Two vendors can both be correct and still print different numbers for the same stock on the same afternoon. The version used everywhere below is the common one: close-to-close log returns, sample standard deviation, times the square root of 252.
How historical volatility is calculated
- Log returns. For each pair of consecutive closes, take the natural log of today's close divided by yesterday's. Log returns add cleanly over time and treat a move up and the same move down symmetrically, which raw percentage changes do not.
- Sample standard deviation. Take the standard deviation of that list of returns, dividing by n minus 1 rather than n. The smaller divisor is the sample correction: you are estimating the spread of a process from a sample of it, not describing a finished population.
- Annualize. Multiply the daily figure by the square root of 252, the approximate count of US trading sessions in a year. Variance, the square of standard deviation, is what adds across independent days, and volatility itself grows with the square root of time.
- Read it as a percent. Multiply by 100. A stock printing 24 has an annualized standard deviation of about 24% of its price.
The whole method fits in one command, standard library only, with no downloads and no data feed. The price path here is invented for the example: twenty jumpy sessions followed by ten quiet ones.
python3 <<'PY'
import math
import statistics
# An invented price path: twenty jumpy sessions, then ten quiet ones.
closes = [
100.00, 102.50, 99.80, 103.10, 100.40, 104.20, 101.60, 105.30,
102.10, 106.40, 103.20, 107.10, 104.00, 108.30, 105.20, 109.40,
106.10, 110.20, 107.30, 111.00, 111.20, 110.90, 111.30, 111.10,
111.40, 111.20, 111.50, 111.30, 111.60, 111.45, 111.65,
]
# Step 1: close-to-close log returns.
log_returns = [math.log(closes[i] / closes[i - 1]) for i in range(1, len(closes))]
def annualized_vol(returns, window):
sample = returns[-window:]
daily = statistics.stdev(sample) # sample stdev: divides by n - 1
return daily * math.sqrt(252) * 100 # steps 3 and 4
for window in (10, 30):
print(f"{window:>2}-day annualized vol: {annualized_vol(log_returns, window):5.1f}%")
PY
The script prints two figures from one price series. The 10-day window sees only the quiet tail and returns the small number. The 30-day window still carries the jumpy stretch and returns a far larger one. Neither figure is wrong. They are answers to two different questions about the same invented stock.
Why 20-day and 252-day historical volatility disagree
Real price series behave the same way. The panel below runs that identical calculation over three lookbacks for six widely held names: 20 sessions, roughly a month; 60 sessions, roughly a quarter; and 252 sessions, a full year.
The exact SQL behind every number
WITH
paths AS
(
SELECT
ticker,
arraySort(x -> tupleElement(x, 1), groupArray((date, toFloat64(close)))) AS path
FROM global_markets.stocks_daily_aggs
WHERE ticker IN ('AAPL', 'KO', 'MSFT', 'NVDA', 'SPY', 'TSLA')
AND date >= today() - 500
AND date < today()
GROUP BY ticker
HAVING count() >= 300
),
log_returns AS
(
SELECT
ticker,
arrayMap(i -> log(tupleElement(path[i + 1], 2) / tupleElement(path[i], 2)),
range(1, length(path))) AS r
FROM paths
)
SELECT
ticker AS symbol,
round(100 * sqrt(252) * arrayReduce('stddevSamp', arraySlice(r, -20)), 1) AS hv_20d_pct,
round(100 * sqrt(252) * arrayReduce('stddevSamp', arraySlice(r, -60)), 1) AS hv_60d_pct,
round(100 * sqrt(252) * arrayReduce('stddevSamp', arraySlice(r, -252)), 1) AS hv_252d_pct
FROM log_returns
ORDER BY hv_252d_pct DESCOrdered by the one-year column, TSLA sits at the top at 46.6% and SPY at the bottom at 12.9%, across 6 names. The more useful reading runs across a row rather than down a column. TSLA measured 64.1% over its last 20 sessions against 46.6% over the full year: one stock, one method, two answers. A 20-day window is responsive and noisy, and a single gap opening can dominate it for a month before dropping out of the sample overnight. A 252-day window is slow and stable, still carrying moves from eleven months ago.
The disagreement is easier to watch over time. This panel recomputes 20-session and 60-session realized volatility for AAPL at every third session across the past 13 months.
The exact SQL behind every number
WITH
daily AS
(
SELECT
date AS session_date,
toFloat64(close) AS close_px,
lagInFrame(toFloat64(close)) OVER
(ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'AAPL'
AND date >= today() - 400
AND date < today()
),
returns AS
(
SELECT
session_date,
log(close_px / prev_close) AS r,
row_number() OVER (ORDER BY session_date) AS n
FROM daily
WHERE prev_close > 0
),
rolling AS
(
SELECT
session_date,
n,
round(100 * sqrt(252) * stddevSamp(r) OVER
(ORDER BY n ROWS BETWEEN 19 PRECEDING AND CURRENT ROW), 1) AS hv_20d_pct,
round(100 * sqrt(252) * stddevSamp(r) OVER
(ORDER BY n ROWS BETWEEN 59 PRECEDING AND CURRENT ROW), 1) AS hv_60d_pct
FROM returns
)
SELECT
toString(session_date) AS date,
hv_20d_pct,
hv_60d_pct
FROM rolling
WHERE n >= 60
AND (n % 3) = 0
ORDER BY dateBoth lines describe the same stock with the same formula. The 20-day line steps up and down sharply; the 60-day line rounds those same moves off and lags them by weeks. Across 72 plotted points, from 2025-09-30 to 2026-08-06, the two readings finish at 38% and 32.5%. When a screener quotes a stock's HV without naming the lookback, that missing detail is doing much of the work.
Historical volatility vs implied volatility: what changes
Implied volatility arrives from the opposite direction. An option already has a market price, and a pricing model maps a volatility input to a theoretical price. Hold everything else fixed, the strike, the time to expiry, the underlying price and the interest rate, and exactly one volatility input makes the model agree with the screen. That input is the implied volatility, and the solve is walked through step by step in how implied volatility is calculated.
Two properties follow from that construction. Implied volatility is forward-looking, covering the span from today to expiry rather than any past window. It also behaves like a price, moving with demand for the options themselves. One stock can carry different implied volatility on two expirations at once, the shape covered in IV term structure.
An implied volatility level means little in isolation. Traders read it against its own past range (IV rank vs IV percentile) or convert it into an expected move in dollars over a stated horizon.
The gap between implied and realized volatility
Both numbers are annualized percentages, so they sit on the same axis. The comparison option sellers watch lines each month's implied volatility up against the realized volatility that actually arrived over the month that followed.
The exact SQL behind every number
WITH
daily AS
(
SELECT
date AS session_date,
toFloat64(close) AS close_px,
lagInFrame(toFloat64(close)) OVER
(ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= today() - 560
AND date < today()
),
realized AS
(
SELECT
toStartOfMonth(session_date) AS month_start,
round(100 * sqrt(252) * stddevSamp(log(close_px / prev_close)), 1) AS realized_vol_pct
FROM daily
WHERE prev_close > 0
GROUP BY month_start
HAVING count() >= 15
),
implied AS
(
SELECT
toStartOfMonth(date) AS month_start,
round(100 * avg(implied_volatility), 1) AS implied_vol_pct
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date >= today() - 560
AND date < today()
AND iv_converged = 1
AND volume > 0
AND days_to_expiry BETWEEN 20 AND 45
AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) < 0.05
GROUP BY month_start
HAVING count() >= 100
)
SELECT
formatDateTime(imp.month_start, '%Y-%m') AS month,
imp.implied_vol_pct AS implied_vol_pct,
rea.realized_vol_pct AS realized_next_month_pct,
round(imp.implied_vol_pct - rea.realized_vol_pct, 1) AS gap_pct
FROM implied AS imp
INNER JOIN realized AS rea ON rea.month_start = addMonths(imp.month_start, 1)
ORDER BY monthThe panel holds 18 monthly pairs for SPY, from 2025-01 through 2026-06. In the final pair, average near-the-money implied volatility measured 15.7% and the realized volatility of the month that followed measured 12.1%. The gap_pct column is the first figure minus the second.
The same alignment, run across a wider set of names:
For TSLA, implied averaged 54.1% over the window while the realized volatility of the following month averaged 54.7%, with implied the larger of the two in 13 of 18 monthly pairs.
That persistent difference has a name in the research literature: the variance risk premium. The standard description is that option buyers pay for protection against outcomes that have not happened, and option sellers collect for carrying the risk of the months when realized volatility lands far above what was implied. The average gap is not a forecast of the next month. The seller's distribution has a long left tail: the rare month when realized volatility overshoots implied is the month that can erase many months of collected premium. A row in the panels above records one month's outcome, never the outcome of a strategy.
Parkinson and Garman-Klass: estimators that read the high and low
Close-to-close volatility throws away most of the session. A stock that travels 4% intraday and closes unchanged contributes a zero to the return series. Range-based estimators recover part of that by reading the other fields on the bar. Parkinson, published in 1980, uses the session high and low. Garman-Klass, from the same year, adds the open and the close to that pair. Both are more efficient in the statistical sense: for the same number of sessions they pin down the same underlying volatility with less noise, which matters most when the lookback is short.
Both also assume continuous trading with no overnight gaps, and both understate volatility for a stock that makes most of its moves between one close and the next open. Their inputs come straight off the daily bar, whose construction is covered in how OHLCV bars are built.
FAQ
Is historical volatility the same as realized volatility?
In ordinary usage, yes. Both names describe volatility computed from prices that have already printed. Some desks reserve "realized" for estimates built from intraday data and "historical" for daily close-to-close, but on retail platforms the two labels point at the same calculation.
Which lookback do traders use for historical volatility?
Twenty sessions, thirty sessions and 252 sessions are the ones most platforms offer. Comparing HV against an option's implied volatility works best when the lookback roughly matches the option's remaining life: a 30-day option lines up with a 20 to 30 session lookback rather than a one-year one.
Why is implied volatility usually higher than historical volatility?
The standard explanation is the variance risk premium: buyers pay for protection against outcomes that have not occurred yet, and sellers are compensated for carrying that risk. Implied volatility also contains dated events falling inside the option's remaining life, such as an earnings report, which no past window can contain.
What does it mean when implied volatility sits below historical volatility?
It means the options market is pricing the weeks ahead as calmer than the recent past was. That reading is common in the days after a one-off event has cleared the calendar: the past window still carries the jump, while the option's remaining life no longer contains it.
Can I calculate historical volatility myself?
Yes. The command above is the entire method: log returns, a sample standard deviation, then the square root of 252. A spreadsheet does the same work with STDEV.S over a column of LN(today divided by yesterday), multiplied by SQRT(252).
Every panel on this page carries the exact SQL that produced it, expandable underneath the chart. To recompute any of these volatility numbers for a different ticker or a different lookback, ask for it in plain English on the Strasmore terminal.