Multichem commited on
Commit
4713c08
1 Parent(s): 1329302

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +307 -176
app.py CHANGED
@@ -1,19 +1,8 @@
1
- import pulp
2
  import numpy as np
3
  import pandas as pd
4
- import random
5
- import sys
6
- import openpyxl
7
- import re
8
- import time
9
  import streamlit as st
10
- import matplotlib
11
- from matplotlib.colors import LinearSegmentedColormap
12
- from st_aggrid import GridOptionsBuilder, AgGrid, GridUpdateMode, DataReturnMode
13
- import json
14
- import requests
15
  import gspread
16
- import plotly.figure_factory as ff
17
 
18
  scope = ['https://www.googleapis.com/auth/spreadsheets',
19
  "https://www.googleapis.com/auth/drive"]
@@ -35,115 +24,303 @@ gc = gspread.service_account_from_dict(credentials)
35
 
36
  st.set_page_config(layout="wide")
37
 
38
- roo_format = {'Top_finish': '{:.2%}','Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}',
39
- '120+%': '{:.2%}','10x%': '{:.2%}','11x%': '{:.2%}','12x%': '{:.2%}','Own': '{:.2%}','LevX': '{:.2%}'}
40
- stat_format = {'Win%': '{:.2%}'}
41
 
42
- game_betting_model = 'https://docs.google.com/spreadsheets/d/1Yq0vGriWK-bS79e-bD6_u9pqrYE6Yrlbb_wEkmH-ot0/edit#gid=172632260'
43
- props_overall = 'DK_NBA_Props'
44
- player_overall = 'https://docs.google.com/spreadsheets/d/1Yq0vGriWK-bS79e-bD6_u9pqrYE6Yrlbb_wEkmH-ot0/edit#gid=172632260'
45
- points_overall = 'DK_Points_Props'
46
- assists_overall = 'DK_Assists_Props'
47
- rebounds_overall = 'DK_Rebounds_Props'
48
- pa_overall = 'DK_PA_Props'
49
- pr_overall = 'DK_PR_Props'
50
- pra_overall = 'DK_PRA_Props'
51
 
52
  @st.cache_data
53
- def create_player_props(URL):
54
- sh = gc.open_by_url(URL)
55
- worksheet = sh.get_worksheet(8)
56
- load_display = pd.DataFrame(worksheet.get_all_records())
57
- overall_data = load_display[['Name', 'Position', 'Team', '3P', 'Points', 'Rebounds', 'Assists', 'Steals', 'Blocks']]
58
- overall_data.rename(columns={"Name": "player"}, inplace = True)
59
- overall_data['Points + Rebounds'] = overall_data['Points'] + overall_data['Rebounds']
60
- overall_data['Points + Assists'] = overall_data['Points'] + overall_data['Assists']
61
- overall_data['Points + Rebounds + Assists'] = overall_data['Points'] + overall_data['Rebounds'] + overall_data['Assists']
62
-
63
- return overall_data
64
-
65
- @st.cache_data
66
- def load_game_betting(URL):
67
- sh = gc.open_by_url(URL)
68
- worksheet = sh.get_worksheet(1)
69
  raw_display = pd.DataFrame(worksheet.get_all_records())
 
 
70
 
71
  return raw_display
72
 
73
  @st.cache_data
74
- def load_props(URL):
75
- sh = gc.open(URL)
76
- worksheet = sh.get_worksheet(0)
77
  raw_display = pd.DataFrame(worksheet.get_all_records())
78
- raw_display.rename(columns={"player": "Player"}, inplace = True)
 
79
 
80
  return raw_display
81
 
82
  @st.cache_data
83
- def load_player_baselines(URL):
84
- sh = gc.open(URL)
85
- worksheet = sh.get_worksheet(0)
86
- raw_display = pd.DataFrame(worksheet.get_all_records())
87
 
88
  return raw_display
89
 
90
  @st.cache_data
91
- def load_stat_specific(URL):
92
- sh = gc.open(URL)
93
- worksheet = sh.get_worksheet(0)
94
  raw_display = pd.DataFrame(worksheet.get_all_records())
95
- raw_display.rename(columns={"player": "Player"}, inplace = True)
96
- raw_display = raw_display.drop(columns=['Model Probability', 'short%', 'mid%', 'long%', 's_weighted%', 'm_weighted%', 'l_weighted%', 'weighted prob%'])
97
 
98
  return raw_display
99
 
100
- team_frame = load_game_betting(game_betting_model)
101
- props_frame = create_player_props(player_overall)
 
 
 
 
 
102
 
103
- tab1, tab2, tab3, tab4 = st.tabs(["Game Betting Model", "Player Prop Baselines", "Stat Specific Props Projections", "Player Prop Simulations"])
104
 
105
  def convert_df_to_csv(df):
106
  return df.to_csv().encode('utf-8')
107
 
108
  with tab1:
109
- if st.button("Reset Data/Load Data", key='reset1'):
110
- # Clear values from *all* all in-memory and on-disk data caches:
111
- # i.e. clear values from both square and cube
112
  st.cache_data.clear()
113
- st.dataframe(team_frame.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  st.download_button(
115
- label="Export Projections",
116
- data=convert_df_to_csv(team_frame),
117
- file_name='NBA_DFS_team_frame.csv',
118
- mime='text/csv',
119
- key='team_frame',
120
  )
121
 
122
  with tab2:
123
- if st.button("Reset Data/Load Data", key='reset2'):
124
- # Clear values from *all* all in-memory and on-disk data caches:
125
- # i.e. clear values from both square and cube
126
  st.cache_data.clear()
127
- team_var1 = st.multiselect('View specific team?', options = props_frame['Team'].unique(), key = 'prop_teamvar')
128
- if team_var1:
129
- props_frame = props_frame[props_frame['Team'].isin(team_var1)]
130
- props_frame = props_frame.set_index('player')
131
- st.dataframe(props_frame.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
 
 
 
 
 
 
 
 
 
 
132
  st.download_button(
133
- label="Export Projections",
134
- data=convert_df_to_csv(props_frame),
135
- file_name='NBA_DFS_props_frame.csv',
136
- mime='text/csv',
137
- key='props_frame',
138
  )
139
 
140
  with tab3:
141
- st.write("The Stat specific models are currently not accurate due to an API issue. Apoligies!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  st.info('The Over and Under percentages are a compositve percentage based on simulations, historical performance, and implied probabilities, and may be different than you would expect based purely on the median projection. Likewise, the Edge of a bet is not the only indicator of if you should make the bet or not as the suggestion is using a base acceptable threshold to determine how much edge you should have for each stat category.')
143
- if st.button("Reset Data/Load Data", key='reset3'):
144
- # Clear values from *all* all in-memory and on-disk data caches:
145
- # i.e. clear values from both square and cube
146
  st.cache_data.clear()
 
 
 
 
 
 
147
  col1, col2 = st.columns([1, 5])
148
 
149
  with col2:
@@ -153,124 +330,81 @@ with tab3:
153
  export_container = st.empty()
154
 
155
  with col1:
156
- prop_type_var = st.selectbox('Select prop category', options = ['Points', 'Assists', 'Rebounds', 'Points + Assists', 'Points + Rebounds', 'Points + Rebounds + Assists'])
157
 
158
  if st.button('Simulate Prop Category'):
159
  with col2:
160
-
161
- with st.spinner('Wait for it...'):
162
 
163
  with df_hold_container.container():
164
 
165
- if prop_type_var == "Points":
166
- player_df = load_stat_specific(points_overall)
167
- prop_df = load_props(props_overall)
168
- prop_df = prop_df[['Player', 'points', 'over_points_line', 'under_points_line']]
169
- prop_df = prop_df.loc[prop_df['points'] > 0]
170
- prop_df['Over'] = np.where(prop_df['over_points_line'] < 0, (-(prop_df['over_points_line'])/((-(prop_df['over_points_line']))+100)), 100/(prop_df['over_points_line']+100))
171
- prop_df['Under'] = np.where(prop_df['under_points_line'] < 0, (-(prop_df['under_points_line'])/((-(prop_df['under_points_line']))+100)), 100/(prop_df['under_points_line']+100))
172
- prop_df.rename(columns={"points": "Prop"}, inplace = True)
173
- df = pd.merge(player_df, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
174
- df.rename(columns={"weighted%": "weighted"}, inplace = True)
175
- elif prop_type_var == "Assists":
176
- player_df = load_stat_specific(assists_overall)
177
- prop_df = load_props(props_overall)
178
- prop_df = prop_df[['Player', 'assists', 'over_assists_line', 'under_assists_line']]
179
- prop_df = prop_df.loc[prop_df['assists'] > 0]
180
- prop_df['Over'] = np.where(prop_df['over_assists_line'] < 0, (-(prop_df['over_assists_line'])/((-(prop_df['over_assists_line']))+100)), 100/(prop_df['over_assists_line']+100))
181
- prop_df['Under'] = np.where(prop_df['under_assists_line'] < 0, (-(prop_df['under_assists_line'])/((-(prop_df['under_assists_line']))+100)), 100/(prop_df['under_assists_line']+100))
182
- prop_df.rename(columns={"assists": "Prop"}, inplace = True)
183
- df = pd.merge(player_df, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
184
- df.rename(columns={"weighted%": "weighted"}, inplace = True)
185
- elif prop_type_var == "Rebounds":
186
- player_df = load_stat_specific(rebounds_overall)
187
- prop_df = load_props(props_overall)
188
- prop_df = prop_df[['Player', 'rebounds', 'over_rebounds_line', 'under_rebounds_line']]
189
- prop_df = prop_df.loc[prop_df['rebounds'] > 0]
190
- prop_df['Over'] = np.where(prop_df['over_rebounds_line'] < 0, (-(prop_df['over_rebounds_line'])/((-(prop_df['over_rebounds_line']))+100)), 100/(prop_df['over_rebounds_line']+100))
191
- prop_df['Under'] = np.where(prop_df['under_rebounds_line'] < 0, (-(prop_df['under_rebounds_line'])/((-(prop_df['under_rebounds_line']))+100)), 100/(prop_df['under_rebounds_line']+100))
192
- prop_df.rename(columns={"rebounds": "Prop"}, inplace = True)
193
- df = pd.merge(player_df, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
194
- df.rename(columns={"weighted%": "weighted"}, inplace = True)
195
- elif prop_type_var == "Points + Assists":
196
- player_df = load_stat_specific(pa_overall)
197
- prop_df = load_props(props_overall)
198
- prop_df = prop_df[['Player', 'points_assists', 'over_points_assists_line', 'under_points_assists_line']]
199
- prop_df = prop_df.loc[prop_df['points_assists'] > 0]
200
- prop_df['Over'] = np.where(prop_df['over_points_assists_line'] < 0, (-(prop_df['over_points_assists_line'])/((-(prop_df['over_points_assists_line']))+100)), 100/(prop_df['over_points_assists_line']+100))
201
- prop_df['Under'] = np.where(prop_df['under_points_assists_line'] < 0, (-(prop_df['under_points_assists_line'])/((-(prop_df['under_points_assists_line']))+100)), 100/(prop_df['under_points_assists_line']+100))
202
- prop_df.rename(columns={"points_assists": "Prop"}, inplace = True)
203
- df = pd.merge(player_df, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
204
- df.rename(columns={"weighted%": "weighted"}, inplace = True)
205
- elif prop_type_var == "Points + Rebounds":
206
- player_df = load_stat_specific(pr_overall)
207
- prop_df = load_props(props_overall)
208
- prop_df = prop_df[['Player', 'points_rebounds', 'over_points_rebounds_line', 'under_points_rebounds_line']]
209
- prop_df = prop_df.loc[prop_df['points_rebounds'] > 0]
210
- prop_df['Over'] = np.where(prop_df['over_points_rebounds_line'] < 0, (-(prop_df['over_points_rebounds_line'])/((-(prop_df['over_points_rebounds_line']))+100)), 100/(prop_df['over_points_rebounds_line']+100))
211
- prop_df['Under'] = np.where(prop_df['under_points_rebounds_line'] < 0, (-(prop_df['under_points_rebounds_line'])/((-(prop_df['under_points_rebounds_line']))+100)), 100/(prop_df['under_points_rebounds_line']+100))
212
- prop_df.rename(columns={"points_rebounds": "Prop"}, inplace = True)
213
- prop_df = prop_df[['Player', 'Prop', 'Over', 'Under']]
214
- df = pd.merge(player_df, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
215
- df.rename(columns={"weighted%": "weighted"}, inplace = True)
216
- elif prop_type_var == "Points + Rebounds + Assists":
217
- player_df = load_stat_specific(pra_overall)
218
- prop_df = load_props(props_overall)
219
- prop_df = prop_df[['Player', 'points_rebounds_assists', 'over_points_rebounds_assists_line', 'under_points_rebounds_assists_line']]
220
- prop_df = prop_df.loc[prop_df['points_rebounds_assists'] > 0]
221
- prop_df['Over'] = np.where(prop_df['over_points_rebounds_assists_line'] < 0, (-(prop_df['over_points_rebounds_assists_line'])/((-(prop_df['over_points_rebounds_assists_line']))+100)), 100/(prop_df['over_points_rebounds_assists_line']+100))
222
- prop_df['Under'] = np.where(prop_df['under_points_rebounds_assists_line'] < 0, (-(prop_df['under_points_rebounds_assists_line'])/((-(prop_df['under_points_rebounds_assists_line']))+100)), 100/(prop_df['under_points_rebounds_assists_line']+100))
223
- prop_df.rename(columns={"points_rebounds_assists": "Prop"}, inplace = True)
224
- prop_df = prop_df[['Player', 'Prop', 'Over', 'Under']]
225
- df = pd.merge(player_df, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
226
- df.rename(columns={"weighted%": "weighted"}, inplace = True)
227
 
228
  prop_dict = dict(zip(df.Player, df.Prop))
229
  over_dict = dict(zip(df.Player, df.Over))
230
  under_dict = dict(zip(df.Player, df.Under))
231
- weighted_dict = dict(zip(df.Player, df.weighted))
232
 
233
  total_sims = 1000
234
 
235
  df.replace("", 0, inplace=True)
236
 
237
- if prop_type_var == "Points":
238
- df['Median'] = df['Points']
239
- elif prop_type_var == "Assists":
240
- df['Median'] = df['Assists']
241
- elif prop_type_var == "Rebounds":
242
- df['Median'] = df['Rebounds']
243
- elif prop_type_var == "Points + Assists":
244
- df['Median'] = df['Points + Assists']
245
- elif prop_type_var == "Points + Rebounds":
246
- df['Median'] = df['Points + Rebounds']
247
- elif prop_type_var == "Points + Rebounds + Assists":
248
- df['Median'] = df['Points + Rebounds + Assists']
249
 
250
  flex_file = df
251
  flex_file['Floor'] = flex_file['Median'] * .20
252
- flex_file['Ceiling'] = flex_file['Median'] + (flex_file['Median'] * .20)
253
- flex_file['STD'] = (flex_file['Median'] / 4)
254
  flex_file['Prop'] = flex_file['Player'].map(prop_dict)
255
  flex_file = flex_file[['Player', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD']]
256
 
257
  hold_file = flex_file
258
  overall_file = flex_file
259
  prop_file = flex_file
260
-
261
  overall_players = overall_file[['Player']]
262
 
263
  for x in range(0,total_sims):
264
  prop_file[x] = prop_file['Prop']
265
 
266
- prop_file = prop_file.drop(['Player', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
267
- prop_file.astype('int').dtypes
268
 
269
  for x in range(0,total_sims):
270
  overall_file[x] = np.random.normal(overall_file['Median'],overall_file['STD'])
271
 
272
  overall_file=overall_file.drop(['Player', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
273
- overall_file.astype('int').dtypes
274
 
275
  players_only = hold_file[['Player']]
276
 
@@ -279,19 +413,17 @@ with tab3:
279
  prop_check = (overall_file - prop_file)
280
 
281
  players_only['Mean_Outcome'] = overall_file.mean(axis=1)
282
- players_only['Weighted_over'] = players_only['Player'].map(weighted_dict)
283
- players_only['Weighted_under'] = 1 - players_only['Player'].map(weighted_dict)
284
  players_only['10%'] = overall_file.quantile(0.1, axis=1)
285
  players_only['90%'] = overall_file.quantile(0.9, axis=1)
286
- players_only['Over'] = prop_check[prop_check >= 1].count(axis=1)/float(total_sims)
287
  players_only['Imp Over'] = players_only['Player'].map(over_dict)
288
- players_only['Over%'] = players_only[["Over", "Weighted_over", "Imp Over"]].mean(axis=1)
289
- players_only['Under'] = prop_check[prop_check < 1].count(axis=1)/float(total_sims)
290
  players_only['Imp Under'] = players_only['Player'].map(under_dict)
291
- players_only['Under%'] = players_only[["Under", "Weighted_under", "Imp Under"]].mean(axis=1)
292
  players_only['Prop'] = players_only['Player'].map(prop_dict)
293
  players_only['Prop_avg'] = players_only['Prop'].mean() / 100
294
- players_only['prop_threshold'] = np.where(.25 - players_only['Prop_avg'] < .10, .10, .25 - players_only['Prop_avg'])
295
  players_only = players_only.loc[players_only['Mean_Outcome'] > 0]
296
  players_only['Over_diff'] = players_only['Over%'] - players_only['Imp Over']
297
  players_only['Under_diff'] = players_only['Under%'] - players_only['Imp Under']
@@ -316,9 +448,8 @@ with tab3:
316
  st.download_button(
317
  label="Export Projections",
318
  data=convert_df_to_csv(final_outcomes),
319
- file_name='NBA_DFS_prop_proj.csv',
320
  mime='text/csv',
321
  key='prop_proj',
322
  )
323
- with tab4:
324
- st.info('Coming soon!')
 
 
1
  import numpy as np
2
  import pandas as pd
 
 
 
 
 
3
  import streamlit as st
 
 
 
 
 
4
  import gspread
5
+ import plotly.express as px
6
 
7
  scope = ['https://www.googleapis.com/auth/spreadsheets',
8
  "https://www.googleapis.com/auth/drive"]
 
24
 
25
  st.set_page_config(layout="wide")
26
 
27
+ game_format = {'Win%': '{:.2%}', 'Vegas': '{:.2%}', 'Win% Diff': '{:.2%}'}
28
+ american_format = {'First Inning Lead Percentage': '{:.2%}', 'Fifth Inning Lead Percentage': '{:.2%}'}
 
29
 
30
+ master_hold = 'https://docs.google.com/spreadsheets/d/1I_1Ve3F4tftgfLQQoRKOJ351XfEG48s36OxXUKxmgS8/edit#gid=694077504'
 
 
 
 
 
 
 
 
31
 
32
  @st.cache_data
33
+ def game_betting_model():
34
+ sh = gc.open_by_url(master_hold)
35
+ worksheet = sh.worksheet('Game_Betting')
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  raw_display = pd.DataFrame(worksheet.get_all_records())
37
+ raw_display.replace('#DIV/0!', np.nan, inplace=True)
38
+ raw_display = raw_display.dropna()
39
 
40
  return raw_display
41
 
42
  @st.cache_data
43
+ def player_stat_table():
44
+ sh = gc.open_by_url(master_hold)
45
+ worksheet = sh.worksheet('Prop_Table')
46
  raw_display = pd.DataFrame(worksheet.get_all_records())
47
+ raw_display.replace('', np.nan, inplace=True)
48
+ raw_display = raw_display.dropna()
49
 
50
  return raw_display
51
 
52
  @st.cache_data
53
+ def timestamp_table():
54
+ sh = gc.open_by_url(master_hold)
55
+ worksheet = sh.worksheet('DK_ROO')
56
+ raw_display = worksheet.acell('U2').value
57
 
58
  return raw_display
59
 
60
  @st.cache_data
61
+ def player_prop_table():
62
+ sh = gc.open_by_url(master_hold)
63
+ worksheet = sh.worksheet('prop_frame')
64
  raw_display = pd.DataFrame(worksheet.get_all_records())
65
+ raw_display.replace('', np.nan, inplace=True)
66
+ raw_display = raw_display.dropna()
67
 
68
  return raw_display
69
 
70
+ game_model = game_betting_model()
71
+ overall_stats = player_stat_table()
72
+ qb_stats = overall_stats.loc[overall_stats['Position'] == 'QB']
73
+ non_qb_stats = overall_stats.loc[overall_stats['Position'] != 'QB']
74
+ timestamp = timestamp_table()
75
+ prop_frame = player_prop_table()
76
+ t_stamp = f"Last Update: " + str(timestamp) + f" CST"
77
 
78
+ tab1, tab2, tab3, tab4, tab5 = st.tabs(["Game Betting Model", "QB Projections", "RB/WR/TE Projections", "Player Prop Simulations", "Stat Specific Simulations"])
79
 
80
  def convert_df_to_csv(df):
81
  return df.to_csv().encode('utf-8')
82
 
83
  with tab1:
84
+ st.info(t_stamp)
85
+ if st.button("Reset Data", key='reset1'):
 
86
  st.cache_data.clear()
87
+ game_model = game_betting_model()
88
+ overall_stats = player_stat_table()
89
+ qb_stats = overall_stats.loc[overall_stats['Position'] == 'QB']
90
+ non_qb_stats = overall_stats.loc[overall_stats['Position'] != 'QB']
91
+ prop_frame = player_prop_table()
92
+ t_stamp = f"Last Update: " + str(prop_frame['timestamp'][0]) + f" CST"
93
+ line_var1 = st.radio('How would you like to display odds?', options = ['Percentage', 'American'], key='line_var1')
94
+ team_frame = game_model
95
+ if line_var1 == 'Percentage':
96
+ team_frame = team_frame[['team', 'Opp', 'Win%', 'Vegas', 'Win% Diff', 'PD Spread', 'Vegas Spread', 'Spread Diff']]
97
+ team_frame = team_frame.set_index('team')
98
+ st.dataframe(team_frame.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(game_format, precision=2), use_container_width = True)
99
+ if line_var1 == 'American':
100
+ team_frame = team_frame[['team', 'Opp', 'Win Line', 'Vegas Line', 'Line Diff', 'PD Spread', 'Vegas Spread', 'Spread Diff']]
101
+ team_frame = team_frame.set_index('team')
102
+ st.dataframe(team_frame.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
103
+
104
  st.download_button(
105
+ label="Export Team Model",
106
+ data=convert_df_to_csv(team_frame),
107
+ file_name='NFL_team_betting_export.csv',
108
+ mime='text/csv',
109
+ key='team_export',
110
  )
111
 
112
  with tab2:
113
+ st.info(t_stamp)
114
+ if st.button("Reset Data", key='reset2'):
 
115
  st.cache_data.clear()
116
+ game_model = game_betting_model()
117
+ overall_stats = player_stat_table()
118
+ qb_stats = overall_stats.loc[overall_stats['Position'] == 'QB']
119
+ non_qb_stats = overall_stats.loc[overall_stats['Position'] != 'QB']
120
+ prop_frame = player_prop_table()
121
+ t_stamp = f"Last Update: " + str(prop_frame['timestamp'][0]) + f" CST"
122
+ split_var1 = st.radio("Would you like to view all teams or specific ones?", ('All', 'Specific Teams'), key='split_var1')
123
+ if split_var1 == 'Specific Teams':
124
+ team_var1 = st.multiselect('Which teams would you like to include in the tables?', options = qb_stats['Team'].unique(), key='team_var1')
125
+ elif split_var1 == 'All':
126
+ team_var1 = qb_stats.Team.values.tolist()
127
+ qb_stats = qb_stats[qb_stats['Team'].isin(team_var1)]
128
+ qb_stats_disp = qb_stats.set_index('Player')
129
+ qb_stats_disp = qb_stats_disp.sort_values(by='PPR', ascending=False)
130
+ st.dataframe(qb_stats_disp.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
131
  st.download_button(
132
+ label="Export Prop Model",
133
+ data=convert_df_to_csv(qb_stats_disp),
134
+ file_name='NFL_qb_stats_export.csv',
135
+ mime='text/csv',
136
+ key='pitcher_prop_export',
137
  )
138
 
139
  with tab3:
140
+ st.info(t_stamp)
141
+ if st.button("Reset Data", key='reset3'):
142
+ st.cache_data.clear()
143
+ game_model = game_betting_model()
144
+ overall_stats = player_stat_table()
145
+ qb_stats = overall_stats.loc[overall_stats['Position'] == 'QB']
146
+ non_qb_stats = overall_stats.loc[overall_stats['Position'] != 'QB']
147
+ prop_frame = player_prop_table()
148
+ t_stamp = f"Last Update: " + str(prop_frame['timestamp'][0]) + f" CST"
149
+ split_var2 = st.radio("Would you like to view all teams or specific ones?", ('All', 'Specific Teams'), key='split_var2')
150
+ if split_var2 == 'Specific Teams':
151
+ team_var2 = st.multiselect('Which teams would you like to include in the tables?', options = non_qb_stats['Team'].unique(), key='team_var2')
152
+ elif split_var2 == 'All':
153
+ team_var2 = non_qb_stats.Team.values.tolist()
154
+ non_qb_stats = non_qb_stats[non_qb_stats['Team'].isin(team_var2)]
155
+ non_qb_stats_disp = non_qb_stats.set_index('Player')
156
+ non_qb_stats_disp = non_qb_stats_disp.sort_values(by='PPR', ascending=False)
157
+ st.dataframe(non_qb_stats_disp.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
158
+ st.download_button(
159
+ label="Export Prop Model",
160
+ data=convert_df_to_csv(non_qb_stats_disp),
161
+ file_name='NFL_nonqb_stats_export.csv',
162
+ mime='text/csv',
163
+ key='hitter_prop_export',
164
+ )
165
+
166
+ with tab4:
167
+ st.info(t_stamp)
168
+ if st.button("Reset Data", key='reset4'):
169
+ st.cache_data.clear()
170
+ game_model = game_betting_model()
171
+ overall_stats = player_stat_table()
172
+ qb_stats = overall_stats.loc[overall_stats['Position'] == 'QB']
173
+ non_qb_stats = overall_stats.loc[overall_stats['Position'] != 'QB']
174
+ prop_frame = player_prop_table()
175
+ t_stamp = f"Last Update: " + str(prop_frame['timestamp'][0]) + f" CST"
176
+ col1, col2 = st.columns([1, 5])
177
+
178
+ with col2:
179
+ df_hold_container = st.empty()
180
+ info_hold_container = st.empty()
181
+ plot_hold_container = st.empty()
182
+
183
+ with col1:
184
+ player_check = st.selectbox('Select player to simulate props', options = overall_stats['Player'].unique())
185
+ prop_type_var = st.selectbox('Select type of prop to simulate', options = ['Pass Yards', 'Pass TDs', 'Rush Yards', 'Rush TDs', 'Receptions', 'Rec Yards', 'Rec TDs', 'Fantasy', 'FD Fantasy', 'PrizePicks'])
186
+
187
+ ou_var = st.selectbox('Select wether it is an over or under', options = ['Over', 'Under'])
188
+ if prop_type_var == 'Pass Yards':
189
+ prop_var = st.number_input('Type in the prop offered (i.e 5.5)', min_value = 100.0, max_value = 400.5, value = 250.5, step = .5)
190
+ elif prop_type_var == 'Pass TDs':
191
+ prop_var = st.number_input('Type in the prop offered (i.e 5.5)', min_value = 0.0, max_value = 5.5, value = 1.5, step = .5)
192
+ elif prop_type_var == 'Rush Yards':
193
+ prop_var = st.number_input('Type in the prop offered (i.e 5.5)', min_value = 0.0, max_value = 155.5, value = 25.5, step = .5)
194
+ elif prop_type_var == 'Rush TDs':
195
+ prop_var = st.number_input('Type in the prop offered (i.e 5.5)', min_value = 0.0, max_value = 5.5, value = 1.5, step = .5)
196
+ elif prop_type_var == 'Receptions':
197
+ prop_var = st.number_input('Type in the prop offered (i.e 5.5)', min_value = 0.0, max_value = 15.5, value = 5.5, step = .5)
198
+ elif prop_type_var == 'Rec Yards':
199
+ prop_var = st.number_input('Type in the prop offered (i.e 5.5)', min_value = 0.0, max_value = 155.5, value = 25.5, step = .5)
200
+ elif prop_type_var == 'Rec TDs':
201
+ prop_var = st.number_input('Type in the prop offered (i.e 5.5)', min_value = 0.0, max_value = 5.5, value = 1.5, step = .5)
202
+ elif prop_type_var == 'Fantasy':
203
+ prop_var = st.number_input('Type in the prop offered (i.e 5.5)', min_value = 0.0, max_value = 50.5, value = 10.5, step = .5)
204
+ elif prop_type_var == 'FD Fantasy':
205
+ prop_var = st.number_input('Type in the prop offered (i.e 5.5)', min_value = 0.0, max_value = 50.5, value = 10.5, step = .5)
206
+ elif prop_type_var == 'PrizePicks':
207
+ prop_var = st.number_input('Type in the prop offered (i.e 5.5)', min_value = 0.0, max_value = 50.5, value = 10.5, step = .5)
208
+ line_var = st.number_input('Type in the line on the prop (i.e. -120)', min_value = -1000, max_value = 1000, value = -150, step = 1)
209
+ line_var = line_var + 1
210
+
211
+ if st.button('Simulate Prop'):
212
+ with col2:
213
+
214
+ with df_hold_container.container():
215
+
216
+ df = overall_stats
217
+
218
+ total_sims = 5000
219
+
220
+ df.replace("", 0, inplace=True)
221
+
222
+ player_var = df.loc[df['Player'] == player_check]
223
+ player_var = player_var.reset_index()
224
+
225
+ if prop_type_var == 'Pass Yards':
226
+ df['Median'] = df['pass_yards']
227
+ elif prop_type_var == 'Pass TDs':
228
+ df['Median'] = df['pass_tds']
229
+ elif prop_type_var == 'Rush Yards':
230
+ df['Median'] = df['rush_yards']
231
+ elif prop_type_var == 'Rush TDs':
232
+ df['Median'] = df['rush_tds']
233
+ elif prop_type_var == 'Receptions':
234
+ df['Median'] = df['rec']
235
+ elif prop_type_var == 'Rec Yards':
236
+ df['Median'] = df['rec_yards']
237
+ elif prop_type_var == 'Rec TDs':
238
+ df['Median'] = df['rec_tds']
239
+ elif prop_type_var == 'Fantasy':
240
+ df['Median'] = df['PPR']
241
+ elif prop_type_var == 'FD Fantasy':
242
+ df['Median'] = df['Half_PPF']
243
+ elif prop_type_var == 'PrizePicks':
244
+ df['Median'] = df['Half_PPF']
245
+
246
+ flex_file = df
247
+ flex_file['Floor'] = flex_file['Median'] * .20
248
+ flex_file['Ceiling'] = flex_file['Median'] + (flex_file['Median'] * .80)
249
+ flex_file['STD'] = flex_file['Median'] / 4
250
+ flex_file = flex_file[['Player', 'Floor', 'Median', 'Ceiling', 'STD']]
251
+
252
+ hold_file = flex_file
253
+ overall_file = flex_file
254
+ salary_file = flex_file
255
+
256
+ overall_players = overall_file[['Player']]
257
+
258
+ for x in range(0,total_sims):
259
+ overall_file[x] = np.random.normal(overall_file['Median'],overall_file['STD'])
260
+
261
+ overall_file=overall_file.drop(['Player', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
262
+ overall_file.astype('int').dtypes
263
+
264
+ players_only = hold_file[['Player']]
265
+
266
+ player_outcomes = pd.merge(players_only, overall_file, left_index=True, right_index=True)
267
+
268
+ players_only['Mean_Outcome'] = overall_file.mean(axis=1)
269
+ players_only['10%'] = overall_file.quantile(0.1, axis=1)
270
+ players_only['90%'] = overall_file.quantile(0.9, axis=1)
271
+ if ou_var == 'Over':
272
+ players_only['beat_prop'] = overall_file[overall_file > prop_var].count(axis=1)/float(total_sims)
273
+ elif ou_var == 'Under':
274
+ players_only['beat_prop'] = (overall_file[overall_file < prop_var].count(axis=1)/float(total_sims))
275
+
276
+ players_only['implied_odds'] = np.where(line_var <= 0, (-(line_var)/((-(line_var))+100)), 100/(line_var+100))
277
+
278
+ players_only['Player'] = hold_file[['Player']]
279
+
280
+ final_outcomes = players_only[['Player', '10%', 'Mean_Outcome', '90%', 'implied_odds', 'beat_prop']]
281
+ final_outcomes['Bet?'] = np.where(final_outcomes['beat_prop'] - final_outcomes['implied_odds'] >= .10, "Bet", "No Bet")
282
+ final_outcomes = final_outcomes.loc[final_outcomes['Player'] == player_check]
283
+ player_outcomes = player_outcomes.loc[player_outcomes['Player'] == player_check]
284
+ player_outcomes = player_outcomes.drop(columns=['Player']).transpose()
285
+ player_outcomes = player_outcomes.reset_index()
286
+ player_outcomes.columns = ['Instance', 'Outcome']
287
+
288
+ x1 = player_outcomes.Outcome.to_numpy()
289
+
290
+ print(x1)
291
+
292
+ hist_data = [x1]
293
+
294
+ group_labels = ['player outcomes']
295
+
296
+ fig = px.histogram(
297
+ player_outcomes, x='Outcome')
298
+ fig.add_vline(x=prop_var, line_dash="dash", line_color="green")
299
+
300
+ with df_hold_container:
301
+ df_hold_container = st.empty()
302
+ format_dict = {'10%': '{:.2f}', 'Mean_Outcome': '{:.2f}','90%': '{:.2f}', 'beat_prop': '{:.2%}','implied_odds': '{:.2%}'}
303
+ st.dataframe(final_outcomes.style.format(format_dict), use_container_width = True)
304
+
305
+ with info_hold_container:
306
+ st.info('The Y-axis is the percent of times in simulations that the player reaches certain thresholds, while the X-axis is the threshold to be met. The Green dotted line is the prop you entered. You can hover over any spot and see the percent to reach that mark.')
307
+
308
+ with plot_hold_container:
309
+ st.dataframe(player_outcomes, use_container_width = True)
310
+ plot_hold_container = st.empty()
311
+ st.plotly_chart(fig, use_container_width=True)
312
+
313
+ with tab5:
314
+ st.info(t_stamp)
315
  st.info('The Over and Under percentages are a compositve percentage based on simulations, historical performance, and implied probabilities, and may be different than you would expect based purely on the median projection. Likewise, the Edge of a bet is not the only indicator of if you should make the bet or not as the suggestion is using a base acceptable threshold to determine how much edge you should have for each stat category.')
316
+ if st.button("Reset Data/Load Data", key='reset5'):
 
 
317
  st.cache_data.clear()
318
+ game_model = game_betting_model()
319
+ overall_stats = player_stat_table()
320
+ qb_stats = overall_stats.loc[overall_stats['Position'] == 'QB']
321
+ non_qb_stats = overall_stats.loc[overall_stats['Position'] != 'QB']
322
+ prop_frame = player_prop_table()
323
+ t_stamp = f"Last Update: " + str(prop_frame['timestamp'][0]) + f" CST"
324
  col1, col2 = st.columns([1, 5])
325
 
326
  with col2:
 
330
  export_container = st.empty()
331
 
332
  with col1:
333
+ prop_type_var = st.selectbox('Select prop category', options = ['Pass Yards', 'Rush Yards', 'Receiving Yards'])
334
 
335
  if st.button('Simulate Prop Category'):
336
  with col2:
 
 
337
 
338
  with df_hold_container.container():
339
 
340
+ if prop_type_var == "Pass Yards":
341
+ prop_df = prop_frame[['Player', 'over_prop', 'over_line', 'under_line', 'prop_type']]
342
+ prop_df = prop_df.loc[prop_df['prop_type'] == 'pass_yards']
343
+ prop_df = prop_df[['Player', 'over_prop', 'over_line', 'under_line']]
344
+ prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
345
+ prop_df = prop_df.loc[prop_df['Prop'] != 0]
346
+ st.table(prop_df)
347
+ prop_df['Over'] = np.where(prop_df['over_line'] < 0, (-(prop_df['over_line'])/((-(prop_df['over_line']))+101)), 101/(prop_df['over_line']+101))
348
+ prop_df['Under'] = np.where(prop_df['under_line'] < 0, (-(prop_df['under_line'])/((-(prop_df['under_line']))+101)), 101/(prop_df['under_line']+101))
349
+ df = pd.merge(overall_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
350
+ elif prop_type_var == "Rush Yards":
351
+ prop_df = prop_frame[['Player', 'over_prop', 'over_line', 'under_line', 'prop_type']]
352
+ prop_df = prop_df.loc[prop_df['prop_type'] == 'rush_yards']
353
+ prop_df = prop_df[['Player', 'over_prop', 'over_line', 'under_line']]
354
+ prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
355
+ prop_df = prop_df.loc[prop_df['Prop'] != 0]
356
+ st.table(prop_df)
357
+ prop_df['Over'] = np.where(prop_df['over_line'] < 0, (-(prop_df['over_line'])/((-(prop_df['over_line']))+101)), 101/(prop_df['over_line']+101))
358
+ prop_df['Under'] = np.where(prop_df['under_line'] < 0, (-(prop_df['under_line'])/((-(prop_df['under_line']))+101)), 101/(prop_df['under_line']+101))
359
+ df = pd.merge(overall_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
360
+ elif prop_type_var == "Receiving Yards":
361
+ prop_df = prop_frame[['Player', 'over_prop', 'over_line', 'under_line', 'prop_type']]
362
+ prop_df = prop_df.loc[prop_df['prop_type'] == 'rec_yards']
363
+ prop_df = prop_df[['Player', 'over_prop', 'over_line', 'under_line']]
364
+ prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
365
+ prop_df = prop_df.loc[prop_df['Prop'] != 0]
366
+ st.table(prop_df)
367
+ prop_df['Over'] = np.where(prop_df['over_line'] < 0, (-(prop_df['over_line'])/((-(prop_df['over_line']))+101)), 101/(prop_df['over_line']+101))
368
+ prop_df['Under'] = np.where(prop_df['under_line'] < 0, (-(prop_df['under_line'])/((-(prop_df['under_line']))+101)), 101/(prop_df['under_line']+101))
369
+ df = pd.merge(overall_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370
 
371
  prop_dict = dict(zip(df.Player, df.Prop))
372
  over_dict = dict(zip(df.Player, df.Over))
373
  under_dict = dict(zip(df.Player, df.Under))
 
374
 
375
  total_sims = 1000
376
 
377
  df.replace("", 0, inplace=True)
378
 
379
+ if prop_type_var == "Pass Yards":
380
+ df['Median'] = df['pass_yards']
381
+ elif prop_type_var == "Rush Yards":
382
+ df['Median'] = df['rush_yards']
383
+ elif prop_type_var == "Receiving Yards":
384
+ df['Median'] = df['rec_yards']
 
 
 
 
 
 
385
 
386
  flex_file = df
387
  flex_file['Floor'] = flex_file['Median'] * .20
388
+ flex_file['Ceiling'] = flex_file['Median'] + (flex_file['Median'] * .80)
389
+ flex_file['STD'] = flex_file['Median'] / 4
390
  flex_file['Prop'] = flex_file['Player'].map(prop_dict)
391
  flex_file = flex_file[['Player', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD']]
392
 
393
  hold_file = flex_file
394
  overall_file = flex_file
395
  prop_file = flex_file
396
+
397
  overall_players = overall_file[['Player']]
398
 
399
  for x in range(0,total_sims):
400
  prop_file[x] = prop_file['Prop']
401
 
402
+ prop_file = prop_file.drop(['Player', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
 
403
 
404
  for x in range(0,total_sims):
405
  overall_file[x] = np.random.normal(overall_file['Median'],overall_file['STD'])
406
 
407
  overall_file=overall_file.drop(['Player', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
 
408
 
409
  players_only = hold_file[['Player']]
410
 
 
413
  prop_check = (overall_file - prop_file)
414
 
415
  players_only['Mean_Outcome'] = overall_file.mean(axis=1)
 
 
416
  players_only['10%'] = overall_file.quantile(0.1, axis=1)
417
  players_only['90%'] = overall_file.quantile(0.9, axis=1)
418
+ players_only['Over'] = prop_check[prop_check > 0].count(axis=1)/float(total_sims)
419
  players_only['Imp Over'] = players_only['Player'].map(over_dict)
420
+ players_only['Over%'] = players_only[["Over", "Imp Over"]].mean(axis=1)
421
+ players_only['Under'] = prop_check[prop_check < 0].count(axis=1)/float(total_sims)
422
  players_only['Imp Under'] = players_only['Player'].map(under_dict)
423
+ players_only['Under%'] = players_only[["Under", "Imp Under"]].mean(axis=1)
424
  players_only['Prop'] = players_only['Player'].map(prop_dict)
425
  players_only['Prop_avg'] = players_only['Prop'].mean() / 100
426
+ players_only['prop_threshold'] = .10
427
  players_only = players_only.loc[players_only['Mean_Outcome'] > 0]
428
  players_only['Over_diff'] = players_only['Over%'] - players_only['Imp Over']
429
  players_only['Under_diff'] = players_only['Under%'] - players_only['Imp Under']
 
448
  st.download_button(
449
  label="Export Projections",
450
  data=convert_df_to_csv(final_outcomes),
451
+ file_name='NFL_prop_proj.csv',
452
  mime='text/csv',
453
  key='prop_proj',
454
  )
455
+