""" Audit Form 4 coverage for all universe_ticker_registry tickers. Prints per-ticker earliest filing_date and P-code buy count. Flags tickers with no data or earliest date after the baseline. Usage (inside container): python scripts/audit_form4_coverage.py [--baseline YYYY-MM-DD] """ import asyncio import os import sys from datetime import date sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) async def audit(baseline: date) -> None: from app.core.database import AsyncSessionLocal from sqlalchemy import text async with AsyncSessionLocal() as db: rows = await db.execute(text(""" WITH u AS (SELECT ticker FROM universe_ticker_registry ORDER BY ticker), e AS ( SELECT ticker, MIN(filing_date)::date AS earliest, COUNT(*) AS total_rows, SUM(CASE WHEN transaction_code = 'P' AND shares > 0 THEN 1 ELSE 0 END) AS p_buys FROM insider_transactions GROUP BY ticker ) SELECT u.ticker, e.earliest, e.total_rows, e.p_buys FROM u LEFT JOIN e USING (ticker) ORDER BY e.earliest NULLS FIRST, u.ticker """)) results = rows.fetchall() no_data, late, ok = [], [], [] for ticker, earliest, total_rows, p_buys in results: if earliest is None: no_data.append(ticker) elif earliest > baseline: late.append((ticker, earliest, total_rows, p_buys)) else: ok.append((ticker, earliest, total_rows, p_buys)) print(f"\n=== Form 4 Coverage Audit (baseline: {baseline}) ===") print(f"Universe: {len(results)} tickers | OK: {len(ok)} | Late: {len(late)} | No data: {len(no_data)}\n") if no_data: print(f"NO DATA ({len(no_data)}): {', '.join(no_data)}\n") if late: print(f"LATE (earliest > {baseline}):") for ticker, earliest, total_rows, p_buys in late: print(f" {ticker:<8} earliest={earliest} rows={total_rows or 0} P-buys={p_buys or 0}") print() print(f"OK: {len(ok)} tickers meet {baseline} baseline") if __name__ == "__main__": import argparse parser = argparse.ArgumentParser() parser.add_argument("--baseline", default="2024-04-01") args = parser.parse_args() baseline = date.fromisoformat(args.baseline) asyncio.run(audit(baseline))