← BirdieAPICONTENT HISTORY
WHAT CHANGED
Update to BirdieAPI
Snapshot Oct 30, 2026 · 00:06 UTC · version 1.0.0
Collection source: downloaded plugin package.
First saved snapshot
No earlier snapshot is available to establish a change.
Save BirdieAPI and check future changes in Following.
Up to 10 plugins free · no card required.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"description": "Builds a win-probability model for a golf tournament from BirdieAPI ratings: rating as of a date, course fit, field list, Monte Carlo simulation of four rounds with a cut, and a comparison with the devigged market. Use when the user wants the chance a golfer wins a major or any stroke-play event, wants to simulate a tournament, or asks why a model disagrees with the odds. Do not use for validating the model's history -- see walk-forward-validation. Do not use for plain player lookups -- see player-scouting.",
"included_files": [],
"name": "outright-model",
"skill_md_contents": "---\nname: outright-model\ndescription: \"Builds a win-probability model for a golf tournament from BirdieAPI ratings: rating as of a date, course fit, field list, Monte Carlo simulation of four rounds with a cut, and a comparison with the devigged market. Use when the user wants the chance a golfer wins a major or any stroke-play event, wants to simulate a tournament, or asks why a model disagrees with the odds. Do not use for validating the model's history -- see walk-forward-validation. Do not use for plain player lookups -- see player-scouting.\"\nmetadata:\n version: 1.0.0\n author: BirdieAPI\n---\n\n# Outright Model\n\n> **Default data tool:** BirdieAPI (`birdieapi-tool`).\n> `get_ratings` with `as_of` (2 credits) is the input. `get_course_history` (5) adds fit. `get_winner_odds` (5) gives the market to compare against. `get_leaderboard` (2) gives past fields and cut sizes.\n\nYou are an expert in simulation models for golf winners. Your goal is to produce honest win probabilities with uncertainty, show which assumptions move them most, and compare them with the market without implying a bet follows.\n\n## When to Use\n\n- \"What is the chance Scheffler wins the PGA Championship?\"\n- \"Simulate the Open with these ratings.\"\n- \"Why does my model give the favourite 7% when the books imply 15%?\"\n\n## When NOT to Use\n\n- Calibrating the output -- see `probability-calibration`\n\n## Commands Available\n\n| Command | What It Does | Credits |\n|---------|-------------|---------|\n| `get_ratings` | Rating per player, `as_of` any date, `min_rounds`, `limit` up to 500 | 2 |\n| `get_player_results` | Rounds with `adj_vs_field`, to estimate round-to-round spread | 5 |\n| `get_course_history` | Course fit inputs (see `course-fit`) | 5 |\n| `get_leaderboard` | Past fields and `cut_count` for the same event | 2 |\n| `list_tournaments` | Tournament row with `cut_round`, `cut_score`, `cut_count`, `field_size` | 1 |\n| `get_winner_odds` | The market's priced golfers (a field proxy) and prices | 5 |\n\n## Commands That Do NOT Exist\n\n| Not Available | Use Instead |\n|--------------|-------------|\n| `get_win_probability`, `get_predictions` | Build it here; BirdieAPI does not serve model predictions |\n| `get_field` for an upcoming event | Not available. Use the priced golfers from `get_winner_odds` as a proxy, or ask the user for the field |\n| `get_tee_times`, `get_weather` | Not available; weather and wave draw are not modelled |\n| `get_live_leaderboard` | Not available; no in-play updating |\n\n## Model\n\nFor golfer `i` in a field of `n`, in round `r`:\n\n```\nstrokes_vs_field[i, r] = skill[i] + fit[i] - field_mean + eps[i, r]\nskill[i] ~ Normal(rating[i], tau) # rating uncertainty, drawn once per simulated tournament\neps[i, r] ~ Normal(0, sigma) # round-to-round noise\n```\n\nHigher is better. Winner = highest total over four rounds (after the cut: 36 holes, then the cut line, then the weekend). Ties are rare in a continuous simulation; real ties go to a playoff, which is close to a coin toss among the tied.\n\nInputs:\n- `rating[i]` from `get_ratings` with `as_of` = the day before the first round.\n- `fit[i]` from `course-fit` (optional, shrunk).\n- `sigma`: round-to-round standard deviation, estimated from `get_player_results` (`adj_vs_field` per round).\n- `tau`: how uncertain the rating is. Larger for few `weighted_rounds`.\n- The field: `n` golfers and their ratings. The field mean cancels in the winner comparison but matters for the cut.\n\n## How It Works\n\n**Step 1: Ratings before the event.**\n\n```\nget_ratings {\"as_of\": \"2024-04-04\", \"limit\": 500, \"min_rounds\": 20}\n```\n\nReal response: 313 rated players, best 2.88 (Scottie Scheffler), lowest -1.68. Ratings are within one tour, so for LIV golfers in a major, widen `tau` and say why; their rating is built against LIV fields.\n\n**Step 2: The field.** The upcoming field is not in the data. Take the priced golfers as a proxy:\n\n```\nget_winner_odds {\"tournament_id\": \"401580344\", \"limit\": 200, \"bookmaker\": \"draftkings\"}\n```\n\n115 golfers were priced for the 2024 Masters; 97 of them had a rating. The unrated ones (old champions, amateurs, qualifiers) are mostly weak. Dropping them makes the field artificially strong and pushes every probability down. Give them a rating below the lowest rated player, or flag it in the output.\n\n**Step 3: Estimate sigma.**\n\n```\nget_player_results {\"player_id\": \"9478\", \"season\": 2023, \"limit\": 50}\n```\n\nReal response: 96 rounds with `adj_vs_field`, mean 3.35, standard deviation 2.53. Pool several players rather than using one. Note this standard deviation also includes slow drift in form, so it slightly overstates pure round noise; that is a modelling choice to state, not hide.\n\n**Step 4: Simulate.**\n\n```python\nimport numpy as np\n\ndef simulate(rating, sigma, tau, cut_n, n_sims=20000, seed=7):\n rng = np.random.default_rng(seed)\n wins = np.zeros(len(rating))\n for _ in range(n_sims // 1000):\n skill = rating[None, :] + rng.normal(0, tau, (1000, len(rating)))\n tot = np.zeros((1000, len(rating)))\n for rd in range(4):\n tot += skill + rng.normal(0, sigma, (1000, len(rating)))\n if rd == 1: # cut after round 2\n kth = np.sort(tot, axis=1)[:, -cut_n][:, None]\n tot = np.where(tot < kth, -1e9, tot)\n wins += np.bincount(np.argmax(tot, axis=1), minlength=len(rating))\n return wins / n_sims\n```\n\n`cut_n` comes from the tournament row (`cut_count` was 50 for the 2024 Masters). Ties at the cut line would let a few more through; ignore them for winner probabilities and say so.\n\n**Step 5: Run the sensitivity, not one number.** First-pass illustration on the 97 rated, priced golfers of the 2024 Masters (ratings as of 2024-04-04, 20,000 simulations, seed 7, no course fit):\n\n| Assumptions | Scheffler | Rahm | Schauffele | McIlroy |\n|-------------|-----------|------|------------|---------|\n| sigma 2.53, tau 1.0 | 6.7% | 5.2% | 4.2% | 3.7% |\n| sigma 2.53, tau 0.5 | 8.7% | 6.3% | 5.0% | 4.4% |\n| sigma 2.53, tau 0.0 | 9.7% | 6.8% | 5.6% | 4.8% |\n| sigma 2.0, tau 0.0 | 14.2% | 8.8% | 7.2% | 6.1% |\n\nFor comparison, the DraftKings latest price devigged by the power or Shin method put Scheffler at 15% to 16% (see `odds-analysis`). The favourite's probability swings from 6.7% to 14.2% on two assumptions. That is the main lesson: the output of a rating-based simulation is governed by `sigma` and `tau`, which must be estimated and validated, not picked to match the market. Matching the market by tuning the inputs defeats the point of the comparison.\n\n**Step 6: Add fit and the market.** Add `fit[i]` from `course-fit` to `skill`. Then compare to the devigged market: where the model disagrees by more than its own sensitivity range, ask why before concluding anything. Common reasons: ratings lag a form change; injury or withdrawal knowledge the data lacks; a field mismatch; a wrong `sigma`.\n\n**Step 7: Blend, don't replace.** The market contains information a rating does not (injury news, equipment, preparation). A defensible final probability is a weighted average of model and devigged market in log-odds, with the weight set by out-of-sample log loss in `walk-forward-validation`.\n\n## Limits to state every time\n\n- Score-based ratings, no shot data, no weather, no tee times, no injury information.\n- Four-round stroke play only. Match play and team formats are not modelled.\n- The 2024 numbers above are a worked illustration of method, not a forecast or a recommendation.\n\n## Credit Usage\n\n| Operation | Credits | Notes |\n|-----------|---------|-------|\n| Ratings as of a date | 2 | one call, up to 500 players |\n| Market and field proxy | 5 | one call |\n| Sigma from five players | 25 | pool across players |\n| Course fit for top 20 | 100 | optional |\n| Minimal build (ratings, market, one sigma pull) | 12 | |\n\n## Anti-patterns\n\n| What the Model Might Do | Why It's Wrong | Do This Instead |\n|---------------------|---------------|-----------------|\n| Use today's rating for a past event | Leakage | `as_of` the day before |\n| Tune `sigma` until the favourite matches the books | Circular; no information left to compare | Estimate it from data |\n| Drop unrated golfers silently | Field too strong, probabilities too low | Include with a low rating, or disclose |\n| Report 6.73% | False precision | Report a range from the sensitivity table |\n| Ignore the cut | Players who miss it cannot win | Apply it after round 2 |\n\n## Output Format\n\n```\n2024 Masters win probability, rating-based simulation (97 golfers, 20,000 runs)\nScottie Scheffler: 7% to 14% depending on sigma and tau (see table). Market, devigged: 15% to 16%.\nInputs: ratings as of 2024-04-04; sigma from data; no course fit; no weather or injury information.\n```\n\n## What to Do Next\n\n| What You Found | Next Action | Skill |\n|----------------|-------------|-------|\n| A probability set | Check calibration on past majors | `probability-calibration` |\n| A fit input | Build it properly | `course-fit` |\n| Parameters to tune | Walk-forward | `walk-forward-validation` |\n"
}SHA-256 of public snapshot: fe483b9c2ccf1cdeb2c83cb7885f6d3cfe457c010d3a02998d200ba55ca97560