Rules

pydfs-lineup-optimizer allows you to set custom rules for optimizer. It has following rules:

  • Number of players from same team.
  • Number of specific positions.
  • Minimum salary cap.
  • Maximum repeating players.
  • Ownership projection constraint.
  • Restrict players from opposing team
  • Restrict players from same team
  • Force players from opposing team
  • Spacing for positions
  • Total teams
  • Minimum starters
  • Teams exposures
  • Stacking rules

Number of players from same team

For setting number of players from same team rule you should call set_players_from_one_team method of optimizer. It accepts dict where key is a team name and value is number of players for this team.

optimizer.set_players_from_one_team({'OKC': 4})

Number of specific positions

For setting specific players positions for multi-position slots optimizer has set_players_with_same_position method. It accepts dict where key is a position name and value is number of players with this position.

optimizer.set_players_with_same_position({'PG': 2})

Note

Positions rule hasn’t effect for dfs sites without multi-position slots(G, UTIL, etc.)

Minimum salary cap

You can set minimum salaries cap using set_min_salary_cap method. If you set min salary cap greater than maximum budget LineupOptimizerException will be raised.

optimizer.set_min_salary_cap(49000)

Maximum repeating players

If you want to make more random lineups you can use set_max_repeating_players method. This method adds constraint that restrict players combinations that used in previous lineup. It accepts only one argument: number of maximum repeating players.

optimizer.set_max_repeating_players(5)

Ownership projections constraint

If you want to avoid a lot of highly-owned players in your lineups you can use set_projected_ownership method. This method working with player projected_ownership field, so if you want to use this rule you should set this field for players before creating lineups. Optimizer’s set_projected_ownership method accepts 2 arguments min_projected_ownership and max_projected_ownership that are max/min percent of average ownership in generated lineup.

for player in optimizer.players:
    player.projected_ownership = 0.1
optimizer.set_projected_ownership(max_projected_ownership=0.6)

If you don’t specify projected_ownership for some players this players will not used in calculating lineup average ownership, but they can appear in result lineup.

Restrict players from opposing team

In some cases you would want to restrict creating of lineup with players from opposing teams, for example prevent of pitchers and hitters from same game. For this you can use restrict_positions_for_opposing_team method of optimizer, it accepts 2 arguments with list of positions for one team and list of positions for another and optional argument that specify max allowed players from opposing team. By default this argument is 0 but you can change it in some cases. For example if you participate in tournament with a few games.

optimizer.restrict_positions_for_opposing_team(['P'], ['C', 'SS', 'OF', '1B', '2B', '3B'])
optimizer.restrict_positions_for_opposing_team(['P'], ['C', 'SS', 'OF', '1B', '2B', '3B'], 1)  # 1 hitter from opposing team is allowed

Note

This constraint works only when players has information about upcoming game and their opponents, in other case LineupOptimizerException will be raised. So it will not work in FantasyDraft (because they doesn’t provide information about opponents) and if you write your custom players importer and don’t pass game_info parameter in players constructors.

Restrict players from same team

In some cases you would want to restrict creating of lineup with players from same team, for example prevent of 2 RB from same team. For this you can use restrict_positions_for_same_team method of optimizer, it takes tuples with 2 positions.

optimizer.restrict_positions_for_same_team(('RB', 'RB'))
optimizer.restrict_positions_for_same_team(('QB', 'DST'), ('RB', 'DST'))

Force players from opposing team

If you want to force players from opposing team you can use force_positions_for_opposing_team rule, it takes tuples with 2 positions.

optimizer.force_positions_for_opposing_team(('QB', 'WR'))

Spacing for positions

For some sports like baseball it can be useful to select players based on lineup ordering (batters hit order). This rule allow you to select players close to each other according to lineup order. For example if you want to restrict optimizer to select players within specific range.

optimizer.set_spacing_for_positions(['1B', '2B', '3B'], 3)  # This will select players close to each other in range of 3 spots. 1-3, 2-4, 3-5 etc.

Note

Because dfs sites doesn’t provide information about batters hit order you should add additional column “Roster Order” where you can set this order, or specify it in Player objects using roster_order attribute. In other case this rule will be ignored.

Total teams

You can control the total number of teams used in lineups using set_total_teams method.

optimizer.set_total_teams(min_teams=4)  # At least 4 teams should be in the lineup
optimizer.set_total_teams(max_teams=6)  # Maximum 6 teams should be in the lineup
optimizer.set_total_teams(min_teams=5, max_teams=6)  # 5 or 6 teams should be in the lineup
optimizer.set_total_teams(min_teams=5, max_teams=5)  # Exact 5 teams should be in the lineup

Minimum starters

You can force optimizer to choose minimum number of starters using set_min_starters method. For marking player as starter you can set is_confirmed_starter attribute of Player object to True or add Confirmed Starter column to csv.

optimizer.set_min_starters(4)

Teams exposures

You can set max exposures for each team it means that players from teams can be used only in a limited number of lineups. The team counted as used in the lineup if at least one player from it is in the lineup.

optimizer.set_teams_max_exposures(0.5)  # Set 0.5 exposure for all teams
optimizer.set_teams_max_exposures(0.5, exposures_by_team={'NYY': 0.8})  # Set 0.5 exposure for all teams except NYY and 0.8 exposure for NYY
optimizer.set_teams_max_exposures(exposures_by_team={'NYY': 0.8})  # Set 0.5 exposure only for NYY
optimizer.set_teams_max_exposures(exposures_by_team={'NYY': 0.5, 'NYM': 0.5}, exposure_strategy=AfterEachExposureStrategy)  # Use another exposure strategy

Stacking

pydfs-lineup-optimizer allows you to set stacking for lineups based on different rules. For this you should pass your stack object to add_stack method of optimizer. Here is a list of available types of stacks:

Team stack

You can set how many players from the same team will be in the lineup, for this you can use TeamStack. Here are examples of using it:

optimizer.add_stack(TeamStack(3))  # stack 3 players
optimizer.add_stack(TeamStack(3, for_teams=['NE', 'BAL', 'KC']))  # stack 3 players from any of specified teams
optimizer.add_stack(TeamStack(3, for_positions=['QB', 'WR', 'TE']))  # stack 3 players with any of specified positions
optimizer.add_stack(TeamStack(3, spacing=2))  # stack 3 players close to each other in range of 2 spots.
optimizer.add_stack(TeamStack(3, max_exposure=0.5))  # stack 3 players from same team with 0.5 exposure for all team stacks
optimizer.add_stack(TeamStack(3, max_exposure=0.5, max_exposure_per_team={'MIA': 0.6}))  # stack 3 players from same team with 0.5 exposure for all team stacks and 0.6 exposure for MIA

Positions stack

You also can add a stack with a known list of positions for players used in the stack. Here are examples of using it:

optimizer.add_stack(PositionsStack(['QB', 'WR']))  # stack QB and WR from same team
optimizer.add_stack(PositionsStack(['QB', ('WR', 'TE')]))  # stack QB and WR or TE from same team
optimizer.add_stack(PositionsStack(['QB', 'WR'], for_teams=['NO', 'MIA', 'KC']))  # stack QB and WR for one of provided teams
optimizer.add_stack(PositionsStack(['QB', 'WR'], max_exposure=0.5))  # stack QB and WR with 0.5 exposure for all team stacks
optimizer.add_stack(PositionsStack(['QB', 'WR'], max_exposure=0.5, max_exposure_per_team={'MIA': 0.6}))  # stack QB and WR  with 0.5 exposure for all team stacks and 0.6 exposure for MIA

Game stack

You can set how many players from the same game will be in the lineup, for this you can use GameStack.

optimizer.add_stack(GameStack(3))  # stack 3 players from the same game
optimizer.add_stack(GameStack(5, min_from_team=2))  # stack 5 players from the same game, 3 from one team and 2 from another

Custom stack

You can create your custom stacks as well. Here is example of creating custom stack so optimizer will create lineups with Rodgers/Adams or Brees/Thomas duos with 0.5 exposure:

rodgers_adams_group = PlayersGroup(optimizer.player_pool.get_players('Aaron Rodgers', 'Davante Adams'), max_exposure=0.5)
brees_thomas_group = PlayersGroup(optimizer.player_pool.get_players('Drew Brees', 'Michael Thomas'), max_exposure=0.5)
optimizer.add_stack(Stack([rodgers_adams_group, brees_thomas_group]))

Group players

You can group players in your lineups using add_players_group method of the optimizer. Here is an example:

group = PlayersGroup(optimizer.player_pool.get_players('LeBron James', 'Anthony Davis'))
optimizer.add_players_group(group)

You can use this method for ungrouping players as well. In this example maximum of one player will be in the lineup.

group = PlayersGroup(optimizer.player_pool.get_players('LeBron James', 'Anthony Davis'), max_from_group=1)
optimizer.add_players_group(group)

Also you can apply these groups conditionally based on another player selection. In the example below one of Travis Kelce or Tyreek Hill will be added to the lineup only with Patrick Mahomes or none of them will be added to the lineup. You can allow generating lineups with the provided group when the dependent player is not in the lineup, for this you can set optional argument strict_depend to False.

group = PlayersGroup(
    optimizer.player_pool.get_players('Tyreek Hill', 'Travis Kelce'),
    max_from_group=1,
    depends_on=optimizer.player_pool.get_player_by_name('Patrick Mahomes'),
    strict_depend=False, # if you want to generate lineups with Hill/Kelce but without Mahomes
)
optimizer.add_players_group(group)