This repo contains a script-based analysis that uses live web sources to:
- fetch current Nasdaq-100 / NDX constituents
- fetch single-stock option-income ETF lineups from issuer pages
- match each NDX stock to any covered-call ETF tied to that stock
- pull matched ETF price history and plot performance comparisons
- assemble a Markdown report with tables and charts
As of the latest generated report (2026-05-02 17:09 UTC), 13 of 101 Nasdaq-100 constituents had a matched stock-specific covered-call ETF from the parsed YieldMax and Kurv lineups. Over the trailing 1-year window, 5 of the 19 matched ETFs outperformed their reference stock, 14 underperformed, and the median ETF-versus-stock spread was -6.6 percentage points.
Read the full HTML report here: reports/ndx_covered_call_etfs.html.
Returns use dividend- and split-adjusted close prices via yfinance, matching the report methodology.
Run it with uv:
uv run python scripts/run_report.pyFirst generate the latest CSV outputs, charts, and Markdown report:
uv run python scripts/run_report.pyThen render the Markdown report to HTML with Pandoc:
pandoc reports/ndx_covered_call_etfs.md --standalone --css=report.css --output reports/ndx_covered_call_etfs.htmlThe report is written to:
reports/ndx_covered_call_etfs.md
reports/ndx_covered_call_etfs.html
The scripts treat "covered call ETF" as a single-stock option-income or synthetic covered-call ETF with a named reference stock. Broad index income funds such as JEPQ, QQQI, or QYLD are intentionally not counted as stock-specific matches.
Useful entry points:
scripts/collect_data.py: fetches live sources, computes matches/performance, and writes CSVsscripts/make_report.py: reads the generated CSVs and assembles the Markdown report/chartsscripts/run_report.py: runs the full pipeline