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:
61
app/db.py
61
app/db.py
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user