DimaKudosh / pydfs-lineup-optimizer

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

Does setting min_exposure per player no longer work? #432

Open EdCarGoes opened 5 days ago

EdCarGoes commented 5 days ago

I swear I've done this successfully many times before, but for whatever reason setting min_exposure does not seem to work at all now. I've tested with Site.DRAFTKINGS and Site.FANDUEL with Sport.FOOTBALL

Here's a snippet of my code:

player = optimizer.player_pool.get_player_by_name("Josh Allen") print(player) player.min_expossure = 0.5 lineups = list(optimizer.optimize(n=10,max_exposure=0.8))

It builds 10 lineups but Josh Allen is only in one of them. The print(player) line returns "Josh Allen QB (BUF)", showing that it is finding the player successfully. The max_exposure for the whole thing is working as no players are in lineups more than 8 times.

Am I not using this right or is there an issue somewhere?

Denwen12 commented 5 days ago

For some reason it doesn't work

On Mon, Sep 23, 2024, 1:38 PM EdCarGoes @.***> wrote:

I swear I've done this successfully many times before, but for whatever reason setting min_exposure does not seem to work at all now. I've tested with Site.DRAFTKINGS and Site.FANDUEL with Sport.FOOTBALL

Here's a snippet of my code:

player = optimizer.player_pool.get_player_by_name("Josh Allen") print(player) player.min_expossure = 0.5 lineups = list(optimizer.optimize(n=10,max_exposure=0.8))

It builds 10 lineups but Josh Allen is only in one of them. The print(player) line returns "Josh Allen QB (BUF)", showing that it is finding the player successfully. The max_exposure for the whole thing is working as no players are in lineups more than 8 times.

Am I not using this right or is there an issue somewhere?

— Reply to this email directly, view it on GitHub https://github.com/DimaKudosh/pydfs-lineup-optimizer/issues/432, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANBWO7U6K7HEUBBLRVGWT4LZYBGX3AVCNFSM6AAAAABOWSGKP6VHI2DSMVQWIX3LMV43ASLTON2WKOZSGU2DGMRVG43TKNA . You are receiving this because you are subscribed to this thread.Message ID: @.***>

Denwen12 commented 5 days ago

In the rule.py

Let’s break down potential issues in your MinExposureRule class and go over the logic step by step to understand why it might not be working as expected.

Possible Issues and Potential Fixes

  1. Tracking of min_exposure_players:

You are using a dictionary self.min_exposure_players to track how many lineups each player should be forced into based on their minimum exposure (player.min_exposure). However, after each lineup result, you're decrementing this count and deleting the player when the count reaches 0.

Issue: Deleting players from self.min_exposure_players can make the list of constraints incomplete, especially if you need to apply the rule over multiple iterations.

Fix: You might want to store the original exposure counts in a separate structure and avoid deleting players. Instead, you can simply skip players whose minimum exposure has already been met.

Example Fix:

def apply_for_iteration(self, solver, result): if not self.min_exposure_players: return if result: for player in result: if player not in self.min_exposure_players: continue self.min_exposure_players[player] -= 1

Skip players with zero remaining exposure instead of deleting

them self._create_constraints(solver)

  1. Inconsistent positions Handling:

In the constructor, you initialize self.positions using get_positions_for_optimizer(). You are passing None as the second argument, which may not be intended.

Issue: Depending on how get_positions_for_optimizer() behaves, passing None might result in incomplete or incorrect positions being returned.

Fix: Ensure that the second argument is correctly passed or handled within the function.

Example:

self.positions = get_positions_for_optimizer(optimizer.settings.positions, context)

  1. Incorrect Calculation of total_force:

The line that calculates total_force is complex, and there could be a logical issue.

Issue: The expression total_force = sum(self.min_exposure_players[p] for p in min_exposure_players) - total_for_positions (remaining_lineups - 1) might be leading to incorrect results. Specifically, the subtraction of total_for_positions (remaining_lineups - 1) may not always yield a valid constraint value.

Fix: Simplify the calculation to ensure that it reflects the correct remaining exposures relative to the number of remaining lineups.

Example Fix:

total_force = sum(self.min_exposure_players[p] for p in min_exposure_players) total_force = min(total_force, total_for_positions) # Simplified to ensure force is bounded

  1. Handling of remaining_lineups:

Issue: The division ceil(total_force / remaining_lineups) can result in unexpected constraints if the total_force is close to zero or if remaining_lineups is incorrectly managed.

Fix: Make sure that remaining_lineups is always positive and that total_force is correctly normalized for the remaining iterations.

  1. Solver Constraints:

The way you're adding constraints to the solver could be problematic if the calculation of total_force or variables is wrong.

Fix: Verify that the variables being passed to solver.add_constraint() are correct and that the total_force is appropriately bounded for the solver.

Example of Simplified Constraint Creation:

def _create_constraints(self, solver: Solver) -> None: remaining_lineups = self.context.remaining_lineups for positions, total_for_positions in self.positions.items(): min_exposure_players = [p for p in self.min_exposure_players if list_intersection(p.positions, positions)] if not min_exposure_players: continue

    # Calculate the remaining force to apply the constraint
    total_force = sum(self.min_exposure_players[p] for p in

min_exposure_players) - total_for_positions * (remaining_lineups - 1)

    if total_force > 0:
        variables = [self.players_dict[p] for p in min_exposure_players]
        total_force = min(total_force, ceil(total_force /

remaining_lineups)) # Normalizing the force solver.add_constraint(variables, None, SolverSign.GTE, total_force)

for player, total_lineups in self.min_exposure_players.items():
    if total_lineups >= remaining_lineups:
        solver.add_constraint([self.players_dict[player]], None,

SolverSign.EQ, 1)

Summary of the Main Fixes:

  1. Avoid deleting players from self.min_exposure_players. Instead, keep track of players' exposures but skip players whose minimum exposure is already met.

  2. Ensure correct handling of positions in the constructor. Make sure the get_positions_for_optimizer function receives the correct arguments.

  3. Simplify and validate the calculation of total_force. Make sure the logic of this constraint is sound and that the force is being normalized correctly.

  4. Check solver constraints. Verify that the constraints being passed are consistent with the logic and the solver's expectations.

Test the updated logic to see if it addresses the issue you’re facing. If you need further assistance, feel free to share more details about the specific problem you're encountering, such as error messages or unexpected results.

On Tue, Sep 24, 2024, 12:50 AM joseph offen @.***> wrote:

For some reason it doesn't work

On Mon, Sep 23, 2024, 1:38 PM EdCarGoes @.***> wrote:

I swear I've done this successfully many times before, but for whatever reason setting min_exposure does not seem to work at all now. I've tested with Site.DRAFTKINGS and Site.FANDUEL with Sport.FOOTBALL

Here's a snippet of my code:

player = optimizer.player_pool.get_player_by_name("Josh Allen") print(player) player.min_expossure = 0.5 lineups = list(optimizer.optimize(n=10,max_exposure=0.8))

It builds 10 lineups but Josh Allen is only in one of them. The print(player) line returns "Josh Allen QB (BUF)", showing that it is finding the player successfully. The max_exposure for the whole thing is working as no players are in lineups more than 8 times.

Am I not using this right or is there an issue somewhere?

— Reply to this email directly, view it on GitHub https://github.com/DimaKudosh/pydfs-lineup-optimizer/issues/432, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANBWO7U6K7HEUBBLRVGWT4LZYBGX3AVCNFSM6AAAAABOWSGKP6VHI2DSMVQWIX3LMV43ASLTON2WKOZSGU2DGMRVG43TKNA . You are receiving this because you are subscribed to this thread.Message ID: @.***>