{"slug":"pairs-trading-and-cointegration","qid":"reversion_by_bucket","label":"Where the KO/PEP spread sat twenty sessions later, by starting z score (2019-2025)","post_title":"Pairs Trading and Cointegration Explained","post_url":"/blog/pairs-trading-and-cointegration#q-reversion_by_bucket","columns":["z_bucket","avg_z_start","avg_z_20d_later","episode_count"],"rows":[{"z_bucket":"z below -2","avg_z_start":-2.42,"avg_z_20d_later":-0.84,"episode_count":138},{"z_bucket":"z -2 to -1","avg_z_start":-1.4,"avg_z_20d_later":-0.59,"episode_count":406},{"z_bucket":"z -1 to 0","avg_z_start":-0.52,"avg_z_20d_later":-0.21,"episode_count":354},{"z_bucket":"z 0 to 1","avg_z_start":0.52,"avg_z_20d_later":0.04,"episode_count":371},{"z_bucket":"z 1 to 2","avg_z_start":1.41,"avg_z_20d_later":0.66,"episode_count":331},{"z_bucket":"z above 2","avg_z_start":2.64,"avg_z_20d_later":0.92,"episode_count":129}],"shape":"ranking","sql":"WITH\n    daily AS (\n        SELECT\n            date,\n            anyIf(toFloat64(close), ticker = 'PEP') AS pep,\n            anyIf(toFloat64(close), ticker = 'KO')  AS ko\n        FROM global_markets.stocks_daily_aggs\n        WHERE ticker IN ('KO', 'PEP')\n          AND date BETWEEN '2018-01-01' AND '2025-12-31'\n        GROUP BY date\n        HAVING pep > 0 AND ko > 0\n    ),\n    spread AS (\n        SELECT\n            date,\n            log(pep / ko) AS log_ratio\n        FROM daily\n    ),\n    scored AS (\n        SELECT\n            date,\n            (log_ratio - avg(log_ratio) OVER (\n                 ORDER BY date ROWS BETWEEN 62 PRECEDING AND CURRENT ROW))\n            / stddevSampStable(log_ratio) OVER (\n                 ORDER BY date ROWS BETWEEN 62 PRECEDING AND CURRENT ROW) AS z\n        FROM spread\n    ),\n    horizon AS (\n        SELECT\n            date,\n            z,\n            leadInFrame(z, 20) OVER (\n                ORDER BY date ROWS BETWEEN CURRENT ROW AND 20 FOLLOWING\n            ) AS z_fwd\n        FROM scored\n        WHERE isFinite(z)\n    )\nSELECT\n    multiIf(z < -2, 'z below -2',\n            z < -1, 'z -2 to -1',\n            z <  0, 'z -1 to 0',\n            z <  1, 'z 0 to 1',\n            z <  2, 'z 1 to 2',\n                    'z above 2')  AS z_bucket,\n    round(avg(z), 2)              AS avg_z_start,\n    round(avg(z_fwd), 2)          AS avg_z_20d_later,\n    count()                       AS episode_count\nFROM horizon\nWHERE date >= '2019-01-01'\n  AND date <= '2025-11-15'\n  AND isFinite(z_fwd)\nGROUP BY z_bucket\nORDER BY avg_z_start","computed_at":"2026-08-13T16:30:37.673126+00:00","elapsed":0.004316554}