What an MIT DFS Paper Taught My NHL Lineup Optimizer

An MIT NHL DFS paper found win probability was the only goalie predictor that mattered. So I rebuilt my NHL lineup optimizer around goalies.

Last week I came across a paper from three MIT operations research people — David Scott Hunter, Juan Pablo Vielma and Tauhid Zaman — called Picking Winners in Daily Fantasy Sports Using Integer Programming. It is about building a set of NHL DFS lineups with a solver, which is exactly what my free NHL lineup optimizer does, so I read it with a pencil in hand. They did not just run simulations: they entered real DraftKings contests and report that “we are able to rank in the top-ten multiple times in hockey and baseball contests with thousands of competing entries.” Then they donated the money — “around $15,000” — to the Greater Boston Food Bank, which I thought was a classy touch.

A good chunk of the paper is theorems and proofs about submodular functions. I skipped those. What I wanted was the strategy: what they stacked, what they found, and whether any of it should change my tool. One thing did, and it made the tool more than twice as fast.

Two bar charts. Seconds per lineup: 2.1 when the solver picks the goalie, 0.9 with the goalie fixed. Lineups built from 150 asked in 240 seconds: 70 versus 115.
Same FanDuel slate, same settings, same machine. Fixing the goalie before the solve cut the time per lineup by more than half.

What they actually built

Strip away the math and their method is the one most lineup optimizers use, mine included: build lineups one at a time, and make each new one maximize projected points while staying different enough from the ones already built. In their words, they “maximize the expected score of an entry subject to a lower bound on its variance and an upper bound on its correlation with previously constructed entries.” The variance part is stacking; the correlation part is an overlap cap. I wrote about why that second half is the hard part in one good lineup is easy, twenty is the hard part.

They tested six combinations of stacking rules, and the winner was the one with the most correlation packed in. Their description: “Type 4 stacking includes goalie stacking, line stacking (complete and partial), defensemen stacking, and at most three different teams.” Goalie stacking means no skaters facing your own goalie. Line stacking means one full forward line plus at least two players from a second line — what I call a 3-2. My optimizer already had every piece of that except the defensemen part, which I come back to below.

The goalie finding

This is the part that got my attention. They built a small prediction model for each position using the public projection sites, and for goalies they also fed in the probability of the goalie’s team winning. The result: “When the win probability is included, it is the only significant feature.” The projection sites added nothing once you knew who was likely to win.

That makes sense when you look at the scoring. A goalie’s win bonus is a big, lumpy chunk of his points — 12 on FanDuel today — and Vegas is very good at pricing who wins a hockey game. The saves and goals against are noise around it.

They also had a practical problem I know well. Starting goalies are only confirmed close to game time; the paper says the information “is generally posted on public websites about 30 minutes before the games begin.” So the whole batch has to be built in that window. They did not do anything clever about it — they measured that “all solvers are able to solve our algorithm for 100 lineups in under four minutes” and called it enough.

Build around goalies

Reading that, I had an idea. If the goalie is the one position where Vegas tells you most of what you need, why let the solver pick him at all? Pick the goalies yourself — the likely winners — split the batch between them, and build each goalie’s share with him locked in. A 10-game slate, 150 lineups, 10 favourites: 15 lineups built around each one.

That is now a section in the tool called Build around goalies. It lists the confirmed and likely starters from Daily Faceoff, with each team’s win probability taken from the moneyline (with the bookmaker’s margin removed). The favourites are ticked by default. You can split the lineups evenly or in proportion to win probability, and a goalie whose group runs out of legal lineups hands his leftover share to the others.

One detail took some care. My optimizer has rules that stop a player from appearing in too many lineups, or in back-to-back lineups. Applied to a goalie who is locked in on purpose, those rules would end his group after one lineup. So the locked goalie is exempt from them, and his team is exempt from the stack cooldown. Everyone else still plays by the normal rules.

Then I measured it on a real FanDuel slate. Same settings, 40 lineups, run twice with the same result both times: 2.1 seconds per lineup with the solver choosing the goalie, 0.9 seconds with five favourites fixed. Asked for 150 lineups in a 240-second budget, the normal build got 70 before the clock ran out. The goalie build got 115 in 143 seconds — and stopped only because a 10-team slate ran out of lineups different enough to satisfy the diversity rules, not because it ran out of time.

Fixing the goalie does not shrink the problem as much as you might think. It removes one choice and the handful of skaters facing him. What makes a lineup optimizer slow is that lineup 60 has to differ from all 59 before it, and that part stays. I have learned the hard way that my intuition about what speeds up a solver is not worth much — the textbook fix once made mine twice as slow — so this one I only believe because I timed it.

Defencemen from the first power play

The missing piece of their Type 4 was this: “defensemen that are on the first power play line score substantially higher than defensemen that are not.” The PP1 defenceman quarterbacks the man advantage and collects assists the other defencemen never see. That is now a checkbox, Defencemen only from a PP1 unit, off by default. It needs the line data loaded, and the tool refuses politely if there are not enough PP1 defencemen on the slate to fill the slots.

What I did not take, yet

Overlap by slate size. They found the right amount of diversity depends on the night: “the maximum lineup overlap should be tuned between four and seven depending on how many games are being played on a given night.” Fewer games means fewer good lineups, so you let them overlap more. My tool already sizes one of its cooldowns to the slate; the player overlap cap is still a fixed number. That is next on the list.

Don’t stop early. They checked whether the first lineups built were the best ones. They weren’t: “the winning lineup is generally one of the later created lineups.” Which is the best argument I have seen for the Add more lineups button over settling for the first 50.

Two lineups at a time. Near the end they float building two lineups in one bigger solve instead of one after the other, and admit “the resulting formulation can be much harder to solve.” I have a different version in mind: let each goalie’s group ignore the other goalies’ lineups. Two lineups with different goalies already differ by one player, so each group would only compare against its own 15 — and independent groups could be built in parallel on a machine with several cores. The price is that two goalies’ lineups could end up with nearly the same skaters. I want to measure that trade before I build it.

A few caveats

Their results come from 38 DraftKings hockey contests between October and December 2015, under that season’s scoring — a goalie win was worth 3 points then. The idea travels; the exact numbers may not. And my timings are from a development machine, not from the website — which brings me to the next section.

The website is slower than my machine

I should be straight about this. The optimizer runs on Render, on a small, cheap instance with less than one CPU. The solver I use builds one lineup at a time on a single core, so the hosted tool is noticeably slower than the machine I timed above. The first time I asked the live site for 150 lineups it built about 50 in the 240-second budget. On the development machine the goalie build got 115.

The slow server also exposed a bug. A goalie whose lineups are hard to find can use up the time allowed for one lineup without finding one. The goalie build read that as the whole batch running out of time and stopped, so two of my runs on the live site ended with zero lineups and most of the clock unused. Now a goalie who stalls hands his share to the next goalie, and the run only ends when the batch clock really runs out or you press Stop.

What I do about the speed, for now:

  • Batches. A web request can only run so long, so each batch is capped at 240 seconds. When a batch stops short, Add more lineups picks up where it left off. It keeps the lineups you already have and keeps every new one different from them. Two or three batches get you to 150, and the paper’s point about later lineups winning says it’s worth doing.
  • The goalie build. It is the fastest setting in the tool, which matters more on a slow server than on a fast one.
  • Running it locally. When I want a big batch in a hurry, I run the same code on my own computer, with a longer time limit.
  • A bigger server. Render sells an instance with a full CPU for about $25 a month. I haven’t decided whether the tool’s traffic justifies it. The goalie groups built in parallel, from the section above, would only pay off on a server with more than one core.

No promises

None of this is a promise that anyone wins money. What I like about the paper is that it is honest about that too: their lineups landed far above or far below the field, and the profit came from the few nights they landed high. That is what tournament DFS is.

If you want to try the goalie build, it is in the free NHL lineup optimizer, right below Lineup patterns. The background on the tool itself is in A Free NHL Lineup Optimizer for DraftKings, and the paper is on arXiv for anyone who wants the theorems I skipped.

Tradeline Supply
Things that I use, like, and am affiliated with:
Mint Mobile offers great cell phone service for $15 flat, get $15 off using the link. Get discounted phones with service activation and no contract.
I never spend money before I check Mr Rebates or Rakuten to get cashbacks, rebates, discounts, coupons or cheaper gift cards.

Leave a Reply