Strasmore Research
Learn Matt ConnorBy Matt Connor · data as of August 6, 2026 · refreshed weekly

IV Rank vs IV Percentile: Formulas Explained

IV rank vs IV percentile: both formulas, one worked example you can check by hand, and the case where the two numbers disagree sharply on the same ticker.

IV rank vs IV percentile comes down to two pieces of arithmetic run over the same data. IV rank measures where today's implied volatility sits inside its 52 week range, from the lowest reading to the highest. IV percentile counts the share of trading days in the lookback window that closed below today's reading. The same ticker, on the same afternoon, can score 18 on one and 70 on the other.

The two formulas, written out

IV rank = (current IV minus the 52 week low IV) / (the 52 week high IV minus the 52 week low IV) x 100

IV percentile = (trading days in the window with IV below today's IV) / (total trading days in the window) x 100

Both land between 0 and 100. Both need the same two inputs: a daily implied volatility series for the stock, and a lookback window, conventionally 252 trading days. Implied volatility itself is the option market's annualized estimate of how far the stock will move, backed out of live option prices, which what implied volatility measures covers from scratch.

What separates the two is how much of the window each one reads. IV rank looks at exactly two days out of 252: the highest and the lowest. Everything in between is scenery. IV percentile looks at every day equally and never asks how far apart the readings were. One is a position inside a range. The other is a count of days.

A worked example you can check by hand

Take a made up ten day IV series, one reading per session: 22, 24, 21, 60, 26, 25, 23, 27, 24, and today at 28. The low is 21 and the high is 60.

IV rank: (28 - 21) / (60 - 21) x 100 = 7 / 39 x 100 = 17.9.

IV percentile: seven of the ten readings, 22, 24, 21, 26, 25, 23 and 24, sit below 28, giving 7 / 10 x 100 = 70.0.

An IV rank of 17.9 reads as cheap volatility. An IV percentile of 70 reads as volatility that has been lower than this on most days of the window. Both are correct descriptions of the same ten numbers.

Now change one value. Replace the 60 with a 30 and leave the other nine readings alone. IV rank becomes (28 - 21) / (30 - 21) x 100 = 77.8. IV percentile does not move: still 70.0. One session, the one that set the high, is worth 60 points of IV rank and nothing at all to IV percentile.

That is the structural weak spot of IV rank. A single spike in the window, an earnings gap or a one day scare, pushes the denominator wide open and pins the rank near the floor for the following twelve months, long after the spike has rolled out of the option chain. When the two scores disagree sharply, the disagreement is usually flagging an outlier inside the window, and the percentile is the more faithful description of where volatility has actually spent its time. IV rank is the better read when the range is smooth and both extremes are populated by more than one session. Neither number says anything about direction.

What a real IV series looks like

Here is the raw material both formulas run on. The panel below builds a daily at the money implied volatility reading for AAPL from contracts 20 to 45 days from expiry and within 5% of the share price, then averages those readings by week.

QueryAAPL at the money implied volatility, weekly, trailing 52 weeks
The exact SQL behind every number
WITH daily AS
(
    SELECT
        date,
        avg(toFloat64(implied_volatility)) * 100 AS atm_iv
    FROM global_markets.options_greeks
    WHERE underlying_symbol = 'AAPL'
      AND date >= today() - 371
      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 date
)
SELECT
    toString(toMonday(date))                    AS week,
    formatDateTime(toMonday(date), '%b %e, %Y') AS week_label,
    round(avg(atm_iv), 2)                       AS aapl_atm_iv_pct,
    round(min(atm_iv), 2)                       AS week_low_iv_pct,
    round(max(atm_iv), 2)                       AS week_high_iv_pct
FROM daily
GROUP BY toMonday(date)
ORDER BY toMonday(date)
Run this yourself

The series carries 54 weekly points, from the week of Jul 28, 2025, which averaged 30.03%, through the week of Aug 3, 2026 at 27.7%. The shape of that line decides whether rank and percentile agree. A line with one tall isolated spike splits them. A line that wanders inside a stable band keeps them close. Our AAPL implied volatility page follows this name over time; for the absolute level question with no history attached, see is 30% IV high.

IV rank vs IV percentile across eight tickers

Same formulas, same lookback, eight liquid names, one session. The gap column is the absolute distance between the two scores.

QueryIV rank vs IV percentile, eight liquid names, 52 week lookback
The exact SQL behind every number
WITH daily AS
(
    SELECT
        underlying_symbol                        AS symbol,
        date,
        avg(toFloat64(implied_volatility)) * 100 AS atm_iv
    FROM global_markets.options_greeks
    WHERE underlying_symbol IN ('AAPL', 'MSFT', 'NVDA', 'AMZN', 'TSLA', 'SPY', 'QQQ', 'KO')
      AND date >= today() - 371
      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 symbol, date
),
latest AS
(
    SELECT
        symbol,
        argMax(atm_iv, date) AS iv_now,
        max(date)            AS as_of
    FROM daily
    GROUP BY symbol
)
SELECT
    d.symbol AS symbol,
    round(100 * (l.iv_now - min(d.atm_iv)) / nullIf(max(d.atm_iv) - min(d.atm_iv), 0), 1) AS iv_rank,
    round(100 * countIf(d.atm_iv < l.iv_now) / count(), 1)                                AS iv_percentile,
    round(abs(iv_rank - iv_percentile), 1)                                                AS gap,
    formatDateTime(any(l.as_of), '%b %e, %Y')                                             AS as_of_label
FROM daily AS d
INNER JOIN latest AS l ON l.symbol = d.symbol
GROUP BY d.symbol, l.iv_now
ORDER BY gap DESC
Run this yourself

As of Aug 3, 2026, the widest disagreement in the table is 35.6 points, at AAPL, where IV rank reads 32.4 against an IV percentile of 68. At the other end of the table, TSLA keeps the two within 6.5 points of each other. A screen built on one number returns a different list from a screen built on the other, which is the practical reason to know which one your platform prints. The highest IV rank stocks screen sorts the market on the first of them.

The range inputs behind every rank in that table

Plug the current, low and high columns into the rank formula and the rank column above comes back out.

QueryCurrent, 52 week low and 52 week high ATM IV for each name
The exact SQL behind every number
WITH daily AS
(
    SELECT
        underlying_symbol                        AS symbol,
        date,
        avg(toFloat64(implied_volatility)) * 100 AS atm_iv
    FROM global_markets.options_greeks
    WHERE underlying_symbol IN ('AAPL', 'MSFT', 'NVDA', 'AMZN', 'TSLA', 'SPY', 'QQQ', 'KO')
      AND date >= today() - 371
      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 symbol, date
),
latest AS
(
    SELECT
        symbol,
        argMax(atm_iv, date) AS iv_now,
        max(date)            AS as_of
    FROM daily
    GROUP BY symbol
)
SELECT
    d.symbol                                  AS symbol,
    round(l.iv_now, 2)                        AS current_iv_pct,
    round(min(d.atm_iv), 2)                   AS low_52w_iv_pct,
    round(max(d.atm_iv), 2)                   AS high_52w_iv_pct,
    count()                                   AS observations,
    formatDateTime(any(l.as_of), '%b %e, %Y') AS as_of_label
FROM daily AS d
INNER JOIN latest AS l ON l.symbol = d.symbol
GROUP BY d.symbol, l.iv_now
ORDER BY current_iv_pct DESC
Run this yourself

Why two platforms report different values for the same ticker

Neither formula is ambiguous. The inputs are. Vendors rarely publish which IV series they feed in, and the common choices sit at opposite ends of the chain: a 30 day constant maturity IV, interpolated between the two expiries either side of 30 days, or the front month at the money contract, which is far twitchier. Some platforms average the whole chain instead. This panel runs one stock through three definitions of the IV input over the same 52 weeks.

QueryOne stock, one session, three definitions of the IV input
The exact SQL behind every number
WITH contracts AS
(
    SELECT
        date,
        days_to_expiry,
        abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) AS moneyness,
        toFloat64(implied_volatility) * 100                            AS iv_pct
    FROM global_markets.options_greeks
    WHERE underlying_symbol = 'AAPL'
      AND date >= today() - 371
      AND iv_converged = 1
      AND volume > 0
),
defs AS
(
    SELECT
        spec.1 AS iv_series,
        spec.2 AS min_dte,
        spec.3 AS max_dte,
        spec.4 AS max_moneyness
    FROM
    (
        SELECT arrayJoin([
            ('Near 30 day ATM', 20, 45, 0.05),
            ('Front month ATM', 1, 19, 0.05),
            ('Wide net, any expiry', 1, 400, 0.30)
        ]) AS spec
    )
),
daily AS
(
    SELECT
        s.iv_series AS iv_series,
        c.date      AS date,
        avg(c.iv_pct) AS atm_iv
    FROM contracts AS c
    CROSS JOIN defs AS s
    WHERE c.days_to_expiry BETWEEN s.min_dte AND s.max_dte
      AND c.moneyness < s.max_moneyness
    GROUP BY iv_series, date
),
latest AS
(
    SELECT
        iv_series,
        argMax(atm_iv, date) AS iv_now
    FROM daily
    GROUP BY iv_series
)
SELECT
    d.iv_series             AS iv_series,
    round(l.iv_now, 2)      AS current_iv_pct,
    round(min(d.atm_iv), 2) AS low_52w_iv_pct,
    round(max(d.atm_iv), 2) AS high_52w_iv_pct,
    round(100 * (l.iv_now - min(d.atm_iv)) / nullIf(max(d.atm_iv) - min(d.atm_iv), 0), 1) AS iv_rank,
    round(100 * countIf(d.atm_iv < l.iv_now) / count(), 1)                                AS iv_percentile
FROM daily AS d
INNER JOIN latest AS l ON l.iv_series = d.iv_series
GROUP BY d.iv_series, l.iv_now
ORDER BY current_iv_pct DESC
Run this yourself

On the latest session, Wide net, any expiry prints 37.6% while Near 30 day ATM prints 27.7%, and their IV ranks land at 23.1 and 32.4. Same stock, same session, same formula, different definition of the input.

The second lever is the lookback length. 52 weeks is the convention, and plenty of platforms offer 30, 60 or 90 day settings alongside it.

QueryThe same session scored at five different lookback windows
The exact SQL behind every number
WITH daily AS
(
    SELECT
        date,
        avg(toFloat64(implied_volatility)) * 100 AS atm_iv
    FROM global_markets.options_greeks
    WHERE underlying_symbol = 'AAPL'
      AND date >= today() - 800
      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 date
),
latest AS
(
    SELECT
        argMax(atm_iv, date) AS iv_now,
        max(date)            AS as_of
    FROM daily
),
windows AS
(
    SELECT
        spec.1 AS lookback_label,
        spec.2 AS lookback_days
    FROM
    (
        SELECT arrayJoin([
            ('1 month', 30),
            ('3 months', 90),
            ('6 months', 180),
            ('12 months', 371),
            ('24 months', 742)
        ]) AS spec
    )
)
SELECT
    w.lookback_label AS lookback_label,
    round(100 * (l.iv_now - min(d.atm_iv)) / nullIf(max(d.atm_iv) - min(d.atm_iv), 0), 1) AS iv_rank,
    round(100 * countIf(d.atm_iv < l.iv_now) / count(), 1)                                AS iv_percentile,
    count()                                                                               AS observations
FROM daily AS d
CROSS JOIN windows AS w
CROSS JOIN latest AS l
WHERE d.date >= l.as_of - w.lookback_days
GROUP BY w.lookback_label, w.lookback_days, l.iv_now
ORDER BY w.lookback_days
Run this yourself

At the 1 month lookback this stock scores 0.4 on IV rank and 4.8 on IV percentile. Stretch the window to 24 months and the same session scores 23.4 and 63.3. Nothing about the option chain changed between those rows. Only the window did. When two screens disagree about a ticker, the lookback setting and the IV series are the first two places to check.

How the two numbers get used

Both readings work as a filter on strategy selection, never as a forecast. Traders who sell premium, covered calls and cash secured puts among them, tend to hunt for high readings, where the option is priced for more movement than the stock has typically delivered across the window. Traders who buy premium look at the low end, where the same logic runs backwards. A relative score beats the raw IV number for this job: 40% IV is ordinary for one stock and extreme for another, and grading a stock against its own history removes that problem. Is high implied volatility good works through the trade offs on each side.

One caution the numbers cannot answer for you. A high reading can go higher, and a rank of 95 on Monday can be a rank of 60 on Friday with no change in your position. Neither score carries information about direction: elevated IV means the market has priced a large move, with no view on which way it goes.

FAQ

Is IV rank or IV percentile better?

They answer different questions. IV percentile holds up better when the lookback window contains one violent spike, since it counts days rather than measuring against a single extreme. IV rank is more intuitive when the range is well populated, since it tells you directly how close today sits to the twelve month high.

What is a high IV rank?

Most desks treat readings above 50 as the upper half of a stock's own range and readings above 80 as genuinely elevated for that name. The score is relative by construction, so a rank of 80 on a quiet consumer staple and a rank of 80 on a volatile growth name describe very different absolute IV levels.

Do IV rank and IV percentile use the same lookback?

Usually 252 trading days for both, though the setting is adjustable on most platforms and the default varies by vendor. The panel above shows one stock scoring differently at each window length, which is the first thing to check when two tools disagree.

Can IV rank be 0 or 100?

Yes. IV rank hits 100 on the day a stock prints a new 52 week high in implied volatility and 0 on a new low, since today's reading is itself one endpoint of the range. IV percentile rarely touches either extreme, since today's own session sits in the denominator.

Why did my IV rank change without IV moving?

The window rolls forward every session. When an old spike drops out of the trailing 52 weeks, the high in the denominator resets to a lower value and the rank rises, even though today's IV is unchanged. IV crush describes the other common surprise, the drop in IV itself right after an earnings report.


Every panel here carries the exact SQL underneath it. Swap the ticker in any one of them to score a different name on the Strasmore terminal.