예제 #1
0
 def to_dict(t):
     return {
         "element_out": get_player(t[0][0]).fpl_api_id,
         "selling_price": t[0][1],
         "element_in": get_player(t[1][0]).fpl_api_id,
         "purchase_price": t[1][1],
     }
예제 #2
0
    def get_sell_price_for_player(
        self,
        player,
        use_api=False,
        gameweek=NEXT_GAMEWEEK,
        dbsession=None,
        apifetcher=fetcher,
    ):
        """Get sale price for player (a player in self.players) in the current
        gameweek of the current season.
        """

        player_id = player.player_id
        price_now = None
        if use_api and self.season == CURRENT_SEASON and gameweek >= NEXT_GAMEWEEK:
            try:
                # first try getting the price for the player from the API
                player_db = get_player(player_id)
                api_id = player_db.fpl_api_id
                if (apifetcher.logged_in and apifetcher.FPL_TEAM_ID
                        and apifetcher.FPL_TEAM_ID != "MISSING_ID"):
                    return apifetcher.get_current_picks(
                    )[api_id]["selling_price"]
                # if not logged in, just get current price from API
                price_now = apifetcher.get_player_summary_data(
                )[api_id]["now_cost"]
            except Exception:
                pass
        # retrieve how much we originally bought the player for from db
        price_bought = player.purchase_price

        if not price_now:
            player_db = get_player(player_id, dbsession=dbsession)

            if player_db:
                price_now = player_db.price(self.season, gameweek)
        if not price_now:
            # if all else fails just use the purchase price as the sale
            # price for this player.
            print(
                "Using purchase price as sale price for",
                player.player_id,
                player,
            )
            price_now = price_bought

        if price_now > price_bought:
            return (price_now + price_bought) // 2
        else:
            return price_now
예제 #3
0
 def to_dict(player, pos_int):
     return {
         "element": get_player(player.player_id).fpl_api_id,
         "position": pos_int,
         "is_captain": player.is_captain,
         "is_vice_captain": player.is_vice_captain,
     }
예제 #4
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
예제 #5
0
def price_transfers(transfer_player_ids, fetcher, current_gw):
    """
    For most gameweeks, we get transfer suggestions from the db, including
    both players to be removed and added.
    """

    transfers = list(zip(*transfer_player_ids))  # [(out,in),(out,in)]

    priced_transfers = [
        [
            [t[0], get_sell_price(fetcher.FPL_TEAM_ID, t[0])],
            [
                t[1],
                fetcher.get_player_summary_data()[get_player(t[1]).fpl_api_id][
                    "now_cost"
                ],
            ],
        ]
        for t in transfers
    ]

    def to_dict(t):
        return {
            "element_out": get_player(t[0][0]).fpl_api_id,
            "selling_price": t[0][1],
            "element_in": get_player(t[1][0]).fpl_api_id,
            "purchase_price": t[1][1],
        }

    transfer_list = [to_dict(transfer) for transfer in priced_transfers]
    return transfer_list
예제 #6
0
def add_players_to_db(players_from_db, players_from_api, player_data_from_api,
                      dbsession):
    print("Updating player table...")
    # find the new player(s) from the API
    api_ids_from_db = [p.fpl_api_id for p in players_from_db]
    new_players = [p for p in players_from_api if p not in api_ids_from_db]
    for player_api_id in new_players:
        first_name = player_data_from_api[player_api_id]["first_name"]
        second_name = player_data_from_api[player_api_id]["second_name"]
        name = "{} {}".format(first_name, second_name)
        # check whether we alreeady have this player in the database -
        # if yes update that player's data, if no create a new player
        p = get_player(name, dbsession=dbsession)
        if p is None:
            print("Adding player {}".format(name))
            p = Player()
            update = False
        elif p.fpl_api_id is None:
            print("Updating player {}".format(name))
            update = True
        else:
            update = True
        p.fpl_api_id = player_api_id
        p.name = name
        if not update:
            dbsession.add(p)
    dbsession.commit()
    return len(new_players)
예제 #7
0
def fill_initial_team(session,
                      season=CURRENT_SEASON,
                      tag="AIrsenal" + CURRENT_SEASON):
    """
    Fill the Transactions table in the database with the initial 15 players, and their costs,
    getting the information from the team history API endpoint (for the list of players in our team)
    and the player history API endpoint (for their price in gw1).
    """
    print("SQUAD Getting selected players for gameweek 1...")
    if NEXT_GAMEWEEK == 1:
        ### Season hasn't started yet - there won't be a team in the DB
        return True

    free_hit = free_hit_used_in_gameweek(1)
    init_players = get_players_for_gameweek(1)
    for pid in init_players:
        player_api_id = get_player(pid).fpl_api_id
        gw1_data = fetcher.get_gameweek_data_for_player(player_api_id, 1)

        if len(gw1_data) == 0:
            # Edge case where API doesn't have player data for gameweek 1, e.g. in 20/21
            # season where 4 teams didn't play gameweek 1. Calculate GW1 price from
            # API using current price and total price change.
            print(
                "Using current data to determine starting price for player {}".
                format(player_api_id))
            pdata = fetcher.get_player_summary_data()[player_api_id]
            price = pdata["now_cost"] - pdata["cost_change_start"]
        else:
            price = gw1_data[0]["value"]

        add_transaction(pid, 1, 1, price, season, tag, free_hit, session)
예제 #8
0
def test_get_player(fill_players):
    """
    test we can get a player object from either a name or an id
    """
    with test_session_scope() as tsession:
        p = get_player("Bob", tsession)
        assert isinstance(p, Player)
        assert p.player_id == 1
def fill_initial_squad(
    season=CURRENT_SEASON,
    tag="AIrsenal" + CURRENT_SEASON,
    fpl_team_id=None,
    dbsession=session,
):
    """
    Fill the Transactions table in the database with the initial 15 players, and their
    costs, getting the information from the team history API endpoint (for the list of
    players in our team) and the player history API endpoint (for their price in gw1).
    """

    if not fpl_team_id:
        fpl_team_id = fetcher.FPL_TEAM_ID
    print(
        "Getting initially selected players in squad {} for first gameweek...".
        format(fpl_team_id))
    if NEXT_GAMEWEEK == 1:
        # Season hasn't started yet - there won't be a team in the DB
        return True

    starting_gw = get_entry_start_gameweek(fpl_team_id)
    print(
        f"Got starting squad from gameweek {starting_gw}. Adding player data..."
    )

    init_players = get_players_for_gameweek(starting_gw, fpl_team_id)
    free_hit = free_hit_used_in_gameweek(starting_gw, fpl_team_id)
    time = fetcher.get_event_data()[starting_gw]["deadline"]
    for pid in init_players:
        player_api_id = get_player(pid).fpl_api_id
        first_gw_data = fetcher.get_gameweek_data_for_player(
            player_api_id, starting_gw)

        if len(first_gw_data) == 0:
            # Edge case where API doesn't have player data for gameweek 1, e.g. in 20/21
            # season where 4 teams didn't play gameweek 1. Calculate GW1 price from
            # API using current price and total price change.
            print(
                "Using current data to determine starting price for player {}".
                format(player_api_id))
            pdata = fetcher.get_player_summary_data()[player_api_id]
            price = pdata["now_cost"] - pdata["cost_change_start"]
        else:
            price = first_gw_data[0]["value"]

        add_transaction(
            pid,
            starting_gw,
            1,
            price,
            season,
            tag,
            free_hit,
            fpl_team_id,
            time,
            dbsession,
        )
예제 #10
0
    def get_sell_price_for_player(
        self,
        player,
        use_api=False,
        season=CURRENT_SEASON,
        gameweek=NEXT_GAMEWEEK,
        dbsession=None,
    ):
        """Get sale price for player (a player in self.players) in the current
        gameweek of the current season.
        """
        price_bought = player.purchase_price
        player_id = player.player_id
        price_now = None
        if use_api and season == CURRENT_SEASON and gameweek >= NEXT_GAMEWEEK:
            try:
                # first try getting the price for the player from the API
                player_db = get_player(player_id)
                price_now = fetcher.get_player_summary_data()[
                    player_db.fpl_api_id]["now_cost"]
            except:
                pass

        if not price_now:
            player_db = get_player(player_id, dbsession=dbsession)

            if player_db:
                price_now = player_db.price(season, gameweek)
        if not price_now:
            # if all else fails just use the purchase price as the sale
            # price for this player.
            print(
                "Using purchase price as sale price for",
                player.player_id,
                player.name,
            )
            price_now = price_bought

        if price_now > price_bought:
            price_sell = (price_now + price_bought) // 2
        else:
            price_sell = price_now
        return price_sell
예제 #11
0
def update_players(season, dbsession):
    """
    See if any new players have been added to FPL since we last filled the 'player'
    table in the db.  If so, add them.
    """
    players_from_db = list_players(
        position="all", team="all", season=season, dbsession=dbsession
    )
    player_data_from_api = fetcher.get_player_summary_data()
    players_from_api = list(player_data_from_api.keys())

    if len(players_from_db) == len(players_from_api):
        print("Player table already up-to-date.")
        return 0
    elif len(players_from_db) > len(players_from_api):
        raise RuntimeError(
            "Something strange has happened - more players in DB than API"
        )
    else:
        print("Updating player table...")
        # find the new player(s) from the API
        api_ids_from_db = [p.fpl_api_id for p in players_from_db]
        new_players = [p for p in players_from_api if p not in api_ids_from_db]
        for player_api_id in new_players:
            first_name = player_data_from_api[player_api_id]["first_name"]
            second_name = player_data_from_api[player_api_id]["second_name"]
            name = "{} {}".format(first_name, second_name)
            # check whether we alreeady have this player in the database -
            # if yes update that player's data, if no create a new player
            p = get_player(name, dbsession=dbsession)
            if p is None:
                print("Adding player {}".format(name))
                p = Player()
                update = False
            elif p.fpl_api_id is None:
                print("Updating player {}".format(name))
                update = True
            else:
                update = True
            p.fpl_api_id = player_api_id
            p.name = name
            if not update:
                dbsession.add(p)
        dbsession.commit()
        return len(new_players)
예제 #12
0
def price_transfers(transfer_player_ids, fetcher, current_gw):

    transfers = list(zip(*transfer_player_ids))  # [(out,in),(out,in)]

    # [[[out, price], [in, price]],[[out,price],[in,price]]]
    priced_transfers = [
        [
            [t[0], get_sell_price(fetcher.FPL_TEAM_ID, t[0])],
            [
                t[1],
                fetcher.get_player_summary_data()[get_player(t[1]).fpl_api_id][
                    "now_cost"
                ],
            ],
        ]
        for t in transfers
    ]

    return priced_transfers
예제 #13
0
파일: player.py 프로젝트: tallamjr/AIrsenal
 def __init__(
     self, player, season=CURRENT_SEASON, gameweek=NEXT_GAMEWEEK, dbsession=None
 ):
     """
     initialize either by name or by ID
     """
     self.dbsession = dbsession
     if isinstance(player, Player):
         pdata = player
     else:
         pdata = get_player(player, self.dbsession)
     self.player_id = pdata.player_id
     self.name = pdata.name
     self.team = pdata.team(season, gameweek)
     self.position = pdata.position(season)
     self.purchase_price = pdata.price(season, gameweek)
     self.is_starting = True  # by default
     self.is_captain = False  # by default
     self.is_vice_captain = False  # by default
     self.predicted_points = {}
     self.sub_position = None
def fill_attributes_table_from_file(detail_data, season, session):
    """Fill player attributes table for previous season using data from
    player detail JSON files.
    """

    for player_name in detail_data.keys():
        # find the player id in the player table.  If they're not
        # there, then we don't care (probably not a current player).
        player = get_player(player_name, dbsession=session)
        if not player:
            print("Couldn't find player {}".format(player_name))
            continue

        print("ATTRIBUTES {} {}".format(season, player.name))
        # now loop through all the fixtures that player played in
        #  Only one attributes row per gameweek - create list of gameweeks
        # encountered so can ignore duplicates (e.g. from double gameweeks).
        previous_gameweeks = []
        for fixture_data in detail_data[player_name]:
            gameweek = int(fixture_data["gameweek"])
            if gameweek in previous_gameweeks:
                # already done this gameweek
                continue
            else:
                previous_gameweeks.append(gameweek)

                pa = PlayerAttributes()
                pa.player = player
                pa.player_id = player.player_id
                pa.season = season
                pa.gameweek = gameweek
                pa.price = int(fixture_data["value"])
                pa.team = fixture_data["played_for"]
                pa.position = fixture_data["position"]
                pa.transfers_balance = int(fixture_data["transfers_balance"])
                pa.selected = int(fixture_data["selected"])
                pa.transfers_in = int(fixture_data["transfers_in"])
                pa.transfers_out = int(fixture_data["transfers_out"])
                session.add(pa)
예제 #15
0
def build_init_priced_transfers(fetcher, fpl_team_id=None):
    """
    Before gameweek 1, there won't be any 'sell' transfer suggestions in the db.
    We can instead query the API for our current 'picks' (requires login).
    """
    if not fpl_team_id:
        if (not fetcher.FPL_TEAM_ID) or fetcher.FPL_TEAM_ID == "MISSING_ID":
            fpl_team_id = int(input("Please enter FPL team ID: "))
        else:
            fpl_team_id = fetcher.FPL_TEAM_ID

    current_squad = fetcher.get_current_picks(fpl_team_id)
    transfers_out = [
        {"element_out": el["element"], "selling_price": el["selling_price"]}
        for el in current_squad
    ]
    transfer_in_suggestions = get_transfer_suggestions(dbsession)
    if len(transfers_out) != len(transfer_in_suggestions):
        raise RuntimeError(
            "Number of transfers in and out don't match: {} {}".format(
                len(transfer_in_suggestions), len(transfers_out)
            )
        )
    transfers_in = []
    for t in transfer_in_suggestions:
        api_id = get_player(t.player_id).fpl_api_id
        price = fetcher.get_player_summary_data()[api_id]["now_cost"]
        transfers_in.append({"element_in": api_id, "purchase_price": price})
    # remove duplicates - can't add a player we already have
    transfers_in, transfers_out = remove_duplicates(transfers_in, transfers_out)
    # re-order both lists so they go DEF, FWD, GK, MID
    transfers_in = sort_by_position(transfers_in)
    transfers_out = sort_by_position(transfers_out)
    transfer_list = [
        {**transfers_in[i], **transfers_out[i]} for i in range(len(transfers_in))
    ]
    return transfer_list
예제 #16
0
def calc_predicted_points_for_player(
    player,
    team_model,
    df_player,
    df_bonus,
    df_saves,
    df_cards,
    season,
    gw_range=None,
    fixtures_behind=None,
    tag="",
    dbsession=session,
):
    """
    Use the team-level model to get the probs of scoring or conceding
    N goals, and player-level model to get the chance of player scoring
    or assisting given that their team scores.
    """
    if isinstance(player, int):
        player = get_player(player, dbsession=dbsession)

    message = "Points prediction for player {}".format(player)

    if not gw_range:
        # by default, go for next three matches
        gw_range = list(range(NEXT_GAMEWEEK,
                              min(NEXT_GAMEWEEK + 3,
                                  38)))  # don't go beyond gw 38!

    if fixtures_behind is None:
        # default to getting recent minutes from the same number of matches we're
        # predicting for
        fixtures_behind = len(gw_range)

    team = player.team(
        season, gw_range[0]
    )  # assume player stays with same team from first gameweek in range
    position = player.position(season)
    fixtures = get_fixtures_for_player(player,
                                       season,
                                       gw_range=gw_range,
                                       dbsession=dbsession)

    # use same recent_minutes from previous gameweeks for all predictions
    recent_minutes = get_recent_minutes_for_player(
        player,
        num_match_to_use=fixtures_behind,
        season=season,
        last_gw=min(gw_range) - 1,
        dbsession=dbsession,
    )
    if len(recent_minutes) == 0:
        # e.g. for gameweek 1
        # this should now be dealt with in get_recent_minutes_for_player, so
        # throw error if not.
        # recent_minutes = estimate_minutes_from_prev_season(
        #    player, season=season, dbsession=session
        # )
        raise ValueError("Recent minutes is empty.")

    expected_points = defaultdict(float)  # default value is 0.
    predictions = []  # list that will hold PlayerPrediction objects

    for fixture in fixtures:
        gameweek = fixture.gameweek
        is_home = fixture.home_team == team
        opponent = fixture.away_team if is_home else fixture.home_team
        home_or_away = "at home" if is_home else "away"
        message += "\ngameweek: {} vs {}  {}".format(gameweek, opponent,
                                                     home_or_away)
        points = 0.0
        expected_points[gameweek] = points

        if sum(recent_minutes) == 0:
            # 'recent_minutes' contains the number of minutes that player played for
            # in the past few matches. If these are all zero, we will for sure predict
            # zero points for this player, so we don't need to call all the functions to
            # calculate appearance points, defending points, attacking points.
            points = 0.0

        elif player.is_injured_or_suspended(season, gw_range[0], gameweek):
            # Points for fixture will be zero if suspended or injured
            points = 0.0

        else:
            # now loop over recent minutes and average
            points = 0
            for mins in recent_minutes:
                points += (get_appearance_points(mins) + get_attacking_points(
                    player.player_id,
                    position,
                    team,
                    opponent,
                    is_home,
                    mins,
                    team_model,
                    df_player[position],
                ) + get_defending_points(position, team, opponent, is_home,
                                         mins, team_model))
                if df_bonus is not None:
                    points += get_bonus_points(player.player_id, mins,
                                               df_bonus)
                if df_cards is not None:
                    points += get_card_points(player.player_id, mins, df_cards)
                if df_saves is not None:
                    points += get_save_points(position, player.player_id, mins,
                                              df_saves)

            points = points / len(recent_minutes)

        # create the PlayerPrediction for this player+fixture
        predictions.append(make_prediction(player, fixture, points, tag))
        expected_points[gameweek] += points
        # and return the per-gameweek predictions as a dict
        message += "\nExpected points: {:.2f}".format(points)

    print(message)
    return predictions
def fill_playerscores_from_json(detail_data, season, dbsession=session):
    for player_name in detail_data.keys():
        # find the player id in the player table.  If they're not
        # there, then we don't care (probably not a current player).
        player = get_player(player_name, dbsession=dbsession)
        if not player:
            print("Couldn't find player {}".format(player_name))
            continue

        print("SCORES {} {}".format(season, player))
        # now loop through all the fixtures that player played in
        for fixture_data in detail_data[player_name]:
            # try to find the result in the result table
            gameweek = int(fixture_data["gameweek"])
            if "played_for" in fixture_data.keys():
                played_for = fixture_data["played_for"]
            else:
                played_for = player.team(season, gameweek)
            if not played_for:
                continue

            if fixture_data["was_home"] == "True":
                was_home = True
            elif fixture_data["was_home"] == "False":
                was_home = False
            else:
                was_home = None

            fixture = find_fixture(
                played_for,
                was_home=was_home,
                other_team=fixture_data["opponent"],
                gameweek=gameweek,
                season=season,
                kickoff_time=fixture_data["kickoff_time"],
                dbsession=dbsession,
            )

            if not fixture or not fixture.result:
                print("  Couldn't find result for {} in gw {}".format(
                    player, gameweek))
                continue
            ps = PlayerScore()
            ps.player_team = played_for
            ps.opponent = fixture_data["opponent"]
            ps.goals = fixture_data["goals"]
            ps.assists = fixture_data["assists"]
            ps.bonus = fixture_data["bonus"]
            ps.points = fixture_data["points"]
            ps.conceded = fixture_data["conceded"]
            ps.minutes = fixture_data["minutes"]
            ps.player = player
            ps.result = fixture.result
            ps.fixture = fixture

            # extended features
            # get features excluding the core ones already populated above
            extended_feats = [
                col for col in ps.__table__.columns.keys() if col not in [
                    "id",
                    "player_team",
                    "opponent",
                    "goals",
                    "assists",
                    "bonus",
                    "points",
                    "conceded",
                    "minutes",
                    "player_id",
                    "result_id",
                    "fixture_id",
                ]
            ]
            for feat in extended_feats:
                try:
                    ps.__setattr__(feat, fixture_data[feat])
                except KeyError:
                    pass

            dbsession.add(ps)
    dbsession.commit()