{"slug":"is-a-high-put-call-ratio-bullish","qid":"pcr_forward_returns","label":"S&P 500 tracker moves after each fifth of the equity put/call ratio, 2022 to July 2026","post_title":"Is a High Put/Call Ratio Bullish?","post_url":"/blog/is-a-high-put-call-ratio-bullish#q-pcr_forward_returns","columns":["pcr_band","observations","band_floor_ratio","fwd_5d_median_pct","fwd_20d_median_pct","fwd_20d_p25_pct","fwd_20d_p75_pct"],"rows":[{"pcr_band":"lowest fifth","observations":226,"band_floor_ratio":0.34,"fwd_5d_median_pct":0.3,"fwd_20d_median_pct":0.91,"fwd_20d_p25_pct":-0.83,"fwd_20d_p75_pct":2.67},{"pcr_band":"second fifth","observations":225,"band_floor_ratio":0.56,"fwd_5d_median_pct":0.7,"fwd_20d_median_pct":1.87,"fwd_20d_p25_pct":-0.27,"fwd_20d_p75_pct":3.35},{"pcr_band":"middle fifth","observations":226,"band_floor_ratio":0.63,"fwd_5d_median_pct":0.14,"fwd_20d_median_pct":1.31,"fwd_20d_p25_pct":-3.47,"fwd_20d_p75_pct":3.9},{"pcr_band":"fourth fifth","observations":225,"band_floor_ratio":0.71,"fwd_5d_median_pct":0.17,"fwd_20d_median_pct":0.83,"fwd_20d_p25_pct":-2.58,"fwd_20d_p75_pct":4.16},{"pcr_band":"highest fifth","observations":226,"band_floor_ratio":0.81,"fwd_5d_median_pct":0.82,"fwd_20d_median_pct":3,"fwd_20d_p25_pct":-1.82,"fwd_20d_p75_pct":5.71}],"shape":"table","sql":"WITH raw AS (\n    SELECT date AS day,\n           sumIf(volume, upper(substring(ticker, length(ticker) - 8, 1)) = 'P') AS put_volume,\n           sumIf(volume, upper(substring(ticker, length(ticker) - 8, 1)) = 'C') AS call_volume\n    FROM global_markets.options_greeks\n    WHERE date >= toDate('2022-01-01')\n      AND date <= toDate('2026-07-31')\n      AND volume > 0\n      AND underlying_symbol IN ('AAPL', 'MSFT', 'NVDA', 'AMZN', 'META',\n                                'TSLA', 'GOOGL', 'JPM', 'KO', 'XOM')\n    GROUP BY day\n    HAVING call_volume > 0\n),\nequity_pcr AS (\n    SELECT day, toFloat64(put_volume) / toFloat64(call_volume) AS pcr\n    FROM raw\n),\nspy_daily AS (\n    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS day,\n           toFloat64(argMax(close, window_start)) AS close\n    FROM global_markets.delayed_stocks_minute_aggs\n    WHERE ticker = 'SPY'\n      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2022-01-01')\n      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-08-01')\n      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60\n           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959\n    GROUP BY day\n),\nforward AS (\n    SELECT day,\n           close,\n           any(close) OVER (ORDER BY day ASC ROWS BETWEEN 5 FOLLOWING AND 5 FOLLOWING) AS close_5,\n           any(close) OVER (ORDER BY day ASC ROWS BETWEEN 20 FOLLOWING AND 20 FOLLOWING) AS close_20\n    FROM spy_daily\n),\njoined AS (\n    SELECT p.day AS day,\n           p.pcr AS pcr,\n           100 * (f.close_5 / f.close - 1) AS fwd_5d_pct,\n           100 * (f.close_20 / f.close - 1) AS fwd_20d_pct\n    FROM equity_pcr AS p\n    INNER JOIN forward AS f ON p.day = f.day\n    WHERE f.close_5 > 0 AND f.close_20 > 0\n),\ncuts AS (\n    SELECT quantilesDeterministic(0.2, 0.4, 0.6, 0.8)(pcr, cityHash64(day)) AS q\n    FROM joined\n)\nSELECT multiIf(pcr < q[1], 'lowest fifth',\n               pcr < q[2], 'second fifth',\n               pcr < q[3], 'middle fifth',\n               pcr < q[4], 'fourth fifth',\n               'highest fifth') AS pcr_band,\n       count() AS observations,\n       round(min(pcr), 2) AS band_floor_ratio,\n       round(quantileDeterministic(0.5)(fwd_5d_pct, cityHash64(day)), 2) AS fwd_5d_median_pct,\n       round(quantileDeterministic(0.5)(fwd_20d_pct, cityHash64(day)), 2) AS fwd_20d_median_pct,\n       round(quantileDeterministic(0.25)(fwd_20d_pct, cityHash64(day)), 2) AS fwd_20d_p25_pct,\n       round(quantileDeterministic(0.75)(fwd_20d_pct, cityHash64(day)), 2) AS fwd_20d_p75_pct\nFROM joined CROSS JOIN cuts\nGROUP BY pcr_band\nORDER BY band_floor_ratio ASC","computed_at":"2026-08-03T08:05:36.417999+00:00","elapsed":0.006936966}