{"slug":"the-volatility-risk-premium","qid":"vrp_by_tenor","label":"The volatility risk premium by option tenor, each matched to its own realized window","post_title":"The Volatility Risk Premium, Measured","post_url":"/blog/the-volatility-risk-premium#q-vrp_by_tenor","columns":["tenor","implied_vol_pct","realized_vol_pct","premium_pct","positive_share_pct"],"rows":[{"tenor":"07-14 days","implied_vol_pct":17.3,"realized_vol_pct":15.05,"premium_pct":2.24,"positive_share_pct":76.2},{"tenor":"15-30 days","implied_vol_pct":17.05,"realized_vol_pct":15.48,"premium_pct":1.58,"positive_share_pct":72.6},{"tenor":"31-60 days","implied_vol_pct":16.89,"realized_vol_pct":15.82,"premium_pct":1.07,"positive_share_pct":72.9},{"tenor":"61-120 days","implied_vol_pct":17.37,"realized_vol_pct":16.08,"premium_pct":1.3,"positive_share_pct":74.3}],"shape":"table","sql":"WITH\ncloses AS\n(\n    SELECT\n        date,\n        toFloat64(any(close)) AS px\n    FROM global_markets.stocks_daily_aggs\n    WHERE ticker = 'SPY'\n      AND date >= '2021-06-01'\n    GROUP BY date\n),\ndaily_returns AS\n(\n    SELECT\n        date,\n        pow(log(px / lagInFrame(px) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)), 2) AS r2\n    FROM closes\n),\nforward_rv AS\n(\n    SELECT\n        date,\n        100 * sqrt(252 * avg(r2) OVER (ORDER BY date ROWS BETWEEN 1 FOLLOWING AND 7 FOLLOWING))  AS rv_07_pct,\n        100 * sqrt(252 * avg(r2) OVER (ORDER BY date ROWS BETWEEN 1 FOLLOWING AND 15 FOLLOWING)) AS rv_15_pct,\n        100 * sqrt(252 * avg(r2) OVER (ORDER BY date ROWS BETWEEN 1 FOLLOWING AND 31 FOLLOWING)) AS rv_31_pct,\n        100 * sqrt(252 * avg(r2) OVER (ORDER BY date ROWS BETWEEN 1 FOLLOWING AND 62 FOLLOWING)) AS rv_62_pct,\n        count(r2) OVER (ORDER BY date ROWS BETWEEN 1 FOLLOWING AND 62 FOLLOWING)                 AS sessions_ahead\n    FROM daily_returns\n    WHERE isFinite(r2)\n),\nby_day AS\n(\n    SELECT\n        g.date AS date,\n        multiIf(g.days_to_expiry <= 14, '07-14 days',\n                g.days_to_expiry <= 30, '15-30 days',\n                g.days_to_expiry <= 60, '31-60 days',\n                                        '61-120 days') AS tenor,\n        avg(100 * toFloat64(g.implied_volatility))      AS iv_pct,\n        any(multiIf(g.days_to_expiry <= 14, f.rv_07_pct,\n                    g.days_to_expiry <= 30, f.rv_15_pct,\n                    g.days_to_expiry <= 60, f.rv_31_pct,\n                                            f.rv_62_pct)) AS rv_pct\n    FROM global_markets.options_greeks AS g\n    INNER JOIN forward_rv AS f ON f.date = g.date\n    WHERE g.underlying_symbol = 'SPY'\n      AND g.iv_converged = 1\n      AND g.volume > 0\n      AND g.days_to_expiry BETWEEN 7 AND 120\n      AND abs(toFloat64(g.strike_price) / toFloat64(g.underlying_close) - 1) < 0.05\n      AND g.date >= '2021-08-01'\n      AND f.sessions_ahead = 62\n    GROUP BY date, tenor\n    HAVING count() >= 5\n)\nSELECT\n    tenor,\n    round(avg(iv_pct), 2)                              AS implied_vol_pct,\n    round(avg(rv_pct), 2)                              AS realized_vol_pct,\n    round(avg(iv_pct - rv_pct), 2)                     AS premium_pct,\n    round(100 * countIf(iv_pct > rv_pct) / count(), 1) AS positive_share_pct\nFROM by_day\nGROUP BY tenor\nORDER BY tenor","computed_at":"2026-10-16T15:53:33.165314+00:00","elapsed":0.009980831}