Spaces:
Running
Running
import streamlit as st | |
import numpy as np | |
from numpy import where as np_where | |
import pandas as pd | |
import gspread | |
import plotly.express as px | |
import scipy.stats as stats | |
from pymongo import MongoClient | |
st.set_page_config(layout="wide") | |
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": "[email protected]", | |
"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" | |
} | |
credentials2 = { | |
"type": "service_account", | |
"project_id": "sheets-api-connect-378620", | |
"private_key_id": st.secrets['sheets_api_connect_pk'], | |
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCtKa01beXwc88R\nnPZVQTNPVQuBnbwoOfc66gW3547ja/UEyIGAF112dt/VqHprRafkKGmlg55jqJNt\na4zceLKV+wTm7vBu7lDISTJfGzCf2TrxQYNqwMKE2LOjI69dBM8u4Dcb4k0wcp9v\ntW1ZzLVVuwTvmrg7JBHjiSaB+x5wxm/r3FOiJDXdlAgFlytzqgcyeZMJVKKBQHyJ\njEGg/1720A0numuOCt71w/2G0bDmijuj1e6tH32MwRWcvRNZ19K9ssyDz2S9p68s\nYDhIxX69OWxwScTIHLY6J2t8txf/XMivL/636fPlDADvBEVTdlT606n8CcKUVQeq\npUVdG+lfAgMBAAECggEAP38SUA7B69eTfRpo658ycOs3Amr0JW4H/bb1rNeAul0K\nZhwd/HnU4E07y81xQmey5kN5ZeNrD5EvqkZvSyMJHV0EEahZStwhjCfnDB/cxyix\nZ+kFhv4y9eK+kFpUAhBy5nX6T0O+2T6WvzAwbmbVsZ+X8kJyPuF9m8ldcPlD0sce\ntj8NwVq1ys52eosqs7zi2vjt+eMcaY393l4ls+vNq8Yf27cfyFw45W45CH/97/Nu\n5AmuzlCOAfFF+z4OC5g4rei4E/Qgpxa7/uom+BVfv9G0DIGW/tU6Sne0+37uoGKt\nW6DzhgtebUtoYkG7ZJ05BTXGp2lwgVcNRoPwnKJDxQKBgQDT5wYPUBDW+FHbvZSp\nd1m1UQuXyerqOTA9smFaM8sr/UraeH85DJPEIEk8qsntMBVMhvD3Pw8uIUeFNMYj\naLmZFObsL+WctepXrVo5NB6RtLB/jZYxiKMatMLUJIYtcKIp+2z/YtKiWcLnwotB\nWdCjVnPTxpkurmF2fWP/eewZ+wKBgQDRMtJg7etjvKyjYNQ5fARnCc+XsI3gkBe1\nX9oeXfhyfZFeBXWnZzN1ITgFHplDznmBdxAyYGiQdbbkdKQSghviUQ0igBvoDMYy\n1rWcy+a17Mj98uyNEfmb3X2cC6WpvOZaGHwg9+GY67BThwI3FqHIbyk6Ko09WlTX\nQpRQjMzU7QKBgAfi1iflu+q0LR+3a3vvFCiaToskmZiD7latd9AKk2ocsBd3Woy9\n+hXXecJHPOKV4oUJlJgvAZqe5HGBqEoTEK0wyPNLSQlO/9ypd+0fEnArwFHO7CMF\nycQprAKHJXM1eOOFFuZeQCaInqdPZy1UcV5Szla4UmUZWkk1m24blHzXAoGBAMcA\nyH4qdbxX9AYrC1dvsSRvgcnzytMvX05LU0uF6tzGtG0zVlub4ahvpEHCfNuy44UT\nxRWW/oFFaWjjyFxO5sWggpUqNuHEnRopg3QXx22SRRTGbN45li/+QAocTkgsiRh1\nqEcYZsO4mPCsQqAy6E2p6RcK+Xa+omxvSnVhq0x1AoGAKr8GdkCl4CF6rieLMAQ7\nLNBuuoYGaHoh8l5E2uOQpzwxVy/nMBcAv+2+KqHEzHryUv1owOi6pMLv7A9mTFoS\n18B0QRLuz5fSOsVnmldfC9fpUc6H8cH1SINZpzajqQA74bPwELJjnzrCnH79TnHG\nJuElxA33rFEjbgbzdyrE768=\n-----END PRIVATE KEY-----\n", | |
"client_email": "gspread-connection@sheets-api-connect-378620.iam.gserviceaccount.com", | |
"client_id": "106625872877651920064", | |
"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%40sheets-api-connect-378620.iam.gserviceaccount.com" | |
} | |
uri = st.secrets['mongo_uri'] | |
client = MongoClient(uri, retryWrites=True, serverSelectionTimeoutMS=100000) | |
dfs_db = client["NCAAF_Database"] | |
props_db = client["Props_DB"] | |
gc = gspread.service_account_from_dict(credentials) | |
gc2 = gspread.service_account_from_dict(credentials2) | |
return gc, gc2, NFL_Data, props_db, dfs_db | |
gcservice_account, gcservice_account2, NFL_Data, props_db, dfs_db = init_conn() | |
game_format = {'Win%': '{:.2%}', 'Vegas': '{:.2%}', 'Win% Diff': '{:.2%}'} | |
american_format = {'First Inning Lead Percentage': '{:.2%}', 'Fifth Inning Lead Percentage': '{:.2%}'} | |
def init_baselines(): | |
collection = dfs_db["NCAAF_GameModel"] | |
cursor = collection.find() | |
raw_display = pd.DataFrame(list(cursor)) | |
game_model = raw_display[['Team', 'Opp', 'Win%', 'Vegas', 'Win% Diff', 'Win Line', 'Vegas Line', 'Line Diff', 'PD Spread', 'Vegas Spread', 'Spread Diff']] | |
collection = props_db["NCAAF_Props"] | |
cursor = collection.find() | |
raw_display = pd.DataFrame(list(cursor)) | |
market_props = raw_display[['Name', 'Position', 'Projection', 'PropType', 'OddsType', 'over_pay', 'under_pay']] | |
market_props['over_prop'] = market_props['Projection'] | |
market_props['over_line'] = market_props['over_pay'].apply(lambda x: (x - 1) * 100 if x >= 2.0 else -100 / (x - 1)) | |
market_props['under_prop'] = market_props['Projection'] | |
market_props['under_line'] = market_props['under_pay'].apply(lambda x: (x - 1) * 100 if x >= 2.0 else -100 / (x - 1)) | |
return game_model, market_props | |
def convert_df_to_csv(df): | |
return df.to_csv().encode('utf-8') | |
def calculate_no_vig(row): | |
def implied_probability(american_odds): | |
if american_odds < 0: | |
return (-american_odds) / ((-american_odds) + 100) | |
else: | |
return 100 / (american_odds + 100) | |
over_line = row['over_line'] | |
under_line = row['under_line'] | |
over_prop = row['over_prop'] | |
over_prob = implied_probability(over_line) | |
under_prob = implied_probability(under_line) | |
total_prob = over_prob + under_prob | |
no_vig_prob = (over_prob / total_prob + 0.5) * over_prop | |
return no_vig_prob | |
prop_table_options = ['NCAAF_GAME_PLAYER_PASSING_YARDS', 'NCAAF_GAME_PLAYER_RUSHING_YARDS', 'NCAAF_GAME_PLAYER_PASSING_ATTEMPTS', 'NCAAF_GAME_PLAYER_PASSING_TOUCHDOWNS', 'NCAAF_GAME_PLAYER_PASSING_COMPLETIONS', 'NCAAF_GAME_PLAYER_RUSHING_ATTEMPTS', | |
'NCAAF_GAME_PLAYER_RECEIVING_RECEPTIONS', 'NCAAF_GAME_PLAYER_RECEIVING_YARDS', 'NCAAF_GAME_PLAYER_RECEIVING_TOUCHDOWNS'] | |
prop_format = {'L3 Success': '{:.2%}', 'L6_Success': '{:.2%}', 'L10_success': '{:.2%}', 'Trending Over': '{:.2%}', 'Trending Under': '{:.2%}', | |
'Implied Over': '{:.2%}', 'Implied Under': '{:.2%}', 'Over Edge': '{:.2%}', 'Under Edge': '{:.2%}'} | |
tab1, tab2 = st.tabs(["Game Model", "Prop Market"]) | |
with tab1: | |
if st.button("Reset Data", key='reset1'): | |
st.cache_data.clear() | |
game_model, market_props = init_baselines() | |
line_var1 = st.radio('How would you like to display odds?', options = ['Percentage', 'American'], key='line_var1') | |
team_frame = game_model | |
if line_var1 == 'Percentage': | |
team_frame = team_frame[['Team', 'Opp', 'Win%', 'Vegas', 'Win% Diff', 'PD Spread', 'Vegas Spread', 'Spread Diff']] | |
team_frame = team_frame.set_index('Team') | |
try: | |
st.dataframe(team_frame.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(game_format, precision=2), use_container_width = True) | |
except: | |
st.dataframe(team_frame.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True) | |
if line_var1 == 'American': | |
team_frame = team_frame[['Team', 'Opp', 'Win Line', 'Vegas Line', 'Line Diff', 'PD Spread', 'Vegas Spread', 'Spread Diff']] | |
team_frame = team_frame.set_index('Team') | |
st.dataframe(team_frame.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), height = 1000, use_container_width = True) | |
st.download_button( | |
label="Export Team Model", | |
data=convert_df_to_csv(team_frame), | |
file_name='NCAAF_team_betting_export.csv', | |
mime='text/csv', | |
key='team_export', | |
) | |
with tab2: | |
if st.button("Reset Data", key='reset4'): | |
st.cache_data.clear() | |
game_model, market_props = init_baselines() | |
market_type = st.selectbox('Select type of prop are you wanting to view', options = prop_table_options, key = 'market_type_key') | |
disp_market = market_props.copy() | |
disp_market = disp_market[disp_market['PropType'] == market_type] | |
disp_market['No_Vig_Prop'] = disp_market.apply(calculate_no_vig, axis=1) | |
fanduel_frame = disp_market[disp_market['OddsType'] == 'FANDUEL'] | |
fanduel_dict = dict(zip(fanduel_frame['Name'], fanduel_frame['No_Vig_Prop'])) | |
draftkings_frame = disp_market[disp_market['OddsType'] == 'DRAFTKINGS'] | |
draftkings_dict = dict(zip(draftkings_frame['Name'], draftkings_frame['No_Vig_Prop'])) | |
mgm_frame = disp_market[disp_market['OddsType'] == 'MGM'] | |
mgm_dict = dict(zip(mgm_frame['Name'], mgm_frame['No_Vig_Prop'])) | |
bet365_frame = disp_market[disp_market['OddsType'] == 'BET_365'] | |
bet365_dict = dict(zip(bet365_frame['Name'], bet365_frame['No_Vig_Prop'])) | |
disp_market['FANDUEL'] = disp_market['Name'].map(fanduel_dict) | |
disp_market['DRAFTKINGS'] = disp_market['Name'].map(draftkings_dict) | |
disp_market['MGM'] = disp_market['Name'].map(mgm_dict) | |
disp_market['BET365'] = disp_market['Name'].map(bet365_dict) | |
disp_market = disp_market[['Name', 'Position','FANDUEL', 'DRAFTKINGS', 'MGM', 'BET365']] | |
disp_market = disp_market.drop_duplicates(subset=['Name'], keep='first', ignore_index=True) | |
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) | |
st.download_button( | |
label="Export Market Props", | |
data=convert_df_to_csv(disp_market), | |
file_name='NCAAF_market_props_export.csv', | |
mime='text/csv', | |
) |