"""
Corrected re-run of research.ipynb (binned_df path). Faithfully reproduces the
notebook pipeline (cells 3-24: load live_data, highest-CLV pick, time-bin target
selection from first 20%, exclude USL/BSA, dedup one snapshot per game near
TARGET_MINS) then applies ONLY the EVALUATION fixes (core strategy untouched:
draws KEPT, original Kalshi-CLV floor >0.04, NO upper cap):

  1. NET returns: win = decimal_odds - 1 (not the gross decimal odds).
  2. Significance run on the NET returns (correct breakeven = 0).
  3. Kalshi Kelly uses pin_fair of the bet side as p_win (not the market ask).
"""
import os, math, sys
import pandas as pd, numpy as np
from scipy import stats
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
os.chdir(r'E:\soccer')

# ---- load (cell 3-4) ----
dfs = []
for f in os.listdir('live_data'):
    if f.endswith('.csv') and f != 'test.csv':
        dfs.append(pd.read_csv('live_data/' + f))
df = pd.concat(dfs)

# ---- highest-CLV pick + correctness (cells 5-6) ----
def highest_clv(h, d, a):
    cd = {'H': h, 'D': d, 'A': a}
    if pd.isna(cd['H']):
        return None, np.nan
    k = max(cd, key=cd.get)
    return k, cd[k]

for bk in ('b365', 'kalshi'):
    df[f'{bk}_highest_clv'] = df.apply(
        lambda r: highest_clv(r[f'clv_{bk}_home'], r[f'clv_{bk}_draw'], r[f'clv_{bk}_away'])[0], axis=1)
    df[f'{bk}_highest_clv_val'] = df.apply(
        lambda r: highest_clv(r[f'clv_{bk}_home'], r[f'clv_{bk}_draw'], r[f'clv_{bk}_away'])[1], axis=1)
df['correct_b365'] = (df['ftr'] == df['b365_highest_clv']).astype(int)
df['correct_kalshi'] = (df['ftr'] == df['kalshi_highest_clv']).astype(int)

# ---- time-bin target selection from first 20% (cells 18-24) ----
dd = df.dropna(subset=['b365_highest_clv', 'kalshi_highest_clv'])
dd = dd[dd['status'] == 'PRE']
num_bins = math.ceil(abs(int(dd['elapsed'].min())) / 240)
bins = np.histogram(dd['elapsed'], bins=num_bins)[1]
def assign_bin(x):
    for i in range(len(bins) - 1):
        if bins[i] <= x <= bins[i + 1]:
            return i
dd['bin'] = dd['elapsed'].apply(assign_bin)
first_20 = round(dd.shape[0] * 0.2)
df_first = dd.head(first_20)
binned = (df_first[['correct_kalshi', 'bin']].groupby('bin')
          .agg({'correct_kalshi': ['mean', 'count']}).reset_index())
binned['bin_mid'] = binned['bin'].apply(lambda x: round((bins[x] + bins[x + 1]) / 2))
best = binned.sort_values(('correct_kalshi', 'mean'), ascending=False).iloc[0]
TARGET_MINS = int(best['bin_mid'].iloc[0]) if hasattr(best['bin_mid'], 'iloc') else int(best['bin_mid'])

df_rem = dd.iloc[first_20:].copy()
df_rem = df_rem[(df_rem['league'] != 'USL') & (df_rem['league'] != 'BSA')]
df_rem['dist'] = (df_rem['elapsed'] - TARGET_MINS).abs()
df_rem = df_rem.sort_values('dist').drop_duplicates(['home', 'away'], keep='first')
df_rem['timestamp'] = df_rem['timestamp'].apply(lambda x: pd.to_datetime(x).timestamp())
g = df_rem.sort_values('timestamp').reset_index(drop=True)
g = g.dropna(subset=['result_home', 'result_away',
                     'clv_kalshi_home', 'clv_kalshi_draw', 'clv_kalshi_away'])
print(f"TARGET_MINS (best bin from first 20%): {TARGET_MINS}")
print(f"games after dedup/exclude USL+BSA: {len(g)}\n")

# ---- Kelly engine (cells 12-13) ----
side = {'H': '_home', 'D': '_draw', 'A': '_away'}
def kelly_size(p, odds, br, mf=0.025):
    b = odds - 1
    f = (p * odds - (1 - p)) / b
    return max(0.0, min(f, mf)) * br

def compound(odds, probs, outcomes, br0=1000.0, mf=0.025):
    br = br0; eq = []
    for o, p, w in zip(odds, probs, outcomes):
        bet = kelly_size(p, o, br, mf)
        br += bet * (o - 1) if w else -bet
        eq.append(br)
    return eq

FLOOR = 0.04   # original notebook floor; draws KEPT, no upper cap (core strategy unchanged)
gate = g[g['kalshi_highest_clv_val'] > FLOOR]

def evaluate(name, pick_col, clv_val_col, correct_col, odds_fn, pinfair_fn):
    """Strategy on its own pick side; original Kalshi-CLV gate (>0.04), draws kept."""
    s = gate.copy()
    odds = s.apply(odds_fn, axis=1)
    pin  = s.apply(pinfair_fn, axis=1)
    won  = s[correct_col].values
    net  = np.where(won == 1, odds - 1, -1.0)                  # FIX: NET returns
    eq   = compound(odds.values, pin.values, won)             # FIX: pin_fair p_win
    # FIX: significance on NET returns
    z = net.mean() / (net.std(ddof=1) / np.sqrt(len(net)))
    p = 1 - stats.norm.cdf(z)
    wr = won.mean()
    return dict(name=name, n=len(s), wr=wr, net_sum=net.sum(),
                roi=100 * net.mean(), z=z, p=p, final=eq[-1], eq=eq)

results = [
    evaluate('B365',
             'b365_highest_clv', 'b365_highest_clv_val', 'correct_b365',
             lambda r: r['b365' + side[r['b365_highest_clv']]],
             lambda r: r['pin_fair' + side[r['b365_highest_clv']]]),
    evaluate('Kalshi',
             'kalshi_highest_clv', 'kalshi_highest_clv_val', 'correct_kalshi',
             lambda r: 1.0 / r['kalshi' + side[r['kalshi_highest_clv']] + '_ask'],
             lambda r: r['pin_fair' + side[r['kalshi_highest_clv']]]),
    evaluate('Kalshi w/ B365',
             'b365_highest_clv', 'b365_highest_clv_val', 'correct_b365',
             lambda r: 1.0 / r['kalshi' + side[r['b365_highest_clv']] + '_ask'],
             lambda r: r['pin_fair' + side[r['b365_highest_clv']]]),
]

print("=== CORRECTED (net returns, pin_fair Kelly) | core unchanged: draws KEPT, floor>0.04, no cap ===")
print(f"{'strategy':>16}{'N':>5}{'win%':>7}{'netSum':>9}{'ROI%':>8}{'z':>7}{'p':>8}{'Kelly$':>10}")
print('-' * 71)
for r in results:
    sig = '*' if r['p'] < 0.05 else ' '
    print(f"{r['name']:>16}{r['n']:>5}{100*r['wr']:>6.1f}%{r['net_sum']:>+9.1f}"
          f"{r['roi']:>+8.1f}{r['z']:>+7.2f}{r['p']:>8.4f}{sig}{r['final']:>9.0f}")
print("\n(Kelly$ = final compounded bankroll from $1000, real Kelly w/ pin_fair, 2.5% cap)")

# ---- equity chart ----
colors = {'B365': '#2077b4', 'Kalshi': '#d62728', 'Kalshi w/ B365': '#2ca02c'}
fig, ax = plt.subplots(figsize=(11, 5.5))
for r in results:
    ax.plot(range(len(r['eq'])), r['eq'], color=colors[r['name']], lw=2,
            label=f"{r['name']} (${r['final']:,.0f}, n={r['n']})")
ax.axhline(1000, color='gray', ls='--', lw=1, alpha=0.6)
ax.set_xlabel('Bets'); ax.set_ylabel('Bankroll ($)')
ax.set_title('Corrected compounded returns (net, pin_fair Kelly) - draws kept, no cap')
ax.legend(loc='best'); ax.grid(True, alpha=0.3); fig.tight_layout()
fig.savefig('test_fixed.png', dpi=120); plt.close(fig)
print("\nchart: test_fixed.png")
