Simulated Scenarios
with
against Rival
Simulated outcomes based on current projections
or
Loading data... Please wait...
What is this page about?

This page shows potential outcomes for next GW (GW{{ current_gw }}) using simulation replications.

What is the purpose of it?

We already have great models for optimizing FPL decisions based on expected value (EV) -- projected points. Using these models will take you a step ahead of other managers, but for practical reasons, lack some aspects. For example, having two or more players on the same team or opposite teams for a game limits how many points you can get this GW. Therefore, even for two teams with exactly same EV but with different players, shape of the outcome distribution will be different. For example, we know that captaining a differential have a big upside, as well as a risky decision, but have no way to quantify it. Unless, we simulate match outcomes and see the distribution itself.

Who needs this?

If you are interested in optimization for FPL and wondering what the potential outcomes look like for your team. Note that, this page shows example outcomes for reference, but I urge you to build your own simulator if you have the means.

How do you generate simulation replications?

Using the Free Model of the amazing FPLReview, I collect goal/assist/bonus rates for each player. Then, using Monte-Carlo simulation (and a bunch of assumptions), I simulate the GW over and over. Similar stats (anytime goalscoring, anytime assist, clean sheet, etc...) are also available on several websites, but not being used here.

What is included in simulations?

  • Goal points
  • Assist points
  • Clean sheet points
  • Goals conceded points
  • Bonus points
  • Autosub replacements

What are limitations and assumptions?

I am hoping to improve quality of simulations in future, but here are current limitations and assumptions.

  • Using expected minute values, I assume a player either plays 90 mins or 0 mins. No subs.
  • Bonus point logic is a bit involved, but I assume only 1 player to get 3 points, 1 player to get 2 points and 1 player to get 1 bonus point.
  • I exclude events like yellow card / red card / penalty miss / penalty save.
  • Current model does not consider vice-captain switch

Why do we need simulation anyway?

If you are serious about optimizing your decisions for FPL, then the next step after the multi-period EV model is to use stochastic optimization. It is a better way to calculate probabilities and in general a better way to approach stochastic nature of FPL from a decision making perspective. Consider a simple case, where it is last GW of the season and you are in 2nd position OR. If you optimize over EV and get the same exact squad as the OR #1 manager, your chance of winning FPL becomes 0%. It is obvious that you need to find a player who is not owned by the top ranked manager, but have a solid EV value. Simulation, in this case for example, provide obvious benefits and can help you to calculate probability of winning. So, you can maximize probability of winning in an optimization model and increase your chance.

Is 100 replications enough?

No, the more the better. But since this website is hosted on GitHub, I use GitHub actions to produce simulations every 6 hours. 100 replications is the limit I can have without increasing my webpage build time significantly. It is also a good point as mobile devices get really slow during JS calculations. If you are doing it yourself, consider having as much replications as you can for the optimization purposes.

Overview
This tool uses 100 randomly generated simulations to evaluate your team selections for the next GW.
These values are approximations based on EV values. For constructing a team, try FPLReview Planner.
Your Team
{{ player.multiplier > 2.5 ? "TC" : "C" }} V X {{ player.points_total }} {{ player.data.web_name }} {{ fixture_dict[player.data.team].str }} P {{ sc_player_avg_full[player.element].avg }} P90 {{ sc_player_avg_full[player.element].pps }}
Rival Team
{{ player.multiplier > 2.5 ? "TC" : "C" }} V X {{ player.points_total }} {{ player.data.web_name }} {{ fixture_dict[player.data.team].str }} P {{ sc_player_avg_full[player.element].avg }} P90 {{ sc_player_avg_full[player.element].pps }}
Win
{{ _.round(scenario_head_2_head.win,0) }}%
Tie
{{ _.round(scenario_head_2_head.tie,0) }}%
Loss
{{ _.round(scenario_head_2_head.loss,0) }}%
Best Diff to Rival
{{ scenario_head_2_head.max }}
Mean Diff to Rival
{{ scenario_head_2_head.mean }}
Worst Diff to Rival
{{ scenario_head_2_head.min }}
Points Analysis
Penalty/Lead
{{ my_penalty }} pts
Average
{{ scenario_stats.avg_score }} pts
Box Plot
Min-Q1-Median-Q3-Max
{{ Math.floor(scenario_stats.quantiles[0]*10)/10 }} {{ Math.floor(scenario_stats.quantiles[4]*10)/10 }} {{ Math.floor(scenario_stats.quantiles[1]*10)/10 }} {{ Math.floor(scenario_stats.quantiles[3]*10)/10 }} {{ Math.floor(scenario_stats.quantiles[2]*10)/10 }}
Most Points
Scenario #{{ (scenario_stats.best_one && scenario_stats.best_one.sim) || '' }}
{{ (scenario_stats.best_one && scenario_stats.best_one.total_score) || 0 }} pts
Least Points
Scenario #{{ (scenario_stats.worst_one && scenario_stats.worst_one.sim) || '' }}
{{ (scenario_stats.worst_one && scenario_stats.worst_one.total_score) || 0 }} pts
Avg. Lineup Points
{{ (scenario_stats.lineup_avg || 0).toFixed(2) }} pts
Avg. Autosub Points
{{ (scenario_stats.autosub_avg || 0).toFixed(2) }} pts
Difference to Field Average Analysis
Average
{{ getWithSign(scenario_stats.avg_diff) }} pts
Box Plot
Min-Q1-Median-Q3-Max
{{ Math.floor(scenario_stats.diff_quantiles[0]*100)/100 }} {{ Math.floor(scenario_stats.diff_quantiles[4]*100)/100 }} {{ Math.floor(scenario_stats.diff_quantiles[1]*100)/100 }} {{ Math.floor(scenario_stats.diff_quantiles[3]*100)/100 }} {{ Math.floor(scenario_stats.diff_quantiles[2]*100)/100 }}
Best Diff. to Field
Scenario #{{ (scenario_stats.best_diff && scenario_stats.best_diff.sim) || '' }}
{{ getWithSign((scenario_stats.best_diff && scenario_stats.best_diff.diff) || 0) }} pts
Worst Diff. to Field
Scenario #{{ (scenario_stats.worst_diff && scenario_stats.worst_diff.sim) || '' }}
{{ getWithSign((scenario_stats.worst_diff && scenario_stats.worst_diff.diff) || 0) }} pts
Click on a row to replace player
Position Name Team Price Own% Avg.Pts Pts per App.
{{ element_type[player.element_type].short }} {{ player.web_name }} {{ teams_ordered[player.team-1].short }} {{ (player.now_cost / 10).toFixed(1) }} {{ player.selected_by_percent }}% {{ sc_player_avg_full[player.id].avg }} {{ sc_player_avg_full[player.id].pps }}
Probability of Points
20+ Pts
{{ (((scenario_stats.probs && scenario_stats.probs['20+']) || 0)*100).toFixed(0) }}%
30+ Pts
{{ (((scenario_stats.probs && scenario_stats.probs['30+']) || 0)*100).toFixed(0) }}%
40+ Pts
{{ (((scenario_stats.probs && scenario_stats.probs['40+']) || 0)*100).toFixed(0) }}%
50+ Pts
{{ (((scenario_stats.probs && scenario_stats.probs['50+']) || 0)*100).toFixed(0) }}%
60+ Pts
{{ (((scenario_stats.probs && scenario_stats.probs['60+']) || 0)*100).toFixed(0) }}%
70+ Pts
{{ (((scenario_stats.probs && scenario_stats.probs['70+']) || 0)*100).toFixed(0) }}%
Rival Probability of Points
20+ Pts
{{ (((scenario_stats_rival.probs && scenario_stats_rival.probs['20+']) || 0)*100).toFixed(0) }}%
30+ Pts
{{ (((scenario_stats_rival.probs && scenario_stats_rival.probs['30+']) || 0)*100).toFixed(0) }}%
40+ Pts
{{ (((scenario_stats_rival.probs && scenario_stats_rival.probs['40+']) || 0)*100).toFixed(0) }}%
50+ Pts
{{ (((scenario_stats_rival.probs && scenario_stats_rival.probs['50+']) || 0)*100).toFixed(0) }}%
60+ Pts
{{ (((scenario_stats_rival.probs && scenario_stats_rival.probs['60+']) || 0)*100).toFixed(0) }}%
70+ Pts
{{ (((scenario_stats_rival.probs && scenario_stats_rival.probs['70+']) || 0)*100).toFixed(0) }}%
Probability of Difference to Field Avg
≤ -10 Pts
{{ (((scenario_stats.probs && scenario_stats.diff_probs['m10']) || 0)*100).toFixed(0) }}%
≤ -5 Pts
{{ (((scenario_stats.probs && scenario_stats.diff_probs['m5']) || 0)*100).toFixed(0) }}%
≤ 0 Pts
{{ (((scenario_stats.probs && scenario_stats.diff_probs['m0']) || 0)*100).toFixed(0) }}%
≥ 0 Pts
{{ (((scenario_stats.probs && scenario_stats.diff_probs['p0']) || 0)*100).toFixed(0) }}%
≥ +5 Pts
{{ (((scenario_stats.probs && scenario_stats.diff_probs['p5']) || 0)*100).toFixed(0) }}%
≥+10 Pts
{{ (((scenario_stats.probs && scenario_stats.diff_probs['p10']) || 0)*100).toFixed(0) }}%
Rival Probability of Difference to Field Avg
≤ -10 Pts
{{ (((scenario_stats_rival.probs && scenario_stats_rival.diff_probs['m10']) || 0)*100).toFixed(0) }}%
≤ -5 Pts
{{ (((scenario_stats_rival.probs && scenario_stats_rival.diff_probs['m5']) || 0)*100).toFixed(0) }}%
≤ 0 Pts
{{ (((scenario_stats_rival.probs && scenario_stats_rival.diff_probs['m0']) || 0)*100).toFixed(0) }}%
≥ 0 Pts
{{ (((scenario_stats_rival.probs && scenario_stats_rival.diff_probs['p0']) || 0)*100).toFixed(0) }}%
≥ +5 Pts
{{ (((scenario_stats_rival.probs && scenario_stats_rival.diff_probs['p5']) || 0)*100).toFixed(0) }}%
≥+10 Pts
{{ (((scenario_stats_rival.probs && scenario_stats_rival.diff_probs['p10']) || 0)*100).toFixed(0) }}%
Player Outcome
Player Play Prob % Average Pts Average Pts
when Play
Min Q1 Median Q3 Max Prob % >= Target
{{ v.web_name }} {{ (v.play_prob*100).toFixed(0) }} {{ (v.avg).toFixed(2) }} {{ isNaN(v.avg90) ? "-" : v.avg90.toFixed(2) }} {{ isNaN(v.q0 ) ? "-" : _.round(v.q0, 1) }} {{ isNaN(v.q25 ) ? "-" : _.round(v.q25, 1) }} {{ isNaN(v.q50 ) ? "-" : _.round(v.q50, 1) }} {{ isNaN(v.q75 ) ? "-" : _.round(v.q75, 1) }} {{ isNaN(v.q100) ? "-" : _.round(v.q100, 1) }} {{ isNaN(v.tp) ? "-" : _.round(v.tp*100, 1) }}
Simulations
Field Average
{{ (current_rep_values.total_field || 0).toFixed(2) }} pts
Team Points
{{ (current_rep_values.total_score || 0).toFixed(0) }} pts
Difference
{{ getWithSign(current_rep_values.diff || 0) }} pts
Top Players of Simulation Run
Pos Name Team £ Own% Points Gain/Loss
{{ element_type[p.data.element_type].short }} {{ p.data.web_name }} {{ teams_ordered[p.data.team-1].short }} {{ p.data.now_cost / 10 }} {{ parseFloat(ownership_rate_dict[p.ID] || p.data.selected_by_percent).toFixed(1) }}% {{ p.Points }} {{ p.eff_points }}
Team Players
Pos Name Team £ Own% Points Gain/Loss
{{ element_type[p.data.element_type].short }} {{ p.data.web_name }} {{ teams_ordered[p.data.team-1].short }} {{ p.data.now_cost / 10 }} {{ p.data.selected_by_percent }}% {{ ( current_rep_dict[p.element] && current_rep_dict[p.element].Points) || 0 }} {{ p.eff_points }}
Lineup Pts {{ current_rep_values.lineup_score }}
Autosub Pts {{ current_rep_values.autosub_score }}
Total {{ current_rep_values.total_score }}
Simulation Game Details
{{ g.home.name }} {{ g.score.home }}
-
{{ g.score.away }} {{ g.away.name }}
Goal {{ elements_dict[event.goal] ? elements_dict[event.goal].web_name : '-' }} Assist {{ event.assist ? (elements_dict[event.assist] ? elements_dict[event.assist].web_name : "-") : "-None-" }}
{{ event.minute }}'
Goal {{ elements_dict[event.goal] ? elements_dict[event.goal].web_name : '-' }} Assist {{ event.assist ? (elements_dict[event.assist] ? elements_dict[event.assist].web_name : "-") : "-None-" }}
{{ g.home.name }} {{ g.home_avg }}
-
{{ g.away_avg }} {{ g.away.name }}
Home Win
Tie
Away Win
{{ (g.home_win_avg * 100).toFixed(0) }}%
{{ (g.tie_avg * 100).toFixed(0) }}%
{{ (g.away_win_avg * 100).toFixed(0) }}%
- No scenario details available -
{{ graph_update_watch }}
Loading data... Please wait...
Last update: