Multichem commited on
Commit
f1f302a
·
verified ·
1 Parent(s): 6be0567

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +165 -117
app.py CHANGED
@@ -2,52 +2,18 @@ import streamlit as st
2
  st.set_page_config(layout="wide")
3
  import numpy as np
4
  import pandas as pd
5
- import gspread
6
  import pymongo
7
- import time
8
 
9
  @st.cache_resource
10
  def init_conn():
11
- scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive']
12
-
13
- credentials = {
14
- "type": "service_account",
15
- "project_id": "model-sheets-connect",
16
- "private_key_id": st.secrets['model_sheets_connect_pk'],
17
- "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",
18
- "client_email": "[email protected]",
19
- "client_id": "100369174533302798535",
20
- "auth_uri": "https://accounts.google.com/o/oauth2/auth",
21
- "token_uri": "https://oauth2.googleapis.com/token",
22
- "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
23
- "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/gspread-connection%40model-sheets-connect.iam.gserviceaccount.com"
24
- }
25
-
26
- credentials2 = {
27
- "type": "service_account",
28
- "project_id": "sheets-api-connect-378620",
29
- "private_key_id": st.secrets['sheets_api_connect_pk'],
30
- "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",
31
- "client_email": "gspread-connection@sheets-api-connect-378620.iam.gserviceaccount.com",
32
- "client_id": "106625872877651920064",
33
- "auth_uri": "https://accounts.google.com/o/oauth2/auth",
34
- "token_uri": "https://oauth2.googleapis.com/token",
35
- "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
36
- "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/gspread-connection%40sheets-api-connect-378620.iam.gserviceaccount.com"
37
- }
38
 
39
  uri = st.secrets['mongo_uri']
40
  client = pymongo.MongoClient(uri, retryWrites=True, serverSelectionTimeoutMS=500000)
41
- db = client["NHL_DFS"]
42
-
43
- NHL_Data = st.secrets['NHL_Data']
44
-
45
- gc = gspread.service_account_from_dict(credentials)
46
- gc2 = gspread.service_account_from_dict(credentials2)
47
 
48
- return gc, gc2, db, NHL_Data
49
 
50
- gcservice_account, gcservice_account2, db, NHL_Data = init_conn()
51
 
52
  percentages_format = {'Exposure': '{:.2%}'}
53
  freq_format = {'Exposure': '{:.2%}', 'Proj Own': '{:.2%}', 'Edge': '{:.2%}'}
@@ -55,10 +21,10 @@ dk_columns = ['C1', 'C2', 'W1', 'W2', 'W3', 'D1', 'D2', 'FLEX', 'G', 'salary', '
55
  fd_columns = ['C1', 'C2', 'W1', 'W2', 'D1', 'D2', 'FLEX1', 'FLEX2', 'G', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']
56
 
57
  @st.cache_data(ttl = 600)
58
- def init_DK_seed_frames():
59
 
60
  collection = db["DK_NHL_seed_frame"]
61
- cursor = collection.find()
62
 
63
  raw_display = pd.DataFrame(list(cursor))
64
  raw_display = raw_display[['C1', 'C2', 'W1', 'W2', 'W3', 'D1', 'D2', 'FLEX', 'G', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']]
@@ -67,10 +33,10 @@ def init_DK_seed_frames():
67
  return DK_seed
68
 
69
  @st.cache_data(ttl = 599)
70
- def init_FD_seed_frames():
71
 
72
  collection = db["FD_NHL_seed_frame"]
73
- cursor = collection.find()
74
 
75
  raw_display = pd.DataFrame(list(cursor))
76
  raw_display = raw_display[['C1', 'C2', 'W1', 'W2', 'D1', 'D2', 'FLEX1', 'FLEX2', 'G', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']]
@@ -80,26 +46,28 @@ def init_FD_seed_frames():
80
 
81
  @st.cache_data(ttl = 599)
82
  def init_baselines():
83
- try:
84
- sh = gcservice_account.open_by_url(NHL_Data)
85
- except:
86
- sh = gcservice_account2.open_by_url(NHL_Data)
87
 
88
- worksheet = sh.worksheet('Player_Level_ROO')
89
- load_display = pd.DataFrame(worksheet.get_all_records())
90
- load_display.replace('', np.nan, inplace=True)
91
  load_display['STDev'] = load_display['Median'] / 3
92
  DK_load_display = load_display[load_display['Site'] == 'Draftkings']
93
  DK_load_display = DK_load_display.drop_duplicates(subset=['Player'], keep='first')
94
 
95
  dk_raw = DK_load_display.dropna(subset=['Median'])
 
96
 
97
  FD_load_display = load_display[load_display['Site'] == 'Fanduel']
98
  FD_load_display = FD_load_display.drop_duplicates(subset=['Player'], keep='first')
99
 
100
  fd_raw = FD_load_display.dropna(subset=['Median'])
 
101
 
102
- return dk_raw, fd_raw
 
 
103
 
104
  @st.cache_data
105
  def convert_df(array):
@@ -121,11 +89,10 @@ def calculate_FD_value_frequencies(np_array):
121
  return combined_array
122
 
123
  @st.cache_data
124
- def sim_contest(Sim_size, seed_frame, maps_dict, sharp_split, Contest_Size):
125
  SimVar = 1
126
  Sim_Winners = []
127
- fp_array = seed_frame[:sharp_split, :]
128
-
129
  # Pre-vectorize functions
130
  vec_projection_map = np.vectorize(maps_dict['Projection_map'].__getitem__)
131
  vec_stdev_map = np.vectorize(maps_dict['STDev_map'].__getitem__)
@@ -135,15 +102,20 @@ def sim_contest(Sim_size, seed_frame, maps_dict, sharp_split, Contest_Size):
135
  while SimVar <= Sim_size:
136
  fp_random = fp_array[np.random.choice(fp_array.shape[0], Contest_Size)]
137
 
138
- sample_arrays1 = np.c_[
139
- fp_random,
140
- np.sum(np.random.normal(
141
- loc=vec_projection_map(fp_random[:, :-7]),
142
- scale=vec_stdev_map(fp_random[:, :-7])),
143
- axis=1)
144
- ]
 
 
 
 
 
145
 
146
- sample_arrays = sample_arrays1
147
 
148
  final_array = sample_arrays[sample_arrays[:, 10].argsort()[::-1]]
149
  best_lineup = final_array[final_array[:, -1].argsort(kind='stable')[::-1][:1]]
@@ -152,9 +124,9 @@ def sim_contest(Sim_size, seed_frame, maps_dict, sharp_split, Contest_Size):
152
 
153
  return Sim_Winners
154
 
155
- DK_seed = init_DK_seed_frames()
156
- FD_seed = init_FD_seed_frames()
157
- dk_raw, fd_raw = init_baselines()
158
 
159
  tab1, tab2 = st.tabs(['Contest Sims', 'Data Export'])
160
  with tab2:
@@ -164,15 +136,17 @@ with tab2:
164
  st.cache_data.clear()
165
  for key in st.session_state.keys():
166
  del st.session_state[key]
167
- DK_seed = init_DK_seed_frames()
168
- FD_seed = init_FD_seed_frames()
169
- dk_raw, fd_raw = init_baselines()
 
 
170
 
171
  slate_var1 = st.radio("Which data are you loading?", ('Main Slate', 'Other Main Slate'))
172
  site_var1 = st.radio("What site are you working with?", ('Draftkings', 'Fanduel'))
 
 
173
  if site_var1 == 'Draftkings':
174
- raw_baselines = dk_raw
175
- column_names = dk_columns
176
 
177
  team_var1 = st.radio("Do you want a frame with specific teams?", ('Full Slate', 'Specific Teams'), key='team_var1')
178
  if team_var1 == 'Specific Teams':
@@ -187,8 +161,6 @@ with tab2:
187
  stack_var2 = [5, 4, 3, 2, 1, 0]
188
 
189
  elif site_var1 == 'Fanduel':
190
- raw_baselines = fd_raw
191
- column_names = fd_columns
192
 
193
  team_var1 = st.radio("Do you want a frame with specific teams?", ('Full Slate', 'Specific Teams'), key='team_var1')
194
  if team_var1 == 'Specific Teams':
@@ -204,6 +176,25 @@ with tab2:
204
 
205
 
206
  if st.button("Prepare data export", key='data_export'):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  data_export = st.session_state.working_seed.copy()
208
  st.download_button(
209
  label="Export optimals set",
@@ -211,6 +202,8 @@ with tab2:
211
  file_name='NHL_optimals_export.csv',
212
  mime='text/csv',
213
  )
 
 
214
 
215
  with col2:
216
  if st.button("Load Data", key='load_data'):
@@ -220,7 +213,12 @@ with tab2:
220
  st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 12], stack_var2)]
221
  st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:1000], columns=column_names)
222
  elif 'working_seed' not in st.session_state:
223
- st.session_state.working_seed = DK_seed.copy()
 
 
 
 
 
224
  st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 11], team_var2)]
225
  st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 12], stack_var2)]
226
  st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:1000], columns=column_names)
@@ -231,7 +229,11 @@ with tab2:
231
  st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 12], stack_var2)]
232
  st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:1000], columns=column_names)
233
  elif 'working_seed' not in st.session_state:
234
- st.session_state.working_seed = FD_seed.copy()
 
 
 
 
235
  st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 11], team_var2)]
236
  st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 12], stack_var2)]
237
  st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:1000], columns=column_names)
@@ -247,17 +249,14 @@ with tab1:
247
  st.cache_data.clear()
248
  for key in st.session_state.keys():
249
  del st.session_state[key]
250
- DK_seed = init_DK_seed_frames()
251
- FD_seed = init_FD_seed_frames()
252
- dk_raw, fd_raw = init_baselines()
 
 
 
253
  sim_slate_var1 = st.radio("Which data are you loading?", ('Main Slate', 'Other Main Slate'), key='sim_slate_var1')
254
  sim_site_var1 = st.radio("What site are you working with?", ('Draftkings', 'Fanduel'), key='sim_site_var1')
255
- if sim_site_var1 == 'Draftkings':
256
- raw_baselines = dk_raw
257
- column_names = dk_columns
258
- elif sim_site_var1 == 'Fanduel':
259
- raw_baselines = fd_raw
260
- column_names = fd_columns
261
 
262
  contest_var1 = st.selectbox("What contest size are you simulating?", ('Small', 'Medium', 'Large', 'Custom'))
263
  if contest_var1 == 'Small':
@@ -272,19 +271,19 @@ with tab1:
272
  if strength_var1 == 'Not Very':
273
  sharp_split = 500000
274
  elif strength_var1 == 'Below Average':
275
- sharp_split = 400000
276
  elif strength_var1 == 'Average':
277
- sharp_split = 300000
278
  elif strength_var1 == 'Above Average':
279
- sharp_split = 200000
280
  elif strength_var1 == 'Very':
281
- sharp_split = 100000
282
 
283
 
284
  with col2:
285
  if st.button("Run Contest Sim"):
286
  if 'working_seed' in st.session_state:
287
- maps_dict = {
288
  'Projection_map':dict(zip(raw_baselines.Player,raw_baselines.Median)),
289
  'Salary_map':dict(zip(raw_baselines.Player,raw_baselines.Salary)),
290
  'Pos_map':dict(zip(raw_baselines.Player,raw_baselines.Position)),
@@ -292,7 +291,7 @@ with tab1:
292
  'Team_map':dict(zip(raw_baselines.Player,raw_baselines.Team)),
293
  'STDev_map':dict(zip(raw_baselines.Player,raw_baselines.STDev))
294
  }
295
- Sim_Winners = sim_contest(1000, st.session_state.working_seed, maps_dict, sharp_split, Contest_Size)
296
  Sim_Winner_Frame = pd.DataFrame(np.concatenate(Sim_Winners))
297
 
298
  #st.table(Sim_Winner_Frame)
@@ -313,16 +312,27 @@ with tab1:
313
 
314
  # Data Copying
315
  st.session_state.Sim_Winner_Export = Sim_Winner_Frame.copy()
 
 
 
316
 
317
  # Data Copying
318
  st.session_state.Sim_Winner_Display = Sim_Winner_Frame.copy()
319
 
320
  else:
321
  if sim_site_var1 == 'Draftkings':
322
- st.session_state.working_seed = DK_seed.copy()
 
 
 
 
323
  elif sim_site_var1 == 'Fanduel':
324
- st.session_state.working_seed = FD_seed.copy()
325
- maps_dict = {
 
 
 
 
326
  'Projection_map':dict(zip(raw_baselines.Player,raw_baselines.Median)),
327
  'Salary_map':dict(zip(raw_baselines.Player,raw_baselines.Salary)),
328
  'Pos_map':dict(zip(raw_baselines.Player,raw_baselines.Position)),
@@ -330,7 +340,7 @@ with tab1:
330
  'Team_map':dict(zip(raw_baselines.Player,raw_baselines.Team)),
331
  'STDev_map':dict(zip(raw_baselines.Player,raw_baselines.STDev))
332
  }
333
- Sim_Winners = sim_contest(1000, st.session_state.working_seed, maps_dict, sharp_split, Contest_Size)
334
  Sim_Winner_Frame = pd.DataFrame(np.concatenate(Sim_Winners))
335
 
336
  #st.table(Sim_Winner_Frame)
@@ -351,6 +361,9 @@ with tab1:
351
 
352
  # Data Copying
353
  st.session_state.Sim_Winner_Export = Sim_Winner_Frame.copy()
 
 
 
354
 
355
  # Data Copying
356
  st.session_state.Sim_Winner_Display = Sim_Winner_Frame.copy()
@@ -363,12 +376,12 @@ with tab1:
363
  freq_working = pd.DataFrame(np.column_stack(np.unique(st.session_state.freq_copy.iloc[:,0:9].values, return_counts=True)),
364
  columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
365
  freq_working['Freq'] = freq_working['Freq'].astype(int)
366
- freq_working['Position'] = freq_working['Player'].map(maps_dict['Pos_map'])
367
- freq_working['Salary'] = freq_working['Player'].map(maps_dict['Salary_map'])
368
- freq_working['Proj Own'] = freq_working['Player'].map(maps_dict['Own_map']) / 100
369
  freq_working['Exposure'] = freq_working['Freq']/(1000)
370
  freq_working['Edge'] = freq_working['Exposure'] - freq_working['Proj Own']
371
- freq_working['Team'] = freq_working['Player'].map(maps_dict['Team_map'])
372
  st.session_state.player_freq = freq_working.copy()
373
 
374
  if sim_site_var1 == 'Draftkings':
@@ -378,12 +391,12 @@ with tab1:
378
  center_working = pd.DataFrame(np.column_stack(np.unique(st.session_state.freq_copy.iloc[:,0:2].values, return_counts=True)),
379
  columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
380
  center_working['Freq'] = center_working['Freq'].astype(int)
381
- center_working['Position'] = center_working['Player'].map(maps_dict['Pos_map'])
382
- center_working['Salary'] = center_working['Player'].map(maps_dict['Salary_map'])
383
- center_working['Proj Own'] = center_working['Player'].map(maps_dict['Own_map']) / 100
384
  center_working['Exposure'] = center_working['Freq']/(1000)
385
  center_working['Edge'] = center_working['Exposure'] - center_working['Proj Own']
386
- center_working['Team'] = center_working['Player'].map(maps_dict['Team_map'])
387
  st.session_state.center_freq = center_working.copy()
388
 
389
  if sim_site_var1 == 'Draftkings':
@@ -393,12 +406,12 @@ with tab1:
393
  wing_working = pd.DataFrame(np.column_stack(np.unique(st.session_state.freq_copy.iloc[:,2:4].values, return_counts=True)),
394
  columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
395
  wing_working['Freq'] = wing_working['Freq'].astype(int)
396
- wing_working['Position'] = wing_working['Player'].map(maps_dict['Pos_map'])
397
- wing_working['Salary'] = wing_working['Player'].map(maps_dict['Salary_map'])
398
- wing_working['Proj Own'] = wing_working['Player'].map(maps_dict['Own_map']) / 100
399
  wing_working['Exposure'] = wing_working['Freq']/(1000)
400
  wing_working['Edge'] = wing_working['Exposure'] - wing_working['Proj Own']
401
- wing_working['Team'] = wing_working['Player'].map(maps_dict['Team_map'])
402
  st.session_state.wing_freq = wing_working.copy()
403
 
404
  if sim_site_var1 == 'Draftkings':
@@ -408,12 +421,12 @@ with tab1:
408
  dmen_working = pd.DataFrame(np.column_stack(np.unique(st.session_state.freq_copy.iloc[:,4:6].values, return_counts=True)),
409
  columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
410
  dmen_working['Freq'] = dmen_working['Freq'].astype(int)
411
- dmen_working['Position'] = dmen_working['Player'].map(maps_dict['Pos_map'])
412
- dmen_working['Salary'] = dmen_working['Player'].map(maps_dict['Salary_map'])
413
- dmen_working['Proj Own'] = dmen_working['Player'].map(maps_dict['Own_map']) / 100
414
  dmen_working['Exposure'] = dmen_working['Freq']/(1000)
415
  dmen_working['Edge'] = dmen_working['Exposure'] - dmen_working['Proj Own']
416
- dmen_working['Team'] = dmen_working['Player'].map(maps_dict['Team_map'])
417
  st.session_state.dmen_freq = dmen_working.copy()
418
 
419
  if sim_site_var1 == 'Draftkings':
@@ -423,12 +436,12 @@ with tab1:
423
  flex_working = pd.DataFrame(np.column_stack(np.unique(st.session_state.freq_copy.iloc[:,6:8].values, return_counts=True)),
424
  columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
425
  flex_working['Freq'] = flex_working['Freq'].astype(int)
426
- flex_working['Position'] = flex_working['Player'].map(maps_dict['Pos_map'])
427
- flex_working['Salary'] = flex_working['Player'].map(maps_dict['Salary_map'])
428
- flex_working['Proj Own'] = flex_working['Player'].map(maps_dict['Own_map']) / 100
429
  flex_working['Exposure'] = flex_working['Freq']/(1000)
430
  flex_working['Edge'] = flex_working['Exposure'] - flex_working['Proj Own']
431
- flex_working['Team'] = flex_working['Player'].map(maps_dict['Team_map'])
432
  st.session_state.flex_freq = flex_working.copy()
433
 
434
  if sim_site_var1 == 'Draftkings':
@@ -438,12 +451,12 @@ with tab1:
438
  goalie_working = pd.DataFrame(np.column_stack(np.unique(st.session_state.freq_copy.iloc[:,8:9].values, return_counts=True)),
439
  columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
440
  goalie_working['Freq'] = goalie_working['Freq'].astype(int)
441
- goalie_working['Position'] = goalie_working['Player'].map(maps_dict['Pos_map'])
442
- goalie_working['Salary'] = goalie_working['Player'].map(maps_dict['Salary_map'])
443
- goalie_working['Proj Own'] = goalie_working['Player'].map(maps_dict['Own_map']) / 100
444
  goalie_working['Exposure'] = goalie_working['Freq']/(1000)
445
  goalie_working['Edge'] = goalie_working['Exposure'] - goalie_working['Proj Own']
446
- goalie_working['Team'] = goalie_working['Player'].map(maps_dict['Team_map'])
447
  st.session_state.goalie_freq = goalie_working.copy()
448
 
449
  if sim_site_var1 == 'Draftkings':
@@ -475,12 +488,13 @@ with tab1:
475
  st.dataframe(st.session_state.Sim_Winner_Display.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
476
  if 'Sim_Winner_Export' in st.session_state:
477
  st.download_button(
 
478
  label="Export Full Frame",
479
  data=st.session_state.Sim_Winner_Export.to_csv().encode('utf-8'),
480
  file_name='MLB_consim_export.csv',
481
  mime='text/csv',
482
  )
483
- tab1, tab2 = st.tabs(['Winning Frame Statistics', 'Flex Exposure Statistics'])
484
 
485
  with tab1:
486
  if 'Sim_Winner_Display' in st.session_state:
@@ -527,6 +541,7 @@ with tab1:
527
  st.dataframe(summary_df.style.format({
528
  'Salary': '{:.2f}',
529
  'Proj': '{:.2f}',
 
530
  'Fantasy': '{:.2f}',
531
  'GPP_Proj': '{:.2f}'
532
  }).background_gradient(cmap='RdYlGn', axis=0, subset=['Salary', 'Proj', 'Own', 'Fantasy', 'GPP_Proj']), use_container_width=True)
@@ -534,7 +549,7 @@ with tab1:
534
  with tab2:
535
  if 'Sim_Winner_Display' in st.session_state:
536
  # Apply position mapping to FLEX column
537
- flex_positions = st.session_state.freq_copy['FLEX'].map(maps_dict['Pos_map'])
538
 
539
  # Count occurrences of each position in FLEX
540
  flex_counts = flex_positions.value_counts()
@@ -558,12 +573,45 @@ with tab1:
558
  st.dataframe(flex_summary.style.format({
559
  'Count': '{:.0f}',
560
  'Avg Proj': '{:.2f}',
 
561
  'Avg Fantasy': '{:.2f}',
562
  'Avg GPP_Proj': '{:.2f}'
563
  }).background_gradient(cmap='RdYlGn', axis=0, subset=['Count', 'Avg Proj', 'Avg Own', 'Avg Fantasy', 'Avg GPP_Proj']), use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
564
 
 
 
 
 
 
 
 
 
 
565
  else:
566
  st.write("Simulation data or position mapping not available.")
 
 
567
  with st.container():
568
  tab1, tab2, tab3, tab4, tab5, tab6, tab7 = st.tabs(['Overall Exposures', 'Center Exposures', 'Wing Exposures', 'Defense Exposures', 'Flex Exposures', 'Goalie Exposures', 'Team Exposures'])
569
  with tab1:
 
2
  st.set_page_config(layout="wide")
3
  import numpy as np
4
  import pandas as pd
 
5
  import pymongo
 
6
 
7
  @st.cache_resource
8
  def init_conn():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  uri = st.secrets['mongo_uri']
11
  client = pymongo.MongoClient(uri, retryWrites=True, serverSelectionTimeoutMS=500000)
12
+ db = client["NHL_Database"]
 
 
 
 
 
13
 
14
+ return db
15
 
16
+ db = init_conn()
17
 
18
  percentages_format = {'Exposure': '{:.2%}'}
19
  freq_format = {'Exposure': '{:.2%}', 'Proj Own': '{:.2%}', 'Edge': '{:.2%}'}
 
21
  fd_columns = ['C1', 'C2', 'W1', 'W2', 'D1', 'D2', 'FLEX1', 'FLEX2', 'G', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']
22
 
23
  @st.cache_data(ttl = 600)
24
+ def init_DK_seed_frames(sharp_split):
25
 
26
  collection = db["DK_NHL_seed_frame"]
27
+ cursor = collection.find().limit(sharp_split)
28
 
29
  raw_display = pd.DataFrame(list(cursor))
30
  raw_display = raw_display[['C1', 'C2', 'W1', 'W2', 'W3', 'D1', 'D2', 'FLEX', 'G', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']]
 
33
  return DK_seed
34
 
35
  @st.cache_data(ttl = 599)
36
+ def init_FD_seed_frames(sharp_split):
37
 
38
  collection = db["FD_NHL_seed_frame"]
39
+ cursor = collection.find().limit(sharp_split)
40
 
41
  raw_display = pd.DataFrame(list(cursor))
42
  raw_display = raw_display[['C1', 'C2', 'W1', 'W2', 'D1', 'D2', 'FLEX1', 'FLEX2', 'G', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']]
 
46
 
47
  @st.cache_data(ttl = 599)
48
  def init_baselines():
49
+ collection = db["Player_Level_ROO"]
50
+ cursor = collection.find()
 
 
51
 
52
+ raw_display = pd.DataFrame(list(cursor))
53
+ load_display = raw_display[['Player', 'Position', 'Team', 'Opp', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '2x%', '3x%', '4x%', 'Own',
54
+ 'Small Field Own%', 'Large Field Own%', 'Cash Own%', 'CPT_Own', 'Site', 'Type', 'Slate', 'player_id', 'timestamp']]
55
  load_display['STDev'] = load_display['Median'] / 3
56
  DK_load_display = load_display[load_display['Site'] == 'Draftkings']
57
  DK_load_display = DK_load_display.drop_duplicates(subset=['Player'], keep='first')
58
 
59
  dk_raw = DK_load_display.dropna(subset=['Median'])
60
+ dk_raw['Team'] = dk_raw['Team'].replace(['TB', 'SJ', 'LA'], ['TBL', 'SJS', 'LAK'])
61
 
62
  FD_load_display = load_display[load_display['Site'] == 'Fanduel']
63
  FD_load_display = FD_load_display.drop_duplicates(subset=['Player'], keep='first')
64
 
65
  fd_raw = FD_load_display.dropna(subset=['Median'])
66
+ fd_raw['Team'] = fd_raw['Team'].replace(['TB', 'SJ', 'LA'], ['TBL', 'SJS', 'LAK'])
67
 
68
+ teams_playing_count = len(dk_raw.Team.unique())
69
+
70
+ return dk_raw, fd_raw, teams_playing_count
71
 
72
  @st.cache_data
73
  def convert_df(array):
 
89
  return combined_array
90
 
91
  @st.cache_data
92
+ def sim_contest(Sim_size, seed_frame, maps_dict, Contest_Size, teams_playing_count):
93
  SimVar = 1
94
  Sim_Winners = []
95
+ fp_array = seed_frame.copy()
 
96
  # Pre-vectorize functions
97
  vec_projection_map = np.vectorize(maps_dict['Projection_map'].__getitem__)
98
  vec_stdev_map = np.vectorize(maps_dict['STDev_map'].__getitem__)
 
102
  while SimVar <= Sim_size:
103
  fp_random = fp_array[np.random.choice(fp_array.shape[0], Contest_Size)]
104
 
105
+ # Calculate stack multipliers first
106
+ stack_multiplier = np.ones(fp_random.shape[0]) # Start with no bonus
107
+ stack_multiplier += np.where(fp_random[:, 12] == 4, 0.025 * (teams_playing_count - 8), 0)
108
+ stack_multiplier += np.where(fp_random[:, 12] >= 5, 0.025 * (teams_playing_count - 12), 0)
109
+
110
+ # Apply multipliers to both loc and scale in the normal distribution
111
+ base_projections = np.sum(np.random.normal(
112
+ loc=vec_projection_map(fp_random[:, :-7]) * stack_multiplier[:, np.newaxis],
113
+ scale=vec_stdev_map(fp_random[:, :-7]) * stack_multiplier[:, np.newaxis]),
114
+ axis=1)
115
+
116
+ final_projections = base_projections
117
 
118
+ sample_arrays = np.c_[fp_random, final_projections]
119
 
120
  final_array = sample_arrays[sample_arrays[:, 10].argsort()[::-1]]
121
  best_lineup = final_array[final_array[:, -1].argsort(kind='stable')[::-1][:1]]
 
124
 
125
  return Sim_Winners
126
 
127
+ dk_raw, fd_raw, teams_playing_count = init_baselines()
128
+ dk_id_dict = dict(zip(dk_raw.Player, dk_raw.player_id))
129
+ fd_id_dict = dict(zip(fd_raw.Player, fd_raw.player_id))
130
 
131
  tab1, tab2 = st.tabs(['Contest Sims', 'Data Export'])
132
  with tab2:
 
136
  st.cache_data.clear()
137
  for key in st.session_state.keys():
138
  del st.session_state[key]
139
+ DK_seed = init_DK_seed_frames(10000)
140
+ FD_seed = init_FD_seed_frames(10000)
141
+ dk_raw, fd_raw, teams_playing_count = init_baselines()
142
+ dk_id_dict = dict(zip(dk_raw.Player, dk_raw.player_id))
143
+ fd_id_dict = dict(zip(fd_raw.Player, fd_raw.player_id))
144
 
145
  slate_var1 = st.radio("Which data are you loading?", ('Main Slate', 'Other Main Slate'))
146
  site_var1 = st.radio("What site are you working with?", ('Draftkings', 'Fanduel'))
147
+ sharp_split_var = st.number_input("How many lineups do you want?", value=10000, max_value=500000, min_value=10000, step=10000)
148
+
149
  if site_var1 == 'Draftkings':
 
 
150
 
151
  team_var1 = st.radio("Do you want a frame with specific teams?", ('Full Slate', 'Specific Teams'), key='team_var1')
152
  if team_var1 == 'Specific Teams':
 
161
  stack_var2 = [5, 4, 3, 2, 1, 0]
162
 
163
  elif site_var1 == 'Fanduel':
 
 
164
 
165
  team_var1 = st.radio("Do you want a frame with specific teams?", ('Full Slate', 'Specific Teams'), key='team_var1')
166
  if team_var1 == 'Specific Teams':
 
176
 
177
 
178
  if st.button("Prepare data export", key='data_export'):
179
+ if 'working_seed' in st.session_state:
180
+ st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 11], team_var2)]
181
+ st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 12], stack_var2)]
182
+ elif 'working_seed' not in st.session_state:
183
+ if site_var1 == 'Draftkings':
184
+ if slate_var1 == 'Main Slate':
185
+ st.session_state.working_seed = init_DK_seed_frames(sharp_split_var)
186
+
187
+ raw_baselines = dk_raw
188
+ column_names = dk_columns
189
+
190
+ elif site_var1 == 'Fanduel':
191
+ if slate_var1 == 'Main Slate':
192
+ st.session_state.working_seed = init_FD_seed_frames(sharp_split_var)
193
+
194
+ raw_baselines = fd_raw
195
+ column_names = fd_columns
196
+ st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 11], team_var2)]
197
+ st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 12], stack_var2)]
198
  data_export = st.session_state.working_seed.copy()
199
  st.download_button(
200
  label="Export optimals set",
 
202
  file_name='NHL_optimals_export.csv',
203
  mime='text/csv',
204
  )
205
+ for key in st.session_state.keys():
206
+ del st.session_state[key]
207
 
208
  with col2:
209
  if st.button("Load Data", key='load_data'):
 
213
  st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 12], stack_var2)]
214
  st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:1000], columns=column_names)
215
  elif 'working_seed' not in st.session_state:
216
+ if slate_var1 == 'Main Slate':
217
+ st.session_state.working_seed = init_DK_seed_frames(sharp_split_var)
218
+
219
+ raw_baselines = dk_raw
220
+ column_names = dk_columns
221
+
222
  st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 11], team_var2)]
223
  st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 12], stack_var2)]
224
  st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:1000], columns=column_names)
 
229
  st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 12], stack_var2)]
230
  st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:1000], columns=column_names)
231
  elif 'working_seed' not in st.session_state:
232
+ if slate_var1 == 'Main Slate':
233
+ st.session_state.working_seed = init_FD_seed_frames(sharp_split_var)
234
+
235
+ raw_baselines = fd_raw
236
+ column_names = fd_columns
237
  st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 11], team_var2)]
238
  st.session_state.working_seed = st.session_state.working_seed[np.isin(st.session_state.working_seed[:, 12], stack_var2)]
239
  st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:1000], columns=column_names)
 
249
  st.cache_data.clear()
250
  for key in st.session_state.keys():
251
  del st.session_state[key]
252
+ DK_seed = init_DK_seed_frames(10000)
253
+ FD_seed = init_FD_seed_frames(10000)
254
+ dk_raw, fd_raw, teams_playing_count = init_baselines()
255
+ dk_id_dict = dict(zip(dk_raw.Player, dk_raw.player_id))
256
+ fd_id_dict = dict(zip(fd_raw.Player, fd_raw.player_id))
257
+
258
  sim_slate_var1 = st.radio("Which data are you loading?", ('Main Slate', 'Other Main Slate'), key='sim_slate_var1')
259
  sim_site_var1 = st.radio("What site are you working with?", ('Draftkings', 'Fanduel'), key='sim_site_var1')
 
 
 
 
 
 
260
 
261
  contest_var1 = st.selectbox("What contest size are you simulating?", ('Small', 'Medium', 'Large', 'Custom'))
262
  if contest_var1 == 'Small':
 
271
  if strength_var1 == 'Not Very':
272
  sharp_split = 500000
273
  elif strength_var1 == 'Below Average':
274
+ sharp_split = 250000
275
  elif strength_var1 == 'Average':
276
+ sharp_split = 100000
277
  elif strength_var1 == 'Above Average':
278
+ sharp_split = 50000
279
  elif strength_var1 == 'Very':
280
+ sharp_split = 10000
281
 
282
 
283
  with col2:
284
  if st.button("Run Contest Sim"):
285
  if 'working_seed' in st.session_state:
286
+ st.session_state.maps_dict = {
287
  'Projection_map':dict(zip(raw_baselines.Player,raw_baselines.Median)),
288
  'Salary_map':dict(zip(raw_baselines.Player,raw_baselines.Salary)),
289
  'Pos_map':dict(zip(raw_baselines.Player,raw_baselines.Position)),
 
291
  'Team_map':dict(zip(raw_baselines.Player,raw_baselines.Team)),
292
  'STDev_map':dict(zip(raw_baselines.Player,raw_baselines.STDev))
293
  }
294
+ Sim_Winners = sim_contest(1000, st.session_state.working_seed, st.session_state.maps_dict, Contest_Size, teams_playing_count)
295
  Sim_Winner_Frame = pd.DataFrame(np.concatenate(Sim_Winners))
296
 
297
  #st.table(Sim_Winner_Frame)
 
312
 
313
  # Data Copying
314
  st.session_state.Sim_Winner_Export = Sim_Winner_Frame.copy()
315
+ for col in st.session_state.Sim_Winner_Export.iloc[:, 0:9].columns:
316
+ st.session_state.Sim_Winner_Export[col] = st.session_state.Sim_Winner_Export[col].map(dk_id_dict)
317
+ st.session_state.Sim_Winner_Export = st.session_state.Sim_Winner_Export.drop_duplicates(subset=['Team', 'Secondary', 'salary', 'unique_id'])
318
 
319
  # Data Copying
320
  st.session_state.Sim_Winner_Display = Sim_Winner_Frame.copy()
321
 
322
  else:
323
  if sim_site_var1 == 'Draftkings':
324
+ if sim_slate_var1 == 'Main Slate':
325
+ st.session_state.working_seed = init_DK_seed_frames(sharp_split)
326
+
327
+ raw_baselines = dk_raw
328
+ column_names = dk_columns
329
  elif sim_site_var1 == 'Fanduel':
330
+ if sim_slate_var1 == 'Main Slate':
331
+ st.session_state.working_seed = init_FD_seed_frames(sharp_split)
332
+
333
+ raw_baselines = fd_raw
334
+ column_names = fd_columns
335
+ st.session_state.maps_dict = {
336
  'Projection_map':dict(zip(raw_baselines.Player,raw_baselines.Median)),
337
  'Salary_map':dict(zip(raw_baselines.Player,raw_baselines.Salary)),
338
  'Pos_map':dict(zip(raw_baselines.Player,raw_baselines.Position)),
 
340
  'Team_map':dict(zip(raw_baselines.Player,raw_baselines.Team)),
341
  'STDev_map':dict(zip(raw_baselines.Player,raw_baselines.STDev))
342
  }
343
+ Sim_Winners = sim_contest(1000, st.session_state.working_seed, st.session_state.maps_dict, Contest_Size, teams_playing_count)
344
  Sim_Winner_Frame = pd.DataFrame(np.concatenate(Sim_Winners))
345
 
346
  #st.table(Sim_Winner_Frame)
 
361
 
362
  # Data Copying
363
  st.session_state.Sim_Winner_Export = Sim_Winner_Frame.copy()
364
+ for col in st.session_state.Sim_Winner_Export.iloc[:, 0:9].columns:
365
+ st.session_state.Sim_Winner_Export[col] = st.session_state.Sim_Winner_Export[col].map(dk_id_dict)
366
+ st.session_state.Sim_Winner_Export = st.session_state.Sim_Winner_Export.drop_duplicates(subset=['Team', 'Secondary', 'salary', 'unique_id'])
367
 
368
  # Data Copying
369
  st.session_state.Sim_Winner_Display = Sim_Winner_Frame.copy()
 
376
  freq_working = pd.DataFrame(np.column_stack(np.unique(st.session_state.freq_copy.iloc[:,0:9].values, return_counts=True)),
377
  columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
378
  freq_working['Freq'] = freq_working['Freq'].astype(int)
379
+ freq_working['Position'] = freq_working['Player'].map(st.session_state.maps_dict['Pos_map'])
380
+ freq_working['Salary'] = freq_working['Player'].map(st.session_state.maps_dict['Salary_map'])
381
+ freq_working['Proj Own'] = freq_working['Player'].map(st.session_state.maps_dict['Own_map']) / 100
382
  freq_working['Exposure'] = freq_working['Freq']/(1000)
383
  freq_working['Edge'] = freq_working['Exposure'] - freq_working['Proj Own']
384
+ freq_working['Team'] = freq_working['Player'].map(st.session_state.maps_dict['Team_map'])
385
  st.session_state.player_freq = freq_working.copy()
386
 
387
  if sim_site_var1 == 'Draftkings':
 
391
  center_working = pd.DataFrame(np.column_stack(np.unique(st.session_state.freq_copy.iloc[:,0:2].values, return_counts=True)),
392
  columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
393
  center_working['Freq'] = center_working['Freq'].astype(int)
394
+ center_working['Position'] = center_working['Player'].map(st.session_state.maps_dict['Pos_map'])
395
+ center_working['Salary'] = center_working['Player'].map(st.session_state.maps_dict['Salary_map'])
396
+ center_working['Proj Own'] = center_working['Player'].map(st.session_state.maps_dict['Own_map']) / 100
397
  center_working['Exposure'] = center_working['Freq']/(1000)
398
  center_working['Edge'] = center_working['Exposure'] - center_working['Proj Own']
399
+ center_working['Team'] = center_working['Player'].map(st.session_state.maps_dict['Team_map'])
400
  st.session_state.center_freq = center_working.copy()
401
 
402
  if sim_site_var1 == 'Draftkings':
 
406
  wing_working = pd.DataFrame(np.column_stack(np.unique(st.session_state.freq_copy.iloc[:,2:4].values, return_counts=True)),
407
  columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
408
  wing_working['Freq'] = wing_working['Freq'].astype(int)
409
+ wing_working['Position'] = wing_working['Player'].map(st.session_state.maps_dict['Pos_map'])
410
+ wing_working['Salary'] = wing_working['Player'].map(st.session_state.maps_dict['Salary_map'])
411
+ wing_working['Proj Own'] = wing_working['Player'].map(st.session_state.maps_dict['Own_map']) / 100
412
  wing_working['Exposure'] = wing_working['Freq']/(1000)
413
  wing_working['Edge'] = wing_working['Exposure'] - wing_working['Proj Own']
414
+ wing_working['Team'] = wing_working['Player'].map(st.session_state.maps_dict['Team_map'])
415
  st.session_state.wing_freq = wing_working.copy()
416
 
417
  if sim_site_var1 == 'Draftkings':
 
421
  dmen_working = pd.DataFrame(np.column_stack(np.unique(st.session_state.freq_copy.iloc[:,4:6].values, return_counts=True)),
422
  columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
423
  dmen_working['Freq'] = dmen_working['Freq'].astype(int)
424
+ dmen_working['Position'] = dmen_working['Player'].map(st.session_state.maps_dict['Pos_map'])
425
+ dmen_working['Salary'] = dmen_working['Player'].map(st.session_state.maps_dict['Salary_map'])
426
+ dmen_working['Proj Own'] = dmen_working['Player'].map(st.session_state.maps_dict['Own_map']) / 100
427
  dmen_working['Exposure'] = dmen_working['Freq']/(1000)
428
  dmen_working['Edge'] = dmen_working['Exposure'] - dmen_working['Proj Own']
429
+ dmen_working['Team'] = dmen_working['Player'].map(st.session_state.maps_dict['Team_map'])
430
  st.session_state.dmen_freq = dmen_working.copy()
431
 
432
  if sim_site_var1 == 'Draftkings':
 
436
  flex_working = pd.DataFrame(np.column_stack(np.unique(st.session_state.freq_copy.iloc[:,6:8].values, return_counts=True)),
437
  columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
438
  flex_working['Freq'] = flex_working['Freq'].astype(int)
439
+ flex_working['Position'] = flex_working['Player'].map(st.session_state.maps_dict['Pos_map'])
440
+ flex_working['Salary'] = flex_working['Player'].map(st.session_state.maps_dict['Salary_map'])
441
+ flex_working['Proj Own'] = flex_working['Player'].map(st.session_state.maps_dict['Own_map']) / 100
442
  flex_working['Exposure'] = flex_working['Freq']/(1000)
443
  flex_working['Edge'] = flex_working['Exposure'] - flex_working['Proj Own']
444
+ flex_working['Team'] = flex_working['Player'].map(st.session_state.maps_dict['Team_map'])
445
  st.session_state.flex_freq = flex_working.copy()
446
 
447
  if sim_site_var1 == 'Draftkings':
 
451
  goalie_working = pd.DataFrame(np.column_stack(np.unique(st.session_state.freq_copy.iloc[:,8:9].values, return_counts=True)),
452
  columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
453
  goalie_working['Freq'] = goalie_working['Freq'].astype(int)
454
+ goalie_working['Position'] = goalie_working['Player'].map(st.session_state.maps_dict['Pos_map'])
455
+ goalie_working['Salary'] = goalie_working['Player'].map(st.session_state.maps_dict['Salary_map'])
456
+ goalie_working['Proj Own'] = goalie_working['Player'].map(st.session_state.maps_dict['Own_map']) / 100
457
  goalie_working['Exposure'] = goalie_working['Freq']/(1000)
458
  goalie_working['Edge'] = goalie_working['Exposure'] - goalie_working['Proj Own']
459
+ goalie_working['Team'] = goalie_working['Player'].map(st.session_state.maps_dict['Team_map'])
460
  st.session_state.goalie_freq = goalie_working.copy()
461
 
462
  if sim_site_var1 == 'Draftkings':
 
488
  st.dataframe(st.session_state.Sim_Winner_Display.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
489
  if 'Sim_Winner_Export' in st.session_state:
490
  st.download_button(
491
+
492
  label="Export Full Frame",
493
  data=st.session_state.Sim_Winner_Export.to_csv().encode('utf-8'),
494
  file_name='MLB_consim_export.csv',
495
  mime='text/csv',
496
  )
497
+ tab1, tab2, tab3 = st.tabs(['Winning Frame Statistics', 'Flex Exposure Statistics', 'Stack Type Statistics'])
498
 
499
  with tab1:
500
  if 'Sim_Winner_Display' in st.session_state:
 
541
  st.dataframe(summary_df.style.format({
542
  'Salary': '{:.2f}',
543
  'Proj': '{:.2f}',
544
+ 'Own': '{:.2f}',
545
  'Fantasy': '{:.2f}',
546
  'GPP_Proj': '{:.2f}'
547
  }).background_gradient(cmap='RdYlGn', axis=0, subset=['Salary', 'Proj', 'Own', 'Fantasy', 'GPP_Proj']), use_container_width=True)
 
549
  with tab2:
550
  if 'Sim_Winner_Display' in st.session_state:
551
  # Apply position mapping to FLEX column
552
+ flex_positions = st.session_state.freq_copy['FLEX'].map(st.session_state.maps_dict['Pos_map'])
553
 
554
  # Count occurrences of each position in FLEX
555
  flex_counts = flex_positions.value_counts()
 
573
  st.dataframe(flex_summary.style.format({
574
  'Count': '{:.0f}',
575
  'Avg Proj': '{:.2f}',
576
+ 'Avg Own': '{:.2f}',
577
  'Avg Fantasy': '{:.2f}',
578
  'Avg GPP_Proj': '{:.2f}'
579
  }).background_gradient(cmap='RdYlGn', axis=0, subset=['Count', 'Avg Proj', 'Avg Own', 'Avg Fantasy', 'Avg GPP_Proj']), use_container_width=True)
580
+ else:
581
+ st.write("Simulation data or position mapping not available.")
582
+
583
+ with tab3:
584
+ if 'Sim_Winner_Display' in st.session_state:
585
+ # Apply position mapping to FLEX column
586
+ stack_counts = st.session_state.freq_copy['Team_count'].value_counts()
587
+
588
+ # Calculate average statistics for each stack size
589
+ stack_stats = st.session_state.freq_copy.groupby('Team_count').agg({
590
+ 'proj': 'mean',
591
+ 'Own': 'mean',
592
+ 'Fantasy': 'mean',
593
+ 'GPP_Proj': 'mean'
594
+ })
595
+
596
+ # Combine counts and average statistics
597
+ stack_summary = pd.concat([stack_counts, stack_stats], axis=1)
598
+ stack_summary.columns = ['Count', 'Avg Proj', 'Avg Own', 'Avg Fantasy', 'Avg GPP_Proj']
599
+ stack_summary = stack_summary.reset_index()
600
+ stack_summary.columns = ['Position', 'Count', 'Avg Proj', 'Avg Own', 'Avg Fantasy', 'Avg GPP_Proj']
601
 
602
+ # Display the summary dataframe
603
+ st.subheader("Stack Type Statistics")
604
+ st.dataframe(stack_summary.style.format({
605
+ 'Count': '{:.0f}',
606
+ 'Avg Proj': '{:.2f}',
607
+ 'Avg Own': '{:.2f}',
608
+ 'Avg Fantasy': '{:.2f}',
609
+ 'Avg GPP_Proj': '{:.2f}'
610
+ }).background_gradient(cmap='RdYlGn', axis=0, subset=['Count', 'Avg Proj', 'Avg Own', 'Avg Fantasy', 'Avg GPP_Proj']), use_container_width=True)
611
  else:
612
  st.write("Simulation data or position mapping not available.")
613
+
614
+
615
  with st.container():
616
  tab1, tab2, tab3, tab4, tab5, tab6, tab7 = st.tabs(['Overall Exposures', 'Center Exposures', 'Wing Exposures', 'Defense Exposures', 'Flex Exposures', 'Goalie Exposures', 'Team Exposures'])
617
  with tab1: