Competition history
Resolves the fixture’s exact tournament and season, then filters performance rows to finished matches before kickoff for the correct team and competition.
today_events.py actually do?It finds upcoming fixtures, gathers auditable player and Bet365 inputs, estimates each player’s conditional scoring probability, adjusts that estimate for the match environment, and prints only candidates that pass a conservative value policy.
The script is a candidate finder, not a betting executor. It never places a bet and it does not claim that a displayed EV is calibrated profit.
The positional argument is a day offset: 0 means today, 1 tomorrow, through 6. The script calls /event/by-date, then keeps events with odds available.
Resolves the fixture’s exact tournament and season, then filters performance rows to finished matches before kickoff for the correct team and competition.
Matches players by ID first, uses unique names only as a fallback, and accepts valid Bet365 anytime-scorer prices only.
Rejects missing, stale, future, malformed, or timezone-less quote timestamps. Unknown settlement rules remain warnings.
Fetches a starting XI only when the provider explicitly says the lineup is confirmed. Otherwise historical participation is used and labelled uncertain/likely.
Stores compressed raw responses, request attempts, hashes, warnings, candidate rows, policy, and summary metadata under a unique run directory.
Requests are serial. HTTP 429/5xx and transient transport failures get bounded retries with preserved attempt-level evidence.
For each quoted player, Stage 2 creates a regularized estimate rather than multiplying goals, odds, and arbitrary position bonuses.
Uses recency weights with a five-match half-life. Non-penalty xG is preferred; missing xG is not silently converted to zero.
Uses competition/position priors with leave-one-player-out logic. A 450-minute prior shrinks small samples toward broader evidence.
Estimates appearance probability and minutes conditional on appearing. Confirmed starters and non-starters use different historical minutes.
This λ is an expected goal count, not yet a probability of scoring.
Stage 4 avoids the removed hand-written forward/midfielder/defender multipliers. It reads paired Bet365 team-total over/under markets for the exact team name.
For each half-goal line, normalizes 1/Over and 1/Under to remove the two-way overround.
Inverts the fair over probability to a Poisson team-goal mean. Requires at least two complete half-goal lines and rejects inconsistent fits.
Compares the market mean with recency-weighted historical team xG, then shrinks the ratio toward neutral using a reliability factor.
For a player who appears, scoring is modelled with a Poisson baseline:
Uncertain participation is kept explicit:
The default policy requires EV per placed stake ≥ 5%, prior share ≤ 65%, medium/high quality, likely or confirmed starter status, complete xG history, valid context, and no unsupported settlement rule.
“Score if plays” is conditional. “Fair” is the decimal price corresponding to that conditional probability.
A high EV means the model’s point estimate exceeds the market price. It is not a confidence level and has not passed calibration yet.
settlement_rules_unknown means non-runner void/refund is assumed, not verified. Quote timestamps may be response-level rather than bookmaker-level.
It prints and publishes text only. There is no staking or execution logic.
Stage 5 is collecting untouched pre-kickoff predictions and post-match outcomes for calibration and paper tracking.
Bet365 non-runner settlement and team-market quote timestamps remain incomplete inputs.
Prior experiments caused HTTP 429s and incomplete results. The current retry policy is bounded and serial.
Every candidate—including rejected ones—is written to candidates.jsonl with the player/event IDs, selected quote, model output, match context, decision reasons, and raw-source links. Stage 5 additionally hashes the candidate file and separates model revisions by source and policy fingerprints.