{"slug":"the-7-5-3-1-rule-mutual-funds","qid":"return_buckets","label":"return_buckets","post_title":"the-7-5-3-1-rule-mutual-funds","post_url":"/blog/the-7-5-3-1-rule-mutual-funds#q-return_buckets","columns":["bucket","window_count","share_pct"],"rows":[{"bucket":"Below 0%","window_count":0,"share_pct":0},{"bucket":"0% to 25%","window_count":17,"share_pct":8.8},{"bucket":"25% to 50%","window_count":34,"share_pct":17.6},{"bucket":"50% to 100%","window_count":13,"share_pct":6.7},{"bucket":"Above 100%","window_count":129,"share_pct":66.8}],"shape":"ranking","sql":"WITH\n    monthly AS\n    (\n        SELECT\n            toStartOfMonth(date)            AS month_start,\n            toDate(min(date))               AS first_session,\n            argMin(toFloat64(close), date)  AS first_close\n        FROM global_markets.stocks_daily_aggs\n        WHERE ticker = 'SPY'\n        GROUP BY month_start\n    ),\n    divs AS\n    (\n        SELECT\n            toStartOfMonth(ex_dividend_date) AS month_start,\n            sum(cash)                        AS month_cash\n        FROM\n        (\n            SELECT\n                ex_dividend_date,\n                max(toFloat64(cash_amount)) AS cash\n            FROM global_markets.stocks_dividends\n            WHERE ticker = 'SPY'\n            GROUP BY ex_dividend_date\n        )\n        GROUP BY month_start\n    ),\n    grid AS\n    (\n        SELECT\n            m.month_start                AS month_start,\n            m.first_session              AS first_session,\n            m.first_close                AS first_close,\n            addMonths(m.month_start, 84) AS end_month,\n            sum(ifNull(d.month_cash, 0)) OVER (ORDER BY m.month_start ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS cash_before\n        FROM monthly AS m\n        LEFT JOIN divs AS d ON d.month_start = m.month_start\n    ),\n    windows AS\n    (\n        SELECT\n            ((e.first_close + e.cash_before - s.cash_before) / s.first_close - 1) * 100 AS ret\n        FROM grid AS s\n        INNER JOIN grid AS e ON e.month_start = s.end_month\n    ),\n    stats AS\n    (\n        SELECT\n            count()                           AS total,\n            countIf(ret < 0)                  AS below_zero,\n            countIf(ret >= 0  AND ret < 25)   AS to_25,\n            countIf(ret >= 25 AND ret < 50)   AS to_50,\n            countIf(ret >= 50 AND ret < 100)  AS to_100,\n            countIf(ret >= 100)               AS above_100\n        FROM windows\n    )\nSELECT\n    tupleElement(band, 1) AS bucket,\n    tupleElement(band, 2) AS window_count,\n    tupleElement(band, 3) AS share_pct\nFROM stats\nARRAY JOIN\n    [\n        ('Below 0%',    below_zero, round(below_zero / total * 100, 1)),\n        ('0% to 25%',   to_25,      round(to_25 / total * 100, 1)),\n        ('25% to 50%',  to_50,      round(to_50 / total * 100, 1)),\n        ('50% to 100%', to_100,     round(to_100 / total * 100, 1)),\n        ('Above 100%',  above_100,  round(above_100 / total * 100, 1))\n    ] AS band","computed_at":"2026-09-17T15:41:34.027476+00:00","elapsed":0.006572499}