Spaces:
Sleeping
Sleeping
James McCool
commited on
Commit
·
158eaa8
1
Parent(s):
2e3cd9d
Add exposure management feature in app.py and implement exposure_spread function
Browse files- Introduced a new exposure management section in the app interface, allowing users to set target exposure for specific players.
- Added the exposure_spread function to adjust player exposure in lineups based on user-defined targets, enhancing lineup optimization.
- Updated session state handling to ensure proper data flow and management during exposure adjustments.
- app.py +12 -0
- global_func/exposure_spread.py +44 -0
app.py
CHANGED
|
@@ -25,6 +25,7 @@ from global_func.volatility_preset import volatility_preset
|
|
| 25 |
from global_func.reduce_volatility_preset import reduce_volatility_preset
|
| 26 |
from global_func.analyze_player_combos import analyze_player_combos
|
| 27 |
from global_func.stratification_function import stratification_function
|
|
|
|
| 28 |
|
| 29 |
freq_format = {'Finish_percentile': '{:.2%}', 'Lineup Edge': '{:.2%}', 'Win%': '{:.2%}'}
|
| 30 |
stacking_sports = ['MLB', 'NHL', 'NFL']
|
|
@@ -1147,6 +1148,17 @@ with tab2:
|
|
| 1147 |
parsed_frame = stratification_function(st.session_state['working_frame'], lineup_target, excluded_cols, sport_var, sorting_choice)
|
| 1148 |
st.session_state['working_frame'] = parsed_frame.reset_index(drop=True)
|
| 1149 |
st.session_state['export_merge'] = st.session_state['working_frame'].copy()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1150 |
with st.container():
|
| 1151 |
if 'export_base' not in st.session_state:
|
| 1152 |
st.session_state['export_base'] = pd.DataFrame(columns=st.session_state['working_frame'].columns)
|
|
|
|
| 25 |
from global_func.reduce_volatility_preset import reduce_volatility_preset
|
| 26 |
from global_func.analyze_player_combos import analyze_player_combos
|
| 27 |
from global_func.stratification_function import stratification_function
|
| 28 |
+
from global_func.exposure_spread import exposure_spread
|
| 29 |
|
| 30 |
freq_format = {'Finish_percentile': '{:.2%}', 'Lineup Edge': '{:.2%}', 'Win%': '{:.2%}'}
|
| 31 |
stacking_sports = ['MLB', 'NHL', 'NFL']
|
|
|
|
| 1148 |
parsed_frame = stratification_function(st.session_state['working_frame'], lineup_target, excluded_cols, sport_var, sorting_choice)
|
| 1149 |
st.session_state['working_frame'] = parsed_frame.reset_index(drop=True)
|
| 1150 |
st.session_state['export_merge'] = st.session_state['working_frame'].copy()
|
| 1151 |
+
with st.expander('Exposure Management'):
|
| 1152 |
+
with st.form(key='Exposures'):
|
| 1153 |
+
exposure_player = st.selectbox("Player", options=sorted(list(player_names)), default=[])
|
| 1154 |
+
exposure_target = st.number_input("Target Exposure", value=.25, min_value=0.0, max_value=1.0, step=0.01)
|
| 1155 |
+
exposure_stack_bool = st.selectbox("Maintain Stacks?", options=['Yes', 'No'], index=0)
|
| 1156 |
+
submitted = st.form_submit_button("Submit")
|
| 1157 |
+
if submitted:
|
| 1158 |
+
st.session_state['settings_base'] = False
|
| 1159 |
+
parsed_frame = exposure_spread(st.session_state['working_frame'], exposure_player, exposure_target, exposure_stack_bool, st.session_state['projections_df'])
|
| 1160 |
+
st.session_state['working_frame'] = parsed_frame.reset_index(drop=True)
|
| 1161 |
+
st.session_state['export_merge'] = st.session_state['working_frame'].copy()
|
| 1162 |
with st.container():
|
| 1163 |
if 'export_base' not in st.session_state:
|
| 1164 |
st.session_state['export_base'] = pd.DataFrame(columns=st.session_state['working_frame'].columns)
|
global_func/exposure_spread.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import random
|
| 2 |
+
|
| 3 |
+
#### Goal is to choose a player and adjust the amount of lineups that have them
|
| 4 |
+
#### First thing you need to do is find comparable players in the projections, so any player in the projections that is within $500 of the player and within 10% of the projection
|
| 5 |
+
#### Take that list of players and create a list that can be accessed for random insertion into the portfolio
|
| 6 |
+
#### Find the player and the amount of rows that contain them and then find an exposure rate which is the percentage of total rows
|
| 7 |
+
#### Use the exposure target argument and try to replace the player from as many rows as necessary to be at or just under the target
|
| 8 |
+
|
| 9 |
+
def exposure_spread(working_frame, exposure_player, exposure_target, exposure_stack_bool, projections_df):
|
| 10 |
+
# Find comparable players in the projections
|
| 11 |
+
comparable_players = projections_df[projections_df['player_names'] == exposure_player]
|
| 12 |
+
comp_salary_high = comparable_players['salary']
|
| 13 |
+
comp_salary_low = comparable_players['salary'] - 500
|
| 14 |
+
comp_projection_high = comparable_players['Projection']
|
| 15 |
+
comp_projection_low = comparable_players['Projection'] - (comparable_players['Projection'] * .9)
|
| 16 |
+
|
| 17 |
+
comparable_players = projections_df[
|
| 18 |
+
(projections_df['salary'] >= comp_salary_low) &
|
| 19 |
+
(projections_df['salary'] <= comp_salary_high) &
|
| 20 |
+
(projections_df['Projection'] >= comp_projection_low) &
|
| 21 |
+
(projections_df['Projection'] <= comp_projection_high)
|
| 22 |
+
]
|
| 23 |
+
|
| 24 |
+
# Create a list of comparable players
|
| 25 |
+
comparable_player_list = comparable_players['Name'].tolist()
|
| 26 |
+
|
| 27 |
+
# find the exposure rate of the player in the working frame
|
| 28 |
+
player_mask = working_frame[working_frame.columns].apply(
|
| 29 |
+
lambda row: exposure_player in list(row), axis=1
|
| 30 |
+
)
|
| 31 |
+
player_exposure = player_mask.sum() / len(working_frame)
|
| 32 |
+
|
| 33 |
+
# find the number of lineups that need to be removed to reach the target exposure
|
| 34 |
+
lineups_to_remove = (player_exposure - exposure_target) * len(working_frame)
|
| 35 |
+
|
| 36 |
+
# isolate the rows that contain the player
|
| 37 |
+
player_rows = working_frame[player_mask]
|
| 38 |
+
|
| 39 |
+
# for each row, replace with random choice from comparable player list
|
| 40 |
+
for row in player_rows.index:
|
| 41 |
+
working_frame.at[row, 'player_names'] = random.choice(comparable_player_list)
|
| 42 |
+
|
| 43 |
+
return working_frame
|
| 44 |
+
|