brackt/app/services/simulations/ncaaw-simulator.ts
Chris Parsons af64a29cfa
Fix NCAAW futures odds simulation and admin import UX (#420)
- Revert ncaaw-simulator to Barthag win probability formula; set
  realistic rating bounds (ratingMin: 0.70, ratingMax: 0.97) so derived
  ratings stay in the range where the formula behaves well
- Add batchSaveFuturesOddsForSimulator which clears all ratings (manual
  and generated) before upserting sourceOdds, so futures odds always
  drive the simulation rather than being silently overridden by existing
  Barthag ratings from Simulator Setup
- Add clearSourceOddsForParticipants to zero out both tables for
  participants excluded from a bulk import
- Add "Clear existing odds" checkbox to the bulk import card; applies
  client-side on match and server-side on submit
- Fix missing sportsSeasonId filter in batchSaveFuturesOddsForSimulator
  pre-clear UPDATE (could have wiped ratings across other seasons)
- Fix race condition: run batchSaveSourceOdds then
  batchSaveFuturesOddsForSimulator sequentially so the simulator inputs
  table always ends in the correct cleared state
- Fix Math.round in convertFuturesToElo collapsing Barthag-scale ratings
  to 0 or 1; Elo callers already round after clamping
- Handle all-identical-odds edge case in convertFuturesToElo (assign
  midpoint instead of throwing)
- Add missingRatingStrategy: worstKnownMinus to ncaaw_bracket manifest
  so fallbackRatingDelta is live config, not dead
- Log warning in resolveRatings when only 1 participant has odds
- Reset clearExisting checkbox after applyMatches

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 01:06:16 -07:00

23 lines
778 B
TypeScript

import { NCAABasketballSimulator } from "./ncaa-basketball-simulator";
import type { Simulator, SimulationResult } from "./types";
export function barthagWinProbability(barthagA: number, barthagB: number): number {
const pA = barthagA * (1 - barthagB);
const pB = barthagB * (1 - barthagA);
const total = pA + pB;
if (total === 0) return 0.5;
return pA / total;
}
export class NCAAWSimulator implements Simulator {
private readonly simulator = new NCAABasketballSimulator({
source: "ncaaw_bracket_rating",
missingRatingName: "Barthag-like rating",
selectionRatingDivisor: 0.08,
winProbability: barthagWinProbability,
});
simulate(sportsSeasonId: string): Promise<SimulationResult[]> {
return this.simulator.simulate(sportsSeasonId);
}
}