@@ -19,11 +19,26 @@ class BettingBrain:
|
||||
SOFT_DIVERGENCE = 0.14
|
||||
EXTREME_MODEL_PROB = 0.85
|
||||
EXTREME_GAP = 0.30
|
||||
# Vetoes that is_value_sniper bypasses (does NOT bypass odds_below_minimum)
|
||||
SNIPER_BYPASSABLE_VETOES = {"calibrated_confidence_too_low", "play_score_too_low"}
|
||||
# Trap market: market implied probability massively exceeds historical band hit rate
|
||||
SNIPER_BYPASSABLE_VETOES = {"play_score_too_low"}
|
||||
TRAP_MARKET_GAP = 0.10
|
||||
|
||||
MARKET_MIN_CONFIDENCE = {
|
||||
"MS": 45.0,
|
||||
"DC": 55.0,
|
||||
"OU25": 48.0,
|
||||
"OU15": 55.0,
|
||||
"OU35": 42.0,
|
||||
"BTTS": 48.0,
|
||||
"HT": 55.0,
|
||||
"HTFT": 65.0,
|
||||
"OE": 55.0,
|
||||
"CARDS": 50.0,
|
||||
"HT_OU05": 55.0,
|
||||
"HT_OU15": 50.0,
|
||||
}
|
||||
|
||||
SNIPER_BLOCKED_MARKETS = {"HT", "HTFT", "OE", "CARDS", "HT_OU05", "HT_OU15"}
|
||||
|
||||
MARKET_PRIORS = {
|
||||
"DC": 4.0,
|
||||
"OU15": 3.0,
|
||||
@@ -31,10 +46,10 @@ class BettingBrain:
|
||||
"BTTS": 0.0,
|
||||
"MS": -2.0,
|
||||
"OU35": -2.0,
|
||||
"HT": -6.0,
|
||||
"HTFT": -12.0,
|
||||
"CARDS": -5.0,
|
||||
"OE": -8.0,
|
||||
"HT": -10.0,
|
||||
"HTFT": -18.0,
|
||||
"CARDS": -8.0,
|
||||
"OE": -12.0,
|
||||
}
|
||||
|
||||
def judge(self, package: Dict[str, Any]) -> Dict[str, Any]:
|
||||
@@ -182,8 +197,10 @@ class BettingBrain:
|
||||
issues.append("base_model_not_playable")
|
||||
|
||||
is_value_sniper = bool(row.get("is_value_sniper"))
|
||||
if market in self.SNIPER_BLOCKED_MARKETS:
|
||||
is_value_sniper = False
|
||||
if is_value_sniper:
|
||||
score += 35.0
|
||||
score += 20.0
|
||||
positives.append("value_sniper_override")
|
||||
|
||||
score += max(0.0, min(20.0, calibrated_conf * 0.22))
|
||||
@@ -197,9 +214,31 @@ class BettingBrain:
|
||||
risk = str((package.get("risk") or {}).get("level") or "MEDIUM").upper()
|
||||
score += {"LOW": 5.0, "MEDIUM": 0.0, "HIGH": -12.0, "EXTREME": -22.0}.get(risk, -4.0)
|
||||
|
||||
# League reliability penalty: weak leagues produce unreliable raw probabilities.
|
||||
# odds_reliability is pre-computed per-league from historical Brier score analysis.
|
||||
odds_rel = self._safe_float(row.get("odds_reliability"), 0.35) or 0.35
|
||||
if odds_rel < 0.30:
|
||||
score -= 22.0
|
||||
issues.append("very_low_reliability_league")
|
||||
if market in {"MS", "DC", "OU25", "BTTS"} and not is_value_sniper:
|
||||
vetoes.append("low_reliability_league_hard_block")
|
||||
elif odds_rel < 0.45:
|
||||
score -= 12.0
|
||||
issues.append("low_reliability_league")
|
||||
elif odds_rel < 0.55:
|
||||
score -= 5.0
|
||||
|
||||
# Inferred features penalty: when ELO/form/H2H come from live enrichment
|
||||
# (not pre-computed table), statistical quality is unknown — penalise hard.
|
||||
dq_flags = list(data_quality.get("flags") or [])
|
||||
if "ai_features_inferred_from_history" in dq_flags:
|
||||
score -= 18.0
|
||||
issues.append("inferred_statistical_features")
|
||||
|
||||
if odds < self.MIN_ODDS:
|
||||
vetoes.append("odds_below_minimum")
|
||||
if calibrated_conf < 38.0 and not is_value_sniper:
|
||||
min_conf = self.MARKET_MIN_CONFIDENCE.get(market, 45.0)
|
||||
if calibrated_conf < min_conf:
|
||||
vetoes.append("calibrated_confidence_too_low")
|
||||
if play_score < 50.0 and not is_value_sniper:
|
||||
vetoes.append("play_score_too_low")
|
||||
@@ -270,7 +309,7 @@ class BettingBrain:
|
||||
score -= 24.0
|
||||
vetoes.append("extreme_probability_without_evidence")
|
||||
|
||||
if market in {"HT", "HTFT", "OE"} and score < 86.0 and not is_value_sniper:
|
||||
if market in {"HT", "HTFT", "OE"} and score < 86.0:
|
||||
vetoes.append("volatile_market_requires_exceptional_evidence")
|
||||
|
||||
# Sniper override: bypass eligible vetoes when value sniper triggered
|
||||
|
||||
Reference in New Issue
Block a user