FanGraphs Lab: A Baseball Simulator
We’re excited to announce that the latest addition to the FanGraphs Lab is a baseball simulator:

You can click on any of the day’s games to pre-fill the rosters, or build your own using current players. The simulator will then simulate a game 10,000 times.
Let’s go over how this works:
- If you select one of the day’s games, we pull in the rosters for each team. We first look to see if there’s a confirmed lineup, and if there isn’t, we use the RosterResource platoon lineup based on the handedness of the opposing starting pitcher.
- Next, we build out the probability of the following events for each possible batter/pitcher matchup: single, double, triple, home run, walk, hit-by-pitch, strikeout, and in play, outs. This is done by taking the ZiPS or Steamer platoon projections for both the batter and the pitcher, depending on the projection system you choose. For instance, if the batter hits right-handed and the pitcher throws left-handed, we would pull in the batter’s “vs L” projections and the pitcher’s “vs R” projections. For Steamer, we go a step further, determining whether the pitcher is a starter or a reliever, and then pulling the specific “vs L as Reliever” projection.
- Once we have the pitcher’s and batter’s individual platoon projections, we do an odds ratio calculation (which includes league averages), and now we have the probability of each event happening for the batter/pitcher matchup.
- We also grab each batter’s Speed Score, stolen base rate and stolen base attempts per opportunity.
- We use all that data to simulate a game. We run 10,000 simulations, and then display the results.
The result set you get is robust.
You can see the percentage chance of each team winning, including the run distribution of all the games simulated, as well as a number of team stats and their corresponding histograms:

We also have average stats for each batter and pitcher:

And if you click on a particular batter or pitcher line, we have histograms of the results for each simulation:

We also include a matchup grid, which shows all the probabilities we’re using for each matchup:

We display three sample games out of the 10,000 simulations:

Finally, if you click on any play, it will show you the probability of the events for that particular matchup:

The simulator also allows you to do fun things like see what would happen if a team entirely composed of Shohei Ohtanis faced off against another team made up entirely of Shohei Ohtanis. The possibilities are nearly endless.
It’s worth asking how we know that the simulator does a decent job of actually simulating baseball.
First, we recreated our win expectancy tables using the simulator. If the simulator is doing a good job, we would expect it to have similar win expectancies based on the base out situation, inning, and game score that we see from real baseball. As you can see, these were nearly identical, with some noise due to sample size. Even 24 million games isn’t enough to remove all the noise:

We also compared the simulator’s rest-of-season results to the Steamer rest-of-season projections:
| Team | Simulation W | Playoff Odds W | Difference |
|---|---|---|---|
| Dodgers | 102.3 | 99.8 | 2.4 |
| Braves | 91.5 | 90.6 | 0.9 |
| Yankees | 90.0 | 88.6 | 1.4 |
| Mariners | 87.8 | 85.1 | 2.7 |
| Tigers | 85.9 | 85.6 | 0.3 |
| Rangers | 85.5 | 83.7 | 1.8 |
| Guardians | 84.4 | 80.8 | 3.7 |
| Diamondbacks | 84.1 | 84.8 | -0.7 |
| Padres | 83.7 | 83.4 | 0.3 |
| Phillies | 83.7 | 82.1 | 1.6 |
| Rays | 83.7 | 81.9 | 1.8 |
| Cubs | 83.6 | 84.5 | -0.9 |
| Pirates | 83.1 | 84.2 | -1.1 |
| Royals | 81.7 | 78.3 | 3.4 |
| Red Sox | 81.5 | 81.6 | -0.1 |
| Brewers | 81.0 | 83.3 | -2.3 |
| Mets | 79.4 | 84.2 | -4.8 |
| Orioles | 79.4 | 80.8 | -1.5 |
| Athletics | 79.1 | 79.1 | 0.1 |
| Giants | 79.1 | 79.4 | -0.2 |
| Twins | 78.7 | 80.1 | -1.5 |
| Cardinals | 78.5 | 78.4 | 0.1 |
| Reds | 77.9 | 78.8 | -0.9 |
| Blue Jays | 77.1 | 81.0 | -4.0 |
| Astros | 75.0 | 77.3 | -2.3 |
| Marlins | 74.6 | 75.6 | -1.0 |
| Angels | 74.6 | 75.6 | -1.0 |
| Nationals | 73.0 | 71.9 | 1.1 |
| White Sox | 68.9 | 67.6 | 1.3 |
| Rockies | 61.0 | 62.0 | -0.9 |
Additionally, the league averages all look reasonable in terms of the simulated distribution of outcomes:
| Source | 1B | 2B | 3B | HR | BB | HBP | K | SB | CS | R/9 |
|---|---|---|---|---|---|---|---|---|---|---|
| Steamer RoS | 14.45% | 4.43% | 0.39% | 2.99% | 9.84% | 1.07% | 21.60% | 2.03% | 0.59% | 4.76 |
| Steamer | 14.76% | 4.50% | 0.42% | 3.32% | 8.75% | 1.02% | 21.31% | 2.03% | 0.59% | 4.83 |
| ZiPS | 14.08% | 4.57% | 0.58% | 3.07% | 8.77% | 1.28% | 21.77% | 2.00% | 0.59% | 4.70 |
| 2025 Stats | 14.28% | 4.23% | 0.34% | 3.09% | 8.41% | 1.05% | 22.22% | 1.88% | 0.54% | 4.52 |
| 2026 Stats | 13.79% | 4.13% | 0.30% | 2.68% | 9.89% | 1.11% | 22.63% | 1.94% | 0.53% | 4.50 |
Finally, we looked at how the full season stats in the simulator compared to Steamer’s full season projected stats:
| Metric | R-Squared |
|---|---|
| AVG | .967 |
| OBP | .913 |
| SLG | .946 |
| K% (Batters) | .990 |
| BB% (Batters) | .934 |
| K% (Pitchers) | .965 |
| BB% (Pitchers) | .965 |
| HR% (Pitchers) | .891 |
| ERA (Starter) | .934 |
| ERA (Reliever) | .384 |
Everything looks pretty good here, except for reliever ERA, which will be a point of future investigation. We are handling inherited runners properly, but reliever ERA is notoriously difficult to project due to sample size. It’s possible this just exposes one difference between running a simulation and a pure projection model.
This is very much a beta product (which is why we have it as part of the Lab), so if you see any issues or have any feature requests, just let us know, either in the comments here or using the Lab’s feedback option.
David Appelman is the creator of FanGraphs.
I think the table comparing Steamer and simulation odds is missing the Mets and Brewers.
Got that fixed (though it was a different run so numbers have changed slightly).