import streamlit as st st.set_page_config(layout="wide") import numpy as np import pandas as pd import gspread import streamlit as st from itertools import combinations @st.cache_resource def init_conn(): scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive'] credentials = { "type": "service_account", "project_id": "model-sheets-connect", "private_key_id": st.secrets['model_sheets_connect_pk'], "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDiu1v/e6KBKOcK\ncx0KQ23nZK3ZVvADYy8u/RUn/EDI82QKxTd/DizRLIV81JiNQxDJXSzgkbwKYEDm\n48E8zGvupU8+Nk76xNPakrQKy2Y8+VJlq5psBtGchJTuUSHcXU5Mg2JhQsB376PJ\nsCw552K6Pw8fpeMDJDZuxpKSkaJR6k9G5Dhf5q8HDXnC5Rh/PRFuKJ2GGRpX7n+2\nhT/sCax0J8jfdTy/MDGiDfJqfQrOPrMKELtsGHR9Iv6F4vKiDqXpKfqH+02E9ptz\nBk+MNcbZ3m90M8ShfRu28ebebsASfarNMzc3dk7tb3utHOGXKCf4tF8yYKo7x8BZ\noO9X4gSfAgMBAAECggEAU8ByyMpSKlTCF32TJhXnVJi/kS+IhC/Qn5JUDMuk4LXr\naAEWsWO6kV/ZRVXArjmuSzuUVrXumISapM9Ps5Ytbl95CJmGDiLDwRL815nvv6k3\nUyAS8EGKjz74RpoIoH6E7EWCAzxlnUgTn+5oP9Flije97epYk3H+e2f1f5e1Nn1d\nYNe8U+1HqJgILcxA1TAUsARBfoD7+K3z/8DVPHI8IpzAh6kTHqhqC23Rram4XoQ6\nzj/ZdVBjvnKuazETfsD+Vl3jGLQA8cKQVV70xdz3xwLcNeHsbPbpGBpZUoF73c65\nkAXOrjYl0JD5yAk+hmYhXr6H9c6z5AieuZGDrhmlFQKBgQDzV6LRXmjn4854DP/J\nI82oX2GcI4eioDZPRukhiQLzYerMQBmyqZIRC+/LTCAhYQSjNgMa+ZKyvLqv48M0\n/x398op/+n3xTs+8L49SPI48/iV+mnH7k0WI/ycd4OOKh8rrmhl/0EWb9iitwJYe\nMjTV/QxNEpPBEXfR1/mvrN/lVQKBgQDuhomOxUhWVRVH6x03slmyRBn0Oiw4MW+r\nrt1hlNgtVmTc5Mu+4G0USMZwYuOB7F8xG4Foc7rIlwS7Ic83jMJxemtqAelwOLdV\nXRLrLWJfX8+O1z/UE15l2q3SUEnQ4esPHbQnZowHLm0mdL14qSVMl1mu1XfsoZ3z\nJZTQb48CIwKBgEWbzQRtKD8lKDupJEYqSrseRbK/ax43DDITS77/DWwHl33D3FYC\nMblUm8ygwxQpR4VUfwDpYXBlklWcJovzamXpSnsfcYVkkQH47NuOXPXPkXQsw+w+\nDYcJzeu7F/vZqk9I7oBkWHUrrik9zPNoUzrfPvSRGtkAoTDSwibhoc5dAoGBAMHE\nK0T/ANeZQLNuzQps6S7G4eqjwz5W8qeeYxsdZkvWThOgDd/ewt3ijMnJm5X05hOn\ni4XF1euTuvUl7wbqYx76Wv3/1ZojiNNgy7ie4rYlyB/6vlBS97F4ZxJdxMlabbCW\n6b3EMWa4EVVXKoA1sCY7IVDE+yoQ1JYsZmq45YzPAoGBANWWHuVueFGZRDZlkNlK\nh5OmySmA0NdNug3G1upaTthyaTZ+CxGliwBqMHAwpkIRPwxUJpUwBTSEGztGTAxs\nWsUOVWlD2/1JaKSmHE8JbNg6sxLilcG6WEDzxjC5dLL1OrGOXj9WhC9KX3sq6qb6\nF/j9eUXfXjAlb042MphoF3ZC\n-----END PRIVATE KEY-----\n", "client_email": "gspread-connection@model-sheets-connect.iam.gserviceaccount.com", "client_id": "100369174533302798535", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/gspread-connection%40model-sheets-connect.iam.gserviceaccount.com" } NFL_Data = st.secrets["NFL_data"] gc_con = gspread.service_account_from_dict(credentials, scope) return gc_con, NFL_Data gc, all_dk_player_projections = init_conn() game_format = {'Win Percentage': '{:.2%}','First Inning Lead Percentage': '{:.2%}', 'Fifth Inning Lead Percentage': '{:.2%}', '8+ runs': '{:.2%}', 'DK LevX': '{:.2%}', 'FD LevX': '{:.2%}'} player_roo_format = {'Top_finish': '{:.2%}','Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '20+%': '{:.2%}', '2x%': '{:.2%}', '3x%': '{:.2%}', '4x%': '{:.2%}','GPP%': '{:.2%}'} @st.cache_data(ttl = 599) def init_baselines(): sh = gc.open_by_url(all_dk_player_projections) worksheet = sh.worksheet('Site_Info') raw_display = pd.DataFrame(worksheet.get_all_records()) site_slates = raw_display worksheet = sh.worksheet('Player_Projections') raw_display = pd.DataFrame(worksheet.get_all_records()) player_stats = raw_display worksheet = sh.worksheet('DK_ROO') load_display = pd.DataFrame(worksheet.get_all_records()) load_display.replace('', np.nan, inplace=True) raw_display = load_display.dropna(subset=['Median']) dk_roo_raw = raw_display worksheet = sh.worksheet('FD_ROO') load_display = pd.DataFrame(worksheet.get_all_records()) load_display.replace('', np.nan, inplace=True) raw_display = load_display.dropna(subset=['Median']) fd_roo_raw = raw_display return site_slates, player_stats, dk_roo_raw, fd_roo_raw @st.cache_data def convert_df_to_csv(df): return df.to_csv().encode('utf-8') site_slates, player_stats, dk_roo_raw, fd_roo_raw = init_baselines() t_stamp = f"Last Update: " + str(dk_roo_raw['timestamp'][0]) + f" CST" col1, col2 = st.columns([1, 5]) tab1, tab2 = st.tabs(['Stack Finder', 'Uploads']) with tab2: st.info("The Projections file can have any columns in any order, but must contain columns explicitly named: 'Player', 'Salary', 'Position', 'Team', 'Opp', 'Median', and 'Own'.") col1, col2 = st.columns([1, 5]) with col1: proj_file = st.file_uploader("Upload Projections File", key = 'proj_uploader') if proj_file is not None: try: proj_dataframe = pd.read_csv(proj_file) except: proj_dataframe = pd.read_excel(proj_file) with col2: if proj_file is not None: st.dataframe(proj_dataframe.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True) with tab1: col1, col2 = st.columns([1, 5]) with col1: st.info(t_stamp) if st.button("Load/Reset Data", key='reset1'): st.cache_data.clear() site_slates, player_stats, dk_roo_raw, fd_roo_raw = init_baselines() t_stamp = f"Last Update: " + str(dk_roo_raw['timestamp'][0]) + f" CST" slate_var1 = st.radio("Which data are you loading?", ('Main Slate', 'Secondary Slate', 'Thurs-Mon Slate', 'User'), key='slate_var1') site_var1 = st.radio("What site are you playing?", ('Draftkings', 'Fanduel'), key='site_var1') if site_var1 == 'Draftkings': if slate_var1 == 'User': raw_baselines = proj_dataframe qb_lookup = raw_baselines[raw_baselines['Position'] == 'QB'] elif slate_var1 != 'User': raw_baselines = dk_roo_raw[dk_roo_raw['slate'] == str(slate_var1)] raw_baselines = raw_baselines[raw_baselines['version'] == 'overall'] qb_lookup = raw_baselines[raw_baselines['Position'] == 'QB'] elif site_var1 == 'Fanduel': if slate_var1 == 'User': raw_baselines = proj_dataframe qb_lookup = raw_baselines[raw_baselines['Position'] == 'QB'] elif slate_var1 != 'User': raw_baselines = fd_roo_raw[fd_roo_raw['slate'] == str(slate_var1)] raw_baselines = raw_baselines[raw_baselines['version'] == 'overall'] qb_lookup = raw_baselines[raw_baselines['Position'] == 'QB'] split_var1 = st.radio("Would you like to run stack analysis for the full slate or individual teams?", ('Full Slate Run', 'Specific Teams'), key='split_var1') if split_var1 == 'Specific Teams': team_var1 = st.multiselect('Which teams would you like to include in the analysis?', options = raw_baselines['Team'].unique(), key='team_var1') elif split_var1 == 'Full Slate Run': team_var1 = raw_baselines.Team.unique().tolist() pos_split1 = st.radio("Are you viewing all positions, specific groups, or specific positions?", ('All Positions', 'Specific Positions'), key='pos_split1') if pos_split1 == 'Specific Positions': pos_var1 = st.multiselect('What Positions would you like to view?', options = ['QB', 'WR', 'TE']) elif pos_split1 == 'All Positions': pos_var1 = 'All' if site_var1 == 'Draftkings': max_sal1 = st.number_input('Max Salary', min_value = 5000, max_value = 50000, value = 35000, step = 100, key='max_sal1') elif site_var1 == 'Fanduel': max_sal1 = st.number_input('Max Salary', min_value = 5000, max_value = 35000, value = 25000, step = 100, key='max_sal1') size_var1 = st.selectbox('What size of stacks are you analyzing?', options = ['QB+1', 'QB+2']) if size_var1 == 'QB+1': stack_size = 2 elif size_var1 == 'QB+2': stack_size = 3 team_dict = dict(zip(raw_baselines.Player, raw_baselines.Team)) proj_dict = dict(zip(raw_baselines.Player, raw_baselines.Median)) own_dict = dict(zip(raw_baselines.Player, raw_baselines.Own)) cost_dict = dict(zip(raw_baselines.Player, raw_baselines.Salary)) qb_dict = dict(zip(qb_lookup.Team, qb_lookup.Player)) with col2: stack_hold_container = st.empty() if st.button('Run stack analysis'): comb_list = [] if pos_split1 == 'All Positions': raw_baselines = raw_baselines elif pos_split1 != 'All Positions': raw_baselines = raw_baselines[raw_baselines['Position'].str.contains('|'.join(pos_var1))] for cur_team in team_var1: working_baselines = raw_baselines working_baselines = working_baselines[working_baselines['Team'] == cur_team] working_baselines = working_baselines[working_baselines['Position'] != 'RB'] working_baselines = working_baselines[working_baselines['Position'] != 'DST'] qb_var = qb_dict[cur_team] order_list = working_baselines['Player'] comb = combinations(order_list, stack_size) for i in list(comb): if qb_var in i: comb_list.append(i) comb_DF = pd.DataFrame(comb_list) if stack_size == 2: comb_DF['Team'] = comb_DF[0].map(team_dict) comb_DF['Proj'] = sum([comb_DF[0].map(proj_dict), comb_DF[1].map(proj_dict)]) comb_DF['Salary'] = sum([comb_DF[0].map(cost_dict), comb_DF[1].map(cost_dict)]) comb_DF['Own%'] = sum([comb_DF[0].map(own_dict), comb_DF[1].map(own_dict)]) elif stack_size == 3: comb_DF['Team'] = comb_DF[0].map(team_dict) comb_DF['Proj'] = sum([comb_DF[0].map(proj_dict), comb_DF[1].map(proj_dict), comb_DF[2].map(proj_dict)]) comb_DF['Salary'] = sum([comb_DF[0].map(cost_dict), comb_DF[1].map(cost_dict), comb_DF[2].map(cost_dict)]) comb_DF['Own%'] = sum([comb_DF[0].map(own_dict), comb_DF[1].map(own_dict), comb_DF[2].map(own_dict)]) elif stack_size == 4: comb_DF['Team'] = comb_DF[0].map(team_dict) comb_DF['Proj'] = sum([comb_DF[0].map(proj_dict), comb_DF[1].map(proj_dict), comb_DF[2].map(proj_dict), comb_DF[3].map(proj_dict)]) comb_DF['Salary'] = sum([comb_DF[0].map(cost_dict), comb_DF[1].map(cost_dict), comb_DF[2].map(cost_dict), comb_DF[3].map(cost_dict)]) comb_DF['Own%'] = sum([comb_DF[0].map(own_dict), comb_DF[1].map(own_dict), comb_DF[2].map(own_dict), comb_DF[3].map(own_dict)]) elif stack_size == 5: comb_DF['Team'] = comb_DF[0].map(team_dict) comb_DF['Proj'] = sum([comb_DF[0].map(proj_dict), comb_DF[1].map(proj_dict), comb_DF[2].map(proj_dict), comb_DF[3].map(proj_dict), comb_DF[4].map(proj_dict)]) comb_DF['Salary'] = sum([comb_DF[0].map(cost_dict), comb_DF[1].map(cost_dict), comb_DF[2].map(cost_dict), comb_DF[3].map(cost_dict), comb_DF[4].map(cost_dict)]) comb_DF['Own%'] = sum([comb_DF[0].map(own_dict), comb_DF[1].map(own_dict), comb_DF[2].map(own_dict), comb_DF[3].map(own_dict), comb_DF[4].map(own_dict)]) comb_DF = comb_DF.sort_values(by='Proj', ascending=False) comb_DF = comb_DF.loc[comb_DF['Salary'] <= max_sal1] cut_var = 0 if stack_size == 2: while cut_var <= int(len(comb_DF)): try: if int(cut_var) == 0: cur_proj = float(comb_DF.iat[cut_var, 3]) cur_own = float(comb_DF.iat[cut_var, 5]) elif int(cut_var) >= 1: check_own = float(comb_DF.iat[cut_var, 5]) if check_own > cur_own: comb_DF = comb_DF.drop([cut_var]) cur_own = cur_own cut_var = cut_var - 1 comb_DF = comb_DF.reset_index() comb_DF = comb_DF.drop(['index'], axis=1) elif check_own <= cur_own: cur_own = float(comb_DF.iat[cut_var, 5]) cut_var = cut_var cut_var += 1 except: cut_var += 1 elif stack_size == 3: while cut_var <= int(len(comb_DF)): try: if int(cut_var) == 0: cur_proj = float(comb_DF.iat[cut_var,4]) cur_own = float(comb_DF.iat[cut_var,6]) elif int(cut_var) >= 1: check_own = float(comb_DF.iat[cut_var,6]) if check_own > cur_own: comb_DF = comb_DF.drop([cut_var]) cur_own = cur_own cut_var = cut_var - 1 comb_DF = comb_DF.reset_index() comb_DF = comb_DF.drop(['index'], axis=1) elif check_own <= cur_own: cur_own = float(comb_DF.iat[cut_var,6]) cut_var = cut_var cut_var += 1 except: cut_var += 1 elif stack_size == 4: while cut_var <= int(len(comb_DF)): try: if int(cut_var) == 0: cur_proj = float(comb_DF.iat[cut_var,5]) cur_own = float(comb_DF.iat[cut_var,7]) elif int(cut_var) >= 1: check_own = float(comb_DF.iat[cut_var,7]) if check_own > cur_own: comb_DF = comb_DF.drop([cut_var]) cur_own = cur_own cut_var = cut_var - 1 comb_DF = comb_DF.reset_index() comb_DF = comb_DF.drop(['index'], axis=1) elif check_own <= cur_own: cur_own = float(comb_DF.iat[cut_var,7]) cut_var = cut_var cut_var += 1 except: cut_var += 1 elif stack_size == 5: while cut_var <= int(len(comb_DF)): try: if int(cut_var) == 0: cur_proj = float(comb_DF.iat[cut_var,6]) cur_own = float(comb_DF.iat[cut_var,8]) elif int(cut_var) >= 1: check_own = float(comb_DF.iat[cut_var,8]) if check_own > cur_own: comb_DF = comb_DF.drop([cut_var]) cur_own = cur_own cut_var = cut_var - 1 comb_DF = comb_DF.reset_index() comb_DF = comb_DF.drop(['index'], axis=1) elif check_own <= cur_own: cur_own = float(comb_DF.iat[cut_var,8]) cut_var = cut_var cut_var += 1 except: cut_var += 1 with stack_hold_container: stack_hold_container = st.empty() st.dataframe(comb_DF.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True) st.download_button( label="Export Tables", data=convert_df_to_csv(comb_DF), file_name='NFL_Stack_Options_export.csv', mime='text/csv', )