From 5974ec665e893610a9b1b5a5d1e9eb90b9061ee0 Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Wed, 11 Oct 2023 00:58:56 -0500 Subject: [PATCH] Full live card gen successful --- calcs_pitcher.py | 6 ++- creation_helpers.py | 25 ++++------ live_series_update.py | 109 +++++++++++++++++++++++++++++++++++------- 3 files changed, 107 insertions(+), 33 deletions(-) diff --git a/calcs_pitcher.py b/calcs_pitcher.py index fccb14b..1dd7b06 100644 --- a/calcs_pitcher.py +++ b/calcs_pitcher.py @@ -1,4 +1,5 @@ import logging +import math import pydantic @@ -293,7 +294,10 @@ class PitchingCardRatingsModel(pydantic.BaseModel): self.walk = self.all_other_ob - self.hbp def calculate_strikouts(self, szn_strikeouts, szn_ab, szn_hits): - self.strikeout = sanitize_chance_output(self.all_outs * Decimal((szn_strikeouts * 1.2) / (szn_ab - szn_hits))) + raw_so = sanitize_chance_output(self.all_outs * Decimal((szn_strikeouts * 1.2) / (szn_ab - szn_hits))) + sum_bb_so = self.walk + raw_so + excess = sum_bb_so - Decimal(math.floor(sum_bb_so)) + self.strikeout = raw_so - excess - Decimal(.05) def calculate_other_outs(self, fb_pct, gb_pct, oppo_pct): rem_outs = Decimal(108) - self.total_chances() diff --git a/creation_helpers.py b/creation_helpers.py index e16071d..a8fbd4e 100644 --- a/creation_helpers.py +++ b/creation_helpers.py @@ -494,25 +494,20 @@ async def pd_pitchingcardratings_df(cardset_id: int): def get_total_ops(df_data): ops_vl = df_data['obp_vL'] + df_data['slg_vL'] ops_vr = df_data['obp_vR'] + df_data['slg_vR'] - return (ops_vr + ops_vl + min(ops_vl, ops_vr)) / 3 + return (ops_vr + ops_vl + max(ops_vl, ops_vr)) / 3 ratings['total_OPS'] = ratings.apply(get_total_ops, axis=1) return ratings - def new_rarity_id(df_data): - if df_data['total_OPS'] >= 1.2: - return 99 - elif df_data['total_OPS'] >= 1: - return 1 - elif df_data['total_OPS'] >= .9: - return 2 - elif df_data['total_OPS'] >= .8: - return 3 - elif df_data['total_OPS'] >= .7: - return 4 - else: - return 5 - ratings['new_rarity_id'] = ratings.apply(new_rarity_id, axis=1) + +async def pd_positions_df(cardset_id: int): + pos_query = await db_get( + 'cardpositions', params=[('cardset_id', cardset_id), ('short_output', True), ('sort', 'innings-desc')]) + if pos_query['count'] == 0: + raise ValueError('No position ratings returned from Paper Dynasty API') + all_pos = pd.DataFrame(pos_query['positions']).rename(columns={'player': 'player_id'}) + + return all_pos def get_batting_stats(file_path: str = None, start_date: datetime.datetime = None, end_date: datetime.datetime = None): diff --git a/live_series_update.py b/live_series_update.py index 47e456f..7c7db37 100644 --- a/live_series_update.py +++ b/live_series_update.py @@ -17,7 +17,7 @@ import pydantic import sys from creation_helpers import pd_players_df, get_batting_stats, pd_battingcards_df, pd_battingcardratings_df, \ - get_pitching_stats, get_pitching_peripherals, pd_pitchingcards_df, pd_pitchingcardratings_df + get_pitching_stats, get_pitching_peripherals, pd_pitchingcards_df, pd_pitchingcardratings_df, pd_positions_df from db_calls import db_get, db_put, db_post, db_patch from typing import Literal from bs4 import BeautifulSoup @@ -29,7 +29,7 @@ logging.basicConfig( format='%(asctime)s - card-creation - %(levelname)s - %(message)s', level=log_level ) -CARD_BASE_URL = 'https://pddev.manticorum.com/api/players' +CARD_BASE_URL = 'https://pddev.manticorum.com/api/v2/players' def sanitize_name(start_name: str) -> str: @@ -265,9 +265,11 @@ async def main(args): position_payload = [] def create_positions(df_data): + no_data = True for pos_data in [(df_1b, '1b'), (df_2b, '2b'), (df_3b, '3b'), (df_ss, 'ss')]: if df_data['key_bbref'] in pos_data[0].index: logging.debug(f'Running {pos_data[1]} stats for {player_data.at[df_data["key_bbref"], "p_name"]}') + no_data = False position_payload.append({ "player_id": int(player_data.at[df_data["key_bbref"], 'player_id']), "position": pos_data[1].upper(), @@ -290,6 +292,7 @@ async def main(args): of_payloads = [] for pos_data in [(df_lf, 'lf'), (df_cf, 'cf'), (df_rf, 'rf')]: if df_data["key_bbref"] in pos_data[0].index: + no_data = False of_payloads.append({ "player_id": int(player_data.at[df_data["key_bbref"], 'player_id']), "position": pos_data[1].upper(), @@ -303,6 +306,7 @@ async def main(args): of_arms.append(int(pos_data[0].at[df_data["key_bbref"], 'bis_runs_outfield'])) if df_data["key_bbref"] in df_of.index and len(of_arms) > 0 and len(of_payloads) > 0: + no_data = False error_rating = cde.get_any_error( pos_code=pos_data[1], errors=int(df_of.at[df_data["key_bbref"], 'E_def']), @@ -324,6 +328,7 @@ async def main(args): raa=int(df_c.at[df_data["key_bbref"], 'bis_runs_catcher_sb']), season_pct=season_pct ) + no_data = False position_payload.append({ "player_id": int(player_data.at[df_data["key_bbref"], 'player_id']), "position": 'C', @@ -351,6 +356,13 @@ async def main(args): ) }) + if no_data: + position_payload.append({ + "player_id": int(player_data.at[df_data["key_bbref"], 'player_id']), + "position": 'DH', + "innings": df_data['PA_vL'] + df_data['PA_vR'] + }) + if 'pull_fielding' in arg_data and arg_data['pull_fielding'].lower() == 'true': print(f'Calculating fielding lines now...') offense_stats.apply(create_positions, axis=1) @@ -503,14 +515,17 @@ async def main(args): params.extend([('cost', new_cost), ('rarity_id', new_rarity)]) if len(params) > 0: - player_updates[df_data.name] = params + if df_data.name not in player_updates.keys(): + player_updates[df_data.name] = params + else: + player_updates[df_data.name].extend(params) player_data.apply(get_player_updates, axis=1) - print(f'Sending {len(player_updates)} player updates to PD database...') - if 'post_batters' not in arg_data or arg_data['post_batters'].lower() == 'true': - for x in player_updates: - await db_patch('players', object_id=x, params=player_updates[x]) + # print(f'Sending {len(player_updates)} player updates to PD database...') + # if 'post_batters' not in arg_data or arg_data['post_batters'].lower() == 'true': + # for x in player_updates: + # await db_patch('players', object_id=x, params=player_updates[x]) print(f'Batter updates are complete') start_time_two = datetime.datetime.now() @@ -601,11 +616,12 @@ async def main(args): print(f'Cards are complete.\n\nPosting cards now...') if 'post_pitchers' not in arg_data or arg_data['post_pitchers'].lower() == 'true': resp = await db_put('pitchingcards', payload={'cards': pitching_cards}, timeout=30) - print(f'Response: {resp}\n\nMatching batting card database IDs to player stats...') + print(f'Response: {resp}\n\nMatching pitching card database IDs to player stats...') # final_pitching_stats = pd.merge( # pitching_stats, await pd_pitchingcards_df(cardset['id']), on='player_id') # final_pitching_stats.set_index('key_bbref', drop=False, inplace=True) # final_pitching_stats = final_pitching_stats.astype({'player_id': int}) + pc_df = await pd_pitchingcards_df(cardset['id']) pitching_stats = pitching_stats.merge(pc_df, how='left', on='player_id').set_index('key_bbref', drop=False) @@ -642,7 +658,7 @@ async def main(args): pitching_stats.apply(create_pit_position, axis=1) print(f'Fielding is complete.\n\nPosting positions now...') if 'post_pitchers' not in arg_data or arg_data['post_pitchers'].lower() == 'true': - resp = await db_put('cardpositions', payload={'positions': position_payload}, timeout=30) + resp = await db_put('cardpositions', payload={'positions': pit_positions}, timeout=30) print(f'Response: {resp}\n') pitching_ratings = [] @@ -712,9 +728,9 @@ async def main(args): total_ratings, on='player_id' ).set_index('player_id', drop=False) - # del total_ratings, pitching_stats + del total_ratings, pitching_stats - player_updates = {} # { : [ (param pairs) ] } + # player_updates = {} # { : [ (param pairs) ] } rarity_group = player_data.query('rarity == new_rarity_id').groupby('rarity') average_ops = rarity_group['total_OPS'].mean().to_dict() # cost_groups = rarity_group['cost'].mean() @@ -819,20 +835,79 @@ async def main(args): params.extend([('cost', new_cost), ('rarity_id', new_rarity)]) if len(params) > 0: - player_updates[df_data.name] = params + if df_data.name not in player_updates.keys(): + player_updates[df_data.name] = params + else: + player_updates[df_data.name].extend(params) player_data.apply(get_player_updates, axis=1) - print(f'Sending {len(player_updates)} player updates to PD database...') - if 'post_pitchers' not in arg_data or arg_data['post_pitchers'].lower() == 'true': - for x in player_updates: - await db_patch('players', object_id=x, params=player_updates[x]) + # print(f'Sending {len(player_updates)} player updates to PD database...') + # if 'post_pitchers' not in arg_data or arg_data['post_pitchers'].lower() == 'true': + # for x in player_updates: + # await db_patch('players', object_id=x, params=player_updates[x]) print(f'Pitcher updates are complete') + start_time_three = datetime.datetime.now() p_run_time = datetime.datetime.now() - start_time_two - t_run_time = datetime.datetime.now() - start_time print(f'Total pitching cards: {len(pitching_cards)}\nNew cardset pitchers: {len(new_players)}\n' f'Pitcher runtime: {round(p_run_time.total_seconds())} seconds\n') + + print(f'Running player position updates') + all_pos = await pd_positions_df(cardset['id']) + + def set_all_positions(df_data): + pos_series = all_pos.query(f'player_id == {df_data["player_id"]}')['position'] + pos_updates = [] + count = 1 + for this_pos in pos_series: + if this_pos == 'P': + this_pitcher = player_data.loc[df_data['player_id']] + if this_pitcher['starter_rating'] > 3: + pos_updates.append((f'pos_{count}', 'SP')) + count += 1 + if this_pitcher['relief_rating'] > 1 or not pd.isna(this_pitcher['closer_rating']): + pos_updates.append((f'pos_{count}', 'RP')) + count += 1 + else: + pos_updates.append((f'pos_{count}', 'RP')) + count += 1 + + if not pd.isna(this_pitcher['closer_rating']): + pos_updates.append((f'pos_{count}', 'CP')) + count += 1 + else: + pos_updates.append((f'pos_{count}', this_pos)) + count += 1 + + if count == 1: + pos_updates.append(('pos_1', 'DH')) + count += 1 + + while count <= 9: + pos_updates.append((f'pos_{count}', 'False')) + count += 1 + + if len(pos_updates) > 0: + if df_data.player_id not in player_updates.keys(): + player_updates[df_data.player_id] = pos_updates + else: + player_updates[df_data.player_id].extend(pos_updates) + + p_data.apply(set_all_positions, axis=1) + # Get all positions from each player in p_data and send position updates + # Consider combining all player updates into one master call to keep from updating each player twice + # (once in batter/pitcher and then here) + + print(f'Sending {len(player_updates)} player updates to PD database...') + if 'post_players' not in arg_data or arg_data['post_players'].lower() == 'true': + for x in player_updates: + await db_patch('players', object_id=x, params=player_updates[x]) + print(f'Player updates are complete\n') + + p_run_time = datetime.datetime.now() - start_time_three + print(f'Player update runtime: {round(p_run_time.total_seconds())} seconds') + t_run_time = datetime.datetime.now() - start_time print(f'Total runtime: {round(t_run_time.total_seconds())} seconds')