{"slug":"kelly-criterion-position-sizing","qid":"edge_inputs","label":"Kelly inputs from daily closes, 2016 through 2025: win rate, average gain, average loss, and the fraction the formula returns","post_title":"Kelly Criterion Position Sizing, Measured","post_url":"/blog/kelly-criterion-position-sizing#q-edge_inputs","columns":["ticker","win_rate_pct","avg_gain_pct","avg_loss_pct","full_kelly_x"],"rows":[{"ticker":"SPY","win_rate_pct":55.3,"avg_gain_pct":0.71,"avg_loss_pct":0.76,"full_kelly_x":10.1},{"ticker":"MSFT","win_rate_pct":54.1,"avg_gain_pct":1.17,"avg_loss_pct":1.16,"full_kelly_x":7.4},{"ticker":"JNJ","win_rate_pct":51.8,"avg_gain_pct":0.79,"avg_loss_pct":0.77,"full_kelly_x":5.8},{"ticker":"KO","win_rate_pct":53,"avg_gain_pct":0.76,"avg_loss_pct":0.8,"full_kelly_x":4.4},{"ticker":"NVDA","win_rate_pct":54.6,"avg_gain_pct":2.28,"avg_loss_pct":2.3,"full_kelly_x":3.8},{"ticker":"TSLA","win_rate_pct":52,"avg_gain_pct":2.71,"avg_loss_pct":2.64,"full_kelly_x":2}],"shape":"table","sql":"WITH daily AS (\n    SELECT ticker,\n           toDate(toTimeZone(window_start, 'America/New_York')) AS dt,\n           argMax(toFloat64(close), window_start) AS c\n    FROM global_markets.delayed_stocks_minute_aggs\n    WHERE ticker IN ('SPY', 'KO', 'JNJ', 'MSFT', 'NVDA', 'TSLA')\n      AND window_start >= '2016-01-01 00:00:00'\n      AND window_start <  '2026-01-01 00:00:00'\n      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60\n           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959\n    GROUP BY ticker, dt\n),\nsteps AS (\n    SELECT ticker, dt, c,\n           lagInFrame(c) OVER (PARTITION BY ticker ORDER BY dt\n                               ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev\n    FROM daily\n),\nrets AS (\n    SELECT ticker, c / prev - 1 AS ret\n    FROM steps\n    WHERE prev > 0 AND c != prev\n)\nSELECT ticker,\n       round(100 * countIf(ret > 0) / count(), 1) AS win_rate_pct,\n       round(100 * avgIf(ret, ret > 0), 2) AS avg_gain_pct,\n       round(100 * abs(avgIf(ret, ret < 0)), 2) AS avg_loss_pct,\n       round(countIf(ret > 0) / count() / abs(avgIf(ret, ret < 0))\n             - countIf(ret < 0) / count() / avgIf(ret, ret > 0), 1) AS full_kelly_x\nFROM rets\nGROUP BY ticker\nHAVING countIf(ret > 0) > 0 AND countIf(ret < 0) > 0\nORDER BY full_kelly_x DESC","computed_at":"2026-07-31T03:06:55.347849+00:00","elapsed":0.006157059}