Пример #1
0
def combine_player_info(player_id, dbsession=DBSESSION):
    """
    Get player's name, club, recent scores, upcoming fixtures, and
    upcoming predictions if available
    """
    info_dict = {"player_id": player_id}
    p = get_player(player_id, dbsession=dbsession)
    info_dict["player_name"] = p.name
    team = p.team(CURRENT_SEASON, NEXT_GAMEWEEK)
    info_dict["team"] = team
    # get recent scores for the player
    rs = get_recent_scores_for_player(p, dbsession=dbsession)
    recent_scores = [{"gameweek": k, "score": v} for k, v in rs.items()]
    info_dict["recent_scores"] = recent_scores
    # get upcoming fixtures
    fixtures = get_fixtures_for_player(p, dbsession=dbsession)[:3]
    info_dict["fixtures"] = []
    for f in fixtures:
        home_or_away = "home" if f.home_team == team else "away"
        opponent = f.away_team if home_or_away == "home" else f.home_team
        info_dict["fixtures"].append({
            "gameweek": f.gameweek,
            "opponent": opponent,
            "home_or_away": home_or_away
        })
    try:
        tag = get_latest_prediction_tag(dbsession=dbsession)
        predicted_points = get_predicted_points_for_player(p,
                                                           tag,
                                                           dbsession=dbsession)
        info_dict["predictions"] = predicted_points
    except (RuntimeError):
        pass
    return info_dict
Пример #2
0
def best_transfer_suggestions(n_transfer, session_id, dbsession=DBSESSION):
    """
    Use our predicted playerscores to suggest the best transfers.
    """
    n_transfer = int(n_transfer)
    if not n_transfer in range(1,3):
        raise RuntimeError("Need to choose 1 or 2 transfers")
    if not validate_session_squad(session_id, dbsession):
        raise RuntimeError("Cannot suggest transfer without complete squad")

    budget = get_session_budget(session_id, dbsession)
    players = [p["id"] for p in get_session_players(session_id, dbsession)]
    t = Team(budget)
    for p in players:
        added_ok = t.add_player(p)
        if not added_ok:
            raise RuntimeError("Cannot add player {}".format(p))
    pred_tag = get_latest_prediction_tag()
    gw=get_next_gameweek(CURRENT_SEASON, dbsession)
    if n_transfer == 1:
        new_team, pid_out, pid_in = make_optimum_transfer(t, pred_tag)
    elif n_transfer == 2:
        new_team, pid_out, pid_in = make_optimum_double_transfer(t, pred_tag)
    return {
        "transfers_out": pid_out,
        "transfers_in": pid_in
    }
Пример #3
0
def get_session_predictions(session_id, dbsession=DBSESSION):
    """
    Query the fixture and predictedscore tables for all
    players in our session squad
    """
    pids = [p["id"] for p in get_session_players(session_id, dbsession)]
    pred_tag = get_latest_prediction_tag()
    gw = NEXT_GAMEWEEK
    return {
        pid: get_session_prediction(pid, session_id, gw, pred_tag, dbsession)
        for pid in pids
    }
Пример #4
0
def get_session_predictions(session_id, dbsession=DBSESSION):
    """
    Query the fixture and predictedscore tables for all
    players in our session squad
    """
    pids = [p["id"] for p in get_session_players(session_id, dbsession)]
    pred_tag = get_latest_prediction_tag()
    gw = get_next_gameweek(CURRENT_SEASON, dbsession)
    pred_scores = {}
    for pid in players:

        pred_scores[pid] = get_session_prediction(pid, session_id, gw,
                                                  pred_tag, dbsession)
    return pred_scores
Пример #5
0
def print_team_for_next_gw(strat):
    """
    Display the team (inc. subs and captain) for the next gameweek
    """
    t = get_starting_squad()
    gameweeks_as_str = strat["points_per_gw"].keys()
    gameweeks_as_int = sorted([int(gw) for gw in gameweeks_as_str])
    next_gw = gameweeks_as_int[0]
    for pidout in strat["players_out"][str(next_gw)]:
        t.remove_player(pidout, gameweek=next_gw)
    for pidin in strat["players_in"][str(next_gw)]:
        t.add_player(pidin, gameweek=next_gw)
    tag = get_latest_prediction_tag()
    expected_points = t.get_expected_points(next_gw, tag)
    print(t)
Пример #6
0
def get_session_prediction(player_id, session_id,
                           gw=None, pred_tag=None,
                           dbsession=DBSESSION):
    """
    Query the fixture and predictedscore tables for a specified player
    """
    if not gw:
        gw = get_next_gameweek(CURRENT_SEASON, dbsession)
    if not pred_tag:
        pred_tag = get_latest_prediction_tag()
    return_dict = {
        "predicted_score": get_predicted_points_for_player(pid,
                                                           pred_tag,
                                                           CURRENT_SEASON,
                                                           dbsession)[gw],
        "fixture": get_next_fixture_for_player(pid,CURRENT_SEASON,dbsession)
    }
    return return_dict
Пример #7
0
def set_lineup(fpl_team_id=None):
    """
    Retrieve the latest lineup and apply the latest prediction to it.

    Note that this assumes that the prediction has been ran recently.
    """
    print("fpl_team_id is {}".format(fpl_team_id))
    fetcher = FPLDataFetcher(fpl_team_id)
    print("Got fetcher {}".format(fetcher.FPL_TEAM_ID))
    picks = get_lineup(fetcher)
    print("Got picks {}".format(picks))
    squad = get_lineup_from_payload(picks)
    print("got squad: {}".format(squad))

    squad.optimize_lineup(NEXT_GAMEWEEK, get_latest_prediction_tag())

    if check_proceed(squad):
        payload = build_lineup_payload(squad)
        post_lineup(payload, fetcher)
Пример #8
0
def run_optimize_squad(num_thread, weeks_ahead, fpl_team_id, dbsession,
                       chips_played):
    """
    Build the initial squad
    """
    gw_range = list(range(NEXT_GAMEWEEK, NEXT_GAMEWEEK + weeks_ahead))
    season = CURRENT_SEASON
    tag = get_latest_prediction_tag(season, tag_prefix="", dbsession=dbsession)
    with warnings.catch_warnings():
        warnings.simplefilter("ignore", TqdmWarning)
        run_optimization(
            gameweeks=gw_range,
            tag=tag,
            season=season,
            fpl_team_id=fpl_team_id,
            num_thread=num_thread,
            chip_gameweeks=chips_played,
        )
    return True
Пример #9
0
def run_make_squad(weeks_ahead, fpl_team_id, dbsession):
    """
    Build the initial squad
    """
    gw_range = list(range(NEXT_GAMEWEEK, NEXT_GAMEWEEK + weeks_ahead))
    season = CURRENT_SEASON
    tag = get_latest_prediction_tag(season, tag_prefix="", dbsession=dbsession)

    best_squad = make_new_squad_pygmo(
        gw_range,
        tag,
    )
    best_squad.get_expected_points(NEXT_GAMEWEEK, tag)
    print(best_squad)
    fill_initial_suggestion_table(best_squad,
                                  fpl_team_id,
                                  tag,
                                  season,
                                  NEXT_GAMEWEEK,
                                  dbsession=dbsession)
    return True
Пример #10
0
def main():
    parser = argparse.ArgumentParser(description="Make a squad from scratch")
    # General parameters
    parser.add_argument(
        "--budget", help="budget, in 0.1 millions", type=int, default=1000
    )
    parser.add_argument("--season", help="season, in format e.g. 1819")
    parser.add_argument("--gw_start", help="gameweek to start from", type=int)
    parser.add_argument(
        "--num_gw", help="how many gameweeks to consider", type=int, default=3
    )
    parser.add_argument(
        "--algorithm",
        help="Which optimization algorithm to use - 'normal' or 'genetic'",
        type=str,
        default="normal",
    )
    # parameters for "normal" optimization
    parser.add_argument(
        "--num_iterations",
        help="number of iterations (normal algorithm only)",
        type=int,
        default=10,
    )
    # parameters for "pygmo" optimization
    parser.add_argument(
        "--num_generations",
        help="number of generations (genetic only)",
        type=int,
        default=100,
    )
    parser.add_argument(
        "--population_size",
        help="number of candidate solutions per generation (genetic only)",
        type=int,
        default=100,
    )
    parser.add_argument(
        "--no_subs",
        help="Don't include points contribution from substitutes (genetic only)",
        action="store_true",
    )
    parser.add_argument(
        "--include_zero",
        help="Include players with zero predicted points (genetic only)",
        action="store_true",
    )
    parser.add_argument(
        "--gw_weight_type",
        help="'constant' to treat all gameweeks equally, or 'linear' to reduce weight of gameweeks with time (genetic only)",
        type=str,
        default="linear",
    )

    args = parser.parse_args()
    if args.season:
        season = args.season
    else:
        season = get_current_season()
    budget = args.budget
    if args.gw_start:
        gw_start = args.gw_start
    else:
        gw_start = NEXT_GAMEWEEK
    gw_range = list(range(gw_start, min(38, gw_start + args.num_gw)))
    tag = get_latest_prediction_tag(season)

    if args.algorithm == "normal":
        from airsenal.framework.optimization_utils import make_new_squad

        num_iterations = args.num_iterations
        best_squad = make_new_squad(args.budget, num_iterations, tag, gw_range, season)

    elif args.algorithm == "genetic":
        from airsenal.framework.optimization_pygmo import make_new_squad

        num_generations = args.num_generations
        population_size = args.population_size
        remove_zero = not args.include_zero
        gw_weight_type = args.gw_weight_type
        uda = pg.sga(gen=num_generations)
        if args.no_subs:
            sub_weights = {"GK": 0, "Outfield": (0, 0, 0)}
        else:
            sub_weights = {"GK": 0.01, "Outfield": (0.4, 0.1, 0.02)}

        best_squad = make_new_squad(
            gw_range,
            tag,
            budget=budget,
            season=season,
            remove_zero=remove_zero,
            sub_weights=sub_weights,
            uda=uda,
            population_size=population_size,
            gw_weight_type=gw_weight_type,
        )
    else:
        raise ValueError("'algorithm' must be 'normal' or 'genetic'")

    points = best_squad.get_expected_points(gw_start, tag)

    print("---------------------")
    print("Best expected points for gameweek {}: {}".format(gw_start, points))
    print("---------------------")
    print(best_squad)
Пример #11
0
def main():
    """
    The main function, to be used as entrypoint.
    """
    parser = argparse.ArgumentParser(
        description="Try some different transfer strategies")
    parser.add_argument("--weeks_ahead", help="how many weeks ahead", type=int)
    parser.add_argument("--gw_start",
                        help="first gameweek to consider",
                        type=int)
    parser.add_argument("--gw_end", help="last gameweek to consider", type=int)
    parser.add_argument("--tag",
                        help="specify a string identifying prediction set")
    parser.add_argument(
        "--wildcard_week",
        help="play wildcard in the specified week. Choose 0 for 'any week'.",
        type=int,
        default=-1,
    )
    parser.add_argument(
        "--free_hit_week",
        help="play free hit in the specified week. Choose 0 for 'any week'.",
        type=int,
        default=-1,
    )
    parser.add_argument(
        "--triple_captain_week",
        help=
        "play triple captain in the specified week. Choose 0 for 'any week'.",
        type=int,
        default=-1,
    )
    parser.add_argument(
        "--bench_boost_week",
        help="play bench_boost in the specified week. Choose 0 for 'any week'.",
        type=int,
        default=-1,
    )
    parser.add_argument("--num_free_transfers",
                        help="how many free transfers do we have",
                        type=int)
    parser.add_argument(
        "--max_hit",
        help="maximum number of points to spend on additional transfers",
        type=int,
        default=8,
    )
    parser.add_argument(
        "--allow_unused",
        help="if set, include strategies that waste free transfers",
        action="store_true",
    )
    parser.add_argument(
        "--num_iterations",
        help="how many iterations to use for Wildcard/Free Hit optimization",
        type=int,
        default=100,
    )
    parser.add_argument("--num_thread",
                        help="how many threads to use",
                        type=int,
                        default=4)
    parser.add_argument(
        "--season",
        help="what season, in format e.g. '2021'",
        type=str,
        default=CURRENT_SEASON,
    )
    parser.add_argument(
        "--profile",
        help="For developers: Profile strategy execution time",
        action="store_true",
    )
    parser.add_argument(
        "--fpl_team_id",
        help="specify fpl team id",
        type=int,
        required=False,
    )
    args = parser.parse_args()

    fpl_team_id = args.fpl_team_id or None

    sanity_check_args(args)
    season = args.season
    # default weeks ahead is not specified (or gw_end is not specified) is three
    if args.weeks_ahead:
        gameweeks = get_gameweeks_array(args.weeks_ahead)
    elif args.gw_start:
        if args.gw_end:
            gameweeks = list(range(args.gw_start, args.gw_end))
        else:
            gameweeks = list(range(args.gw_start, args.gw_start + 3))
    else:
        gameweeks = list(range(get_next_gameweek(), get_next_gameweek() + 3))

    num_iterations = args.num_iterations
    if args.num_free_transfers:
        num_free_transfers = args.num_free_transfers
    else:
        num_free_transfers = None  # will work it out in run_optimization
    tag = args.tag or get_latest_prediction_tag(season=season)
    max_total_hit = args.max_hit
    allow_unused_transfers = args.allow_unused
    num_thread = args.num_thread
    profile = args.profile or False
    chip_gameweeks = {
        "wildcard": args.wildcard_week,
        "free_hit": args.free_hit_week,
        "triple_captain": args.triple_captain_week,
        "bench_boost": args.bench_boost_week,
    }

    if not check_tag_valid(tag, gameweeks, season=season):
        print(
            "ERROR: Database does not contain predictions",
            "for all the specified optimsation gameweeks.\n",
            "Please run 'airsenal_run_prediction' first with the",
            "same input gameweeks and season you specified here.",
        )
        sys.exit(1)

    set_multiprocessing_start_method(num_thread)

    with warnings.catch_warnings():
        warnings.simplefilter("ignore", TqdmWarning)
        run_optimization(
            gameweeks,
            tag,
            season,
            fpl_team_id,
            chip_gameweeks,
            num_free_transfers,
            max_total_hit,
            allow_unused_transfers,
            2,
            num_iterations,
            num_thread,
            profile,
        )
Пример #12
0
from airsenal.framework.squad import TOTAL_PER_POSITION

from airsenal.framework.utils import (
    NEXT_GAMEWEEK,
    CURRENT_SEASON,
    get_latest_prediction_tag,
)

# -------------------------
#         INPUTS
# -------------------------
# Gameweek range and budget
gw_start = NEXT_GAMEWEEK
num_gw = 3
season = CURRENT_SEASON
tag = get_latest_prediction_tag()
budget = 1000

# Gameweek weightings - either 'constant' to treat all gameweeks equally, or 'linear'
# to reduce weight by 1/15 for each subsequent gameweek.
gw_weight_type = "linear"

# Weighting given to substitutes (GK, and 1st, 2nd, 3rd outfield sub).
# 1 means points scored by subs treated as important as points scored by the first XI
# 0 means points scored by subs not considered in optimisation
sub_weights = {"GK": 0.01, "Outfield": (0.4, 0.1, 0.02)}

# Can choose not to optimize full squad by changing the number of players per position.
# In that case, to create valid squads during the optimization, the empty slots are
# filled with dummy players. Each dummy player has a cost of 'dummy_sub_cost'.
players_per_position = TOTAL_PER_POSITION
Пример #13
0
def main():
    parser = argparse.ArgumentParser(
        description="Try some different transfer strategies")
    parser.add_argument("--weeks_ahead",
                        help="how many weeks ahead",
                        type=int,
                        default=3)
    parser.add_argument("--tag",
                        help="specify a string identifying prediction set")
    parser.add_argument("--num_iterations",
                        help="how many trials to run",
                        type=int,
                        default=100)
    parser.add_argument(
        "--allow_wildcard",
        help="include possibility of wildcarding in one of the weeks",
        action="store_true",
    )
    parser.add_argument(
        "--allow_free_hit",
        help="include possibility of playing free hit in one of the weeks",
        action="store_true",
    )
    parser.add_argument(
        "--allow_bench_boost",
        help="include possibility of playing bench boost in one of the weeks",
        action="store_true",
    )
    parser.add_argument(
        "--allow_triple_captain",
        help=
        "include possibility of playing triple captain in one of the weeks",
        action="store_true",
    )
    parser.add_argument(
        "--no_unused_transfers",
        help="don't consider strategies that waste free transfers",
        action="store_true",
    )
    parser.add_argument(
        "--max_points_hit",
        help="how many points are we prepared to lose on transfers",
        type=int,
        default=4,
    )
    parser.add_argument(
        "--num_free_transfers",
        help="how many free transfers do we have",
        type=int,
        default=1,
    )
    parser.add_argument(
        "--bank",
        help="how much money do we have in the bank (multiplied by 10)?",
        type=int,
        default=0,
    )
    parser.add_argument("--num_thread",
                        help="how many threads to use",
                        type=int,
                        default=4)
    parser.add_argument(
        "--season",
        help="what season, in format e.g. '1819'",
        type=int,
        default=CURRENT_SEASON,
    )
    parser.add_argument(
        "--profile",
        help="For developers: Profile strategy execution time",
        action="store_true",
    )

    if NEXT_GAMEWEEK == 1:
        print(("This function suggests transfers to make from "
               "an existing squad and can't be used before "
               "the season has started.\n"
               "Use 'airsenal_make_squad' to generate a "
               "starting squad instead."))
        return

    args = parser.parse_args()
    season = args.season
    num_weeks_ahead = args.weeks_ahead
    num_iterations = args.num_iterations
    allow_wildcard = args.allow_wildcard
    allow_free_hit = args.allow_free_hit
    allow_bench_boost = args.allow_bench_boost
    allow_triple_captain = args.allow_triple_captain
    allow_unused_transfers = not args.no_unused_transfers
    num_free_transfers = args.num_free_transfers
    budget = args.bank
    max_points_hit = args.max_points_hit
    if args.tag:
        tag = args.tag
    else:
        # get most recent set of predictions from DB table
        tag = get_latest_prediction_tag()

    # create the output directory for temporary json files
    # giving the points prediction for each strategy
    os.makedirs(OUTPUT_DIR, exist_ok=True)
    if len(os.listdir(OUTPUT_DIR)) > 0:
        os.system("rm " + OUTPUT_DIR + "/*")

    # first get a baseline prediction
    baseline_score, baseline_dict = get_baseline_prediction(
        num_weeks_ahead, tag)

    # create a queue that we will add strategies to, and some processes to take
    # things off it
    squeue = Queue()
    procs = []
    # create one progress bar for each thread
    progress_bars = []
    for i in range(args.num_thread):
        progress_bars.append(tqdm(total=100))
    # generate the list of transfer strategies
    strategies = generate_transfer_strategies(
        num_weeks_ahead,
        free_transfers=num_free_transfers,
        max_total_hit=max_points_hit,
        allow_wildcard=allow_wildcard,
        allow_free_hit=allow_free_hit,
        allow_bench_boost=allow_bench_boost,
        allow_triple_captain=allow_triple_captain,
        allow_unused_transfers=allow_unused_transfers,
    )
    # define overall progress bar
    total_progress = tqdm(total=len(strategies), desc="Total progress")

    # functions to be passed to subprocess to update or reset progress bars
    def reset_progress(index, strategy_string):
        if strategy_string == "DONE":
            progress_bars[index].close()
        else:
            progress_bars[index].n = 0
            progress_bars[index].desc = "strategy: " + strategy_string
            progress_bars[index].refresh()

    def update_progress(increment=1, index=None):
        if index is None:
            # outer progress bar
            nfiles = len(os.listdir(OUTPUT_DIR))
            total_progress.n = nfiles
            total_progress.refresh()
            if nfiles == len(strategies):
                total_progress.close()
                for pb in progress_bars:
                    pb.close()
        else:
            progress_bars[index].update(increment)
            progress_bars[index].refresh()

    for i in range(args.num_thread):
        processor = Process(
            target=process_strat,
            args=(
                squeue,
                i,
                num_iterations,
                tag,
                baseline_dict,
                update_progress,
                reset_progress,
                budget,
                args.profile,
            ),
        )
        processor.daemon = True
        processor.start()
        procs.append(processor)

    # add the strategies to the queue
    for strat in strategies:
        squeue.put(strat)
    for i in range(args.num_thread):
        squeue.put("DONE")
    # now rejoin the main thread
    for i, p in enumerate(procs):
        progress_bars[i].close()
        progress_bars[i] = None
        p.join()

    # find the best from all the strategies tried
    best_strategy = find_best_strat_from_json(tag)

    fill_suggestion_table(baseline_score, best_strategy, season)
    for i in range(len(procs)):
        print("\n")
    print("\n====================================\n")
    print("Baseline score: {}".format(baseline_score))
    print("Best score: {}".format(best_strategy["total_score"]))
    print_strat(best_strategy)
    print_team_for_next_gw(best_strategy)
Пример #14
0
def main():
    parser = argparse.ArgumentParser(description="Make a squad from scratch")
    # General parameters
    parser.add_argument(
        "--budget", help="budget, in 0.1 millions", type=int, default=1000
    )
    parser.add_argument("--season", help="season, in format e.g. 1819")
    parser.add_argument("--gw_start", help="gameweek to start from", type=int)
    parser.add_argument(
        "--num_gw", help="how many gameweeks to consider", type=int, default=3
    )
    parser.add_argument(
        "--algorithm",
        help="Which optimization algorithm to use - 'normal' or 'genetic'",
        type=str,
        default="genetic",
    )
    # parameters for "normal" optimization
    parser.add_argument(
        "--num_iterations",
        help="number of iterations (normal algorithm only)",
        type=int,
        default=10,
    )
    # parameters for "pygmo" optimization
    parser.add_argument(
        "--num_generations",
        help="number of generations (genetic only)",
        type=int,
        default=100,
    )
    parser.add_argument(
        "--population_size",
        help="number of candidate solutions per generation (genetic only)",
        type=int,
        default=100,
    )
    parser.add_argument(
        "--no_subs",
        help="Don't include points contribution from substitutes (genetic only)",
        action="store_true",
    )
    parser.add_argument(
        "--include_zero",
        help="Include players with zero predicted points (genetic only)",
        action="store_true",
    )
    parser.add_argument(
        "--verbose",
        help="Print details on optimsation progress",
        action="store_true",
    )
    parser.add_argument(
        "--fpl_team_id",
        help="ID for your FPL team",
        type=int,
    )
    args = parser.parse_args()
    season = args.season or get_current_season()
    budget = args.budget
    gw_start = args.gw_start or NEXT_GAMEWEEK
    gw_range = list(range(gw_start, min(38, gw_start + args.num_gw)))
    tag = get_latest_prediction_tag(season)
    if not check_tag_valid(tag, gw_range, season=season):
        print(
            "ERROR: Database does not contain predictions",
            "for all the specified optimsation gameweeks.\n",
            "Please run 'airsenal_run_prediction' first with the",
            "same input gameweeks and season you specified here.",
        )
        sys.exit(1)
    algorithm = args.algorithm
    num_iterations = args.num_iterations
    num_generations = args.num_generations
    population_size = args.population_size
    remove_zero = not args.include_zero
    verbose = args.verbose
    if args.no_subs:
        sub_weights = {"GK": 0, "Outfield": (0, 0, 0)}
    else:
        sub_weights = {"GK": 0.01, "Outfield": (0.4, 0.1, 0.02)}
    if algorithm == "genetic":
        try:
            import pygmo as pg

            uda = pg.sga(gen=num_generations)
        except ModuleNotFoundError as e:
            print(e)
            print("Defaulting to algorithm=normal instead")
            algorithm = "normal"
            uda = None
    else:
        uda = None

    best_squad = make_new_squad(
        gw_range,
        tag,
        budget=budget,
        season=season,
        algorithm=algorithm,
        remove_zero=remove_zero,
        sub_weights=sub_weights,
        uda=uda,
        population_size=population_size,
        num_iterations=num_iterations,
        verbose=verbose,
    )
    if best_squad is None:
        raise RuntimeError(
            "best_squad is None: make_new_squad failed to generate a valid team or "
            "something went wrong with the squad expected points calculation."
        )

    points = best_squad.get_expected_points(gw_start, tag)
    print("---------------------")
    print("Best expected points for gameweek {}: {}".format(gw_start, points))
    print("---------------------")
    print(best_squad)

    fpl_team_id = args.fpl_team_id or fetcher.FPL_TEAM_ID
    fill_initial_suggestion_table(
        best_squad,
        fpl_team_id,
        tag,
        season=season,
        gameweek=gw_start,
    )
Пример #15
0
def main():
    """
    The main function, to be used as entrypoint.
    """
    parser = argparse.ArgumentParser(
        description="Try some different transfer strategies")
    parser.add_argument("--weeks_ahead", help="how many weeks ahead", type=int)
    parser.add_argument("--gw_start",
                        help="first gameweek to consider",
                        type=int)
    parser.add_argument("--gw_end", help="last gameweek to consider", type=int)
    parser.add_argument("--tag",
                        help="specify a string identifying prediction set")
    parser.add_argument(
        "--allow_wildcard",
        help="include possibility of wildcarding in one of the weeks",
        action="store_true",
    )
    parser.add_argument(
        "--allow_free_hit",
        help="include possibility of playing free hit in one of the weeks",
        action="store_true",
    )
    parser.add_argument(
        "--allow_triple_captain",
        help=
        "include possibility of playing triple captain in one of the weeks",
        action="store_true",
    )
    parser.add_argument(
        "--allow_bench_boost",
        help="include possibility of playing bench boost in one of the weeks",
        action="store_true",
    )
    parser.add_argument("--num_free_transfers",
                        help="how many free transfers do we have",
                        type=int)
    parser.add_argument(
        "--num_iterations",
        help="how many iterations to use for Wildcard/Free Hit optimization",
        type=int,
        default=100,
    )
    parser.add_argument("--num_thread",
                        help="how many threads to use",
                        type=int,
                        default=4)
    parser.add_argument(
        "--season",
        help="what season, in format e.g. '2021'",
        type=str,
        default=CURRENT_SEASON,
    )
    parser.add_argument(
        "--profile",
        help="For developers: Profile strategy execution time",
        action="store_true",
    )
    args = parser.parse_args()

    args_ok = sanity_check_args(args)
    season = args.season
    if args.weeks_ahead:
        gameweeks = list(
            range(get_next_gameweek(),
                  get_next_gameweek() + args.weeks_ahead))
    else:
        gameweeks = list(range(args.gw_start, args.gw_end))
    num_iterations = args.num_iterations
    if args.allow_wildcard:
        wildcard = True
    else:
        wildcard = False
    if args.allow_free_hit:
        free_hit = True
    else:
        free_hit = False
    if args.allow_triple_captain:
        triple_captain = True
    else:
        triple_captain = False
    if args.allow_bench_boost:
        bench_boost = True
    else:
        bench_boost = False
    if args.num_free_transfers:
        num_free_transfers = args.num_free_transfers
    else:
        num_free_transfers = None  # will work it out in run_optimization
    if args.tag:
        tag = args.tag
    else:
        ## get most recent set of predictions from DB table
        tag = get_latest_prediction_tag()
    num_thread = args.num_thread
    profile = args.profile if args.profile else False

    run_optimization(
        gameweeks,
        tag,
        season,
        wildcard,
        free_hit,
        triple_captain,
        bench_boost,
        num_free_transfers,
        num_iterations,
        num_thread,
    )