A Naive Experiment in Programmatically Optimizing DraftKings NFL Lineups: Part 1
Published on .
DraftKings is a daily fantasy sports (DFS) sports site that has awarded millions of dollars of payouts every season and enticed millions of players to join and deposit, all under of the premise of believing they are “smarter than the average fan.” I set out to test how good players are at maximizing player value within the salary cap, compared to an algorithm. The test had many shortcomings, but in 10 free Week 1 contests, the algorithm’s average finish was the 40th percentile which is promising for winning 50/50 and H2H contests.
The Algorithm
Each lineup must have 1 QB, 2 RB, 3 WR, 1 TE, 1 FLEX and 1 DST with a total salary less than $50,000, which allows for around half-a-billion combinations. We want to maximize the total team score, so we will use freely available score projections to compare lineups, ensuring that they are projected according to DraftKings NFL scoring rules.
My algorithm compares a randomly selected lineup to the current top lineup and keeps the winner, `n` times. Once it has selected a winner, it checks if there is a better player for each position at the remaining salary.
Note: after I did this, I learned this is a well documented as the “knapsack problem.”
You can read the resulting 300 LOC of PHP on Github, which is all triggered by main()
function main($draftGroupId) { $players = generatePlayers($draftGroupId); $players = filterTopPlayers($players); $maxTeam = array(0,array()); $scores=array(); for($i = 0; $i < TRIALS; $i++) { $team = pickRandomTeam($players); $score = calcTeamScoreSimple($team); $scores[] = $score; if( isMaxScore($score,$maxTeam[0]) ) { $maxTeam = array($score,$team); } } $previousMaxTeamScore = $maxTeam[0]; $maxTeam[1] = maximizeTeamSimple($maxTeam[1],$players); $maxTeam[0] = calcTeamScoreSimple($maxTeam[1]); $maximizationGain = $maxTeam[0] - $previousMaxTeamScore; //Print Results echo printScores(calcScoreCounts($scores)); echo "Score of ".$maxTeam[0]." for salary of $".calcTeamSalary($maxTeam[1]). " after a maximization gain of ".$maximizationGain."\n"; echo printTeamInOrder($maxTeam[1]); }
The Test
My test was simple and incomplete.
- Select a lineup with the algorithm
- Enter the lineup in a free tournament contest
- Measure performance as the finishing place out of the total entries
The Results
On average, the algorithm finished in the 40th percentile, with a max of 12th and min of 86%. No analysis of the competitors has been attempted.
Game | Rank | Enrties | Tier | Points | Max | 1% | 5% | 10% | 25% | 50% |
---|---|---|---|---|---|---|---|---|---|---|
9169909 | 2664 | 6565 | 41% | 122 | 204 | 170 | 155 | 147 | 132 | 116 |
9169898 | 3576 | 6953 | 51% | 115 | 212 | 175 | 160 | 150 | 134 | 116 |
8296816 | 5622 | 47414 | 12% | 150 | 215 | 179 | 161 | 152 | 137 | 120 |
8469652 | 48308 | 331428 | 15% | 144 | 221 | 177 | 159 | 150 | 134 | 116 |
8777686 | 32303 | 42299 | 76% | 108 | 223 | 185 | 168 | 159 | 144 | 127 |
9172130 | 6029 | 6974 | 86% | 108 | 215 | 189 | 175 | 167 | 154 | 137 |
9273251 | 777 | 6426 | 12% | 142 | 191 | 168 | 152 | 144 | 131 | 116 |
9169884 | 4116 | 6852 | 60% | 103 | 189 | 164 | 149 | 140 | 125 | 109 |
9169853 | 1262 | 13108 | 10% | 144 | 201 | 167 | 152 | 144 | 132 | 118 |