{"slug":"stocks-with-the-biggest-iv-rv-gap","qid":"gap_frequency","label":"gap_frequency","post_title":"stocks-with-the-biggest-iv-rv-gap","post_url":"/blog/stocks-with-the-biggest-iv-rv-gap#q-gap_frequency","columns":["month","names_measured","positive_gap_share_pct","median_gap_pct"],"rows":[{"month":"2025-10","names_measured":432,"positive_gap_share_pct":69.9,"median_gap_pct":5.2},{"month":"2025-11","names_measured":320,"positive_gap_share_pct":87.8,"median_gap_pct":9.3},{"month":"2025-12","names_measured":369,"positive_gap_share_pct":33.9,"median_gap_pct":-4},{"month":"2026-01","names_measured":395,"positive_gap_share_pct":34.4,"median_gap_pct":-5.1},{"month":"2026-02","names_measured":319,"positive_gap_share_pct":59.9,"median_gap_pct":2.6},{"month":"2026-03","names_measured":338,"positive_gap_share_pct":72.5,"median_gap_pct":6.7},{"month":"2026-04","names_measured":358,"positive_gap_share_pct":63.7,"median_gap_pct":3.2},{"month":"2026-05","names_measured":396,"positive_gap_share_pct":38.6,"median_gap_pct":-1.9},{"month":"2026-06","names_measured":357,"positive_gap_share_pct":58.8,"median_gap_pct":2.4}],"shape":"series","sql":"WITH\n    split_tickers AS\n    (\n        SELECT DISTINCT ticker\n        FROM global_markets.stocks_splits\n        WHERE execution_date >= '2025-10-01'\n          AND execution_date <  '2026-08-01'\n    ),\n    px AS\n    (\n        SELECT\n            ticker                AS symbol,\n            date                  AS session,\n            max(toFloat64(close)) AS px\n        FROM global_markets.stocks_daily_aggs\n        WHERE date >= '2025-10-01'\n          AND date <  '2026-08-01'\n          AND ticker NOT IN (SELECT ticker FROM split_tickers)\n          AND ticker NOT IN ('SPCX')\n        GROUP BY symbol, session\n    ),\n    iv_rows AS\n    (\n        SELECT\n            g.symbol  AS symbol,\n            g.session AS session,\n            g.iv      AS iv\n        FROM\n        (\n            SELECT\n                underlying_symbol       AS symbol,\n                toDate(date)            AS session,\n                toFloat64(strike_price) AS strike,\n                implied_volatility      AS iv\n            FROM global_markets.options_greeks\n            WHERE date >= '2025-10-01'\n              AND date <  '2026-07-01'\n              AND lower(toString(option_type)) IN ('c', 'call')\n              AND days_to_expiry BETWEEN 20 AND 45\n              AND implied_volatility > 0\n        ) AS g\n        INNER JOIN px AS p ON p.symbol = g.symbol AND p.session = g.session\n        WHERE p.px > 10\n          AND abs(g.strike / p.px - 1) < 0.05\n    ),\n    implied AS\n    (\n        SELECT\n            symbol,\n            iv_month,\n            addMonths(iv_month, 1) AS forward_month,\n            implied_vol_pct\n        FROM\n        (\n            SELECT\n                symbol,\n                toStartOfMonth(session) AS iv_month,\n                round(100 * avg(iv), 1) AS implied_vol_pct\n            FROM iv_rows\n            GROUP BY symbol, iv_month\n            HAVING countDistinct(session) >= 15\n               AND count() >= 150\n        )\n    ),\n    daily_returns AS\n    (\n        SELECT\n            symbol,\n            arrayJoin(arrayMap((a, b) -> (tupleElement(a, 1), log(tupleElement(a, 2) / tupleElement(b, 2))),\n                               arraySlice(series, 2),\n                               arraySlice(series, 1, length(series) - 1))) AS ret\n        FROM\n        (\n            SELECT\n                symbol,\n                arraySort(groupArray((session, px))) AS series\n            FROM px\n            WHERE symbol IN (SELECT symbol FROM implied)\n            GROUP BY symbol\n        )\n    ),\n    realized AS\n    (\n        SELECT\n            symbol,\n            toStartOfMonth(tupleElement(ret, 1))                         AS rv_month,\n            round(100 * sqrt(252) * stddevSamp(tupleElement(ret, 2)), 1) AS realized_vol_pct\n        FROM daily_returns\n        GROUP BY symbol, rv_month\n        HAVING count() >= 15\n    )\nSELECT\n    formatDateTime(implied.iv_month, '%Y-%m') AS month,\n    count()                                   AS names_measured,\n    round(100 * countIf(implied.implied_vol_pct > realized.realized_vol_pct) / count(), 1) AS positive_gap_share_pct,\n    round(quantileDeterministic(0.5)(implied.implied_vol_pct - realized.realized_vol_pct,\n                                     cityHash64(implied.symbol)), 1) AS median_gap_pct\nFROM implied\nINNER JOIN realized ON realized.symbol = implied.symbol\n                   AND realized.rv_month = implied.forward_month\nGROUP BY month\nORDER BY month","computed_at":"2026-10-01T15:32:03.937705+00:00","elapsed":53.640320765}