Syntrex commited on
Commit
67f928e
·
verified ·
1 Parent(s): 424a63c

Update analytics/recommendation_engine.py

Browse files
Files changed (1) hide show
  1. analytics/recommendation_engine.py +33 -4
analytics/recommendation_engine.py CHANGED
@@ -29,7 +29,7 @@ def build_upcoming_hitter_recommendations(
29
  ) -> list[dict]:
30
  """
31
  Decision-layer wrapper.
32
- Uses simulated fair rows, then adds:
33
  1) opportunity adjustment
34
  2) confidence
35
  3) recommendation tier
@@ -45,7 +45,7 @@ def build_upcoming_hitter_recommendations(
45
  recommendations: list[dict] = []
46
 
47
  for row in rows:
48
- slot = row.get("slot", "current")
49
  lineup_distance = _lineup_distance_from_slot(slot)
50
 
51
  opportunity = estimate_plate_appearance_probability(
@@ -55,7 +55,7 @@ def build_upcoming_hitter_recommendations(
55
 
56
  expected_pa = float(opportunity.get("expected_pa", 1.0) or 1.0)
57
 
58
- # Apply opportunity adjustment to downstream probabilities
59
  for prob_col in ["hit_prob", "hr_prob", "tb2p_prob"]:
60
  if prob_col in row and row.get(prob_col) is not None:
61
  try:
@@ -64,7 +64,36 @@ def build_upcoming_hitter_recommendations(
64
  except Exception:
65
  pass
66
 
67
- # Carry opportunity diagnostics forward for debugging/auditing
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  row["lineup_distance"] = lineup_distance
69
  row["pa_prob_this_inning"] = opportunity.get("pa_prob_this_inning")
70
  row["pa_prob_next_two_innings"] = opportunity.get("pa_prob_next_two_innings")
 
29
  ) -> list[dict]:
30
  """
31
  Decision-layer wrapper.
32
+ Uses simulated fair rows, then applies:
33
  1) opportunity adjustment
34
  2) confidence
35
  3) recommendation tier
 
45
  recommendations: list[dict] = []
46
 
47
  for row in rows:
48
+ slot = row.get("slot", "Current")
49
  lineup_distance = _lineup_distance_from_slot(slot)
50
 
51
  opportunity = estimate_plate_appearance_probability(
 
55
 
56
  expected_pa = float(opportunity.get("expected_pa", 1.0) or 1.0)
57
 
58
+ # Apply opportunity adjustment to the simulated probabilities
59
  for prob_col in ["hit_prob", "hr_prob", "tb2p_prob"]:
60
  if prob_col in row and row.get(prob_col) is not None:
61
  try:
 
64
  except Exception:
65
  pass
66
 
67
+ # Recalculate fair odds and edges after probability adjustment
68
+ if row.get("hit_prob") is not None:
69
+ row["fair_hit_odds"] = probability_to_american(row["hit_prob"])
70
+ if row.get("hr_prob") is not None:
71
+ row["fair_hr_odds"] = probability_to_american(row["hr_prob"])
72
+ if row.get("tb2p_prob") is not None:
73
+ row["fair_tb2p_odds"] = probability_to_american(row["tb2p_prob"])
74
+
75
+ try:
76
+ book_hit_odds = float(row.get("book_hit_odds"))
77
+ row["hit_edge"] = compute_edge(row["hit_prob"], 100 / (book_hit_odds + 100))
78
+ row["hit_bet_ev"] = compute_bet_ev(row["hit_prob"], int(book_hit_odds))
79
+ except Exception:
80
+ pass
81
+
82
+ try:
83
+ book_hr_odds = float(row.get("book_hr_odds"))
84
+ row["hr_edge"] = compute_edge(row["hr_prob"], 100 / (book_hr_odds + 100))
85
+ row["hr_bet_ev"] = compute_bet_ev(row["hr_prob"], int(book_hr_odds))
86
+ except Exception:
87
+ pass
88
+
89
+ try:
90
+ book_tb2p_odds = float(row.get("book_tb2p_odds"))
91
+ row["tb2p_edge"] = compute_edge(row["tb2p_prob"], 100 / (book_tb2p_odds + 100))
92
+ row["tb2p_bet_ev"] = compute_bet_ev(row["tb2p_prob"], int(book_tb2p_odds))
93
+ except Exception:
94
+ pass
95
+
96
+ # Carry diagnostics forward
97
  row["lineup_distance"] = lineup_distance
98
  row["pa_prob_this_inning"] = opportunity.get("pa_prob_this_inning")
99
  row["pa_prob_next_two_innings"] = opportunity.get("pa_prob_next_two_innings")