Overview
In an NFL survivor pool, you pick one team to win each week. If they win, you survive; if they lose, you're out. The catch: you can never pick the same team twice. That constraint turns a simple weekly prediction into a season-long optimization problem, because burning a strong team on an easy week means you won't have them when you really need them.
FF Survivor is a tool I built to solve that problem properly. It pulls live odds from multiple sportsbooks, strips out the bookmaker margin to get true win probabilities, and then uses mathematical optimization to find the best possible sequence of picks across the entire remaining schedule.
Odds ingestion and probability modeling
The app integrates with The Odds API to pull moneyline odds from multiple sportsbooks in real time. Raw odds from any single book include the house edge (the "vig"), so the probabilities they imply always add up to more than 100%. To get usable numbers, the pipeline:
- Collects odds across books, converts American moneylines to implied probabilities, and filters statistical outliers using the interquartile range method.
- Removes the bookmaker margin from the aggregated odds to produce calibrated, no-vig win probabilities for every game.
- Syncs automatically via a daily background job, so probabilities stay current as lines move through the week.
The result is a clean probability for every matchup, grounded in the collective pricing of the betting market rather than any single model's opinion.
Optimization engine
The core solver uses Google OR-Tools to formulate the pick selection as a mixed-integer program. The constraints encode the rules of a survivor pool (one pick per week, each team used at most once), and the objective maximizes the overall probability of surviving the full season. The solver finds a provably optimal solution, not just a good heuristic.
For comparison and analysis, the app also includes a greedy strategy (always pick the highest-probability team available each week) and the ability to override any game's probability by hand for what-if scenarios.
Monte Carlo simulation and statistical analysis
Beyond finding the optimal pick sequence, the app runs Monte Carlo simulations (up to 1,000,000 iterations) to answer the question that matters most: what are your actual chances of surviving the whole season?
Each simulation plays out the full schedule using the calibrated probabilities, producing:
- An overall survival rate with Wilson score confidence intervals.
- Week-by-week survival curves and hazard rates, showing exactly where in the season the risk concentrates.
- Average and median weeks survived, so you can see the shape of the distribution, not just the headline number.
The simulation runs as a background job, so results are available without blocking the interface.
Architecture
The app is built on Rails 8 with Hotwire (Turbo and Stimulus) for a responsive UI without a JavaScript build step. PostgreSQL handles multiple database roles: primary data, Solid Cache, Solid Queue for background jobs, and Solid Cable for real-time updates. Auth0 provides authentication via OmniAuth.
Good Job manages the background work (daily odds syncs, simulation runs) with a built-in admin dashboard for monitoring. The app is deployed on Render with separate web and worker processes, containerized with Docker.
Stack
Core technologies on this project: