{"slug":"covered-call-etfs-explained","qid":"regime_returns","label":"Total return by calendar year: a Nasdaq index fund vs a Nasdaq covered call fund","post_title":"Covered Call ETFs: the Real Tradeoff","post_url":"/blog/covered-call-etfs-explained#q-regime_returns","columns":["regime","index_fund_total_pct","covered_call_total_pct"],"rows":[{"regime":"2022 decline","index_fund_total_pct":-32.8,"covered_call_total_pct":-18.7},{"regime":"2023 rebound","index_fund_total_pct":53.6,"covered_call_total_pct":21.2},{"regime":"2024 advance","index_fund_total_pct":26.6,"covered_call_total_pct":18.5},{"regime":"2025 advance","index_fund_total_pct":20,"covered_call_total_pct":7.9}],"shape":"ranking","sql":"WITH ranges AS (\n    SELECT arrayJoin([('2022 decline', toDate('2022-01-03'), toDate('2022-12-30')),\n                      ('2023 rebound', toDate('2023-01-03'), toDate('2023-12-29')),\n                      ('2024 advance', toDate('2024-01-02'), toDate('2024-12-31')),\n                      ('2025 advance', toDate('2025-01-02'), toDate('2025-12-31'))]) AS r\n),\npx AS (\n    SELECT r.1 AS regime,\n           m.ticker AS ticker,\n           argMin(m.close, m.window_start) AS p0,\n           argMax(m.close, m.window_start) AS p1\n    FROM ranges, global_markets.delayed_stocks_minute_aggs AS m\n    WHERE m.ticker IN ('QYLD', 'QQQ')\n      AND toDate(toTimeZone(m.window_start, 'America/New_York')) BETWEEN r.2 AND r.3\n      AND (toHour(toTimeZone(m.window_start, 'America/New_York')) * 60\n           + toMinute(toTimeZone(m.window_start, 'America/New_York'))) BETWEEN 570 AND 959\n    GROUP BY regime, ticker\n),\ndv AS (\n    SELECT r.1 AS regime,\n           d.ticker AS ticker,\n           sum(d.cash_amount) AS dist\n    FROM ranges, global_markets.stocks_dividends AS d\n    WHERE d.ticker IN ('QYLD', 'QQQ')\n      AND d.cash_amount > 0\n      AND d.ex_dividend_date BETWEEN r.2 AND r.3\n    GROUP BY regime, ticker\n)\nSELECT px.regime AS regime,\n       round(maxIf((px.p1 - px.p0 + dv.dist) / px.p0 * 100, px.ticker = 'QQQ'), 1) AS index_fund_total_pct,\n       round(maxIf((px.p1 - px.p0 + dv.dist) / px.p0 * 100, px.ticker = 'QYLD'), 1) AS covered_call_total_pct\nFROM px\nINNER JOIN dv ON px.regime = dv.regime AND px.ticker = dv.ticker\nGROUP BY regime\nORDER BY regime","computed_at":"2026-08-01T02:22:25.500442+00:00","elapsed":11.023470699}