DimaKudosh / pydfs-lineup-optimizer

Daily Fantasy Sports lineup optimzer for all popular daily fantasy sports sites
MIT License
418 stars 157 forks source link

How To Optimize With Just a BaseSettings Object #78

Closed snake-plissken closed 5 years ago

snake-plissken commented 5 years ago

Hi @DimaKudosh, I'm trying to create optimized lineups by using the BaseSettings object. The idea is to allow more flexibility with the types of game lineups without having to add new games to pydfs_lineup_optimizer.sites and support dynamic game types i.e. all FLEX or 3 QB and 3 TE.

After reading and stepping through the code I came away with the understanding that the Solver's constraints are initially set by what is in the list of LineupPosition objects returned via the pydfs_lineup_optimizer.sites lookups. And so all I would have to do is build up the LineupPosition collection and assign it to settings.BaseSettings.positions:

positions = [
        settings.LineupPosition('QB', ('QB',)),
        settings.LineupPosition('WR1', ('WR',)),
        settings.LineupPosition('WR2', ('WR',)),
        settings.LineupPosition('WR3', ('WR',)),
        settings.LineupPosition('RB1', ('RB',)),
        settings.LineupPosition('RB2', ('RB',)),
        settings.LineupPosition('TE', ('TE',)),
        settings.LineupPosition('FLEX', ('WR', 'RB', 'TE')),
        settings.LineupPosition('DST', ('DST',))
]

base_settings = settings.BaseSettings()
base_settings.site = Site.DRAFTKINGS
base_settings.sport = 'FOOTBALL'
base_settings.budget = 50000
base_settings.positions = positions

optimizer = LineupOptimizer(base_settings)
optimizer.load_players_from_csv("C:\\Salaries.csv")

lineup_generator = optimizer.optimize(10)

for lineup in lineup_generator:
    print(lineup)

I am still using the settings.BaseSettings.site and settings.BaseSettings.sport so that the correct csv importer is chosen.

When I try to print some lineups, it throws a SolverException as I am getting a -1 for prob.status in pulp_solver. What am I missing here?

DimaKudosh commented 5 years ago

Hi, for creating custom settings is better to create new settings class that inherits BaseSettings.

class CustomSettings(BaseSettings):
    site = Site.DRAFTKINGS
    budget = 50000
    sport = Sport.FOOTBALL
    positions = [
        LineupPosition('QB', ('QB', )),
        # etc
    ]

optimizer = LineupOptimizer(CustomSettings)

In you case you got SolverException. It means that pulp can't solve your optimization problem. I don't know what can cause this problem, probably some constraints for pulp are incorrect for your custom positions, please check that positions from csv and in code are matches

snake-plissken commented 5 years ago

@DimaKudosh thanks mate, it works! I'm a little rusty in the Python so I don't completely understand how inheriting from that type fixed it, but I think it was this in pydfc_lineup_optimizer.settings, it's the only thing which was different.

if TYPE_CHECKING:  # pragma: no cover
    from pydfs_lineup_optimizer.rules import OptimizerRule

But nothing in settings.py references this, so it must be accessed somewhere else?

Thanks again!

DimaKudosh commented 5 years ago

I import OptimizerRule for mypy, that checks types correctness in library

asardinha commented 5 years ago

I think this is what I was looking for in issue #71. Essentially I can designate a player to a “custom” position (i.e D=D1).

I can do a back test to confirm.