---
name: research.ipynb "highest-CLV pick" exploration — debugged, doesn't beat live Kalshi strategy
description: A separate research notebook tried picking the H/D/A side with the highest CLV (B365, Kalshi, cross-book). After fixing 4 bugs the corrected results don't beat the running Kalshi strategy. User shelved it 2026-06-02.
type: project
---

`E:\soccer\research.ipynb` is a research thread (distinct from the live pipeline and from project_strategy_C_research) exploring three "bet the side with the highest CLV" strategies: B365 (B365 picks + B365 odds), Kalshi (Kalshi picks + ask), and cross-book "Kalshi w/ B365" (B365 picks, Kalshi executes). It uses a time-bin "TARGET_MINS" snapshot-selection (pick the elapsed bin with best win rate on the first 20%, then dedupe one snapshot per game near that minute on the remaining 80%).

**Outcome (2026-06-02): user shelved it — "this wasn't very useful, I'll stick to our strategy."** After fixing the bugs, nothing beats the live Kalshi leg.

**Four bugs that were inflating it (all fixed in-session):**
1. Gross vs net returns: win was scored as `decimal_odds`, should be `decimal_odds - 1` (and the binned path had a stray trailing `-1` that double-subtracted). Net breakeven = 0.
2. Fake Kelly: the two Kalshi `cumulative_kelly` calls passed the ASK price (`kalshi_bet`) as the win-probability arg instead of the bet side's `pin_fair_*`. With the corrected formula `f*=(p-ask)/(1-ask)`, p=ask -> f*=0 -> flat equity line (the "why is Kalshi flat" symptom). Fix: add `pin_fair_kalshi` col, pass pin_fair.
3. Kelly formula numerator: cell had `(p*odds-(1-p))/b`; correct binary Kelly is `(p*odds-1)/b = (p-ask)/(1-ask)`. Wrong one over-stakes longshots.
4. Sign-flip in snapshot selection: cell 23 builds `bin_mid` as `-1*round(...)` so TARGET_MINS is a POSITIVE magnitude while `elapsed` is NEGATIVE (min before KO). The target in elapsed units is `-TARGET_MINS`. A filter like `elapsed <= TARGET_MINS` is a silent no-op (neg <= +1239 always true) and the dedup then picks the snapshot nearest KICKOFF, not nearest target. Correct distance = `(elapsed + TARGET_MINS).abs()` (symmetric) or one-sided causal `elapsed >= -TARGET_MINS` then `elapsed + TARGET_MINS`.

**How to apply:** Don't reopen this notebook expecting an edge over the live Kalshi strategy — it was debugged and shelved. If a future variant is tried, watch for these 4 traps (net returns, pin_fair-as-p_win not the ask, `(p*odds-1)/b` Kelly, and the TARGET_MINS sign convention). The ROI-gate (win10/warm8 skip) was also wired into this notebook and remains a wash on terminal wealth — see project_league_filter_study.
