Spaces:
Running
Running
James McCool
commited on
Commit
·
dfa08e1
1
Parent(s):
7ae617b
Added a Props_DB database conn, added a new tab for prop market
Browse files
app.py
CHANGED
|
@@ -51,15 +51,16 @@ def init_conn():
|
|
| 51 |
uri = st.secrets['mongo_uri']
|
| 52 |
client = pymongo.MongoClient(uri, retryWrites=True, serverSelectionTimeoutMS=100000)
|
| 53 |
db = client["NBA_DFS"]
|
|
|
|
| 54 |
|
| 55 |
NBA_Data = st.secrets['NBA_Data']
|
| 56 |
|
| 57 |
gc_con = gspread.service_account_from_dict(credentials)
|
| 58 |
gc_con2 = gspread.service_account_from_dict(credentials2)
|
| 59 |
|
| 60 |
-
return gc_con, gc_con2, db, NBA_Data
|
| 61 |
|
| 62 |
-
gcservice_account, gcservice_account2, db, NBA_Data = init_conn()
|
| 63 |
|
| 64 |
game_format = {'Paydirt Win%': '{:.2%}', 'Vegas Win%': '{:.2%}'}
|
| 65 |
prop_format = {'L5 Success': '{:.2%}', 'L10_Success': '{:.2%}', 'L20_success': '{:.2%}', 'Matchup Boost': '{:.2%}', 'Trending Over': '{:.2%}', 'Trending Under': '{:.2%}',
|
|
@@ -156,21 +157,50 @@ def init_baselines():
|
|
| 156 |
['Jaren Jackson Jr.', 'Nicolas Claxton', 'Jabari Smith Jr.', 'Luguentz Dort', 'Moritz Wagner', 'Kyle Kuzma Jr.',
|
| 157 |
'Trey Murphy III', 'Cam Thomas'], inplace=True)
|
| 158 |
|
| 159 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
|
| 161 |
def convert_df_to_csv(df):
|
| 162 |
return df.to_csv().encode('utf-8')
|
| 163 |
|
| 164 |
-
game_model, raw_baselines, player_stats, prop_frame, pick_frame, timestamp = init_baselines()
|
| 165 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 166 |
|
| 167 |
-
tab1, tab2, tab3, tab4, tab5 = st.tabs(["Game Betting Model", "Player Projections", "Prop Trend Table", "Player Prop Simulations", "Stat Specific Simulations"])
|
| 168 |
|
| 169 |
with tab1:
|
| 170 |
st.info(t_stamp)
|
| 171 |
if st.button("Reset Data", key='reset1'):
|
| 172 |
st.cache_data.clear()
|
| 173 |
-
game_model, raw_baselines, player_stats, prop_frame, pick_frame, timestamp = init_baselines()
|
| 174 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 175 |
line_var1 = st.radio('How would you like to display odds?', options = ['Percentage', 'American'], key='line_var1')
|
| 176 |
team_frame = game_model
|
|
@@ -193,9 +223,44 @@ with tab1:
|
|
| 193 |
|
| 194 |
with tab2:
|
| 195 |
st.info(t_stamp)
|
| 196 |
-
if st.button("Reset Data", key='
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 197 |
st.cache_data.clear()
|
| 198 |
-
game_model, raw_baselines, player_stats, prop_frame, pick_frame, timestamp = init_baselines()
|
| 199 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 200 |
split_var1 = st.radio("Would you like to view all teams or specific ones?", ('All', 'Specific Teams'), key='split_var1')
|
| 201 |
if split_var1 == 'Specific Teams':
|
|
@@ -213,11 +278,11 @@ with tab2:
|
|
| 213 |
mime='text/csv',
|
| 214 |
)
|
| 215 |
|
| 216 |
-
with
|
| 217 |
st.info(t_stamp)
|
| 218 |
-
if st.button("Reset Data", key='
|
| 219 |
st.cache_data.clear()
|
| 220 |
-
game_model, raw_baselines, player_stats, prop_frame, pick_frame, timestamp = init_baselines()
|
| 221 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 222 |
split_var5 = st.radio("Would you like to view all teams or specific ones?", ('All', 'Specific Teams'), key='split_var5')
|
| 223 |
if split_var5 == 'Specific Teams':
|
|
@@ -242,11 +307,11 @@ with tab3:
|
|
| 242 |
mime='text/csv',
|
| 243 |
)
|
| 244 |
|
| 245 |
-
with
|
| 246 |
st.info(t_stamp)
|
| 247 |
-
if st.button("Reset Data", key='
|
| 248 |
st.cache_data.clear()
|
| 249 |
-
game_model, raw_baselines, player_stats, prop_frame, pick_frame, timestamp = init_baselines()
|
| 250 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 251 |
col1, col2 = st.columns([1, 5])
|
| 252 |
|
|
@@ -389,12 +454,12 @@ with tab4:
|
|
| 389 |
plot_hold_container = st.empty()
|
| 390 |
st.plotly_chart(fig, use_container_width=True)
|
| 391 |
|
| 392 |
-
with
|
| 393 |
st.info(t_stamp)
|
| 394 |
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.')
|
| 395 |
if st.button("Reset Data/Load Data", key='reset6'):
|
| 396 |
st.cache_data.clear()
|
| 397 |
-
game_model, raw_baselines, player_stats, prop_frame, pick_frame, timestamp = init_baselines()
|
| 398 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 399 |
col1, col2 = st.columns([1, 5])
|
| 400 |
|
|
|
|
| 51 |
uri = st.secrets['mongo_uri']
|
| 52 |
client = pymongo.MongoClient(uri, retryWrites=True, serverSelectionTimeoutMS=100000)
|
| 53 |
db = client["NBA_DFS"]
|
| 54 |
+
prop_db = client["Props_DB"]
|
| 55 |
|
| 56 |
NBA_Data = st.secrets['NBA_Data']
|
| 57 |
|
| 58 |
gc_con = gspread.service_account_from_dict(credentials)
|
| 59 |
gc_con2 = gspread.service_account_from_dict(credentials2)
|
| 60 |
|
| 61 |
+
return gc_con, gc_con2, db, prop_db, NBA_Data
|
| 62 |
|
| 63 |
+
gcservice_account, gcservice_account2, db, prop_db, NBA_Data = init_conn()
|
| 64 |
|
| 65 |
game_format = {'Paydirt Win%': '{:.2%}', 'Vegas Win%': '{:.2%}'}
|
| 66 |
prop_format = {'L5 Success': '{:.2%}', 'L10_Success': '{:.2%}', 'L20_success': '{:.2%}', 'Matchup Boost': '{:.2%}', 'Trending Over': '{:.2%}', 'Trending Under': '{:.2%}',
|
|
|
|
| 157 |
['Jaren Jackson Jr.', 'Nicolas Claxton', 'Jabari Smith Jr.', 'Luguentz Dort', 'Moritz Wagner', 'Kyle Kuzma Jr.',
|
| 158 |
'Trey Murphy III', 'Cam Thomas'], inplace=True)
|
| 159 |
|
| 160 |
+
collection = prop_db["NBA_Props"]
|
| 161 |
+
cursor = collection.find()
|
| 162 |
+
|
| 163 |
+
raw_display = pd.DataFrame(list(cursor))
|
| 164 |
+
market_props = raw_display[['Name', 'Position', 'Projection', 'PropType', 'OddsType', 'over_pay', 'under_pay']]
|
| 165 |
+
market_props['over_prop'] = market_props['Projection']
|
| 166 |
+
market_props['over_line'] = market_props['over_pay'].apply(lambda x: (x - 1) * 100 if x >= 2.0 else -100 / (x - 1))
|
| 167 |
+
market_props['under_prop'] = market_props['Projection']
|
| 168 |
+
market_props['under_line'] = market_props['under_pay'].apply(lambda x: (x - 1) * 100 if x >= 2.0 else -100 / (x - 1))
|
| 169 |
+
|
| 170 |
+
return game_model, raw_baselines, player_stats, prop_frame, pick_frame, market_props, timestamp
|
| 171 |
+
|
| 172 |
+
def calculate_no_vig(row):
|
| 173 |
+
def implied_probability(american_odds):
|
| 174 |
+
if american_odds < 0:
|
| 175 |
+
return (-american_odds) / ((-american_odds) + 100)
|
| 176 |
+
else:
|
| 177 |
+
return 100 / (american_odds + 100)
|
| 178 |
+
|
| 179 |
+
over_line = row['over_line']
|
| 180 |
+
under_line = row['under_line']
|
| 181 |
+
over_prop = row['over_prop']
|
| 182 |
+
|
| 183 |
+
over_prob = implied_probability(over_line)
|
| 184 |
+
under_prob = implied_probability(under_line)
|
| 185 |
+
|
| 186 |
+
total_prob = over_prob + under_prob
|
| 187 |
+
no_vig_prob = (over_prob / total_prob + 0.5) * over_prop
|
| 188 |
+
|
| 189 |
+
return no_vig_prob
|
| 190 |
|
| 191 |
def convert_df_to_csv(df):
|
| 192 |
return df.to_csv().encode('utf-8')
|
| 193 |
|
| 194 |
+
game_model, raw_baselines, player_stats, prop_frame, pick_frame, market_props, timestamp = init_baselines()
|
| 195 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 196 |
|
| 197 |
+
tab1, tab2, tab3, tab4, tab5, tab6 = st.tabs(["Game Betting Model", 'Prop Market', "Player Projections", "Prop Trend Table", "Player Prop Simulations", "Stat Specific Simulations"])
|
| 198 |
|
| 199 |
with tab1:
|
| 200 |
st.info(t_stamp)
|
| 201 |
if st.button("Reset Data", key='reset1'):
|
| 202 |
st.cache_data.clear()
|
| 203 |
+
game_model, raw_baselines, player_stats, prop_frame, pick_frame, market_props, timestamp = init_baselines()
|
| 204 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 205 |
line_var1 = st.radio('How would you like to display odds?', options = ['Percentage', 'American'], key='line_var1')
|
| 206 |
team_frame = game_model
|
|
|
|
| 223 |
|
| 224 |
with tab2:
|
| 225 |
st.info(t_stamp)
|
| 226 |
+
if st.button("Reset Data", key='reset1'):
|
| 227 |
+
st.cache_data.clear()
|
| 228 |
+
game_model, raw_baselines, player_stats, prop_frame, pick_frame, market_props, timestamp = init_baselines()
|
| 229 |
+
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 230 |
+
market_type = st.selectbox('Select type of prop are you wanting to view', options = prop_table_options, key = 'market_type_key')
|
| 231 |
+
disp_market = market_props.copy()
|
| 232 |
+
disp_market = disp_market[disp_market['PropType'] == market_type]
|
| 233 |
+
disp_market['No_Vig_Prop'] = disp_market.apply(calculate_no_vig, axis=1)
|
| 234 |
+
fanduel_frame = disp_market[disp_market['OddsType'] == 'FANDUEL']
|
| 235 |
+
fanduel_dict = dict(zip(fanduel_frame['Name'], fanduel_frame['No_Vig_Prop']))
|
| 236 |
+
draftkings_frame = disp_market[disp_market['OddsType'] == 'DRAFTKINGS']
|
| 237 |
+
draftkings_dict = dict(zip(draftkings_frame['Name'], draftkings_frame['No_Vig_Prop']))
|
| 238 |
+
mgm_frame = disp_market[disp_market['OddsType'] == 'MGM']
|
| 239 |
+
mgm_dict = dict(zip(mgm_frame['Name'], mgm_frame['No_Vig_Prop']))
|
| 240 |
+
bet365_frame = disp_market[disp_market['OddsType'] == 'BET_365']
|
| 241 |
+
bet365_dict = dict(zip(bet365_frame['Name'], bet365_frame['No_Vig_Prop']))
|
| 242 |
+
|
| 243 |
+
disp_market['FANDUEL'] = disp_market['Name'].map(fanduel_dict)
|
| 244 |
+
disp_market['DRAFTKINGS'] = disp_market['Name'].map(draftkings_dict)
|
| 245 |
+
disp_market['MGM'] = disp_market['Name'].map(mgm_dict)
|
| 246 |
+
disp_market['BET365'] = disp_market['Name'].map(bet365_dict)
|
| 247 |
+
|
| 248 |
+
disp_market = disp_market[['Name', 'Position','FANDUEL', 'DRAFTKINGS', 'MGM', 'BET365']]
|
| 249 |
+
disp_market = disp_market.drop_duplicates(subset=['Name'], keep='first', ignore_index=True)
|
| 250 |
+
|
| 251 |
+
st.dataframe(disp_market.style.background_gradient(axis=1, subset=['FANDUEL', 'DRAFTKINGS', 'MGM', 'BET365'], cmap='RdYlGn').format(prop_format, precision=2), height = 1000, use_container_width = True)
|
| 252 |
+
st.download_button(
|
| 253 |
+
label="Export Market Props",
|
| 254 |
+
data=convert_df_to_csv(disp_market),
|
| 255 |
+
file_name='NFL_market_props_export.csv',
|
| 256 |
+
mime='text/csv',
|
| 257 |
+
)
|
| 258 |
+
|
| 259 |
+
with tab3:
|
| 260 |
+
st.info(t_stamp)
|
| 261 |
+
if st.button("Reset Data", key='reset3'):
|
| 262 |
st.cache_data.clear()
|
| 263 |
+
game_model, raw_baselines, player_stats, prop_frame, pick_frame, market_props, timestamp = init_baselines()
|
| 264 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 265 |
split_var1 = st.radio("Would you like to view all teams or specific ones?", ('All', 'Specific Teams'), key='split_var1')
|
| 266 |
if split_var1 == 'Specific Teams':
|
|
|
|
| 278 |
mime='text/csv',
|
| 279 |
)
|
| 280 |
|
| 281 |
+
with tab4:
|
| 282 |
st.info(t_stamp)
|
| 283 |
+
if st.button("Reset Data", key='reset4'):
|
| 284 |
st.cache_data.clear()
|
| 285 |
+
game_model, raw_baselines, player_stats, prop_frame, pick_frame, market_props, timestamp = init_baselines()
|
| 286 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 287 |
split_var5 = st.radio("Would you like to view all teams or specific ones?", ('All', 'Specific Teams'), key='split_var5')
|
| 288 |
if split_var5 == 'Specific Teams':
|
|
|
|
| 307 |
mime='text/csv',
|
| 308 |
)
|
| 309 |
|
| 310 |
+
with tab5:
|
| 311 |
st.info(t_stamp)
|
| 312 |
+
if st.button("Reset Data", key='reset5'):
|
| 313 |
st.cache_data.clear()
|
| 314 |
+
game_model, raw_baselines, player_stats, prop_frame, pick_frame, market_props, timestamp = init_baselines()
|
| 315 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 316 |
col1, col2 = st.columns([1, 5])
|
| 317 |
|
|
|
|
| 454 |
plot_hold_container = st.empty()
|
| 455 |
st.plotly_chart(fig, use_container_width=True)
|
| 456 |
|
| 457 |
+
with tab6:
|
| 458 |
st.info(t_stamp)
|
| 459 |
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.')
|
| 460 |
if st.button("Reset Data/Load Data", key='reset6'):
|
| 461 |
st.cache_data.clear()
|
| 462 |
+
game_model, raw_baselines, player_stats, prop_frame, pick_frame, market_props, timestamp = init_baselines()
|
| 463 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 464 |
col1, col2 = st.columns([1, 5])
|
| 465 |
|