add whale/public semi-win scoring, expand to last 50, and full history modal

- Whale/public picks now track 2nd pick and score SEMI (0.5 pts) like model
- Prediction table expanded from 20 to 50 rows
- "View All History" modal with pagination (50/page), fetches up to 500
- Accuracy rows use semi-win scoring for all three columns
This commit is contained in:
2026-02-26 09:51:08 +05:00
parent d1dc8f62fa
commit 5fd4894599
2 changed files with 183 additions and 43 deletions

View File

@@ -1260,7 +1260,8 @@ def _compute_whale_public_picks(client, game_nos):
for gno in game_nos:
users = game_data.get(gno, {})
if not users:
picks[gno] = {"whale_pick": None, "public_pick": None,
picks[gno] = {"whale_pick": None, "whale_second_pick": None,
"public_pick": None, "public_second_pick": None,
"whale_count": 0, "public_count": 0,
"bettor_counts": {"A": 0, "B": 0, "C": 0}}
continue
@@ -1280,7 +1281,13 @@ def _compute_whale_public_picks(client, game_nos):
for c in CHAIR_LABELS:
whale_money[c] += users[uid].get(c, 0)
whale_total = sum(whale_money.values())
whale_pick = max(CHAIR_LABELS, key=lambda c: whale_money[c]) if whale_total > 0 else None
if whale_total > 0:
whale_ranked = sorted(CHAIR_LABELS, key=lambda c: whale_money[c], reverse=True)
whale_pick = whale_ranked[0]
whale_second_pick = whale_ranked[1]
else:
whale_pick = None
whale_second_pick = None
# Sum public money per chair
pub_money = {"A": 0, "B": 0, "C": 0}
@@ -1289,7 +1296,13 @@ def _compute_whale_public_picks(client, game_nos):
pub_money[c] += users[uid].get(c, 0)
pub_total = sum(pub_money.values())
total_bettors = len(user_totals)
public_pick = max(CHAIR_LABELS, key=lambda c: pub_money[c]) if pub_total > 0 and total_bettors > 5 else None
if pub_total > 0 and total_bettors > 5:
pub_ranked = sorted(CHAIR_LABELS, key=lambda c: pub_money[c], reverse=True)
public_pick = pub_ranked[0]
public_second_pick = pub_ranked[1]
else:
public_pick = None
public_second_pick = None
# Count bettors per chair
bettor_counts = {"A": 0, "B": 0, "C": 0}
@@ -1300,7 +1313,9 @@ def _compute_whale_public_picks(client, game_nos):
picks[gno] = {
"whale_pick": whale_pick,
"whale_second_pick": whale_second_pick,
"public_pick": public_pick,
"public_second_pick": public_second_pick,
"whale_count": len(whale_uids),
"public_count": len(pub_uids),
"bettor_counts": bettor_counts,
@@ -1372,25 +1387,29 @@ def get_prediction_analysis() -> dict:
# Backtesting
backtest = _backtest_theories(winners)
# Last 20 prediction vs actual
last_20_raw = _last_n_predictions(winners, 20)
# Attach game_nos to last_20
for entry in last_20_raw:
# Last 50 prediction vs actual
last_50_raw = _last_n_predictions(winners, 50)
# Attach game_nos to last_50
for entry in last_50_raw:
idx = entry["index"]
entry["game_no"] = game_nos[idx] if idx < len(game_nos) else 0
# Merge whale/public picks into last_20
last_20_game_nos = [e["game_no"] for e in last_20_raw if e.get("game_no")]
wp_data = _compute_whale_public_picks(client, last_20_game_nos)
for entry in last_20_raw:
# Merge whale/public picks into last_50
last_50_game_nos = [e["game_no"] for e in last_50_raw if e.get("game_no")]
wp_data = _compute_whale_public_picks(client, last_50_game_nos)
for entry in last_50_raw:
gno = entry.get("game_no", 0)
wp = wp_data.get(gno, {})
entry["whale_pick"] = wp.get("whale_pick")
entry["whale_second_pick"] = wp.get("whale_second_pick")
entry["public_pick"] = wp.get("public_pick")
entry["public_second_pick"] = wp.get("public_second_pick")
entry["bettor_counts"] = wp.get("bettor_counts", {"A": 0, "B": 0, "C": 0})
actual = entry["actual"]
entry["whale_hit"] = (wp.get("whale_pick") == actual) if wp.get("whale_pick") else None
entry["whale_semi"] = (not entry["whale_hit"] and wp.get("whale_second_pick") == actual) if wp.get("whale_pick") else None
entry["public_hit"] = (wp.get("public_pick") == actual) if wp.get("public_pick") else None
entry["public_semi"] = (not entry["public_hit"] and wp.get("public_second_pick") == actual) if wp.get("public_pick") else None
# Card analysis
card_values = _card_value_distribution(cards_data)
@@ -1419,7 +1438,7 @@ def get_prediction_analysis() -> dict:
return {
"total_games": len(winners),
"last_winners": winners[-10:] if len(winners) >= 10 else winners,
"last_20_predictions": last_20_raw,
"last_20_predictions": last_50_raw,
"prediction": prediction,
"signals": signals,
"markov1": {"matrix": markov1, "counts": {k: dict(v) for k, v in markov1_counts.items()}},
@@ -1461,8 +1480,10 @@ def get_prediction_history(limit: int = 100) -> dict:
# Merge and compute accuracy
whale_hits = 0
whale_semi_hits = 0
whale_total = 0
public_hits = 0
public_semi_hits = 0
public_total = 0
model_full_hits = 0
model_semi_hits = 0
@@ -1471,11 +1492,15 @@ def get_prediction_history(limit: int = 100) -> dict:
gno = entry.get("game_no", 0)
wp = wp_data.get(gno, {})
entry["whale_pick"] = wp.get("whale_pick")
entry["whale_second_pick"] = wp.get("whale_second_pick")
entry["public_pick"] = wp.get("public_pick")
entry["public_second_pick"] = wp.get("public_second_pick")
entry["bettor_counts"] = wp.get("bettor_counts", {"A": 0, "B": 0, "C": 0})
actual = entry["actual"]
entry["whale_hit"] = (wp.get("whale_pick") == actual) if wp.get("whale_pick") else None
entry["whale_semi"] = (not entry["whale_hit"] and wp.get("whale_second_pick") == actual) if wp.get("whale_pick") else None
entry["public_hit"] = (wp.get("public_pick") == actual) if wp.get("public_pick") else None
entry["public_semi"] = (not entry["public_hit"] and wp.get("public_second_pick") == actual) if wp.get("public_pick") else None
# Remove internal index from output
del entry["index"]
@@ -1489,13 +1514,19 @@ def get_prediction_history(limit: int = 100) -> dict:
whale_total += 1
if entry["whale_hit"]:
whale_hits += 1
elif entry.get("whale_semi"):
whale_semi_hits += 1
if entry["public_hit"] is not None:
public_total += 1
if entry["public_hit"]:
public_hits += 1
elif entry.get("public_semi"):
public_semi_hits += 1
total_pred = len(predictions)
model_score = model_full_hits + model_semi_hits * 0.5
whale_score = whale_hits + whale_semi_hits * 0.5
public_score = public_hits + public_semi_hits * 0.5
return {
"total_games": len(winners),
@@ -1510,13 +1541,15 @@ def get_prediction_history(limit: int = 100) -> dict:
},
"whale": {
"hits": whale_hits,
"semi": whale_semi_hits,
"total": whale_total,
"pct": round(whale_hits / whale_total * 100, 1) if whale_total else 0,
"pct": round(whale_score / whale_total * 100, 1) if whale_total else 0,
},
"public": {
"hits": public_hits,
"semi": public_semi_hits,
"total": public_total,
"pct": round(public_hits / public_total * 100, 1) if public_total else 0,
"pct": round(public_score / public_total * 100, 1) if public_total else 0,
},
},
}