{"slug":"the-volatility-risk-premium","qid":"vrp_distribution","label":"Distribution of the 21 session volatility risk premium, in volatility points","post_title":"The Volatility Risk Premium, Measured","post_url":"/blog/the-volatility-risk-premium#q-vrp_distribution","columns":["bucket","windows","share_pct"],"rows":[{"bucket":"under -10","windows":35,"share_pct":2.7},{"bucket":"-10 to -5","windows":74,"share_pct":5.7},{"bucket":"-5 to 0","windows":215,"share_pct":16.7},{"bucket":"0 to +5","windows":706,"share_pct":54.8},{"bucket":"+5 to +10","windows":253,"share_pct":19.6},{"bucket":"+10 to +15","windows":5,"share_pct":0.4}],"shape":"ranking","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 21 FOLLOWING)) AS rv_pct,\n        count(r2) OVER (ORDER BY date ROWS BETWEEN 1 FOLLOWING AND 21 FOLLOWING)                 AS sessions_ahead\n    FROM daily_returns\n    WHERE isFinite(r2)\n),\nimplied AS\n(\n    SELECT\n        date,\n        100 * avg(toFloat64(implied_volatility)) AS iv_pct\n    FROM global_markets.options_greeks\n    WHERE underlying_symbol = 'SPY'\n      AND iv_converged = 1\n      AND volume > 0\n      AND days_to_expiry BETWEEN 20 AND 45\n      AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) < 0.05\n      AND date >= '2021-08-01'\n    GROUP BY date\n    HAVING count() >= 20\n),\npaired AS\n(\n    SELECT i.iv_pct - f.rv_pct AS premium_pct\n    FROM implied AS i\n    INNER JOIN forward_rv AS f ON f.date = i.date\n    WHERE f.sessions_ahead = 21\n),\ntotals AS\n(\n    SELECT count() AS all_windows FROM paired\n)\nSELECT\n    multiIf(\n        p.premium_pct < -10, 'under -10',\n        p.premium_pct <  -5, '-10 to -5',\n        p.premium_pct <   0, '-5 to 0',\n        p.premium_pct <   5, '0 to +5',\n        p.premium_pct <  10, '+5 to +10',\n        p.premium_pct <  15, '+10 to +15',\n                             'over +15')        AS bucket,\n    count()                                      AS windows,\n    round(100 * count() / any(t.all_windows), 1) AS share_pct\nFROM paired AS p\nCROSS JOIN totals AS t\nGROUP BY bucket\nORDER BY min(p.premium_pct)","computed_at":"2026-10-16T15:53:33.050675+00:00","elapsed":0.005863511}