Calculating the Highest Value to Bid on Each Player in an Auction Draft: The Bid Up To Value

In this post, I calculate the highest value you should bid on each player in an auction draft—what I refer to as the “bid up to” value. In a previous post, I showed how to determine the best starting lineup to draft using an optimizer tool. The “bid up to” value is calculated by finding the highest cost up to which a player is still on the best lineup, as determined by the optimizer.

How it Works

The optimizer tool finds the starting lineup that maximizes your team’s projected points, while staying within your risk tolerance. By placing the optimization function in a loop, we can calculate the optimal starting lineup for each player at each cost. For example, to find Tom Brady’s bid up to value, we can start his cost at $1 and run the optimization function. At this price, Tom Brady is on the best starting lineup, so we increase his cost by $1 while keeping all other players at their expected cost. At $2, Tom Brady is still on the best starting lineup, so we increase his cost again by $1. We repeat this until Tom Brady’s cost is too high for him to be on the best starting lineup. As of this writing and given my league settings, Tom Brady’s bid up to value is $16. That means that Tom Brady is a good value up to $16—if he’s above that price, I should draft someone else because he is no longer on the optimal starting lineup at this cost. After calculating Tom Brady’s bid up to value, we reset his cost to his expected cost and then we calculate the bid up to value for the next player. We repeat this for all players to calculate each player’s bid up to value.

The R Script

The R Script for looping the optimizer to find each player’s bid up to value is located here:

Conclusion

I demonstrated how to calculate a bid up to value for each player. Calculating a bid up to value for each player is a great way to calculate a player’s value in an auction draft because it helps you determine the highest bid you should make for each player. If a player goes for more than his bid up to value, you should draft someone else.

Share this:

Related

My name is Isaac and I’m an assistant professor with a Ph.D. in Clinical Psychology. Why am I writing about fantasy football and data analysis? Because fantasy football involves the intersection of two things I love: sports and statistics. With this site, I hope to demonstrate the relevance of statistics for choosing the best team in fantasy football.

Was interested in how to actually go about running this script – seems like it needs a bunch of other scripts/package(s) to work correctly. Do you know what I should download to be able to run it / is there something I’m missing?

We haven’t updated this particular script for this season, so it might require some re-working. But the proof-of-concept is what’s most crucial here. So you should be able to adapt it to meet your needs.
-Isaac

Hey Isaac,
I just found your site recently and love it. Great job! I’m wondering if there’s a place to input the number of teams in my league and the number of RBs, WRs, etc that we start within the app?

1) reading other comments on “cost” & “bid-up value”, I’m not sure how to apply this in actual drafts. how should I use the “cost” column?

2) does optimal strategy change based on actions of other teams in league? (which positions were already taken, how much they’ve already spent on each player at each position, etc.) if so, can you make it so we can add how much each player goes for (and maybe even to which team in the league)?

3) the present speed of the tool (for free thank you) would make it hard to use in a live auction, is there a paid version that is faster?

4) is this usable in a live draft? if yes, what’s best strategy for the tool?

2) Optimal strategy could change based on other teams. We haven’t gotten to adding that logic yet. Right now, you can modify players’ costs by selecting your AAV source and choosing the Low/Mid/High rank and multiplier.

3) We are working on an offline tool. We’ve had a number of users use the tool during Auction drafts without a problem. We’re trying to find ways to speed it up, but it’s faster than it takes most players to be picked in an Auction Draft, and it doesn’t have to re-optimize after every player is selected.

We have plans to update the GitHub repo after we finish the draft tools. In the meantime, you can update the scripts to calculate a “Bid-Up-To” value for the 2015 season. However, note that there isn’t a “true value” cost of players because research has shown you should be willing to over-spend on key players: https://harvardsportsanalysis.files.wordpress.com/2012/04/fantasyfootballdraftanalysis1.pdf. In other words, there is no simple way of translating points to cost.

While not a “bid up to value” per se, I wanted to find out the highest price where I basically had to take a certain player (regardless of whether I like him or not).

I figured that an easy way to do this was to find the player with the highest VOR per $ ( using average auction value) and use that figure as a benchmark. In the data I just pulled from the projections that ends up being Andre Ellington at around 2.84 VOR/$.

From there I rearranged the formula so that a given players “Must buy at price”, x, was equal to their VOR/2.84.
This basically gives me the price at which any player is as efficient (on a VOR/$ basis) as the most efficient player in the league.

Does this make sense? Maybe you have a better method to calculate the price ceiling at which I HAVE to bid on a given player.

The “Bid-Up-To” value discussed in the above article is a simulation that takes time to run and is specific to your league settings, so it wouldn’t be practical for a webapp. You could always run it offline, though. If you have ideas how to efficiently calculate a Bid-Up-To value, I’m all ears!

These resources are absolutely fantastic, I appreciate the great work. Your projections provide a cornerstone of my draft preparation and strategy.

I implemented a different version of your Optimizer using Excel. It runs more quickly for me locally, and also provides me more control to tweak the Cost values on the fly based on how results come rolling in. (Solver only allows you to optimize over 200 variables, but since I ideally won’t dip past the top 200 for my starting roster, I find that this is enough.) I was able to ‘win’ my 8-team Yahoo draft and will refine the model for a 16-team ESPN keeper draft I have coming up.

One of the biggest benefits of the local implementation, however, is that I am able to integrate a Bid-Up-To tool. Your approach above is robust but, as you note, rather impractical. A first thought that struck me is that you might be better served to start at a player’s expected cost and DECREASE this by one until the player is included in the optimal set. This assumes that, on average, a player will become optimal at some value >50% of the projected cost, which I think is accurate for top-level players at least. To add a layer of refinement, you could investigate this question for a variety of players, try to find some proxy (such as perhaps VOR) that helps classify players by whether bid-up-to is > or = the points baseline from Step 1.
4) Change the objective from maximizing points to minimizing cost. (Steps 3 and 4 change your program from “maximize my points subject to cost constraints, along with position, risk, etc. constraints” to “minimize the cost subject to achieving at least as many points as before, along with position, risk, etc. constraints.” The program remains linear.) Run the optimizer.
5) Subtract the minimized roster cost from your remaining starter budget. This is the bid-up-to value for the player.

This does require a bit of back-and-forth between calculating your baseline and calculating the bid-up-to for any player. The baseline must be recalculated any time your roster changes or one of the players on your optimal roster is selected. I would also periodically update my cost estimates based on live results, which would also require a new baseline. And then whenever a potential starter is nominated, the bid-up-to program would be run against the current baseline.

I haven’t yet implemented a program for calculating bid-up-to for players on the optimal roster. Your method of incrementing is a good start (starting of course with the player’s cost, not at 0). However, it could also be done in two steps:
1) Remove the player from the pool and calculate a “second-best” point baseline (the points of your optimal roster if this player is not available).
2) Run the program described above using this “second-best” point baseline.

I’d be happy to discuss any of this further – feel free to reach out to me.
Thanks,
Jason

It’s actually much faster in R than in Excel. It’s slower online because we have to send lots of data across servers. Agreed that it’s easier to calculate a Bid-Up-To value locally that’s specific to your league settings. You could decrease from their expected projected cost (except for players already selected by the optimizer at that cost).

My comment above was somehow cut in the middle, so it stops making sense at about the mention of using VOR as a proxy. 🙂

One can (and I did) use a single linear program to optimize for bid-up-to, once you have your optimal roster baseline. This program works for any player NOT on your optimal roster already. I’ll sketch it here:
1) Calculate the optimal roster baseline subject to the normal constraints and whatever positions are already satisfied on your roster. Consider the expected points for the lineup as the “points baseline.”
2) Taking the player that you want to calculate “bid-up-to” for, set the integer for this player to 1 and his cost to 0. This implies selecting the player at cost = 0.
2a) Note: This obviously doesn’t make sense if the player will violate your constraints, e.g. he is a second QB. In this case the optimizer of course won’t be able to find a value, but you could use some logic against the constraints before starting the optimizer just to save time.
3) Remove the cost constraint and add a constraint whereby points must be >= the points baseline from Step 1.
4) Change the objective from maximizing points to minimizing cost. (Steps 3 and 4 change your program from “maximize my points subject to cost constraints, along with position, risk, etc. constraints” to “minimize the cost subject to achieving at least as many points as before, along with position, risk, etc. constraints.” The program remains linear.) Run the optimizer.
5) Subtract the minimized roster cost from your remaining starter budget. This is the bid-up-to value for the player.

So, a single run of the simplex method gives you your answer – no search algorithm needed. For a player already on the roster, see the two steps at the end of my note above.

I have no doubt that R will run faster (and is much more powerful for running scripts, etc.) but I have just basic R literacy and am much more comfortable in Excel for now. Maybe next season that will have changed 🙂

Jason/Isaac,
I have been trying to replicate in excel a lot of what Isaac has been trying to do and have come to a few obstacles. First is that the solver function in excel is not 100% accurate when using the Simplex LP. Solver with that method is very close to accurate, but gave me 10 points less than what I found to be the optimal lineup using trial and error. (I caught this because I was using a bid up to macro and noticed that if a player increased in value the optimal lineup increased?!?!)
So I began to research why this is. If you use the GRG Nonlinear or Evolutionary solving methods they are more accurate, but can take hours, days, or with enough constaints, years to return their results.
Jason,
I would like to see your excel spreadsheet if you don’t mind sharing. I plan to start learning how to use R and hopefully can check the excel results for optimal lineups/bid up to amounts against it.

I recently started dabbling in auction drafts, and so I have implemented the optimizer and the bid up to value tool. I have a couple of thoughts regarding this issue.

1. I agree with Isaac that Excel seems like a pain to use here. It is very slow and generally ill suited for this purpose. I used MATLAB since that is what I’m most proficient at, but languages like R and Python are also great.

2. Starting at a players cost and going down is a bad idea. The assumption “on average, a player will become optimal at some value >50% of the projected cost” is indeed accurate for top level players. The problem is that in my tests the players with bid up to value greater than 0 become optimal at a value which is on average 1.5 times the projected cost. Thus you cannot assume that the projected cost is some upper limit.

3. The best strategy here I can think of is to use a binary search. Stepping down or up by 1 is inefficient. Instead, start at some reasonable estimate, e.g. projected cost. Then repeatedly double (setting the current value as the lower limit) or half (setting the current value as the upper limit) the estimate, depending on if it was too small or big respectively. Do this until you hit 0 or have an upper and lower limit on the value. From there try the middle, and half that interval until the size of the interval is 1, at which point you have the correct value.

In some quick tests with 300 players and the roster [QB, WR, WR, WR, RB, RB, TE, K, DST], binary search works around 3 times as fast as stepping up from 0 for top players (players with a bid up value significantly larger than 0). However for later players, the difference is basically nonexistent since they almost always have a bid up value of 0, in which case both methods use just 1 optimiser call anyway.

Eirik, this is helpful. I now agree that my discussion above doesn’t take enough factors into account – e.g., given the differences existing between different positions, what players have already been drafted, etc. would make it difficult to use some sort of proxy. Given this, your binary search makes more sense (although use of a single linear program, see my reply comment above, should be more optimal yet for players not on the optimal roster).

I do however wonder how you arrive at bid-up-to values “on average 1.5 times the projected cost.” It seems to me that this can only be the case for players on your optimal roster already – otherwise, if a player is optimal at 1.5x more than expected cost, he should also be optimal at his expected cost, and therefore on the optimal roster? And even for players on the optimal roster, I have not seen instances where the bid-up-to value is so high. What sort of projections and optimal rosters do you use when getting these results?

Yes now that I see your entire comment I fully agree your method is even better, since at most you need two runs. I actually have implemented your version now, and it seems to work very well with only a few very minor differences in the computed bid up to values, so thank you for the idea.

You are of course right regarding large bid up to values. I wrote this fairly early in the morning, so I suspect i managed to invert the ratio 😉

I will have to see if I can find the time for it. I’m a bit of an R novice and unfamiliar with the packages and data setup used here; however, I’ll see if I can’t put together a couple hours to take a stab at it.

I’m wondering generally what the correct bid-up-to value is in an auction draft, for those who have run these calculations locally. I understand that it is different based on different scenarios, but lets assume that I’m speaking of the top 20 players. Should we bid +10% their expected cost? +5%?

I can’t define bid-up-to value better than Isaac does in the post above: “The “bid up to” value is calculated by finding the highest cost up to which a player is still on the best lineup, as determined by the optimizer.”

Unfortunately there is no simple general formula like +10% to projected cost to compute the bid-up-to value. It is not very hard to calculate it using a computer, but you probably need some proficiency with programming.

This also means every player not selected by the optimizer will have a bid-up-to value lower than projected cost, because if not, they would have been selected by the optimizer by definition of bid up to value. Thus even in the top 20, most players will have a bid up to value lower than their projected cost. For example, in my last auction draft 18 of the top 20 players had a bid-up-to value lower than expected cost.

Initially 18 of 20 I should add, because the bid-up-to values change as players gets picked. For example, if I didn’t get one of those players, some other player in the top 20 would probably replace him in the optimizer, which means his bid-up-to value changed to at least his projected cost.

Should I use this to decide what keepers I should pick?
Below are players I’m considering keeping. The first price is what it would cost me to keep. The second price is from the the cost column in the optimizer.